diff --git a/.gitattributes b/.gitattributes index 18415085c..f89d1fc6f 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,2 @@ *.[ch] whitespace=tab-in-indent,trailing-space +test/dmidecode-dumps/*.bin binary diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 5db53a457..ca8213863 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -7,15 +7,20 @@ about: A report of an error in a recent systemd version **systemd version the issue has been seen with** > … - - + + + + **Used distribution** > … **Linux kernel version used** (`uname -a`) - > … + + > `…` **CPU architecture issue was seen on** > … @@ -28,3 +33,15 @@ about: A report of an error in a recent systemd version **Steps to reproduce the problem** > … + +**Additional program output to the terminal or log subsystem illustrating the issue** + + +```text +… +``` diff --git a/.github/ISSUE_TEMPLATE/Feature_request.md b/.github/ISSUE_TEMPLATE/Feature_request.md index c56aae873..3c53d728d 100644 --- a/.github/ISSUE_TEMPLATE/Feature_request.md +++ b/.github/ISSUE_TEMPLATE/Feature_request.md @@ -12,3 +12,6 @@ A clear and concise description of what you want to happen. **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered. + +**The systemd version you checked that didn't have the feature you are asking for** + diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..773d57500 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,38 @@ +hwdb: + - hwdb.d/**/* +units: + - units/**/* +documentation: + - NEWS + - docs/* +network: + - src/libsystemd-network/**/* + - src/network/**/* +udev: + - src/udev/**/* + - src/libudev/* +selinux: + - '**/*selinux*' +apparmor: + - '**/*apparmor*' +meson: + - meson_option.txt +mkosi: + - .mkosi/* + - mkosi.build +busctl: + - src/busctl/* +systemctl: + - src/systemctl/* +journal: + - src/journal/* +journal-remote: + - src/journal-remote/* +portable: + - src/portable/**/* +resolve: + - src/resolve/* +timedate: + - src/timedate/* +timesync: + - src/timesync/* diff --git a/.github/workflows/ubuntu-build-check.sh b/.github/workflows/build_test.sh similarity index 93% rename from .github/workflows/ubuntu-build-check.sh rename to .github/workflows/build_test.sh index d4f110653..8ad7e7679 100755 --- a/.github/workflows/ubuntu-build-check.sh +++ b/.github/workflows/build_test.sh @@ -12,6 +12,7 @@ ARGS=( "--optimization=s" "--optimization=3 -Db_lto=true" "--optimization=3 -Db_lto=false" + "--optimization=3 -Ddns-over-tls=openssl" "-Db_ndebug=true" ) PACKAGES=( @@ -37,6 +38,7 @@ PACKAGES=( libpwquality-dev libqrencode-dev libssl-dev + libtss2-dev libxkbcommon-dev libxtables-dev libzstd-dev @@ -79,7 +81,7 @@ elif [[ "$COMPILER" == gcc ]]; then AR="gcc-ar-$COMPILER_VERSION" # Latest gcc stack deb packages provided by # https://launchpad.net/~ubuntu-toolchain-r/+archive/ubuntu/test - sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test + add-apt-repository -y ppa:ubuntu-toolchain-r/test PACKAGES+=(gcc-$COMPILER_VERSION) else fatal "Unknown compiler: $COMPILER" @@ -98,6 +100,8 @@ pip3 install --user -U meson ninja export PATH="$HOME/.local/bin:$PATH" $CC --version +meson --version +ninja --version for args in "${ARGS[@]}"; do SECONDS=0 @@ -107,9 +111,8 @@ for args in "${ARGS[@]}"; do fatal "meson failed with $args" fi - ninja --version - if ! ninja -C build; then - fatal "ninja failed with $args" + if ! meson compile -C build; then + fatal "'meson compile' failed with $args" fi git clean -dxf diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml index c9aec779c..dc136a5aa 100644 --- a/.github/workflows/build_test.yml +++ b/.github/workflows/build_test.yml @@ -21,9 +21,10 @@ jobs: - { COMPILER: "gcc", COMPILER_VERSION: "10" } - { COMPILER: "clang", COMPILER_VERSION: "10" } - { COMPILER: "clang", COMPILER_VERSION: "11" } + - { COMPILER: "clang", COMPILER_VERSION: "12" } env: ${{ matrix.env }} steps: - name: Repository checkout uses: actions/checkout@v1 - name: Build check (${{ env.COMPILER }}-${{ env.COMPILER_VERSION }}) - run: sudo -E .github/workflows/ubuntu-build-check.sh + run: sudo -E .github/workflows/build_test.sh diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml index ed6db50d9..14d81a67f 100644 --- a/.github/workflows/cifuzz.yml +++ b/.github/workflows/cifuzz.yml @@ -14,7 +14,7 @@ on: - 'tools/oss-fuzz.sh' push: branches: - - master + - main jobs: Fuzzing: runs-on: ubuntu-latest diff --git a/.github/workflows/coverity.yml b/.github/workflows/coverity.yml new file mode 100644 index 000000000..a0eb0f01f --- /dev/null +++ b/.github/workflows/coverity.yml @@ -0,0 +1,39 @@ +--- +# vi: ts=2 sw=2 et: +# +name: Coverity + +on: + schedule: + # Run Coverity daily at midnight + - cron: '0 0 * * *' + +jobs: + build: + runs-on: ubuntu-20.04 + if: github.repository == 'systemd/systemd' + env: + COVERITY_SCAN_BRANCH_PATTERN: "${{ github.ref}}" + COVERITY_SCAN_NOTIFICATION_EMAIL: "" + COVERITY_SCAN_PROJECT_NAME: "${{ github.repository }}" + # Set in repo settings -> secrets -> repository secrets + COVERITY_SCAN_TOKEN: "${{ secrets.COVERITY_SCAN_TOKEN }}" + CURRENT_REF: "${{ github.ref }}" + steps: + - name: Repository checkout + uses: actions/checkout@v1 + # https://docs.github.com/en/free-pro-team@latest/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + - name: Set the $COVERITY_SCAN_NOTIFICATION_EMAIL env variable + run: echo "COVERITY_SCAN_NOTIFICATION_EMAIL=$(git log -1 ${{ github.sha }} --pretty=\"%aE\")" >> $GITHUB_ENV + - name: Install Coverity tools + run: tools/get-coverity.sh + # Reuse the setup phase of the unit test script to avoid code duplication + - name: Install build dependencies + run: sudo -E .github/workflows/unit_tests.sh SETUP + # Preconfigure with meson to prevent Coverity from capturing meson metadata + - name: Preconfigure the build directory + run: meson cov-build -Dman=false + - name: Build + run: tools/coverity.sh build + - name: Upload the results + run: tools/coverity.sh upload diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000..76d67a3a5 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,13 @@ +name: "Pull Request Labeler" +on: +- pull_request_target + +jobs: + triage: + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@main + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/labeler.yml + sync-labels: "" # This is a workaround for issue 18671 diff --git a/.github/workflows/mkosi.yml b/.github/workflows/mkosi.yml new file mode 100644 index 000000000..2c9630dec --- /dev/null +++ b/.github/workflows/mkosi.yml @@ -0,0 +1,55 @@ +name: mkosi + +# Simple boot tests that build and boot the mkosi images generated by the mkosi config files in .mkosi. + +on: + push: + branches: + - main + pull_request: + branches: + - main + +jobs: + ci: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + distro: + - arch + - debian + - ubuntu + - fedora + + steps: + - uses: actions/checkout@v2 + - uses: systemd/mkosi@v9 + + - name: Install + run: sudo apt-get update && sudo apt-get install --no-install-recommends python3-pexpect + + - name: Symlink + run: ln -s .mkosi/mkosi.${{ matrix.distro }} mkosi.default + + # Ubuntu's systemd-nspawn doesn't support faccessat2() syscall, which is + # required, since current Arch's glibc implements faccessat() via faccessat2(). + - name: Update systemd-nspawn + if: ${{ matrix.distro == 'arch' }} + run: | + echo "deb-src http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list + sudo apt update + sudo apt build-dep systemd + meson build + ninja -C build + sudo ln -svf $PWD/build/systemd-nspawn `which systemd-nspawn` + systemd-nspawn --version + + - name: Build ${{ matrix.distro }} + run: sudo python3 -m mkosi --password= --qemu-headless build + + - name: Boot ${{ matrix.distro }} systemd-nspawn + run: sudo ./.github/workflows/test_mkosi_boot.py python3 -m mkosi --password= --qemu-headless boot + + - name: Boot ${{ matrix.distro }} QEMU + run: sudo ./.github/workflows/test_mkosi_boot.py python3 -m mkosi --password= --qemu-headless qemu diff --git a/.github/workflows/test_mkosi_boot.py b/.github/workflows/test_mkosi_boot.py new file mode 100755 index 000000000..37904eb05 --- /dev/null +++ b/.github/workflows/test_mkosi_boot.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +import pexpect +import sys + + +def run() -> None: + p = pexpect.spawnu(" ".join(sys.argv[1:]), logfile=sys.stdout, timeout=300) + + p.expect("login:") + p.sendline("root") + + p.expect("#") + p.sendline("systemctl poweroff") + + p.expect(pexpect.EOF) + + +try: + run() +except pexpect.EOF: + print("UNEXPECTED EOF") + sys.exit(1) +except pexpect.TIMEOUT: + print("TIMED OUT") + sys.exit(1) diff --git a/.github/workflows/unit_tests.sh b/.github/workflows/unit_tests.sh new file mode 100755 index 000000000..d48c4b4bf --- /dev/null +++ b/.github/workflows/unit_tests.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP}) +RELEASE="$(lsb_release -cs)" +ADDITIONAL_DEPS=( + clang + expect + fdisk + libfdisk-dev + libfido2-dev + libp11-kit-dev + libpwquality-dev + libqrencode-dev + libssl-dev + libtss2-dev + libzstd-dev + perl + python3-libevdev + python3-pyparsing + zstd +) + +function info() { + echo -e "\033[33;1m$1\033[0m" +} + +set -ex + +for phase in "${PHASES[@]}"; do + case $phase in + SETUP) + info "Setup phase" + bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list" + # PPA with some newer build dependencies + add-apt-repository -y ppa:upstream-systemd-ci/systemd-ci + apt-get -y update + apt-get -y build-dep systemd + apt-get -y install "${ADDITIONAL_DEPS[@]}" + ;; + RUN|RUN_GCC|RUN_CLANG) + if [[ "$phase" = "RUN_CLANG" ]]; then + export CC=clang + export CXX=clang++ + fi + meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true -Dman=true build + ninja -C build -v + meson test -C build --print-errorlogs + ;; + RUN_ASAN_UBSAN|RUN_GCC_ASAN_UBSAN|RUN_CLANG_ASAN_UBSAN) + MESON_ARGS=(--optimization=1) + + if [[ "$phase" = "RUN_CLANG_ASAN_UBSAN" ]]; then + export CC=clang + export CXX=clang++ + # Build fuzzer regression tests only with clang (for now), + # see: https://github.com/systemd/systemd/pull/15886#issuecomment-632689604 + # -Db_lundef=false: See https://github.com/mesonbuild/meson/issues/764 + MESON_ARGS+=(-Db_lundef=false -Dfuzz-tests=true) + fi + meson --werror -Dtests=unsafe -Db_sanitize=address,undefined "${MESON_ARGS[@]}" build + ninja -C build -v + + export ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 + # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb. + export UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 + + # FIXME + # For some strange reason the GH Actions VM stops responding after + # executing first ~150 tests, _unless_ there's something producing + # output (either running `meson test` in verbose mode, or something + # else in background). Despite my efforts so far I haven't been able + # to identify the culprit (since the issue is not reproducible + # during debugging, wonderful), so let's at least keep a workaround + # here to make the builds stable for the time being. + (set +x; while :; do echo -ne "\n[WATCHDOG] $(date)\n"; sleep 30; done) & + meson test --timeout-multiplier=3 -C build --print-errorlogs + ;; + CLEANUP) + info "Cleanup phase" + ;; + *) + echo >&2 "Unknown phase '$phase'" + exit 1 + esac +done diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml new file mode 100644 index 000000000..ca1e6e0c3 --- /dev/null +++ b/.github/workflows/unit_tests.yml @@ -0,0 +1,23 @@ +--- +# vi: ts=2 sw=2 et: +# +name: Unit tests +on: + pull_request: + branches: + - main + +jobs: + build: + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + run_phase: [GCC, GCC_ASAN_UBSAN, CLANG, CLANG_ASAN_UBSAN] + steps: + - name: Repository checkout + uses: actions/checkout@v1 + - name: Install build dependencies + run: sudo -E .github/workflows/unit_tests.sh SETUP + - name: Build & test (${{ matrix.run_phase }}) + run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }} diff --git a/.gitignore b/.gitignore index 0b2092d74..d6f6caca5 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,6 @@ __pycache__/ /mkosi.builddir/ /mkosi.output/ /mkosi.default +mkosi.default.d/* +!mkosi.default.d/10-systemd.conf /tags diff --git a/.mailmap b/.mailmap index 662ea13a6..7abaedc87 100644 --- a/.mailmap +++ b/.mailmap @@ -115,12 +115,14 @@ Michael Biebl Michael Buesch Michael Hoy Michael Olbrich +Michael Trapp Michal Soltys Michal Suchanek Michal Suchanek Michal Sekletár Michał Szczepański Michel Kraus <27o@users.noreply.github.com> +Michele Guerini Rocco Miklos Vajna Milan Pässler Neil Brown @@ -209,3 +211,4 @@ Andrey Yashkin <38919268+AndreyYashkin@users.noreply.github.com> Ronald Tschalär Jay Burger Yi Gao +Weblate diff --git a/.mkosi/mkosi.arch b/.mkosi/mkosi.arch index c50ee4923..6192c1910 100644 --- a/.mkosi/mkosi.arch +++ b/.mkosi/mkosi.arch @@ -8,15 +8,7 @@ [Distribution] Distribution=arch -[Output] -Format=raw_btrfs -Bootable=yes - -[Partitions] -RootSize=3G - [Packages] -Cache=/var/cache/pacman/pkg/ BuildPackages= acl bzip2 @@ -54,5 +46,9 @@ BuildPackages= zstd Packages= + gdb libidn2 + nano qrencode + strace + vi diff --git a/.mkosi/mkosi.debian b/.mkosi/mkosi.debian index ba9077eaa..b1173a67d 100644 --- a/.mkosi/mkosi.debian +++ b/.mkosi/mkosi.debian @@ -7,13 +7,6 @@ Distribution=debian Release=unstable -[Output] -Format=raw_btrfs -Bootable=yes - -[Partitions] -RootSize=2G - [Packages] BuildPackages= acl @@ -24,7 +17,6 @@ BuildPackages= git gnu-efi gperf - libiptc-dev libacl1-dev libaudit-dev libblkid-dev @@ -35,19 +27,23 @@ BuildPackages= libdbus-1-dev libdw-dev libfdisk-dev + libfido2-dev libgcrypt20-dev libgnutls28-dev libidn2-0-dev + libiptc-dev libkmod-dev - liblzma-dev liblz4-dev liblz4-tool + liblzma-dev libmicrohttpd-dev libmount-dev libpam0g-dev libqrencode-dev libseccomp-dev libsmartcols-dev + libssl-dev + libtss2-dev libxkbcommon-dev libzstd-dev m4 @@ -62,6 +58,14 @@ BuildPackages= zstd Packages= - libqrencode4 - locales + gdb + libfdisk1 + libfido2-1 libidn2-0 + libqrencode4 + # We pull in the -dev package here, since the binary ones appear to change names too often, and the -dev package pulls the right deps in automatically + libtss2-dev + locales + nano + strace + vim-tiny diff --git a/.mkosi/mkosi.fedora b/.mkosi/mkosi.fedora index a3e68acdf..e24507ad1 100644 --- a/.mkosi/mkosi.fedora +++ b/.mkosi/mkosi.fedora @@ -7,13 +7,6 @@ Distribution=fedora Release=33 -[Output] -Format=gpt_ext4 -Bootable=yes - -[Partitions] -RootSize=3G - [Packages] BuildPackages= audit-libs-devel @@ -66,17 +59,20 @@ BuildPackages= python3-lxml qrencode-devel rpm + tpm2-tss-devel tree valgrind-devel xz-devel zstd Packages= + gdb # libfido2 + libzstd can be dropped once the Fedora RPM gets a dependency on them libfido2 libzstd + nano # procps-ng provides a set of useful utilies (ps, free, etc) procps-ng - -BuildDirectory=mkosi.builddir -Cache=mkosi.cache + strace + tpm2-tss + vi diff --git a/.mkosi/mkosi.opensuse b/.mkosi/mkosi.opensuse index 9f3abbc74..15f70a435 100644 --- a/.mkosi/mkosi.opensuse +++ b/.mkosi/mkosi.opensuse @@ -7,17 +7,7 @@ Distribution=opensuse Release=tumbleweed -[Output] -Format=raw_btrfs -Bootable=yes - -[Partitions] -RootSize=3G - [Packages] -# Uncomment to share system RPM cache (works only with Tumbleweed) -#Cache=/var/cache/zypp/packages -BuildDirectory=mkosi.builddir BuildPackages= docbook-xsl-stylesheets fdupes @@ -62,6 +52,7 @@ BuildPackages= timezone Packages= + gdb # brought in via meson->python3 libp11-kit0 # --bootable=no @@ -75,4 +66,7 @@ Packages= libqrencode4 libseccomp2 pam + nano + strace util-linux + vi diff --git a/.mkosi/mkosi.ubuntu b/.mkosi/mkosi.ubuntu index baf4daec4..dd1036fc8 100644 --- a/.mkosi/mkosi.ubuntu +++ b/.mkosi/mkosi.ubuntu @@ -8,13 +8,6 @@ Distribution=ubuntu Release=focal Repositories=main,universe -[Output] -Format=raw_btrfs -Bootable=no - -[Partitions] -RootSize=2G - [Packages] BuildPackages= acl @@ -35,6 +28,7 @@ BuildPackages= libdbus-1-dev libdw-dev libfdisk-dev + libfido2-dev libgcrypt20-dev libgnutls28-dev libidn2-0-dev @@ -50,6 +44,8 @@ BuildPackages= libqrencode-dev libseccomp-dev libsmartcols-dev + libssl-dev + libtss2-dev libxkbcommon-dev libxtables-dev libzstd-dev @@ -66,6 +62,13 @@ BuildPackages= zstd Packages= - libqrencode4 - locales + gdb + libfido2-1 libidn2-0 + libqrencode4 + # We pull in the -dev package here, since the binary ones appear to change names too often, and the -dev package pulls the right deps in automatically + libtss2-dev + locales + nano + strace + vim-tiny diff --git a/.packit.yml b/.packit.yml new file mode 100644 index 000000000..75f9d3abc --- /dev/null +++ b/.packit.yml @@ -0,0 +1,40 @@ +--- +# vi:ts=2 sw=2 et: +# +# Docs: https://packit.dev/docs/ + +specfile_path: .packit_rpm/systemd.spec +synced_files: + - .packit.yaml + - src: .packit_rpm/systemd.spec + dest: systemd.spec +upstream_package_name: systemd +downstream_package_name: systemd +# `git describe` returns in systemd's case 'v245-xxx' which breaks RPM version +# detection (that expects 245-xxxx'). Let's tweak the version string accordingly +upstream_tag_template: "v{version}" + +actions: + post-upstream-clone: + # Use the Fedora Rawhide specfile + - "git clone https://src.fedoraproject.org/rpms/systemd .packit_rpm --depth=1" + # Drop backported patches from the specfile, but keep the downstream-only ones + # - Patch0000-0499: backported patches from upstream + # - Patch0500-9999: downstream-only patches + - "sed -ri '/^Patch0[0-4]?[0-9]{0,2}\\:.+\\.patch/d' .packit_rpm/systemd.spec" + # Build the RPM with --werror. Even though --werror doesn't work in all + # cases (see [0]), we can't use -Dc_args=/-Dcpp_args= here because of the + # RPM hardening macros, that use $CFLAGS/$CPPFLAGS (see [1]). + # + # [0] https://github.com/mesonbuild/meson/issues/7360 + # [1] https://github.com/systemd/systemd/pull/18908#issuecomment-792250110 + - 'sed -i "/^CONFIGURE_OPTS=(/a--werror" .packit_rpm/systemd.spec' + +jobs: +- job: copr_build + trigger: pull_request + metadata: + targets: + - fedora-rawhide-aarch64 + - fedora-rawhide-i386 + - fedora-rawhide-x86_64 diff --git a/semaphoreci/semaphore-runner.sh b/.semaphore/semaphore-runner.sh similarity index 100% rename from semaphoreci/semaphore-runner.sh rename to .semaphore/semaphore-runner.sh diff --git a/.semaphore/semaphore.yml b/.semaphore/semaphore.yml new file mode 100644 index 000000000..06f162007 --- /dev/null +++ b/.semaphore/semaphore.yml @@ -0,0 +1,27 @@ +--- +# vi: ts=2 sw=2 et: + +version: v1.0 +name: Debian autopkgtest (LXC) +agent: + machine: + type: e1-standard-2 + os_image: ubuntu1804 + +# Cancel any running or queued job for the same ref +auto_cancel: + running: + when: "true" + +execution_time_limit: + hours: 1 + +blocks: + - name: "Setup & test" + task: + jobs: + - name: "Install dependencies & run the Debian autopkgtest" + commands: + - checkout --use-cache + - .semaphore/semaphore-runner.sh SETUP + - .semaphore/semaphore-runner.sh RUN diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 50f8e6a23..000000000 --- a/.travis.yml +++ /dev/null @@ -1,84 +0,0 @@ ---- -# vi: ts=2 sw=2 et: - -language: bash -dist: bionic -services: - - 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" - 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: - # '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 - -# 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 - -# Inject another (single) job into the matrix for Coverity -jobs: - include: - - stage: Coverity - language: bash - env: - - FEDORA_RELEASE="31" - - TOOL_BASE="/var/tmp/coverity-scan-analysis" - - CONT_NAME="coverity-fedora-$FEDORA_RELEASE" - - DOCKER_EXEC="docker exec -ti $CONT_NAME" - - 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 diff --git a/Makefile b/Makefile index b7e13fba2..eeb0dbc62 100644 --- a/Makefile +++ b/Makefile @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + all: ninja -C build diff --git a/NEWS b/NEWS index 49e19cec2..52c646f86 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,485 @@ systemd System and Service Manager +CHANGES WITH 248: + + * A concept of system extension images is introduced. Such images may + be used to extend the /usr/ and /opt/ directory hierarchies at + runtime with additional files (even if the file system is read-only). + When a system extension image is activated, its /usr/ and /opt/ + hierarchies and os-release information are combined via overlayfs + with the file system hierarchy of the host OS. + + A new systemd-sysext tool can be used to merge, unmerge, list, and + refresh system extension hierarchies. See + https://www.freedesktop.org/software/systemd/man/systemd-sysext.html. + + The systemd-sysext.service automatically merges installed system + extensions during boot (before basic.target, but not in very early + boot, since various file systems have to be mounted first). + + The SYSEXT_LEVEL= field in os-release(5) may be used to specify the + supported system extension level. + + * A new ExtensionImages= unit setting can be used to apply the same + system extension image concept from systemd-sysext to the namespaced + file hierarchy of specific services, following the same rules and + constraints. + + * Support for a new special "root=tmpfs" kernel command-line option has + been added. When specified, a tmpfs is mounted on /, and mount.usr= + should be used to point to the operating system implementation. + + * A new configuration file /etc/veritytab may be used to configure + dm-verity integrity protection for block devices. Each line is in the + format "volume-name data-device hash-device roothash options", + similar to /etc/crypttab. + + * A new kernel command-line option systemd.verity.root_options= may be + used to configure dm-verity behaviour for the root device. + + * The key file specified in /etc/crypttab (the third field) may now + refer to an AF_UNIX/SOCK_STREAM socket in the file system. The key is + acquired by connecting to that socket and reading from it. This + allows the implementation of a service to provide key information + dynamically, at the moment when it is needed. + + * When the hostname is set explicitly to "localhost", systemd-hostnamed + will respect this. Previously such a setting would be mostly silently + ignored. The goal is to honour configuration as specified by the + user. + + * The fallback hostname that will be used by the system manager and + systemd-hostnamed can now be configured in two new ways: by setting + DEFAULT_HOSTNAME= in os-release(5), or by setting + $SYSTEMD_DEFAULT_HOSTNAME in the environment block. As before, it can + also be configured during compilation. The environment variable is + intended for testing and local overrides, the os-release(5) field is + intended to allow customization by different variants of a + distribution that share the same compiled packages. + + * The environment block of the manager itself may be configured through + a new ManagerEnvironment= setting in system.conf or user.conf. This + complements existing ways to set the environment block (the kernel + command line for the system manager, the inherited environment and + user@.service unit file settings for the user manager). + + * systemd-hostnamed now exports the default hostname and the source of + the configured hostname ("static", "transient", or "default") as + D-Bus properties. + + * systemd-hostnamed now exports the "HardwareVendor" and + "HardwareModel" D-Bus properties, which are supposed to contain a + pair of cleaned up, human readable strings describing the system's + vendor and model. It's typically sourced from the firmware's DMI + tables, but may be augmented from a new hwdb database. hostnamectl + shows this in the status output. + + * Support has been added to systemd-cryptsetup for extracting the + PKCS#11 token URI and encrypted key from the LUKS2 JSON embedded + metadata header. This allows the information how to open the + encrypted device to be embedded directly in the device and obviates + the need for configuration in an external file. + + * systemd-cryptsetup gained support for unlocking LUKS2 volumes using + TPM2 hardware, as well as FIDO2 security tokens (in addition to the + pre-existing support for PKCS#11 security tokens). + + * systemd-repart may enroll encrypted partitions using TPM2 + hardware. This may be useful for example to create an encrypted /var + partition bound to the machine on first boot. + + * A new systemd-cryptenroll tool has been added to enroll TPM2, FIDO2 + and PKCS#11 security tokens to LUKS volumes, list and destroy + them. See: + + http://0pointer.net/blog/unlocking-luks2-volumes-with-tpm2-fido2-pkcs11-security-hardware-on-systemd-248.html + + It also supports enrolling "recovery keys" and regular passphrases. + + * The libfido2 dependency is now based on dlopen(), so that the library + is used at runtime when installed, but is not a hard runtime + dependency. + + * systemd-cryptsetup gained support for two new options in + /etc/crypttab: "no-write-workqueue" and "no-read-workqueue" which + request synchronous processing of encryption/decryption IO. + + * The manager may be configured at compile time to use the fexecve() + instead of the execve() system call when spawning processes. Using + fexecve() closes a window between checking the security context of an + executable and spawning it, but unfortunately the kernel displays + stale information in the process' "comm" field, which impacts ps + output and such. + + * The configuration option -Dcompat-gateway-hostname has been dropped. + "_gateway" is now the only supported name. + + * The ConditionSecurity=tpm2 unit file setting may be used to check if + the system has at least one TPM2 (tpmrm class) device. + + * A new ConditionCPUFeature= has been added that may be used to + conditionalize units based on CPU features. For example, + ConditionCPUFeature=rdrand will condition a unit so that it is only + run when the system CPU supports the RDRAND opcode. + + * The existing ConditionControlGroupController= setting has been + extended with two new values "v1" and "v2". "v2" means that the + unified v2 cgroup hierarchy is used, and "v1" means that legacy v1 + hierarchy or the hybrid hierarchy are used. + + * A new PrivateIPC= setting on a unit file allows executed processes to + be moved into a private IPC namespace, with separate System V IPC + identifiers and POSIX message queues. + + A new IPCNamespacePath= allows the unit to be joined to an existing + IPC namespace. + + * The tables of system calls in seccomp filters are now automatically + generated from kernel lists exported on + https://fedora.juszkiewicz.com.pl/syscalls.html. + + The following architectures should now have complete lists: + alpha, arc, arm64, arm, i386, ia64, m68k, mips64n32, mips64, mipso32, + powerpc, powerpc64, s390, s390x, tilegx, sparc, x86_64, x32. + + * The MountAPIVFS= service file setting now additionally mounts a tmpfs + on /run/ if it is not already a mount point. A writable /run/ has + always been a requirement for a functioning system, but this was not + guaranteed when using a read-only image. + + Users can always specify BindPaths= or InaccessiblePaths= as + overrides, and they will take precedence. If the host's root mount + point is used, there is no change in behaviour. + + * New bind mounts and file system image mounts may be injected into the + mount namespace of a service (without restarting it). This is exposed + respectively as 'systemctl bind …' and + 'systemctl mount-image …'. + + * The StandardOutput= and StandardError= settings can now specify files + to be truncated for output (as "truncate:"). + + * The ExecPaths= and NoExecPaths= settings may be used to specify + noexec for parts of the file system. + + * sd-bus has a new function sd_bus_open_user_machine() to open a + connection to the session bus of a specific user in a local container + or on the local host. This is exposed in the existing -M switch to + systemctl and similar tools: + + systemctl --user -M lennart@foobar start foo + + This will connect to the user bus of a user "lennart" in container + "foobar". If no container name is specified, the specified user on + the host itself is connected to + + systemctl --user -M lennart@ start quux + + * sd-bus also gained a convenience function sd_bus_message_send() to + simplify invocations of sd_bus_send(), taking only a single + parameter: the message to send. + + * sd-event allows rate limits to be set on event sources, for dealing + with high-priority event sources that might starve out others. See + the new man page sd_event_source_set_ratelimit(3) for details. + + * systemd.link files gained a [Link] Promiscuous= switch, which allows + the device to be raised in promiscuous mode. + + New [Link] TransmitQueues= and ReceiveQueues= settings allow the + number of TX and RX queues to be configured. + + New [Link] TransmitQueueLength= setting allows the size of the TX + queue to be configured. + + New [Link] GenericSegmentOffloadMaxBytes= and + GenericSegmentOffloadMaxSegments= allow capping the packet size and + the number of segments accepted in Generic Segment Offload. + + * systemd-networkd gained support for the "B.A.T.M.A.N. advanced" + wireless routing protocol that operates on ISO/OSI Layer 2 only and + uses ethernet frames to route/bridge packets. This encompasses a new + "batadv" netdev Type=, a new [BatmanAdvanced] section with a bunch of + new settings in .netdev files, and a new BatmanAdvanced= setting in + .network files. + + * systemd.network files gained a [Network] RouteTable= configuration + switch to select the routing policy table. + + systemd.network files gained a [RoutingPolicyRule] Type= + configuration switch (one of "blackhole, "unreachable", "prohibit"). + + systemd.network files gained a [IPv6AcceptRA] RouteDenyList= and + RouteAllowList= settings to ignore/accept route advertisements from + routers matching specified prefixes. The DenyList= setting has been + renamed to PrefixDenyList= and a new PrefixAllowList= option has been + added. + + systemd.network files gained a [DHCPv6] UseAddress= setting to + optionally ignore the address provided in the lease. + + systemd.network files gained a [DHCPv6PrefixDelegation] + ManageTemporaryAddress= switch. + + systemd.network files gained a new ActivationPolicy= setting which + allows configuring how the UP state of an interface shall be managed, + i.e. whether the interface is always upped, always downed, or may be + upped/downed by the user using "ip link set dev". + + * The default for the Broadcast= setting in .network files has slightly + changed: the broadcast address will not be configured for wireguard + devices. + + * systemd.netdev files gained a [VLAN] Protocol=, IngressQOSMaps=, + EgressQOSMaps=, and [MACVLAN] BroadcastMulticastQueueLength= + configuration options for VLAN packet handling. + + * udev rules may now set log_level= option. This allows debug logs to + be enabled for select events, e.g. just for a specific subsystem or + even a single device. + + * udev now exports the VOLUME_ID, LOGICAL_VOLUME_ID, VOLUME_SET_ID, and + DATA_PREPARED_ID properties for block devices with ISO9660 file + systems. + + * udev now exports decoded DMI information about installed memory slots + as device properties under the /sys/class/dmi/id/ pseudo device. + + * /dev/ is not mounted noexec anymore. This didn't provide any + significant security benefits and would conflict with the executable + mappings used with /dev/sgx device nodes. The previous behaviour can + be restored for individual services with NoExecPaths=/dev (or by allow- + listing and excluding /dev from ExecPaths=). + + * Permissions for /dev/vsock are now set to 0o666, and /dev/vhost-vsock + and /dev/vhost-net are owned by the kvm group. + + * The hardware database has been extended with a list of fingerprint + readers that correctly support USB auto-suspend using data from + libfprint. + + * systemd-resolved can now answer DNSSEC questions through the stub + resolver interface in a way that allows local clients to do DNSSEC + validation themselves. For a question with DO+CD set, it'll proxy the + DNS query and respond with a mostly unmodified packet received from + the upstream server. + + * systemd-resolved learnt a new boolean option CacheFromLocalhost= in + resolved.conf. If true the service will provide caching even for DNS + lookups made to an upstream DNS server on the 127.0.0.1/::1 + addresses. By default (and when the option is false) systemd-resolved + will not cache such lookups, in order to avoid duplicate local + caching, under the assumption the local upstream server caches + anyway. + + * systemd-resolved now implements RFC5001 NSID in its local DNS + stub. This may be used by local clients to determine whether they are + talking to the DNS resolver stub or a different DNS server. + + * When resolving host names and other records resolvectl will now + report where the data was acquired from (i.e. the local cache, the + network, locally synthesized, …) and whether the network traffic it + effected was encrypted or not. Moreover the tool acquired a number of + new options --cache=, --synthesize=, --network=, --zone=, + --trust-anchor=, --validate= that take booleans and may be used to + tweak a lookup, i.e. whether it may be answered from cached + information, locally synthesized information, information acquired + through the network, the local mDNS/LLMNR zone, the DNSSEC trust + anchor, and whether DNSSEC validation shall be executed for the + lookup. + + * systemd-nspawn gained a new --ambient-capability= setting + (AmbientCapability= in .nspawn files) to configure ambient + capabilities passed to the container payload. + + * systemd-nspawn gained the ability to configure the firewall using the + nftables subsystem (in addition to the existing iptables + support). Similarly, systemd-networkd's IPMasquerade= option now + supports nftables as back-end, too. In both cases NAT on IPv6 is now + supported too, in addition to IPv4 (the iptables back-end still is + IPv4-only). + + "IPMasquerade=yes", which was the same as "IPMasquerade=ipv4" before, + retains its meaning, but has been deprecated. Please switch to either + "ivp4" or "both" (if covering IPv6 is desired). + + * systemd-importd will now download .verity and .roothash.p7s files + along with the machine image (as exposed via machinectl pull-raw). + + * systemd-oomd now gained a new DefaultMemoryPressureDurationSec= + setting to configure the time a unit's cgroup needs to exceed memory + pressure limits before action will be taken, and a new + ManagedOOMPreference=none|avoid|omit setting to avoid killing certain + units. + + systemd-oomd is now considered fully supported (the usual + backwards-compatiblity promises apply). Swap is not required for + operation, but it is still recommended. + + * systemd-timesyncd gained a new ConnectionRetrySec= setting which + configures the retry delay when trying to contact servers. + + * systemd-stdio-bridge gained --system/--user options to connect to the + system bus (previous default) or the user session bus. + + * systemd-localed may now call locale-gen to generate missing locales + on-demand (UTF-8-only). This improves integration with Debian-based + distributions (Debian/Ubuntu/PureOS/Tanglu/...) and Arch Linux. + + * systemctl --check-inhibitors=true may now be used to obey inhibitors + even when invoked non-interactively. The old --ignore-inhibitors + switch is now deprecated and replaced by --check-inhibitors=false. + + * systemctl import-environment will now emit a warning when called + without any arguments (i.e. to import the full environment block of + the called program). This command will usually be invoked from a + shell, which means that it'll inherit a bunch of variables which are + specific to that shell, and usually to the TTY the shell is connected + to, and don't have any meaning in the global context of the system or + user service manager. Instead, only specific variables should be + imported into the manager environment block. + + Similarly, programs which update the manager environment block by + directly calling the D-Bus API of the manager, should also push + specific variables, and not the full inherited environment. + + * systemctl's status output now shows unit state with a more careful + choice of Unicode characters: units in maintenance show a "○" symbol + instead of the usual "●", failed units show "×", and services being + reloaded "↻". + + * coredumpctl gained a --debugger-arguments= switch to pass arguments + to the debugger. It also gained support for showing coredump info in + a simple JSON format. + + * systemctl/loginctl/machinectl's --signal= option now accept a special + value "list", which may be used to show a brief table with known + process signals and their numbers. + + * networkctl now shows the link activation policy in status. + + * Various tools gained --pager/--no-pager/--json= switches to + enable/disable the pager and provide JSON output. + + * Various tools now accept two new values for the SYSTEMD_COLORS + environment variable: "16" and "256", to configure how many terminal + colors are used in output. + + * less 568 or newer is now required for the auto-paging logic of the + various tools. Hyperlink ANSI sequences in terminal output are now + used even if a pager is used, and older versions of less are not able + to display these sequences correctly. SYSTEMD_URLIFY=0 may be used to + disable this output again. + + * Builds with support for separate / and /usr/ hierarchies ("split-usr" + builds, non-merged-usr builds) are now officially deprecated. A + warning is emitted during build. Support is slated to be removed in + about a year (when the Debian Bookworm release development starts). + + * Systems with the legacy cgroup v1 hierarchy are now marked as + "tainted", to make it clearer that using the legacy hierarchy is not + recommended. + + * systemd-localed will now refuse to configure a keymap which is not + installed in the file system. This is intended as a bug fix, but + could break cases where systemd-localed was used to configure the + keymap in advanced of it being installed. It is necessary to install + the keymap file first. + + * The main git development branch has been renamed to 'main'. + + * mmcblk[0-9]boot[0-9] devices will no longer be probed automatically + for partitions, as in the vast majority of cases they contain none + and are used internally by the bootloader (eg: uboot). + + * systemd will now set the $SYSTEMD_EXEC_PID environment variable for + spawned processes to the PID of the process itself. This may be used + by programs for detecting whether they were forked off by the service + manager itself or are a process forked off further down the tree. + + * The sd-device API gained four new calls: sd_device_get_action() to + determine the uevent add/remove/change/… action the device object has + been seen for, sd_device_get_seqno() to determine the uevent sequence + number, sd_device_new_from_stat_rdev() to allocate a new sd_device + object from stat(2) data of a device node, and sd_device_trigger() to + write to the 'uevent' attribute of a device. + + * For most tools the --no-legend= switch has been replaced by + --legend=no and --legend=yes, to force whether tables are shown with + headers/legends. + + * Units acquired a new property "Markers" that takes a list of zero, + one or two of the following strings: "needs-reload" and + "needs-restart". These markers may be set via "systemctl + set-property". Once a marker is set, "systemctl reload-or-restart + --marked" may be invoked to execute the operation the units are + marked for. This is useful for package managers that want to mark + units for restart/reload while updating, but effect the actual + operations at a later step at once. + + * The sd_bus_message_read_strv() API call of sd-bus may now also be + used to parse arrays of D-Bus signatures and D-Bus paths, in addition + to regular strings. + + * bootctl will now report whether the UEFI firmware used a TPM2 device + and measured the boot process into it. + + * systemd-tmpfiles learnt support for a new environment variable + $SYSTEMD_TMPFILES_FORCE_SUBVOL which takes a boolean value. If true + the v/q/Q lines in tmpfiles.d/ snippets will create btrfs subvolumes + even if the root fs of the system is not itself a btrfs volume. + + * systemd-detect-virt/ConditionVirtualization= will now explicitly + detect Docker/Podman environments where possible. Moreover, they + should be able to generically detect any container manager as long as + it assigns the container a cgroup. + + * portablectl gained a new "reattach" verb for detaching/reattaching a + portable service image, useful for updating images on-the-fly. + + * Intel SGX enclave device nodes (which expose a security feature of + newer Intel CPUs) will now be owned by a new system group "sgx". + + Contributions from: Adam Nielsen, Adrian Vovk, AJ Jordan, Alan Perry, + Alastair Pharo, Alexander Batischev, Ali Abdallah, Andrew Balmos, + Anita Zhang, Annika Wickert, Ansgar Burchardt, Antonio Terceiro, + Antonius Frie, Ardy, Arian van Putten, Ariel Fermani, Arnaud T, + A S Alam, Bastien Nocera, Benjamin Berg, Benjamin Robin, Björn Daase, + caoxia, Carlo Wood, Charles Lee, ChopperRob, chri2, Christian Ehrhardt, + Christian Hesse, Christopher Obbard, clayton craft, corvusnix, cprn, + Daan De Meyer, Daniele Medri, Daniel Rusek, Dan Sanders, Dan Streetman, + Darren Ng, David Edmundson, David Tardon, Deepak Rawat, Devon Pringle, + Dmitry Borodaenko, dropsignal, Einsler Lee, Endre Szabo, + Evgeny Vereshchagin, Fabian Affolter, Fangrui Song, Felipe Borges, + feliperodriguesfr, Felix Stupp, Florian Hülsmann, Florian Klink, + Florian Westphal, Franck Bui, Frantisek Sumsal, Gablegritule, + Gaël PORTAY, Gaurav, Giedrius Statkevičius, Greg Depoire-Ferrer, + Gustavo Costa, Hans de Goede, Hela Basa, heretoenhance, hide, + Iago López Galeiras, igo95862, Ilya Dmitrichenko, Jameer Pathan, + Jan Tojnar, Jiehong, Jinyuan Si, Joerg Behrmann, John Slade, + Jonathan G. Underwood, Jonathan McDowell, Josh Triplett, Joshua Watt, + Julia Cartwright, Julien Humbert, Kairui Song, Karel Zak, + Kevin Backhouse, Kevin P. Fleming, Khem Raj, Konomi, krissgjeng, + l4gfcm, Lajos Veres, Lennart Poettering, Lincoln Ramsay, Luca Boccassi, + Luca BRUNO, Lucas Werkmeister, Luka Kudra, Luna Jernberg, + Marc-André Lureau, Martin Wilck, Matthias Klumpp, Matt Turner, + Michael Gisbers, Michael Marley, Michael Trapp, Michal Fabik, + Michał Kopeć, Michal Koutný, Michal Sekletár, Michele Guerini Rocco, + Mike Gilbert, milovlad, moson-mo, Nick, nihilix-melix, Oğuz Ersen, + Ondrej Mosnacek, pali, Pavel Hrdina, Pavel Sapezhko, Perry Yuan, + Peter Hutterer, Pierre Dubouilh, Piotr Drąg, Pjotr Vertaalt, + Richard Laager, RussianNeuroMancer, Sam Lunt, Sebastiaan van Stijn, + Sergey Bugaev, shenyangyang4, simmon, Simonas Kazlauskas, + Slimane Selyan Amiri, Stefan Agner, Steve Ramage, Susant Sahani, + Sven Mueller, Tad Fisher, Takashi Iwai, Thomas Haller, Tom Shield, + Topi Miettinen, Torsten Hilbrich, tpgxyz, Tyler Hicks, ulf-f, + Ulrich Ölmann, Vincent Pelletier, Vinnie Magro, Vito Caputo, Vlad, + walbit-de, Whired Planck, wouter bolsterlee, Xℹ Ruoyao, Yangyang Shen, + Yuri Chornoivan, Yu Watanabe, Zach Smith, Zbigniew Jędrzejewski-Szmek, + Zmicer Turok, Дамјан Георгиевски + + — Berlin, 2021-03-30 + CHANGES WITH 247: * KERNEL API INCOMPATIBILITY: Linux 4.14 introduced two new uevents @@ -3809,7 +4289,7 @@ CHANGES WITH 237: by default even when owned by root and read-only. This behaviour was inherited from older tools, but there have been requests to remove it, and it's not obvious why this restriction was made in the first - place. Please speak up now, if you are aware of software that reqires + place. Please speak up now, if you are aware of software that requires this behaviour, otherwise we'll remove the restriction in v238. * A new environment variable $SYSTEMD_OFFLINE is now understood by @@ -5049,7 +5529,7 @@ CHANGES WITH 232: * Support for dynamically creating users for the lifetime of a service has been added. If DynamicUser=yes is specified, user and group IDs - will be allocated from the range 61184..65519 for the lifetime of the + will be allocated from the range 61184…65519 for the lifetime of the service. They can be resolved using the new nss-systemd.so NSS module. The module must be enabled in /etc/nsswitch.conf. Services started in this way have PrivateTmp= and RemoveIPC= enabled, so that @@ -5791,7 +6271,7 @@ CHANGES WITH 230: * The LimitNICE= setting now optionally takes normal UNIX nice values in addition to the raw integer limit value. If the specified - parameter is prefixed with "+" or "-" and is in the range -20..19 the + parameter is prefixed with "+" or "-" and is in the range -20…19 the value is understood as UNIX nice value. If not prefixed like this it is understood as raw RLIMIT_NICE limit. @@ -6129,10 +6609,10 @@ CHANGES WITH 228: individual indexes. * The various memory-related resource limit settings (such as - LimitAS=) now understand the usual K, M, G, ... suffixes to + LimitAS=) now understand the usual K, M, G, … suffixes to the base of 1024 (IEC). Similar, the time-related resource - limit settings understand the usual min, h, day, ... - suffixes now. + limit settings understand the usual min, h, day, … suffixes + now. * There's a new system.conf setting DefaultTasksMax= to control the default TasksMax= setting for services and @@ -6907,7 +7387,7 @@ CHANGES WITH 220: * New /etc/fstab options x-systemd.requires= and x-systemd.requires-mounts-for= are now supported to express additional dependencies for mounts. This is useful for - journalling file systems that support external journal + journaling file systems that support external journal devices or overlay file systems that require underlying file systems to be mounted. @@ -7066,7 +7546,7 @@ CHANGES WITH 220: * /usr/lib/os-release gained a new optional field VARIANT= for distributions that support multiple variants (such as a - desktop edition, a server edition, ...) + desktop edition, a server edition, …) Contributions from: Aaro Koskinen, Adam Goode, Alban Crequy, Alberto Fanjul Alonso, Alexander Sverdlin, Alex Puchades, Alin @@ -7521,7 +8001,7 @@ CHANGES WITH 218: * nspawn's --link-journal= switch gained two new values "try-guest" and "try-host" that work like "guest" and "host", but do not fail if the host has no persistent - journalling enabled. -j is now equivalent to + journaling enabled. -j is now equivalent to --link-journal=try-guest. * macvlan network devices created by nspawn will now have @@ -7565,7 +8045,7 @@ CHANGES WITH 218: into account when storing rfkill state on disk, as the name might be dynamically assigned and not stable. Instead, the ID_PATH udev variable combined with the rfkill type (wlan, - bluetooth, ...) is used. + bluetooth, …) is used. * A new service systemd-machine-id-commit.service has been added. When used on systems where /etc is read-only during @@ -7795,7 +8275,7 @@ CHANGES WITH 217: * Calendar time specifications in .timer units now also understand the strings "semi-annually", "quarterly" and "minutely" as shortcuts (in addition to the preexisting - "annually", "hourly", ...). + "annually", "hourly", …). * systemd-tmpfiles will now correctly create files in /dev at boot which are marked for creation only at boot. It is @@ -9015,7 +9495,7 @@ CHANGES WITH 209: match against MAC address, device path, driver name and type, and will apply attributes like the naming policy, link speed, MTU, duplex settings, Wake-on-LAN settings, MAC address, MAC - address assignment policy (randomized, ...). + address assignment policy (randomized, …). * The configuration of network interface naming rules for "permanent interface names" has changed: a new NamePolicy= @@ -9092,7 +9572,7 @@ CHANGES WITH 209: recent boots with their times and boot IDs. * The various tools like systemctl, loginctl, timedatectl, - busctl, systemd-run, ... have gained a new switch "-M" to + busctl, systemd-run, … have gained a new switch "-M" to connect to a specific, local OS container (as direct connection, without requiring SSH). This works on any container that is registered with machined, such as those @@ -9841,7 +10321,7 @@ CHANGES WITH 205: * If a privileged process logs a journal message with the OBJECT_PID= field set, then journald will automatically augment this with additional OBJECT_UID=, OBJECT_GID=, - OBJECT_COMM=, OBJECT_EXE=, ... fields. This is useful if + OBJECT_COMM=, OBJECT_EXE=, … fields. This is useful if system services want to log events about specific client processes. journactl/systemctl has been updated to make use of this information if all log messages regarding a specific @@ -10045,7 +10525,7 @@ CHANGES WITH 201: * 'systemctl status' will also shown information about any drop-in configuration file for units. (Drop-In configuration files in this context are files such as - /etc/systemd/systemd/foobar.service.d/*.conf) + /etc/systemd/system/foobar.service.d/*.conf) * systemd-cgtop now optionally shows summed up CPU times of cgroups. Press '%' while running cgtop to switch between @@ -10981,7 +11461,7 @@ CHANGES WITH 190: inhibitors during their runtime. A simple way to achieve that is to invoke the DE wrapped in an invocation of: - systemd-inhibit --what=handle-power-key:handle-sleep-key:handle-lid-switch ... + systemd-inhibit --what=handle-power-key:handle-sleep-key:handle-lid-switch … * Access to unit operations is now checked via SELinux taking the unit file label and client process label into account. @@ -11388,7 +11868,7 @@ CHANGES WITH 183: should be used to create dead device nodes as workarounds for broken subsystems. - * udev: RUN+="socket:..." and udev_monitor_new_from_socket() is + * udev: RUN+="socket:…" and udev_monitor_new_from_socket() is no longer supported. udev_monitor_new_from_netlink() needs to be used to subscribe to events. diff --git a/README b/README index 7b1157226..e0b7fbf8b 100644 --- a/README +++ b/README @@ -44,7 +44,7 @@ REQUIREMENTS: CONFIG_SIGNALFD CONFIG_TIMERFD CONFIG_EPOLL - CONFIG_NET + CONFIG_UNIX (it requires CONFIG_NET, but every other flag in it is not necessary) CONFIG_SYSFS CONFIG_PROC_FS CONFIG_FHANDLE (libudev, mount and bind mount handling) @@ -126,6 +126,9 @@ REQUIREMENTS: Required for systemd-nspawn: CONFIG_DEVPTS_MULTIPLE_INSTANCES or Linux kernel >= 4.7 + Required for systemd-oomd: + CONFIG_PSI + Note that kernel auditing is broken when used with systemd's container code. When using systemd in conjunction with containers, please make sure to either turn off auditing at @@ -187,7 +190,7 @@ REQUIREMENTS: polkit (optional) To build in directory build/: - meson build/ && ninja -C build + meson setup build/ && meson compile -C build/ Any configuration options can be specified as -Darg=value... arguments to meson. After the build directory is initially configured, meson will @@ -197,10 +200,10 @@ REQUIREMENTS: their current values. Useful commands: - ninja -v some/target - ninja test - sudo ninja install - DESTDIR=... ninja install + meson compile -v -C build/ some/target + meson test -C build/ + sudo meson install -C build/ + DESTDIR=... meson install -C build/ A tarball can be created with: git archive --format=tar --prefix=systemd-222/ v222 | xz > systemd-222.tar.xz @@ -219,9 +222,10 @@ REQUIREMENTS: Note that the build prefix for systemd must be /usr. (Moreover, packages systemd relies on — such as D-Bus — really should use the same prefix, otherwise you are on your own.) -Dsplit-usr=false (which is the - default and does not need to be specified) is the recommended setting, - and -Dsplit-usr=true should be used on systems which have /usr on a - separate partition. + default and does not need to be specified) is the recommended setting. + -Dsplit-usr=true can be used to give a semblance of support for systems + with programs installed split between / and /usr. Moving everything + under /usr is strongly encouraged. Additional packages are necessary to run some tests: - busybox (used by test/TEST-13-NSPAWN-SMOKE) @@ -273,7 +277,7 @@ NSS: with machined to their respective IP addresses. nss-systemd enables resolution of users/group registered via the - User/Group Record Lookup API (https://systemd.io/USER_GROUP_API/), + User/Group Record Lookup API (https://systemd.io/USER_GROUP_API), including all dynamically allocated service users. (See the DynamicUser= setting in unit files.) diff --git a/README.md b/README.md index e8703ea6e..26622fe03 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,16 @@ System and Service Manager Count of open issues over time Count of open pull requests over time -[![Semaphore CI Build Status](https://semaphoreci.com/api/v1/projects/28a5a3ca-3c56-4078-8b5e-7ed6ef912e14/443470/shields_badge.svg)](https://semaphoreci.com/systemd/systemd)
+[![Semaphore CI 2.0 Build Status](https://the-real-systemd.semaphoreci.com/badges/systemd/branches/main.svg?style=shields)](https://the-real-systemd.semaphoreci.com/projects/systemd)
[![Coverity Scan Status](https://scan.coverity.com/projects/350/badge.svg)](https://scan.coverity.com/projects/350)
[![OSS-Fuzz Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/systemd.svg)](https://oss-fuzz-build-logs.storage.googleapis.com/index.html#systemd)
[![CIFuzz](https://github.com/systemd/systemd/workflows/CIFuzz/badge.svg)](https://github.com/systemd/systemd/actions)
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/1369/badge)](https://bestpractices.coreinfrastructure.org/projects/1369)
-[![Travis CI Build Status](https://travis-ci.org/systemd/systemd.svg?branch=master)](https://travis-ci.org/systemd/systemd)
[![Language Grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/systemd/systemd.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/systemd/systemd/context:cpp)
[![CentOS CI - CentOS 7](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20CentOS%207&job=upstream-centos7)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-centos7/)
[![CentOS CI - Arch](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20Arch&job=upstream-vagrant-archlinux)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-vagrant-archlinux/)
[![CentOS CI - Arch (sanitizers)](https://jenkins-systemd.apps.ocp.ci.centos.org/buildStatus/icon?subject=CentOS%20CI%20-%20Arch%20(sanitizers)&job=upstream-vagrant-archlinux-sanitizers)](https://jenkins-systemd.apps.ocp.ci.centos.org/job/upstream-vagrant-archlinux-sanitizers/)
-[![Build Status](https://dev.azure.com/evvers/systemd-systemd/_apis/build/status/systemd.systemd?branchName=master)](https://dev.azure.com/evvers/systemd-systemd/_build/latest?definitionId=1&branchName=master)
-[![Fossies codespell report](https://fossies.org/linux/test/systemd-master.tar.gz/codespell.svg)](https://fossies.org/linux/test/systemd-master.tar.gz/codespell.html)
+[![Fossies codespell report](https://fossies.org/linux/test/systemd-main.tar.gz/codespell.svg)](https://fossies.org/linux/test/systemd-main.tar.gz/codespell.html)
[![Packaging status](https://repology.org/badge/tiny-repos/systemd.svg)](https://repology.org/project/systemd/versions) ## Details diff --git a/TODO b/TODO index 89f7455e5..451d9f34c 100644 --- a/TODO +++ b/TODO @@ -7,6 +7,8 @@ Bugfixes: * userdbctl: "Password OK: yes" is shown even when there are no passwords or the password is locked. +* Get rid of nftw(). We should refuse to use such useless APIs on principle. + External: * Fedora: add an rpmlint check that verifies that all unit files in the RPM are listed in %systemd_post macros. @@ -20,8 +22,139 @@ Janitorial Clean-ups: Features: +* maybe add a tool that displays most recent journal logs as QR code to scan + off screen and run it automatically on boot failures, emergency logs and + such. Use DRM APIs directly, see + https://github.com/dvdhrm/docs/blob/master/drm-howto/modeset.c for an example + for doing that. + +* pass systemd-detect-virt result to generators as env var. Modifying behaviour + based on whether we are virtualized or not is a pretty common thing, hence + maybe just pass that info along for free in an env var. We cache the result + anyway, so it's basically free. + +* systemd-repart: read LUKS encryption key from $CREDENTIALS_PATH + +* introduce /dev/disk/root/* symlinks that allow referencing partitions on the + disk the rootfs is on in a reasonably secure way. + +* systemd-repart: add a switch to factory reset the partition table without + immediately applying the new configuration again. i.e. --factory-reset=leave + or so. (this is useful to factory reset an image, then putting it into + another machine, ensuring that luks key is generated on new machine, not old) + +* move logind udev rules to top-level rule.d/ directory + +* move multiseat vid/pid matches from logind udev rule to hwdb + +* nspawn: default to 1:1 userns + +* Provide a reasonably bespoke solution for mounting host $HOME directories + into containers: + • add new option --mount-user=$USER for mounting $HOME of the user into the + container at the same place + • check /etc/passwd for UID or user name clashes. If UID clash pick a different + UID in container, and map via userns. If user name clash, refuse. If + matching user already exists use that. + • otherwise: write user record of specified user into /run/host/passwd or so + • in nss-systemd pick up user record from there and make available to system + With all that in place if nspawn host and container payload are up-to-date + enough we have a very simple way to make host users available in containers. + +* systemd-sysusers: pick up passwords from credentials logic, so that users can + easily set root user pw. enable cred inheriting for root user from PID 1, so + that for containers we can configure the root pw automatically via nspawn's + --set-credential= switch. (Also do this for systemd-firstboot) + +* whenever we receive fds via SCM_RIGHTS make sure none got dropped due to the + reception limit the kernel silently enforces. + +* add an Open= setting to service unit files that can open arbitrary file + system paths at service startup time and pass them to the service process via + our usual socket activation protocol. If passed path refers to AF_UNIX + socket: connect() to it. + +* add a ConnectSocket= setting to service unit files, that may reference a + socket unit, and which will connect to the socket defined therein, and pass + the resulting fd to the service program via socket activation proto. + +* Add a concept of ListenStream=anonymous to socket units: listen on a socket + that is deleted in the fs. Usecase would be with ConnectSocket= above. + +* Hook up journald's FSS logic with TPM2: seal the verification disk by + time-based policy, so that the verification key can remain on host and ve + validated via TPM. + +* sd-boot: define a drop-in dir in the ESP that may contain X.509 + certificates. If the firmware is detected to be in setup mode, automatically + enroll them as PK/KEK/db, turn off setup mode and proceed. Optionally, + instead of auto-enrolling them add them to the sd-boot menu, giving the user + the option to manually enroll them, after selecting the menu entry. This way, + installer images can just drop the certfiicates in the ESP, and on first boot + can easily enroll the keys without ever booting up. + +* efi stub: optionally, load initrd from disk as a separate file, HMAC check it + with key from TPM, bound to PCR, refusing if failing. This would then allow + traditional distros that generate initrds locally to secure them with TPM: + after generating the initrd, do the HMAC calculation, put result in initrd + filename, done. This would then bind the validity of the initrd to the local + host, and used kernel, and means people cannot change initrd or kernel + without booting the kernel + initrd. + +* importd: add ability download images for portabled + sysext + +* importd: support image signature verification with PKCS#7 + OpenBSD signify + logic, as alternative to crummy gpg + +* sd-boot: add service that automatically runs "bootctl update" on every boot, + in a graceful way, so that updated /usr trees automatically propagate into + updated boot loaders on reboot. + +* sysext: optionally, if the merged trees allow it use bind mounts instead of + overlayfs + +* nspawn: add support for sysext extensions, too. i.e. a new --extension= + switch that takes one or more arguments, and applies the extensions already + during startup. + +* add "systemd-analyze debug" + AttachDebugger= in unit files: The former + specifies a command to execute; the latter specifies that an already running + "systemd-analyze debug" instance shall be contacted and execution paused + until it gives an OK. That way, tools like gdb or strace can be safely be + invoked on processes forked off PID 1. + +* expose MS_NOSYMFOLLOW in various places + +* tpm2: support a PIN policy, i.e. allowing windows-style short authentication + passwords by using the TPM2 to enforce ratelimiting and such, use for + cryptsetup and homed + +* Add concept for upgrading TPM2 enrollments, maybe a new switch + --pcrs=4: or so, i.e. select a PCR to include in the hash, and then + override its hash + +* homed: store PKCS#11 + FIDO2 token info in LUKS2 header, compatible with + systemd-cryptsetup, so that it can unlock homed volumes + +* cryptenroll: politely refuse enrolling new keys to homed volumes, since we + we cannot update identity info + +* TPM2: auto-reenroll in cryptsetup, as fallback for hosed firmware upgrades + and such + +* cryptsetup: if only recovery keys are registered and no regular passphrases, + ask user for "recovery key", not "passphrase" + +* cyptsetup: add option for automatically removing empty password slot on boot + * cryptsetup: optionally, when run during boot-up and password is never - entered, and we are on AC power (or so), power off machine again + entered, and we are on battery power (or so), power off machine again + +* cryptsetup: when FIDO2/PKCS#11/TPM2 token/chip didn't show up after some + time, abort the attempt, fallback to asking for pw + +* cryptsetup: when waiting for FIDO2/PKCS#11 token, tell plymouth that, and + allow plymouth to abort the waiting and enter pw instead * when configuring loopback netif, and it fails due to EPERM, eat up error if it happens to be set up alright already. @@ -76,9 +209,6 @@ Features: * make use of new glibc 2.32 APIs sigabbrev_np() and strerrorname_np(). -* cryptsetup: if keyfile specified in crypttab is AF_UNIX socket, connect to it - and read from it (like we do elsewhere with READ_FULL_FILE_CONNECT_SOCKET) - * when main nspawn supervisor process gets suspended due to SIGSTOP/SIGTTOU or so, freeze the payload too. @@ -107,17 +237,11 @@ Features: client UID, so that synthetic hash table collisions can slow down a specific user's journal stream down but not the others. -* add "throttling" to sd-event event sources: optionally, when we wake up too - often for one, let's turn it off entirely for a while. Use that for the - /proc/self/mountinfo logic. - * nspawn: support time namespaces * systemd-firstboot: make sure to always use chase_symlinks() before reading/writing files -* add ConditionSecurity=tpm2 - * Remove any support for booting without /usr pre-mounted in the initrd entirely. Update INITRD_INTERFACE.md accordingly. @@ -140,10 +264,6 @@ Features: o move into separate libsystemd-shared-iptables.so .so - iptables-libs (only used by nspawn + networkd) -* seccomp: when SystemCallArchitectures=native is set then don't install any - other seccomp filters for any of the other archs, in order to reduce the - number of seccomp filters we install needlessly. - * seccomp: maybe use seccomp_merge() to merge our filters per-arch if we can. Apparently kernel performance is much better with fewer larger seccomp filters than with more smaller seccomp filters. @@ -207,9 +327,6 @@ Features: thus allows defining OS images which can be A/B updated and we default to the newest version automatically, both in nspawn and in sd-boot -* cryptsetup: support FIDO2 tokens for deriving keys (i.e. do what homed can do - also in plain cryptsetup) - * systemd-gpt-auto should probably set x-systemd.growfs on the mounts it creates @@ -248,12 +365,6 @@ Features: * add growvol and makevol options for /etc/crypttab, similar to x-systemd.growfs and x-systemd-makefs. -* hook up the TPM to /etc/crypttab, with a new option that is similar to the - new PKCS#11 option in crypttab, and allows unlocking a LUKS volume via a key - unsealed from the TPM. Optionally, if TPM is not available fall back to - TPM-less mode, and set up linear DM mapping instead (inspired by kpartx), so - that the device paths stay the same, regardless if crypto is used or not. - * systemd-repart: by default generate minimized partition tables (i.e. tables that only cover the space actually used, excluding any free space at the end), in order to maximize dd'ability. Requires libfdisk work, see @@ -304,7 +415,7 @@ Features: initrd had set. * sd-event: add native support for P_ALL waitid() watching, then move PID 1 to - it fo reaping assigned but unknown children. This needs to some special care + it for reaping assigned but unknown children. This needs to some special care to operate somewhat sensibly in light of priorities: P_ALL will return arbitrary processes, regardless of the priority we want to watch them with, hence on each event loop iteration check all processes which we shall watch @@ -800,9 +911,6 @@ Features: picked up by systemd unless they contain a medium. This would mirror the behaviour we already have for CD drives. -* networkd/udev: implement SR_IOV configuration in .link files: - http://lists.freedesktop.org/archives/systemd-devel/2015-January/027451.html - * hostnamectl: show root image uuid * Find a solution for SMACK capabilities stuff: @@ -1017,7 +1125,7 @@ Features: - logind: when the power button is pressed short, just popup a logout dialog. If it is pressed for 1s, do the usual shutdown. Inspiration are Macs here. - - expose "Locked" property on logind sesison objects + - expose "Locked" property on logind session objects - maybe allow configuration of the StopTimeout for session scopes - rename session scope so that it includes the UID. THat way the session scope can be arranged freely in slices and we don't have @@ -1210,6 +1318,7 @@ Features: - creating new directories/subvolumes/fifos/device nodes should not follow symlinks. None of the other adjustment or creation calls follow symlinks. + - add --test mode * make sure systemd-ask-password-wall does not shutdown systemd-ask-password-console too early @@ -1311,7 +1420,6 @@ Features: for all routes to it. possibly a second default for DHCP routes. - allow Name= to be specified repeatedly in the [Match] section. Maybe also support Name=foo*|bar*|baz ? - - duplicate address check for static IPs (like ARPCHECK in network-scripts) - whenever uplink info changes, make DHCP server send out FORCERENEW * Figure out how to do unittests of networkd's state serialization diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index b32196266..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,15 +0,0 @@ -trigger: -- master - -jobs: -- job: FuzzBuzz - displayName: FuzzBuzz - - pool: - vmImage: 'ubuntu-latest' - - steps: - - script: | - set -e - ./travis-ci/managers/fuzzbuzz.sh - displayName: 'This is where it gets darker' diff --git a/coccinelle/errno.cocci b/coccinelle/errno.cocci index c92826648..4e594e782 100644 --- a/coccinelle/errno.cocci +++ b/coccinelle/errno.cocci @@ -25,6 +25,13 @@ expression e; - return r; @@ identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; +@@ ++ return + log_LEVEL_errno(r, ...); +- return r; +@@ +identifier log_LEVEL_errno =~ "^log_(debug|info|notice|warning|error|emergency)_errno$"; expression e; @@ + return @@ -39,3 +46,57 @@ local idexpression r; - log_LEVEL_errno(e, args); - r = e; + r = log_LEVEL_errno(e, args); +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|netdev|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; +expression e; +expression u; +@@ +- r = -e; ++ r = + log_UNIT_LEVEL_errno(u, e, ...); +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|netdev|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; +expression e; +expression u; +@@ ++ r = + log_UNIT_LEVEL_errno(u, e, ...); +- r = -e; +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|netdev|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; +expression e; +expression u; +@@ +- r = ++ return + log_UNIT_LEVEL_errno(u, e, ...); +- return r; +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|netdev|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +local idexpression r; +expression u; +@@ ++ return + log_UNIT_LEVEL_errno(u, r, ...); +- return r; +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|netdev|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +expression e; +expression u; +@@ ++ return + log_UNIT_LEVEL_errno(u, e, ...); +- return -e; +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|netdev|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +expression list args; +expression e; +expression u; +local idexpression r; +@@ +- log_UNIT_LEVEL_errno(u, e, args); +- r = e; ++ r = log_UNIT_LEVEL_errno(u, e, args); diff --git a/coccinelle/flags-set.cocci b/coccinelle/flags-set.cocci index f6cc8ba68..22620f184 100644 --- a/coccinelle/flags-set.cocci +++ b/coccinelle/flags-set.cocci @@ -8,7 +8,8 @@ position p : script:python() { p[0].current_element == "log_set_max_level_realm" or p[0].current_element == "unichar_is_valid") }; -expression x, y; +expression x; +constant y; @@ ( - ((x@p) & (y)) == (y) diff --git a/coccinelle/run-coccinelle.sh b/coccinelle/run-coccinelle.sh index 871547a88..d1af412ac 100755 --- a/coccinelle/run-coccinelle.sh +++ b/coccinelle/run-coccinelle.sh @@ -7,6 +7,7 @@ EXCLUDED_PATHS=( "src/basic/linux/*" # Symlinked to test-bus-vtable-cc.cc, which causes issues with the IN_SET macro "src/libsystemd/sd-bus/test-bus-vtable.c" + "src/libsystemd/sd-journal/lookup3.c" ) top="$(git rev-parse --show-toplevel)" diff --git a/coccinelle/strjoina.cocci b/coccinelle/strjoina.cocci index a6236eb0f..b20963348 100644 --- a/coccinelle/strjoina.cocci +++ b/coccinelle/strjoina.cocci @@ -1,6 +1,7 @@ @@ +position p : script:python() { p[0].current_element != "test_strjoina" }; expression n, m; expression list s; @@ -- n = strjoina(m, s, NULL); +- n = strjoina@p(m, s, NULL); + n = strjoina(m, s); diff --git a/coccinelle/synthetic-errno.cocci b/coccinelle/synthetic-errno.cocci index 650c37e08..dcae069f7 100644 --- a/coccinelle/synthetic-errno.cocci +++ b/coccinelle/synthetic-errno.cocci @@ -15,9 +15,15 @@ log_debug("Found no default boot entry :("); expression e; expression list args; @@ +( +/* Ignore specific cases in src/import/{export,import,pull}.c where we want to return positive value on success. */ +log_info("Exiting."); +return -r; +| - log_info(args); - return -e; + return log_info_errno(SYNTHETIC_ERRNO(e), args); +) @@ expression e; expression list args; @@ -46,3 +52,211 @@ expression list args; @@ - log_LEVEL_errno(ERRNO, args); + log_LEVEL_errno(SYNTHETIC_ERRNO(ERRNO), args); +@@ +identifier log_UNIT_LEVEL_errno =~ "^log_(unit|link|device|token)_(debug|info|notice|warning|error|emergency)_errno$"; +identifier ERRNO =~ "^E[A-Z]+$"; +expression u; +expression list args; +@@ +- log_UNIT_LEVEL_errno(u, ERRNO, args); ++ log_UNIT_LEVEL_errno(u, SYNTHETIC_ERRNO(ERRNO), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_unit_debug(u, args); +- return -e; ++ return log_unit_debug_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_unit_info(u, args); +- return -e; ++ return log_unit_info_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_unit_notice(u, args); +- return -e; ++ return log_unit_notice_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_unit_error(u, args); +- return -e; ++ return log_unit_error_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_unit_emergency(u, args); +- return -e; ++ return log_unit_emergency_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_link_debug(u, args); +- return -e; ++ return log_link_debug_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_link_info(u, args); +- return -e; ++ return log_link_info_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_link_notice(u, args); +- return -e; ++ return log_link_notice_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_link_error(u, args); +- return -e; ++ return log_link_error_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_link_emergency(u, args); +- return -e; ++ return log_link_emergency_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_netdev_debug(u, args); +- return -e; ++ return log_netdev_debug_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_netdev_info(u, args); +- return -e; ++ return log_netdev_info_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_netdev_notice(u, args); +- return -e; ++ return log_netdev_notice_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_netdev_error(u, args); +- return -e; ++ return log_netdev_error_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_netdev_emergency(u, args); +- return -e; ++ return log_netdev_emergency_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_device_debug(u, args); +- return -e; ++ return log_device_debug_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_device_info(u, args); +- return -e; ++ return log_device_info_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_device_notice(u, args); +- return -e; ++ return log_device_notice_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_device_error(u, args); +- return -e; ++ return log_device_error_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_device_emergency(u, args); +- return -e; ++ return log_device_emergency_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_token_debug(u, args); +- return -e; ++ return log_token_debug_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_token_info(u, args); +- return -e; ++ return log_token_info_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_token_notice(u, args); +- return -e; ++ return log_token_notice_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_token_error(u, args); +- return -e; ++ return log_token_error_errno(u, SYNTHETIC_ERRNO(e), args); +@@ +expression e; +expression u; +expression list args; +@@ +- log_token_emergency(u, args); +- return -e; ++ return log_token_emergency_errno(u, SYNTHETIC_ERRNO(e), args); diff --git a/configure b/configure index 5247074b6..fb9d01e1a 100755 --- a/configure +++ b/configure @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later set -e cflags=CFLAGS="$CFLAGS" diff --git a/docs/CODE_QUALITY.md b/docs/CODE_QUALITY.md index a724d663f..0933a0e49 100644 --- a/docs/CODE_QUALITY.md +++ b/docs/CODE_QUALITY.md @@ -10,13 +10,15 @@ The systemd project has a number of code quality tools set up in the source tree and on the github infrastructure. Here's an incomprehensive list of the available functionality: -1. Use `ninja -C build test` to run the unit tests. Some tests are skipped if +1. Use `meson test -C build` to run the unit tests. Some tests are skipped if no privileges are available, hence consider also running them with `sudo - ninja -C build test`. A couple of unit tests are considered "unsafe" (as - they change system state); to run those too, build with `meson + meson test -C build`. A couple of unit tests are considered "unsafe" (as + they change system state); to run those too, build with `meson setup -Dtests=unsafe`. Finally, some unit tests are considered to be very slow, - build them too with `meson -Dslow-tests=true`. (Note that there are a couple - of manual tests in addition to these unit tests.) + build them too with `meson setup -Dslow-tests=true`. (Note that there are a + couple of manual tests in addition to these unit tests.) (Also note: you can + change these flags for an already set up build tree, too, with "meson + configure -C build -D…".) 2. Use `./test/run-integration-tests.sh` to run the full integration test suite. This will build OS images with a number of integration tests and run @@ -35,14 +37,14 @@ available functionality: `./tools/find-tabs.sh recpatch` to fix them. (Again, grain of salt, foreign headers should usually be left unmodified.) -6. Use `ninja -C build check-api-docs` to compare the list of exported +6. Use `meson compile -C build check-api-docs` to compare the list of exported symbols of `libsystemd.so` and `libudev.so` with the list of man pages. Symbols lacking documentation are highlighted. -7. Use `ninja -C build hwdb-update` to automatically download and import the +7. Use `meson compile -C build update-hwdb` to automatically download and import the PCI, USB and OUI databases into hwdb. -8. Use `ninja -C build man/update-man-rules` to update the meson rules for +8. Use `meson compile -C build update-man-rules` to update the meson rules for building man pages automatically from the docbook XML files included in `man/`. diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md index 851676bc2..e4b0d9183 100644 --- a/docs/CODING_STYLE.md +++ b/docs/CODING_STYLE.md @@ -587,6 +587,12 @@ layout: default time you need that please immediately undefine `basename()`, and add a comment about it, so that no code ever ends up using the POSIX version! +- Never use `FILENAME_MAX`. Use `PATH_MAX` instead (for checking maximum size + of paths) and `NAME_MAX` (for checking maximum size of filenames). + `FILENAME_MAX` is not POSIX, and is a confusingly named alias for `PATH_MAX` + on Linux. Note the `NAME_MAX` does not include space for a trailing `NUL`, + but `PATH_MAX` does. UNIX FTW! + ## Committing to git - Commit message subject lines should be prefixed with an appropriate component diff --git a/docs/DISCOVERABLE_PARTITIONS.md b/docs/DISCOVERABLE_PARTITIONS.md index fd8e92781..9ce4ebc94 100644 --- a/docs/DISCOVERABLE_PARTITIONS.md +++ b/docs/DISCOVERABLE_PARTITIONS.md @@ -99,7 +99,7 @@ partitions, the partition flag bit 63 ("*no-auto*") may be used to turn off auto-discovery for the specific partition. If set, the partition will not be automatically mounted or enabled. -For the root, `/usr/` server data, home, variable data and temporary data +For the root, `/usr/`, server data, home, variable data and temporary data partitions, the partition flag bit 60 ("*read-only*") may be used to mark a partition for read-only mounts only. If set, the partition will be mounted read-only instead of read-write. Note that the variable data partition and the @@ -225,10 +225,12 @@ appliance-like installations. ### What partitioning tools will create a DPS-compliant partition table? -As of util-linux 2.25.2, the fdisk tool provides type codes to create the root, -home, and swap partitions that the DPS expects, but the gdisk tool (version -0.8.10) and its variants do not support creation of a root file system with a -matching type code. By default, fdisk will create an old-style MBR, not a GPT, -so typing 'l' to list partition types will not show the choices that the root -partition with the correct UUID. You must first create an empty GPT and then -type 'l' in order for the DPS-compliant type codes to be available. +As of util-linux 2.25.2, the `fdisk` tool provides type codes to create the +root, home, and swap partitions that the DPS expects. By default, `fdisk` will +create an old-style MBR, not a GPT, so typing `l` to list partition types will +not show the choices to let you set the correct UUID. Make sure to first create +an empty GPT, then type `l` in order for the DPS-compliant type codes to be +available. + +The `gdisk` tool (from version 1.0.5 onward) and its variants (`sgdisk`, +`cgdisk`) also support creation of partitions with a matching type code. diff --git a/docs/ENVIRONMENT.md b/docs/ENVIRONMENT.md index 74a71bba9..ad2d3ad84 100644 --- a/docs/ENVIRONMENT.md +++ b/docs/ENVIRONMENT.md @@ -19,18 +19,17 @@ documented in the proper man pages. All tools: -* `$SYSTEMD_OFFLINE=[0|1]` — if set to `1`, then `systemctl` will - refrain from talking to PID 1; this has the same effect as the historical - detection of `chroot()`. Setting this variable to `0` instead has a similar - effect as `SYSTEMD_IGNORE_CHROOT=1`; i.e. tools will try to - communicate with PID 1 even if a `chroot()` environment is detected. - You almost certainly want to set this to `1` if you maintain a package build system - or similar and are trying to use a modern container system and not plain - `chroot()`. +* `$SYSTEMD_OFFLINE=[0|1]` — if set to `1`, then `systemctl` will refrain from + talking to PID 1; this has the same effect as the historical detection of + `chroot()`. Setting this variable to `0` instead has a similar effect as + `SYSTEMD_IGNORE_CHROOT=1`; i.e. tools will try to communicate with PID 1 even + if a `chroot()` environment is detected. You almost certainly want to set + this to `1` if you maintain a package build system or similar and are trying + to use a modern container system and not plain `chroot()`. * `$SYSTEMD_IGNORE_CHROOT=1` — if set, don't check whether being invoked in a `chroot()` environment. This is particularly relevant for systemctl, as it - will not alter its behaviour for `chroot()` environments if set. Normally it + will not alter its behaviour for `chroot()` environments if set. Normally it refrains from talking to PID 1 in such a case; turning most operations such as `start` into no-ops. If that's what's explicitly desired, you might consider setting `SYSTEMD_OFFLINE=1`. @@ -39,22 +38,35 @@ All tools: will print latency information at runtime. * `$SYSTEMD_PROC_CMDLINE` — if set, the contents are used as the kernel command - line instead of the actual one in /proc/cmdline. This is useful for + line instead of the actual one in `/proc/cmdline`. This is useful for debugging, in order to test generators and other code against specific kernel command lines. -* `$SYSTEMD_FSTAB` — if set, use this path instead of /etc/fstab. Only useful +* `$SYSTEMD_FSTAB` — if set, use this path instead of `/etc/fstab`. Only useful for debugging. -* `$SYSTEMD_CRYPTTAB` — if set, use this path instead of /etc/crypttab. Only - useful for debugging. Currently only supported by systemd-cryptsetup-generator. +* `$SYSTEMD_CRYPTTAB` — if set, use this path instead of `/etc/crypttab`. Only + useful for debugging. Currently only supported by + `systemd-cryptsetup-generator`. + +* `$SYSTEMD_VERITYTAB` — if set, use this path instead of + `/etc/veritytab`. Only useful for debugging. Currently only supported by + `systemd-veritysetup-generator`. * `$SYSTEMD_EFI_OPTIONS` — if set, used instead of the string in the - SystemdOptions EFI variable. Analogous to `$SYSTEMD_PROC_CMDLINE`. + `SystemdOptions` EFI variable. Analogous to `$SYSTEMD_PROC_CMDLINE`. -* `$SYSTEMD_IN_INITRD` — takes a boolean. If set, overrides initrd detection. - This is useful for debugging and testing initrd-only programs in the main - system. +* `$SYSTEMD_DEFAULT_HOSTNAME` — override the compiled-in fallback hostname + (relevant in particular for the system manager and `systemd-hostnamed`). + Must be a valid hostname (either a single label or a FQDN). + +* `$SYSTEMD_IN_INITRD=[auto|lenient|0|1]` — if set, specifies initrd detection + method. Defaults to `auto`. Behavior is defined as follows: + `auto`: Checks if `/etc/initrd-release` exists, and a temporary fs is mounted + on `/`. If both conditions meet, then it's in initrd. + `lenient`: Similar to `auto`, but the rootfs check is skipped. + `0|1`: Simply overrides initrd detection. This is useful for debugging and + testing initrd-only programs in the main system. * `$SYSTEMD_BUS_TIMEOUT=SECS` — specifies the maximum time to wait for method call completion. If no time unit is specified, assumes seconds. The usual other units @@ -62,23 +74,23 @@ All tools: to 0, then the built-in default is used. * `$SYSTEMD_MEMPOOL=0` — if set, the internal memory caching logic employed by - hash tables is turned off, and libc malloc() is used for all allocations. + hash tables is turned off, and libc `malloc()` is used for all allocations. -* `$SYSTEMD_EMOJI=0` — if set, tools such as "systemd-analyze security" will +* `$SYSTEMD_EMOJI=0` — if set, tools such as `systemd-analyze security` will not output graphical smiley emojis, but ASCII alternatives instead. Note that this only controls use of Unicode emoji glyphs, and has no effect on other Unicode glyphs. * `$RUNTIME_DIRECTORY` — various tools use this variable to locate the - appropriate path under /run. This variable is also set by the manager when - RuntimeDirectory= is used, see systemd.exec(5). + appropriate path under `/run/`. This variable is also set by the manager when + `RuntimeDirectory=` is used, see systemd.exec(5). * `$SYSTEMD_CRYPT_PREFIX` — if set configures the hash method prefix to use for - UNIX crypt() when generating passwords. By default the system's "preferred - method" is used, but this can be overridden with this environment - variable. Takes a prefix such as `$6$` or `$y$`. (Note that this is only - honoured on systems built with libxcrypt and is ignored on systems using - glibc's original, internal crypt() implementation.) + UNIX `crypt()` when generating passwords. By default the system's "preferred + method" is used, but this can be overridden with this environment variable. + Takes a prefix such as `$6$` or `$y$`. (Note that this is only honoured on + systems built with libxcrypt and is ignored on systems using glibc's + original, internal `crypt()` implementation.) * `$SYSTEMD_RDRAND=0` — if set, the RDRAND instruction will never be used, even if the CPU supports it. @@ -87,10 +99,10 @@ All tools: support for it is compiled in and available in the kernel. * `$SYSTEMD_LOG_SECCOMP=1` — if set, system calls blocked by seccomp filtering, - for example in systemd-nspawn, will be logged to the audit log, if the current - kernel version supports this. + for example in `systemd-nspawn`, will be logged to the audit log, if the + kernel supports this. -systemctl: +`systemctl`: * `$SYSTEMCTL_FORCE_BUS=1` — if set, do not connect to PID1's private D-Bus listener, and instead always connect through the dbus-daemon D-bus broker. @@ -98,16 +110,16 @@ systemctl: * `$SYSTEMCTL_INSTALL_CLIENT_SIDE=1` — if set, enable or disable unit files on the client side, instead of asking PID 1 to do this. -* `$SYSTEMCTL_SKIP_SYSV=1` — if set, do not call out to SysV compatibility hooks. +* `$SYSTEMCTL_SKIP_SYSV=1` — if set, do not call SysV compatibility hooks. -systemd-nspawn: +`systemd-nspawn`: -* `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` — if set, force nspawn into unified - cgroup hierarchy mode. +* `$SYSTEMD_NSPAWN_UNIFIED_HIERARCHY=1` — if set, force `systemd-nspawn` into + unified cgroup hierarchy mode. -* `$SYSTEMD_NSPAWN_API_VFS_WRITABLE=1` — if set, make /sys and /proc/sys and - friends writable in the container. If set to "network", leave only - /proc/sys/net writable. +* `$SYSTEMD_NSPAWN_API_VFS_WRITABLE=1` — if set, make `/sys/`, `/proc/sys/`, + and friends writable in the container. If set to "network", leave only + `/proc/sys/net/` writable. * `$SYSTEMD_NSPAWN_CONTAINER_SERVICE=…` — override the "service" name nspawn uses to register with machined. If unset defaults to "nspawn", but with this @@ -118,52 +130,41 @@ systemd-nspawn: * `$SYSTEMD_NSPAWN_LOCK=0` — if set, do not lock container images when running. -* `$SYSTEMD_NSPAWN_TMPFS_TMP=0` — if set, do not overmount /tmp in the +* `$SYSTEMD_NSPAWN_TMPFS_TMP=0` — if set, do not overmount `/tmp/` in the container with a tmpfs, but leave the directory from the image in place. -systemd-logind: +`systemd-logind`: * `$SYSTEMD_BYPASS_HIBERNATION_MEMORY_CHECK=1` — if set, report that hibernation is available even if the swap devices do not provide enough room for it. -systemd-udevd: - -* `$NET_NAMING_SCHEME=` – if set, takes a network naming scheme (i.e. one of - "v238", "v239", "v240"…, or the special value "latest") as parameter. If - specified udev's net_id builtin will follow the specified naming scheme when - determining stable network interface names. This may be used to revert to - naming schemes of older udev versions, in order to provide more stable naming - across updates. This environment variable takes precedence over the kernel - command line option `net.naming-scheme=`, except if the value is prefixed - with `:` in which case the kernel command line option takes precedence, if it - is specified as well. - -* `$SYSTEMD_REBOOT_TO_FIRMWARE_SETUP` — if set overrides systemd-logind's - built-in EFI logic of requesting a reboot into the firmware. Takes a - boolean. If set to false the functionality is turned off entirely. If set to - true instead of requesting a reboot into the firmware setup UI through EFI a - file `/run/systemd/reboot-to-firmware-setup` is created whenever this is +* `$SYSTEMD_REBOOT_TO_FIRMWARE_SETUP` — if set, overrides `systemd-logind`'s + built-in EFI logic of requesting a reboot into the firmware. Takes a boolean. + If set to false, the functionality is turned off entirely. If set to true, + instead of requesting a reboot into the firmware setup UI through EFI a file, + `/run/systemd/reboot-to-firmware-setup` is created whenever this is requested. This file may be checked for by services run during system shutdown in order to request the appropriate operation from the firmware in an alternative fashion. * `$SYSTEMD_REBOOT_TO_BOOT_LOADER_MENU` — similar to the above, allows - overriding of systemd-logind's built-in EFI logic of requesting a reboot into - the boot loader menu. Takes a boolean. If set to false the functionality is - turned off entirely. If set to true instead of requesting a reboot into the - boot loader menu through EFI a file `/run/systemd/reboot-to-boot-loader-menu` - is created whenever this is requested. The file contains the requested boot - loader menu timeout in µs, formatted in ASCII decimals, or zero in case no - timeout is requested. This file may be checked for by services run during - system shutdown in order to request the appropriate operation from the boot - loader in an alternative fashion. + overriding of `systemd-logind`'s built-in EFI logic of requesting a reboot + into the boot loader menu. Takes a boolean. If set to false, the + functionality is turned off entirely. If set to true, instead of requesting a + reboot into the boot loader menu through EFI, the file + `/run/systemd/reboot-to-boot-loader-menu` is created whenever this is + requested. The file contains the requested boot loader menu timeout in µs, + formatted in ASCII decimals, or zero in case no timeout is requested. This + file may be checked for by services run during system shutdown in order to + request the appropriate operation from the boot loader in an alternative + fashion. * `$SYSTEMD_REBOOT_TO_BOOT_LOADER_ENTRY` — similar to the above, allows - overriding of systemd-logind's built-in EFI logic of requesting a reboot into - a specific boot loader entry. Takes a boolean. If set to false the - functionality is turned off entirely. If set to true instead of requesting a - reboot into a specific boot loader entry through EFI a file + overriding of `systemd-logind`'s built-in EFI logic of requesting a reboot + into a specific boot loader entry. Takes a boolean. If set to false, the + functionality is turned off entirely. If set to true, instead of requesting a + reboot into a specific boot loader entry through EFI, the file `/run/systemd/reboot-to-boot-loader-entry` is created whenever this is requested. The file contains the requested boot loader entry identifier. This file may be checked for by services run during system shutdown in order to @@ -178,18 +179,31 @@ systemd-udevd: `/run/boot-loader-entries/loader/entries/*.conf`, and the files referenced by the drop-ins (including the kernels and initrds) somewhere else below `/run/boot-loader-entries/`. Note that all these files may be (and are - supposed to be) symlinks. systemd-logind will load these files on-demand, + supposed to be) symlinks. `systemd-logind` will load these files on-demand, these files can hence be updated (ideally atomically) whenever the boot loader configuration changes. A foreign boot loader installer script should hence synthesize drop-in snippets and symlinks for all boot entries at boot - or whenever they change if it wants to integrate with systemd-logind's APIs. + or whenever they change if it wants to integrate with `systemd-logind`'s + APIs. + +`systemd-udevd`: + +* `$NET_NAMING_SCHEME=` – if set, takes a network naming scheme (i.e. one of + "v238", "v239", "v240"…, or the special value "latest") as parameter. If + specified udev's `net_id` builtin will follow the specified naming scheme + when determining stable network interface names. This may be used to revert + to naming schemes of older udev versions, in order to provide more stable + naming across updates. This environment variable takes precedence over the + kernel command line option `net.naming-scheme=`, except if the value is + prefixed with `:` in which case the kernel command line option takes + precedence, if it is specified as well. installed systemd tests: * `$SYSTEMD_TEST_DATA` — override the location of test data. This is useful if a test executable is moved to an arbitrary location. -nss-systemd: +`nss-systemd`: * `$SYSTEMD_NSS_BYPASS_SYNTHETIC=1` — if set, `nss-systemd` won't synthesize user/group records for the `root` and `nobody` users if they are missing from @@ -203,20 +217,20 @@ nss-systemd: dynamic user lookups. This is primarily useful to make `nss-systemd` work safely from within `dbus-daemon`. -systemd-timedated: +`systemd-timedated`: * `$SYSTEMD_TIMEDATED_NTP_SERVICES=…` — colon-separated list of unit names of NTP client services. If set, `timedatectl set-ntp on` enables and starts the first existing unit listed in the environment variable, and `timedatectl set-ntp off` disables and stops all listed units. -systemd-sulogin-shell: +`systemd-sulogin-shell`: * `$SYSTEMD_SULOGIN_FORCE=1` — This skips asking for the root password if the root password is not available (such as when the root account is locked). See `sulogin(8)` for more details. -bootctl and other tools that access the EFI System Partition (ESP): +`bootctl` and other tools that access the EFI System Partition (ESP): * `$SYSTEMD_RELAX_ESP_CHECKS=1` — if set, the ESP validation checks are relaxed. Specifically, validation checks that ensure the specified ESP path @@ -225,11 +239,11 @@ bootctl and other tools that access the EFI System Partition (ESP): * `$SYSTEMD_ESP_PATH=…` — override the path to the EFI System Partition. This may be used to override ESP path auto detection, and redirect any accesses to - the ESP to the specified directory. Not that unlike with bootctl's --path= - switch only very superficial validation of the specified path is done when - this environment variable is used. + the ESP to the specified directory. Note that unlike with `bootctl`'s + `--path=` switch only very superficial validation of the specified path is + done when this environment variable is used. -systemd itself: +`systemd` itself: * `$SYSTEMD_ACTIVATION_UNIT` — set for all NSS and PAM module invocations that are done by the service manager on behalf of a specific unit, in child @@ -247,16 +261,55 @@ systemd itself: it is either set to `system` or `user` depending on whether the NSS/PAM module is called by systemd in `--system` or `--user` mode. -systemd-remount-fs: +`systemd-remount-fs`: * `$SYSTEMD_REMOUNT_ROOT_RW=1` — if set and no entry for the root directory - exists in /etc/fstab (this file always takes precedence), then the root + exists in `/etc/fstab` (this file always takes precedence), then the root directory is remounted writable. This is primarily used by - systemd-gpt-auto-generator to ensure the root partition is mounted writable + `systemd-gpt-auto-generator` to ensure the root partition is mounted writable in accordance to the GPT partition flags. -systemd-firstboot and localectl: +`systemd-firstboot` and `localectl`: -* `SYSTEMD_LIST_NON_UTF8_LOCALES=1` – if set non-UTF-8 locales are listed among +* `SYSTEMD_LIST_NON_UTF8_LOCALES=1` – if set, non-UTF-8 locales are listed among the installed ones. By default non-UTF-8 locales are suppressed from the selection, since we are living in the 21st century. + +`systemd-sysext`: + +* `SYSTEMD_SYSEXT_HIERARCHIES` – this variable may be used to override which + hierarchies are managed by `systemd-sysext`. By default only `/usr/` and + `/opt/` are managed, and directories may be added or removed to that list by + setting this environment variable to a colon-separated list of absolute + paths. Only "real" file systems and directories that only contain "real" file + systems as submounts should be used. Do not specify API file systems such as + `/proc/` or `/sys/` here, or hierarchies that have them as submounts. In + particular, do not specify the root directory `/` here. + +`systemd-tmpfiles`: + +* `SYSTEMD_TMPFILES_FORCE_SUBVOL` — if unset, `v`/`q`/`Q` lines will create + subvolumes only if the OS itself is installed into a subvolume. If set to `1` + (or another value interpreted as true), these lines will always create + subvolumes if the backing filesystem supports them. If set to `0`, these + lines will always create directories. + +`systemd-sysv-generator`: + +* `$SYSTEMD_SYSVINIT_PATH` — Controls where `systemd-sysv-generator` looks for + SysV init scripts. + +* `$SYSTEMD_SYSVRCND_PATH` — Controls where `systemd-sysv-generator` looks for + SysV init script runlevel link farms. + +fuzzers: + +* `$SYSTEMD_FUZZ_OUTPUT` — A boolean that specifies whether to write output to + stdout. Setting to true is useful in manual invocations, since all output is + suppressed by default. + +* `$SYSTEMD_FUZZ_RUNS` — The number of times execution should be repeated in + manual invocations. + +Note that is may be also useful to set `$SYSTEMD_LOG_LEVEL`, since all logging +is suppressed by default. diff --git a/docs/GROUP_RECORD.md b/docs/GROUP_RECORD.md index 01800494d..26809c483 100644 --- a/docs/GROUP_RECORD.md +++ b/docs/GROUP_RECORD.md @@ -7,7 +7,7 @@ layout: default # JSON Group Records Long story short: JSON Group Records are to `struct group` what [JSON User -Records](https://systemd.io/USER_RECORD.md) are to `struct passwd`. +Records](https://systemd.io/USER_RECORD) are to `struct passwd`. Conceptually, much of what applies to JSON user records also applies to JSON group records. They also consist of seven sections, with similar properties and diff --git a/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION b/docs/GVARIANT-SERIALIZATION.md similarity index 96% rename from src/libsystemd/sd-bus/GVARIANT-SERIALIZATION rename to docs/GVARIANT-SERIALIZATION.md index 973a06376..54e3705ba 100644 --- a/src/libsystemd/sd-bus/GVARIANT-SERIALIZATION +++ b/docs/GVARIANT-SERIALIZATION.md @@ -1,5 +1,10 @@ -How we use GVariant for serializing D-Bus messages --------------------------------------------------- +--- +title: GVariant D-Bus Message Serialization +category: Interfaces +layout: default +--- + +# GVariant D-Bus Message Serialization We stay close to the original dbus1 framing as possible, but make certain changes to adapt for GVariant. dbus1 has the following diff --git a/docs/HACKING.md b/docs/HACKING.md index 7ec3dde95..6a44db09a 100644 --- a/docs/HACKING.md +++ b/docs/HACKING.md @@ -44,28 +44,37 @@ generate a disk image `image.raw` you can boot either in `systemd-nspawn` or in an UEFI-capable VM: ``` -# systemd-nspawn -bi image.raw +# mkosi boot ``` or: ``` -# qemu-system-x86_64 -enable-kvm -m 512 -smp 2 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd -hda image.raw +# mkosi qemu ``` Every time you rerun the `mkosi` command a fresh image is built, incorporating -all current changes you made to the project tree. +all current changes you made to the project tree. To save time when rebuilding, +you can use mkosi's incremental mode (`-i`). This instructs mkosi to build a set +of cache images that make future builds a lot faster. Note that the `-i` flag +both instructs mkosi to build cached images if they don't exist yet and to use +cached images if they already exist so make sure to always specify `-i` if you +want mkosi to use the cached images. -Alternatively, you may install the systemd version from your git check-out -directly on top of your host system's directory tree. This mostly works fine, -but of course you should know what you are doing as you might make your system -unbootable in case of a bug in your changes. Also, you might step into your -package manager's territory with this. Be careful! +If you're going to build mkosi images that use the same distribution and release +that you're currently using, you can speed up the initial mkosi run by having it +reuse the host's package cache. To do this, create a mkosi override file in +mkosi.default.d/ (e.g 20-local.conf) and add the following contents: -And never forget: most distributions provide very simple and convenient ways to -install all development packages necessary to build systemd. For example, on -Fedora the following command line should be sufficient to install all of -systemd's build dependencies: +``` +[Packages] +Cache= # (e.g. /var/cache/dnf) +``` + +If you want to do a local build without mkosi, most distributions also provide +very simple and convenient ways to install all development packages necessary +to build systemd. For example, on Fedora the following command line should be +sufficient to install all of systemd's build dependencies: ``` # dnf builddep systemd @@ -81,12 +90,11 @@ $ git clone https://github.com/systemd/systemd.git $ cd systemd $ vim src/core/main.c # or wherever you'd like to make your changes $ meson build # configure the build -$ ninja -C build # build it locally, see if everything compiles fine -$ ninja -C build test # run some simple regression tests +$ meson compile -C build # build it locally, see if everything compiles fine +$ meson test -C build # run some simple regression tests $ ln -s .mkosi/mkosi.fedora mkosi.default # Configure mkosi to build a fedora image -$ (umask 077; echo 123 > mkosi.rootpw) # set root password used by mkosi $ sudo mkosi # build a test image -$ sudo systemd-nspawn -bi image.raw # boot up the test image +$ sudo mkosi boot # boot up the test image $ git add -p # interactively put together your patch $ git commit # commit it $ git push REMOTE HEAD:refs/heads/BRANCH @@ -136,3 +144,83 @@ For more details on building fuzzers and integrating with OSS-Fuzz, visit: - [Setting up a new project - OSS-Fuzz](https://google.github.io/oss-fuzz/getting-started/new-project-guide/) - [Tutorials - OSS-Fuzz](https://google.github.io/oss-fuzz/reference/useful-links/#tutorials) + +## mkosi + clangd + +[clangd](https://clangd.llvm.org/) is a language server that provides code completion, diagnostics and more +right in your editor of choice (with the right plugin installed). When using mkosi, we can run clangd in the +mkosi build container to avoid needing to build systemd on the host machine just to make clangd work. To +achieve this, create a script with the following contents in systemd's project directory on the host: + +```sh +#!/usr/bin/env sh +tee mkosi-clangd.build > /dev/null << EOF +#!/usr/bin/env sh +exec clangd \\ + --compile-commands-dir=/root/build \\ + --path-mappings=\\ +"\\ +$(pwd)=/root/src,\\ +$(pwd)/mkosi.builddir=/root/build,\\ +$(pwd)/mkosi.includedir=/usr/include,\\ +$(pwd)/mkosi.installdir=/root/dest\\ +" \\ + --header-insertion=never +EOF +chmod +x mkosi-clangd.build +exec sudo mkosi --source-file-transfer=mount --incremental --skip-final-phase --build-script mkosi-clangd.build build +``` + +Next, mark the script as executable and point your editor plugin to use this script to start clangd. For +vscode's clangd extension, this is done via setting the `clangd.path` option to the path of the +mkosi-clangd.sh script. + +To be able to navigate to include files of systemd's dependencies, we need to make the /usr/include folder of +the build image available on the host. mkosi supports this by setting the `IncludeDirectory` option in +mkosi's config. The easiest way to set the option is to create a file 20-local.conf in mkosi.default.d/ and +add the following contents: + +``` +[Packages] +IncludeDirectory=mkosi.includedir +``` + +This will make the contents of /usr/include available in mkosi.includedir in the systemd project directory. +We already configured clangd to map any paths in /usr/include in the build image to mkosi.includedir/ on the +host in the mkosi-clangd.sh script. + +We also need to make sure clangd is installed in the build image. To have mkosi install clangd in the build +image, edit the 20-local.conf file we created earlier and add the following contents under the `[Packages]` +section: + +``` +BuildPackages= +``` + +Note that the exact package containing clangd will differ depending on the distribution used. Some +distributions have a separate clangd package, others put the clangd binary in a clang-tools-extra package and +some bundle clangd in the clang package. + +Because mkosi needs to run as root, we also need to make sure we can enter the root password when the editor +plugin tries to run the mkosi-clangd.sh script. To be able to enter the root password in non-interactive +scripts, we use an askpass provider. This is a program that sudo will launch if it detects it's being +executed from a non-interactive shell so that the root password can still be entered. There are multiple +implementations such as gnome askpass and KDE askpass. Install one of the askpass packages your distro +provides and set the `SUDO_ASKPASS` environment variable to the path of the askpass binary you want to use. +If configured correctly, a window will appear when your editor plugin tries to run the mkosi-clangd.sh script +allowing you to enter the root password. + +Due to a bug in btrfs, it's currently impossible to mount two mkosi btrfs images at the same time. Because of +this, trying to do a regular build while the clangd image is running will fail. To circumvent this, use ext4 +instead of btrfs for the images by adding the following contents to 20-local.conf: + +``` +[Output] +Format=gpt_ext4 +``` + +Finally, to ensure clangd starts up quickly in the editor, run an incremental build with mkosi to make sure +the cached images are initialized (`mkosi -i`). + +Now, your editor will start clangd in the mkosi build image and all of clangd's features will work as +expected. diff --git a/docs/PORTABILITY_AND_STABILITY.md b/docs/PORTABILITY_AND_STABILITY.md index 0caa5cc04..5d5260867 100644 --- a/docs/PORTABILITY_AND_STABILITY.md +++ b/docs/PORTABILITY_AND_STABILITY.md @@ -82,7 +82,7 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy | [hostnamed](https://www.freedesktop.org/wiki/Software/systemd/hostnamed) | D-Bus | yes | yes | GNOME | yes | [Ubuntu](https://launchpad.net/ubuntu/+source/ubuntu-system-service), [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially | | [localed](https://www.freedesktop.org/wiki/Software/systemd/localed) | D-Bus | yes | yes | GNOME | yes | [Ubuntu](https://launchpad.net/ubuntu/+source/ubuntu-system-service), [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially | | [timedated](https://www.freedesktop.org/wiki/Software/systemd/timedated) | D-Bus | yes | yes | GNOME | yes | [Gentoo](http://www.gentoo.org/proj/en/desktop/gnome/openrc-settingsd.xml), [BSD](http://uglyman.kremlin.cc/gitweb/gitweb.cgi?p=systembsd.git;a=summary) | partially | -| [initrd interface](https://systemd.io/INITRD_INTERFACE/) | Environment, flag files | yes | yes | dracut, ArchLinux | yes | ArchLinux | no | +| [initrd interface](https://systemd.io/INITRD_INTERFACE) | Environment, flag files | yes | yes | dracut, ArchLinux | yes | ArchLinux | no | | [Container interface](https://systemd.io/CONTAINER_INTERFACE) | Environment, Mounts | yes | yes | libvirt/LXC | yes | - | no | | [Boot Loader interface](https://systemd.io/BOOT_LOADER_INTERFACE) | EFI variables | yes | yes | gummiboot | yes | - | no | | [Service bus API](https://www.freedesktop.org/wiki/Software/systemd/dbus) | D-Bus | yes | yes | system-config-services | no | - | no | @@ -94,14 +94,14 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy | [$XDG_RUNTIME_DIR](https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html) | Environment | yes | yes | glib, GNOME | yes | - | no | | [$LISTEN_FDS $LISTEN_PID FD Passing](https://www.freedesktop.org/software/systemd/man/sd_listen_fds.html) | Environment | yes | yes | numerous (via sd-daemon.h) | yes | - | no | | [$NOTIFY_SOCKET Daemon Notifications](https://www.freedesktop.org/software/systemd/man/sd_notify.html) | Environment | yes | yes | a few, including udev | yes | - | no | -| [argv[0][0]='@' Logic](https://systemd.io/ROOT_STORAGE_DAEMONS/) | `/proc` marking | yes | yes | mdadm | yes | - | no | +| [argv[0][0]='@' Logic](https://systemd.io/ROOT_STORAGE_DAEMONS) | `/proc` marking | yes | yes | mdadm | yes | - | no | | [Unit file format](https://www.freedesktop.org/software/systemd/man/systemd.unit.html) | File format | yes | yes | numerous | no | - | no | | [Network](https://www.freedesktop.org/software/systemd/man/systemd.network.html) & [Netdev file format](https://www.freedesktop.org/software/systemd/man/systemd.netdev.html) | File format | yes | yes | no | no | - | no | | [Link file format](https://www.freedesktop.org/software/systemd/man/systemd.link.html) | File format | yes | yes | no | no | - | no | | [Journal File Format](https://systemd.io/JOURNAL_FILE_FORMAT) | File format | yes | yes | - | maybe | - | no | | [Journal Export Format](https://www.freedesktop.org/wiki/Software/systemd/export) | File format | yes | yes | - | yes | - | no | | [Cooperation in cgroup tree](https://www.freedesktop.org/wiki/Software/systemd/PaxControlGroups) | Treaty | yes | yes | libvirt | yes | libvirt | no | -| [Password Agents](https://systemd.io/PASSWORD_AGENTS/) | Socket+Files | yes | yes | - | yes | - | no | +| [Password Agents](https://systemd.io/PASSWORD_AGENTS) | Socket+Files | yes | yes | - | yes | - | no | | [udev multi-seat properties](https://www.freedesktop.org/software/systemd/man/sd-login.html) | udev Property | yes | yes | X11, gdm | no | - | no | | udev session switch ACL properties | udev Property | no | no | - | no | - | no | | [CLI of systemctl,...](https://www.freedesktop.org/software/systemd/man/systemctl.html) | CLI | yes | yes | numerous | no | - | no | @@ -120,7 +120,7 @@ And now, here's the list of (hopefully) all APIs that we have introduced with sy | `/run` | File hierarchy change | yes | yes | numerous | yes | OpenSUSE, Debian, ArchLinux | no | | [Generators](https://www.freedesktop.org/software/systemd/man/systemd.generator.html) | Subprocess | yes | yes | - | no | - | no | | [System Updates](https://www.freedesktop.org/software/systemd/man/systemd.offline-updates.html) | System Mode | yes | yes | - | no | - | no | -| [Presets](https://freedesktop.org/wiki/Software/systemd/Preset) | File format | yes | yes | - | no | - | no | +| [Presets](https://www.freedesktop.org/software/systemd/man/systemd.preset.html) | File format | yes | yes | - | no | - | no | | Udev rules | File format | yes | yes | numerous | no | no | partially | diff --git a/docs/RELEASE.md b/docs/RELEASE.md index a93c0c641..cafe766e0 100644 --- a/docs/RELEASE.md +++ b/docs/RELEASE.md @@ -7,16 +7,17 @@ layout: default # Steps to a Successful Release 1. Add all items to NEWS -2. Update the contributors list in NEWS (`ninja -C build git-contrib`) +2. Update the contributors list in NEWS (`meson compile -C build git-contrib`) 3. Update the time and place in NEWS -4. [RC1] Update version and library numbers in `meson.build` -5. Check dbus docs with `ninja -C build man/update-dbus-docs` -6. Tag the release: `version=vXXX-rcY && git tag -s "${version}" -m "systemd ${version}"` -7. Do `ninja -C build` -8. Make sure that the version string and package string match: `build/systemctl --version` -9. Upload the documentation: `ninja -C build doc-sync` -10. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones) -11. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate. -12. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically. -13. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released`) -14. [FINAL] Push commits to stable, create an empty -stable branch: `git push systemd-stable origin/master:master origin/master:refs/heads/${version}-stable`, and change the default branch to latest release (https://github.com/systemd/systemd-stable/settings/branches). +4. Update hwb (`meson compile -C build update-hwdb update-hwdb-autosuspend`) +5. [RC1] Update version and library numbers in `meson.build` +6. Check dbus docs with `meson compile -C build update-dbus-docs` +7. Tag the release: `version=vXXX-rcY && git tag -s "${version}" -m "systemd ${version}"` +8. Do `meson compile -C build` +9. Make sure that the version string and package string match: `build/systemctl --version` +10. Upload the documentation: `meson compile -C build doc-sync` +11. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones) +12. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate. +13. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically. +14. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released`) +15. [FINAL] Push commits to stable, create an empty -stable branch: `git push systemd-stable origin/master:master origin/master:refs/heads/${version}-stable`, and change the default branch to latest release (https://github.com/systemd/systemd-stable/settings/branches). diff --git a/docs/ROOT_STORAGE_DAEMONS.md b/docs/ROOT_STORAGE_DAEMONS.md index e18ac45bd..08af00926 100644 --- a/docs/ROOT_STORAGE_DAEMONS.md +++ b/docs/ROOT_STORAGE_DAEMONS.md @@ -108,7 +108,7 @@ to find a different solution to your problem._ The recommended way to distinguish between run-from-initrd and run-from-rootfs for a daemon is to check for `/etc/initrd-release` (which exists on all modern initrd implementations, see the [initrd -Interface](https://systemd.io/INITRD_INTERFACE/) for details) which when exists +Interface](https://systemd.io/INITRD_INTERFACE) for details) which when exists results in `argv[0][0]` being set to `@`, and otherwise doesn't. Something like this: @@ -190,4 +190,4 @@ few additional notes for supporting these setups: program consult this blog story: [Socket Activation](http://0pointer.de/blog/projects/socket-activation.html) -* Consider having a look at the [initrd Interface of systemd](https://systemd.io/INITRD_INTERFACE/). +* Consider having a look at the [initrd Interface of systemd](https://systemd.io/INITRD_INTERFACE). diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md index 50b9a42fa..9f69a3162 100644 --- a/docs/TRANSIENT-SETTINGS.md +++ b/docs/TRANSIENT-SETTINGS.md @@ -272,7 +272,8 @@ All cgroup/resource control settings are available for transient units ✓ IPAddressDeny= ✓ ManagedOOMSwap= ✓ ManagedOOMMemoryPressure= -✓ ManagedOOMMemoryPressureLimitPercent= +✓ ManagedOOMMemoryPressureLimit= +✓ ManagedOOMPreference= ``` ## Process Killing Settings diff --git a/docs/TRANSLATORS.md b/docs/TRANSLATORS.md index a120bcafb..fa74e19fe 100644 --- a/docs/TRANSLATORS.md +++ b/docs/TRANSLATORS.md @@ -26,7 +26,7 @@ To create a translation to a language not yet available, start by creating the initial template: ``` -$ ninja -C build/ systemd-pot +$ meson compile -C build/ systemd-pot ``` This will generate file `po/systemd.pot` in the source tree. @@ -50,7 +50,7 @@ using the `poedit` GUI editor.) Start by updating the `*.po` files from the latest template: ``` -$ ninja -C build/ systemd-update-po +$ meson compile -C build/ systemd-update-po ``` This will touch all the `*.po` files, so you'll want to pay attention when @@ -74,7 +74,7 @@ using `git checkout -- po/` after you commit the changes you do want to keep.) You can recompile the `*.po` files using the following command: ``` -$ ninja -C build/ systemd-gmo +$ meson compile -C build/ systemd-gmo ``` The resulting files will be saved in the `build/po/` directory. diff --git a/docs/USER_GROUP_API.md b/docs/USER_GROUP_API.md index ca88b3a16..51132b9a3 100644 --- a/docs/USER_GROUP_API.md +++ b/docs/USER_GROUP_API.md @@ -247,7 +247,7 @@ user is a member of the group. If both arguments are specified the specified membership will be tested for, but no others, and the pair is returned if it is defined. Unless both arguments are specified the method call needs to be made with `more` set, so that multiple replies can be returned (since typically -there are are multiple members per group and also multiple groups a user is +there are multiple members per group and also multiple groups a user is member of). As with `GetUserRecord` and `GetGroupRecord` the `service` parameter needs to contain the name of the service being talked to, in order to allow implementation of multiple service within the same IPC socket. In case no diff --git a/docs/USER_NAMES.md b/docs/USER_NAMES.md index ec07b19f3..daafdf2dc 100644 --- a/docs/USER_NAMES.md +++ b/docs/USER_NAMES.md @@ -87,8 +87,8 @@ hyphen. A size limit is enforced: the minimum of `sysconf(_SC_LOGIN_NAME_MAX)` (typically 256 on Linux; rationale: this is how POSIX suggests to detect the limit), `UT_NAMESIZE-1` (typically 31 on Linux; rationale: names longer than this cannot correctly appear in `utmp`/`wtmp` and create ambiguity with login -accounting) and `FILENAME_MAX` (4096 on Linux; rationale: user names typically -appear in directory names, i.e. the home directory), thus MIN(256, 31, 4096) = +accounting) and `NAME_MAX` (255 on Linux; rationale: user names typically +appear in directory names, i.e. the home directory), thus MIN(256, 31, 255) = 31. Note that these rules are both more strict and more relaxed than all of the diff --git a/docs/_includes/footer.html b/docs/_includes/footer.html index 95289732b..e103a278c 100644 --- a/docs/_includes/footer.html +++ b/docs/_includes/footer.html @@ -1,5 +1,5 @@ diff --git a/docs/style.css b/docs/style.css index 8a2ae719d..951e3f5a4 100644 --- a/docs/style.css +++ b/docs/style.css @@ -116,6 +116,11 @@ footer { margin-top: 4rem; } +/* Make tables vertically aligned to the top */ +tbody td { + vertical-align: top; +} + /* Github Code Highlighting */ .highlight table td { padding: 5px; } .highlight table pre { margin: 0; } diff --git a/hwdb.d/20-OUI.hwdb b/hwdb.d/20-OUI.hwdb index dba1cc6f8..5deed1b78 100644 --- a/hwdb.d/20-OUI.hwdb +++ b/hwdb.d/20-OUI.hwdb @@ -2418,7 +2418,7 @@ OUI:000323* ID_OUI_FROM_DATABASE=Cornet Technology, Inc. OUI:000324* - ID_OUI_FROM_DATABASE=SANYO Consumer Electronics Co., Ltd. + ID_OUI_FROM_DATABASE=SANYO Techno Solutions Tottori Co., Ltd. OUI:000325* ID_OUI_FROM_DATABASE=Arima Computer Corp. @@ -3453,7 +3453,7 @@ OUI:00047C* ID_OUI_FROM_DATABASE=Skidata AG OUI:00047D* - ID_OUI_FROM_DATABASE=Pelco + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. OUI:00047E* ID_OUI_FROM_DATABASE=Siqura B.V. @@ -6186,7 +6186,7 @@ OUI:00080B* ID_OUI_FROM_DATABASE=Birka BPA Informationssystem AB OUI:00080C* - ID_OUI_FROM_DATABASE=VDA Elettronica spa + ID_OUI_FROM_DATABASE=VDA Group S.p.a. OUI:00080D* ID_OUI_FROM_DATABASE=Toshiba @@ -8544,7 +8544,7 @@ OUI:000B39* ID_OUI_FROM_DATABASE=Keisoku Giken Co.,Ltd. OUI:000B3A* - ID_OUI_FROM_DATABASE=QuStream Corporation + ID_OUI_FROM_DATABASE=PESA OUI:000B3B* ID_OUI_FROM_DATABASE=devolo AG @@ -15369,7 +15369,7 @@ OUI:00141C* ID_OUI_FROM_DATABASE=Cisco Systems, Inc OUI:00141D* - ID_OUI_FROM_DATABASE=LTI-Motion GmbH + ID_OUI_FROM_DATABASE=KEBA Industrial Automation Germany GmbH OUI:00141E* ID_OUI_FROM_DATABASE=P.A. Semi, Inc. @@ -18753,7 +18753,7 @@ OUI:001884* ID_OUI_FROM_DATABASE=Fon Technology S.L. OUI:001885* - ID_OUI_FROM_DATABASE=Avigilon Corporation + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. OUI:001886* ID_OUI_FROM_DATABASE=EL-TECH, INC. @@ -20292,7 +20292,7 @@ OUI:001A85* ID_OUI_FROM_DATABASE=NV Michel Van de Wiele OUI:001A86* - ID_OUI_FROM_DATABASE=AdvancedIO Systems Inc + ID_OUI_FROM_DATABASE=New Wave Design & Verification OUI:001A87* ID_OUI_FROM_DATABASE=Canhold International Limited @@ -24768,7 +24768,7 @@ OUI:001F91* ID_OUI_FROM_DATABASE=DBS Lodging Technologies, LLC OUI:001F92* - ID_OUI_FROM_DATABASE=Avigilon Corporation + ID_OUI_FROM_DATABASE=Motorola Solutions Inc. OUI:001F93* ID_OUI_FROM_DATABASE=Xiotech Corporation @@ -27045,7 +27045,7 @@ OUI:002288* ID_OUI_FROM_DATABASE=Sagrad, Inc. OUI:002289* - ID_OUI_FROM_DATABASE=Vandelrande APC inc. + ID_OUI_FROM_DATABASE=Vanderlande APC inc. OUI:00228A* ID_OUI_FROM_DATABASE=Teratronik elektronische systeme gmbh @@ -27963,7 +27963,7 @@ OUI:0023BA* ID_OUI_FROM_DATABASE=Chroma OUI:0023BB* - ID_OUI_FROM_DATABASE=Schmitt Industries + ID_OUI_FROM_DATABASE=Accretech SBS, Inc. OUI:0023BC* ID_OUI_FROM_DATABASE=EQ-SYS GmbH @@ -30593,6 +30593,9 @@ OUI:002CC8* OUI:002D76* ID_OUI_FROM_DATABASE=TITECH GmbH +OUI:002DB3* + ID_OUI_FROM_DATABASE=AMPAK Technology,Inc. + OUI:002EC7* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -33935,6 +33938,9 @@ OUI:00664B* OUI:006762* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:00682B* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:0068EB* ID_OUI_FROM_DATABASE=HP Inc. @@ -34530,7 +34536,7 @@ OUI:00808B* ID_OUI_FROM_DATABASE=DACOLL LIMITED OUI:00808C* - ID_OUI_FROM_DATABASE=NetAlly + ID_OUI_FROM_DATABASE=NETSCOUT SYSTEMS INC OUI:00808D* ID_OUI_FROM_DATABASE=WESTCOAST TECHNOLOGY B.V. @@ -35802,7 +35808,7 @@ OUI:00A00D* ID_OUI_FROM_DATABASE=THE PANDA PROJECT OUI:00A00E* - ID_OUI_FROM_DATABASE=NetAlly + ID_OUI_FROM_DATABASE=NETSCOUT SYSTEMS INC OUI:00A00F* ID_OUI_FROM_DATABASE=Broadband Technologies @@ -37155,7 +37161,7 @@ OUI:00C069* ID_OUI_FROM_DATABASE=Axxcelera Broadband Wireless OUI:00C06A* - ID_OUI_FROM_DATABASE=ZAHNER-ELEKTRIK GMBH & CO. KG + ID_OUI_FROM_DATABASE=Zahner-Elektrik Ingeborg Zahner-Schiller GmbH & Co. KG. OUI:00C06B* ID_OUI_FROM_DATABASE=OSI PLUS CORPORATION @@ -37649,6 +37655,9 @@ OUI:00CBB4* OUI:00CBBD* ID_OUI_FROM_DATABASE=Cambridge Broadband Networks Group +OUI:00CC34* + ID_OUI_FROM_DATABASE=Juniper Networks + OUI:00CC3F* ID_OUI_FROM_DATABASE=Universal Electronics, Inc. @@ -39207,7 +39216,7 @@ OUI:00E0DE* ID_OUI_FROM_DATABASE=DATAX NV OUI:00E0DF* - ID_OUI_FROM_DATABASE=KEYMILE GmbH + ID_OUI_FROM_DATABASE=DZS GmbH OUI:00E0E0* ID_OUI_FROM_DATABASE=SI ELECTRONICS, LTD. @@ -39326,8 +39335,11 @@ OUI:00E400* OUI:00E406* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:00E421* + ID_OUI_FROM_DATABASE=Sony Interactive Entertainment Inc. + OUI:00E5E4* - ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co., Ltd. + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:00E666* ID_OUI_FROM_DATABASE=ARIMA Communications Corp. @@ -39419,6 +39431,9 @@ OUI:00FA21* OUI:00FA3B* ID_OUI_FROM_DATABASE=CLOOS ELECTRONIC GMBH +OUI:00FAB6* + ID_OUI_FROM_DATABASE=Kontakt Micro-Location Sp z o.o. + OUI:00FC58* ID_OUI_FROM_DATABASE=WebSilicon Ltd. @@ -39524,6 +39539,51 @@ OUI:040E3C* OUI:040EC2* ID_OUI_FROM_DATABASE=ViewSonic Mobile China Limited +OUI:0411190* + ID_OUI_FROM_DATABASE=FORT Robotics Inc. + +OUI:0411191* + ID_OUI_FROM_DATABASE=Acentury + +OUI:0411192* + ID_OUI_FROM_DATABASE=Alethea Communications Technologies Pvt. Ltd. + +OUI:0411193* + ID_OUI_FROM_DATABASE=SUZHOU RIBAO TECHNOLOGY CO.,LTD. + +OUI:0411194* + ID_OUI_FROM_DATABASE=Bolicom Innovation Technology (BeiJing) Co.,LTD. + +OUI:0411195* + ID_OUI_FROM_DATABASE=CEITA COMMUNICATION TECHNOLOGY CO.,LTD + +OUI:0411196* + ID_OUI_FROM_DATABASE=ZPD technology Co., Ltd + +OUI:0411197* + ID_OUI_FROM_DATABASE=Herrick Tech Labs + +OUI:0411198* + ID_OUI_FROM_DATABASE=Shenzhen YIZHENG Technology Co.,Ltd + +OUI:0411199* + ID_OUI_FROM_DATABASE=AC Power Distribution / ACT Entmt. + +OUI:041119A* + ID_OUI_FROM_DATABASE=CyOne Security AG + +OUI:041119B* + ID_OUI_FROM_DATABASE=Hubei Baobao Intelligent Technology Co.,LTD + +OUI:041119C* + ID_OUI_FROM_DATABASE=Haerbin Donglin Technology Co., Ltd. + +OUI:041119D* + ID_OUI_FROM_DATABASE=Nuance Hearing Ltd. + +OUI:041119E* + ID_OUI_FROM_DATABASE=JULIDA LIMITED + OUI:041552* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -39584,12 +39644,18 @@ OUI:042234* OUI:0425C5* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:0425E0* + ID_OUI_FROM_DATABASE=Taicang T&W Electronics + OUI:042605* ID_OUI_FROM_DATABASE=GFR Gesellschaft für Regelungstechnik und Energieeinsparung mbH OUI:042665* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:042728* + ID_OUI_FROM_DATABASE=Microsoft Corporation + OUI:042758* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -39719,6 +39785,9 @@ OUI:0455CA* OUI:045604* ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co.,Ltd. +OUI:0456E5* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:04572F* ID_OUI_FROM_DATABASE=Sertel Electronics UK Ltd @@ -39777,7 +39846,7 @@ OUI:046B1B* ID_OUI_FROM_DATABASE=SYSDINE Co., Ltd. OUI:046B25* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOM CO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:046C59* ID_OUI_FROM_DATABASE=Intel Corporate @@ -39842,6 +39911,9 @@ OUI:04714BD* OUI:04714BE* ID_OUI_FROM_DATABASE=Gimso Mobile Ltd +OUI:047153* + ID_OUI_FROM_DATABASE=SERNET (SUZHOU) TECHNOLOGIES CORPORATION + OUI:047295* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -39875,6 +39947,9 @@ OUI:0479B7* OUI:047A0B* ID_OUI_FROM_DATABASE=Beijing Xiaomi Electronics Co., Ltd. +OUI:047BCB* + ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. + OUI:047D50* ID_OUI_FROM_DATABASE=Shenzhen Kang Ying Technology Co.Ltd. @@ -39929,6 +40004,9 @@ OUI:048C9A* OUI:048D38* ID_OUI_FROM_DATABASE=Netcore Technology Inc. +OUI:049081* + ID_OUI_FROM_DATABASE=Pensando Systems, Inc. + OUI:049162* ID_OUI_FROM_DATABASE=Microchip Technology Inc. @@ -39975,7 +40053,7 @@ OUI:049F06* ID_OUI_FROM_DATABASE=Smobile Co., Ltd. OUI:049F81* - ID_OUI_FROM_DATABASE=NetAlly + ID_OUI_FROM_DATABASE=NETSCOUT SYSTEMS INC OUI:049FCA* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -40031,6 +40109,12 @@ OUI:04B466* OUI:04B648* ID_OUI_FROM_DATABASE=ZENNER +OUI:04B9E3* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + +OUI:04BA1C* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:04BA36* ID_OUI_FROM_DATABASE=Li Seng Technology Ltd @@ -40082,6 +40166,9 @@ OUI:04C23E* OUI:04C241* ID_OUI_FROM_DATABASE=Nokia +OUI:04C29B* + ID_OUI_FROM_DATABASE=Aura Home, Inc. + OUI:04C3E60* ID_OUI_FROM_DATABASE=DREAMKAS LLC @@ -40208,6 +40295,9 @@ OUI:04D16ED* OUI:04D16EE* ID_OUI_FROM_DATABASE=Evolute Systems Private Limited +OUI:04D320* + ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED + OUI:04D395* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company @@ -40229,9 +40319,15 @@ OUI:04D4C4* OUI:04D590* ID_OUI_FROM_DATABASE=Fortinet, Inc. +OUI:04D60E* + ID_OUI_FROM_DATABASE=FUNAI ELECTRIC CO., LTD. + OUI:04D6AA* ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND) +OUI:04D6F4* + ID_OUI_FROM_DATABASE=GD Midea Air-Conditioning Equipment Co.,Ltd. + OUI:04D783* ID_OUI_FROM_DATABASE=Y&H E&C Co.,LTD. @@ -40325,6 +40421,9 @@ OUI:04EE03* OUI:04EE91* ID_OUI_FROM_DATABASE=x-fabric GmbH +OUI:04EEEE* + ID_OUI_FROM_DATABASE=Laplace System Co., Ltd. + OUI:04F021* ID_OUI_FROM_DATABASE=Compex Systems Pte Ltd @@ -40815,7 +40914,7 @@ OUI:080090* ID_OUI_FROM_DATABASE=SONOMA SYSTEMS OUI:08010F* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:08028E* ID_OUI_FROM_DATABASE=NETGEAR @@ -40832,6 +40931,9 @@ OUI:080581* OUI:0805CD* ID_OUI_FROM_DATABASE=DongGuang EnMai Electronic Product Co.Ltd. +OUI:0805E2* + ID_OUI_FROM_DATABASE=Juniper Networks + OUI:0808C2* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -40862,6 +40964,9 @@ OUI:080EA8* OUI:080FFA* ID_OUI_FROM_DATABASE=KSP INC. +OUI:081086* + ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. + OUI:08115E* ID_OUI_FROM_DATABASE=Bitel Co., Ltd. @@ -40943,9 +41048,18 @@ OUI:082CB0* OUI:082CB6* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:082CED* + ID_OUI_FROM_DATABASE=Technity Solutions Inc. + +OUI:082E36* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:082E5F* ID_OUI_FROM_DATABASE=Hewlett Packard +OUI:082FE9* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:08306B* ID_OUI_FROM_DATABASE=Palo Alto Networks @@ -40985,6 +41099,9 @@ OUI:0838E6* OUI:083A2F* ID_OUI_FROM_DATABASE=Guangzhou Juan Intelligent Tech Joint Stock Co.,Ltd +OUI:083A38* + ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd + OUI:083A5C* ID_OUI_FROM_DATABASE=Junilab, Inc. @@ -41030,6 +41147,9 @@ OUI:084296* OUI:084656* ID_OUI_FROM_DATABASE=VEO-LABS +OUI:08474C* + ID_OUI_FROM_DATABASE=Nokia + OUI:0847D0* ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd. @@ -41129,6 +41249,9 @@ OUI:0868EA* OUI:086A0A* ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP +OUI:086AC5* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:086BD1* ID_OUI_FROM_DATABASE=Shenzhen SuperElectron Technology Co.,Ltd. @@ -41198,6 +41321,9 @@ OUI:087F98* OUI:088039* ID_OUI_FROM_DATABASE=Cisco SPVTG +OUI:0881B2* + ID_OUI_FROM_DATABASE=Logitech (China) Technology Co., Ltd + OUI:0881BC* ID_OUI_FROM_DATABASE=HongKong Ipro Technology Co., Limited @@ -41282,12 +41408,21 @@ OUI:089F97* OUI:08A12B* ID_OUI_FROM_DATABASE=ShenZhen EZL Technology Co., Ltd +OUI:08A189* + ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. + OUI:08A5C8* ID_OUI_FROM_DATABASE=Sunnovo International Limited OUI:08A6BC* ID_OUI_FROM_DATABASE=Amazon Technologies Inc. +OUI:08A7C0* + ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. + +OUI:08A842* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:08A8A1* ID_OUI_FROM_DATABASE=Cyclotronics Power Concepts, Inc @@ -41297,6 +41432,9 @@ OUI:08A95A* OUI:08AA55* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company +OUI:08AA89* + ID_OUI_FROM_DATABASE=zte corporation + OUI:08ACA5* ID_OUI_FROM_DATABASE=Benu Video, Inc. @@ -41342,6 +41480,9 @@ OUI:08BA22* OUI:08BA5F* ID_OUI_FROM_DATABASE=Qingdao Hisense Electronics Co.,Ltd. +OUI:08BB3C* + ID_OUI_FROM_DATABASE=Flextronics Tech.(Ind) Pvt Ltd + OUI:08BBCC* ID_OUI_FROM_DATABASE=AK-NORD EDV VERTRIEBSGES. mbH @@ -41546,6 +41687,9 @@ OUI:08F458* OUI:08F4AB* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:08F606* + ID_OUI_FROM_DATABASE=zte corporation + OUI:08F69C* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -41747,6 +41891,9 @@ OUI:0C41E9* OUI:0C42A1* ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc. +OUI:0C4314* + ID_OUI_FROM_DATABASE=Silicon Laboratories + OUI:0C45BA* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -41783,9 +41930,6 @@ OUI:0C4F5A* OUI:0C5101* ID_OUI_FROM_DATABASE=Apple, Inc. -OUI:0C51D0* - ID_OUI_FROM_DATABASE=Altice Labs S.A. - OUI:0C51F7* ID_OUI_FROM_DATABASE=CHAUVIN ARNOUX @@ -41825,12 +41969,60 @@ OUI:0C5A19* OUI:0C5A9E* ID_OUI_FROM_DATABASE=Wi-SUN Alliance +OUI:0C5CB50* + ID_OUI_FROM_DATABASE=Yamasei + +OUI:0C5CB51* + ID_OUI_FROM_DATABASE=avxav Electronic Trading LLC + +OUI:0C5CB52* + ID_OUI_FROM_DATABASE=HongKong Blossom Limited + +OUI:0C5CB53* + ID_OUI_FROM_DATABASE=iH&S Technology Limited + +OUI:0C5CB54* + ID_OUI_FROM_DATABASE=Annapurna labs + +OUI:0C5CB55* + ID_OUI_FROM_DATABASE=The Raymond Corporation + +OUI:0C5CB56* + ID_OUI_FROM_DATABASE=S2C limited + +OUI:0C5CB57* + ID_OUI_FROM_DATABASE=Energybox Limited + +OUI:0C5CB58* + ID_OUI_FROM_DATABASE=Shenzhen C & D Electronics Co., Ltd. + +OUI:0C5CB59* + ID_OUI_FROM_DATABASE=Colordeve International + +OUI:0C5CB5A* + ID_OUI_FROM_DATABASE=Zhengzhou coal machinery hydraulic electric control Co.,Ltd + +OUI:0C5CB5B* + ID_OUI_FROM_DATABASE=ADI + +OUI:0C5CB5C* + ID_OUI_FROM_DATABASE=Hunan Newman Car NetworKing Technology Co.,Ltd + +OUI:0C5CB5D* + ID_OUI_FROM_DATABASE=BSU Inc + +OUI:0C5CB5E* + ID_OUI_FROM_DATABASE=Munters Europe AB + OUI:0C5CD8* ID_OUI_FROM_DATABASE=DOLI Elektronik GmbH OUI:0C5F35* ID_OUI_FROM_DATABASE=Niagara Video Corporation +OUI:0C6046* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:0C6076* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. @@ -41978,6 +42170,9 @@ OUI:0C826A* OUI:0C839A* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:0C83CC* + ID_OUI_FROM_DATABASE=Alpha Networks Inc. + OUI:0C8411* ID_OUI_FROM_DATABASE=A.O. Smith Water Products @@ -42014,6 +42209,9 @@ OUI:0C8BFD* OUI:0C8C24* ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD +OUI:0C8C69* + ID_OUI_FROM_DATABASE=Shenzhen elink smart Co., ltd + OUI:0C8C8F* ID_OUI_FROM_DATABASE=Kamo Technology Limited @@ -42023,6 +42221,9 @@ OUI:0C8CDC* OUI:0C8D98* ID_OUI_FROM_DATABASE=TOP EIGHT IND CORP +OUI:0C8DCA* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:0C8DDB* ID_OUI_FROM_DATABASE=Cisco Meraki @@ -42062,6 +42263,9 @@ OUI:0C96E6* OUI:0C9838* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd +OUI:0C9A3C* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:0C9A42* ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED @@ -42197,6 +42401,9 @@ OUI:0CC844* OUI:0CC9C6* ID_OUI_FROM_DATABASE=Samwin Hong Kong Limited +OUI:0CCB0C* + ID_OUI_FROM_DATABASE=iSYS RTS GmbH + OUI:0CCB85* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company @@ -42215,6 +42422,9 @@ OUI:0CCDFB* OUI:0CCEF6* ID_OUI_FROM_DATABASE=Guizhou Fortuneship Technology Co., Ltd +OUI:0CCF89* + ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD + OUI:0CCFD1* ID_OUI_FROM_DATABASE=SPRINGWAVE Co., Ltd @@ -42278,6 +42488,9 @@ OUI:0CE0DC* OUI:0CE0E4* ID_OUI_FROM_DATABASE=PLANTRONICS, INC. +OUI:0CE441* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:0CE4A0* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. @@ -42548,6 +42761,9 @@ OUI:1008B1* OUI:10090C* ID_OUI_FROM_DATABASE=Janome Sewing Machine Co., Ltd. +OUI:1009F9* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:100BA9* ID_OUI_FROM_DATABASE=Intel Corporate @@ -42575,6 +42791,9 @@ OUI:100E7E* OUI:100F18* ID_OUI_FROM_DATABASE=Fu Gang Electronic(KunShan)CO.,LTD +OUI:101081* + ID_OUI_FROM_DATABASE=zte corporation + OUI:1010B6* ID_OUI_FROM_DATABASE=McCain Inc @@ -42591,7 +42810,7 @@ OUI:101250* ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. OUI:1012B4* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOM CO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:1012FB* ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. @@ -42620,6 +42839,9 @@ OUI:101D51* OUI:101DC0* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:101EDA* + ID_OUI_FROM_DATABASE=INGENICO TERMINALS SAS + OUI:101F74* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -42632,6 +42854,9 @@ OUI:102779* OUI:1027BE* ID_OUI_FROM_DATABASE=TVIP +OUI:1027F5* + ID_OUI_FROM_DATABASE=TP-Link Corporation Limited + OUI:102831* ID_OUI_FROM_DATABASE=Morion Inc. @@ -42644,6 +42869,9 @@ OUI:1029AB* OUI:102AB3* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd +OUI:102B41* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:102C6B* ID_OUI_FROM_DATABASE=AMPAK Technology, Inc. @@ -42653,6 +42881,9 @@ OUI:102C83* OUI:102D31* ID_OUI_FROM_DATABASE=Shenzhen Americas Trading Company LLC +OUI:102D41* + ID_OUI_FROM_DATABASE=Sichuan AI-Link Technology Co., Ltd. + OUI:102D96* ID_OUI_FROM_DATABASE=Looxcie Inc. @@ -42692,9 +42923,15 @@ OUI:10364A* OUI:103711* ID_OUI_FROM_DATABASE=Simlink AS +OUI:10381F* + ID_OUI_FROM_DATABASE=Sichuan AI-Link Technology Co., Ltd. + OUI:103917* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:10394E* + ID_OUI_FROM_DATABASE=Hisense broadband multimedia technology Co.,Ltd + OUI:1039E9* ID_OUI_FROM_DATABASE=Juniper Networks @@ -42704,6 +42941,9 @@ OUI:103B59* OUI:103D0A* ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD +OUI:103D1C* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:103D3E* ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. @@ -42770,12 +43010,18 @@ OUI:104FA8* OUI:105072* ID_OUI_FROM_DATABASE=Sercomm Corporation. +OUI:105107* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:105172* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:10521C* ID_OUI_FROM_DATABASE=Espressif Inc. +OUI:105403* + ID_OUI_FROM_DATABASE=INTARSO GmbH + OUI:105611* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -42854,6 +43100,9 @@ OUI:10683F* OUI:106F3F* ID_OUI_FROM_DATABASE=BUFFALO.INC +OUI:106FD9* + ID_OUI_FROM_DATABASE=CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. + OUI:106FEF* ID_OUI_FROM_DATABASE=Ad-Sol Nissin Corp @@ -42905,6 +43154,9 @@ OUI:107B44* OUI:107BA4* ID_OUI_FROM_DATABASE=Olive & Dove Co.,Ltd. +OUI:107BCE* + ID_OUI_FROM_DATABASE=Nokia + OUI:107BEF* ID_OUI_FROM_DATABASE=Zyxel Communications Corporation @@ -42959,6 +43211,9 @@ OUI:109397* OUI:1093E9* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:109497* + ID_OUI_FROM_DATABASE=Logitech Hong Kong + OUI:1094BB* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -43007,6 +43262,9 @@ OUI:10A4B9* OUI:10A4BE* ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD +OUI:10A4DA* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:10A5D0* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -43121,6 +43379,9 @@ OUI:10C73F* OUI:10C753* ID_OUI_FROM_DATABASE=Qingdao Intelligent&Precise Electronics Co.,Ltd. +OUI:10C9CA* + ID_OUI_FROM_DATABASE=Ace Technology Corp. + OUI:10CA81* ID_OUI_FROM_DATABASE=PRECIA @@ -43163,6 +43424,9 @@ OUI:10D38A* OUI:10D542* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:10D561* + ID_OUI_FROM_DATABASE=Tuya Smart Inc. + OUI:10D7B0* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -43241,6 +43505,9 @@ OUI:10E3C7* OUI:10E4AF* ID_OUI_FROM_DATABASE=APR, LLC +OUI:10E4C2* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:10E68F* ID_OUI_FROM_DATABASE=KWANGSUNG ELECTRONICS KOREA CO.,LTD. @@ -43343,6 +43610,9 @@ OUI:140708* OUI:1407E0* ID_OUI_FROM_DATABASE=Abrantix AG +OUI:1409B4* + ID_OUI_FROM_DATABASE=zte corporation + OUI:1409DC* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -43481,6 +43751,9 @@ OUI:14205E* OUI:142233* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:14223B* + ID_OUI_FROM_DATABASE=Google, Inc. + OUI:1422DB* ID_OUI_FROM_DATABASE=eero inc. @@ -43562,6 +43835,9 @@ OUI:14373B* OUI:143AEA* ID_OUI_FROM_DATABASE=Dynapower Company LLC +OUI:143B42* + ID_OUI_FROM_DATABASE=Realfit(Shenzhen) Intelligent Technology Co., Ltd + OUI:143CC3* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -43682,9 +43958,15 @@ OUI:144FD7D* OUI:144FD7E* ID_OUI_FROM_DATABASE=Edan Instruments, Inc. +OUI:145051* + ID_OUI_FROM_DATABASE=SHARP Corporation + OUI:145120* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:14517E* + ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd + OUI:145290* ID_OUI_FROM_DATABASE=KNS Group LLC (YADRO Company) @@ -43718,6 +44000,9 @@ OUI:145A05* OUI:145A83* ID_OUI_FROM_DATABASE=Logi-D inc +OUI:145AFC* + ID_OUI_FROM_DATABASE=Liteon Technology Corporation + OUI:145BD1* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -43749,7 +44034,7 @@ OUI:146308* ID_OUI_FROM_DATABASE=JABIL CIRCUIT (SHANGHAI) LTD. OUI:1469A2* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOM CO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:146A0B* ID_OUI_FROM_DATABASE=Cypress Electronics Limited @@ -43787,6 +44072,9 @@ OUI:1479F3* OUI:147BAC* ID_OUI_FROM_DATABASE=Nokia +OUI:147D05* + ID_OUI_FROM_DATABASE=SERCOMM PHILIPPINES INC + OUI:147DB3* ID_OUI_FROM_DATABASE=JOA TELECOM.CO.,LTD @@ -43802,6 +44090,9 @@ OUI:14825B* OUI:148430* ID_OUI_FROM_DATABASE=MITAC COMPUTING TECHNOLOGY CORPORATION +OUI:14857F* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:148692* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -43811,15 +44102,24 @@ OUI:14876A* OUI:1488E6* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:148919* + ID_OUI_FROM_DATABASE=2bps + OUI:14893E* ID_OUI_FROM_DATABASE=VIXTEL TECHNOLOGIES LIMTED +OUI:1489CB* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:1489FD* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd OUI:148A70* ID_OUI_FROM_DATABASE=ADS GmbH +OUI:148C4A* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:148F21* ID_OUI_FROM_DATABASE=Garmin International @@ -44060,6 +44360,9 @@ OUI:14C913* OUI:14CAA0* ID_OUI_FROM_DATABASE=Hu&Co +OUI:14CB19* + ID_OUI_FROM_DATABASE=HP Inc. + OUI:14CC20* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -44102,6 +44405,9 @@ OUI:14DAE9* OUI:14DB85* ID_OUI_FROM_DATABASE=S NET MEDIA +OUI:14DD9C* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:14DDA9* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. @@ -44312,6 +44618,9 @@ OUI:182861* OUI:182A44* ID_OUI_FROM_DATABASE=HIROSE ELECTRONIC SYSTEM +OUI:182A57* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:182A7B* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. @@ -44339,6 +44648,9 @@ OUI:18300C* OUI:1831BF* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:183219* + ID_OUI_FROM_DATABASE=EM Microelectronic + OUI:1832A2* ID_OUI_FROM_DATABASE=LAON TECHNOLOGY CO., LTD. @@ -44411,6 +44723,9 @@ OUI:18421D* OUI:18422F* ID_OUI_FROM_DATABASE=Alcatel Lucent +OUI:1842D4* + ID_OUI_FROM_DATABASE=Wuhan Hosan Telecommunication Technology Co.,Ltd + OUI:184462* ID_OUI_FROM_DATABASE=Riava Networks, Inc. @@ -44432,6 +44747,9 @@ OUI:184644* OUI:18473D* ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD. +OUI:184859* + ID_OUI_FROM_DATABASE=Castlenet Technology Inc. + OUI:1848CA* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -44450,6 +44768,9 @@ OUI:184BDF* OUI:184C08* ID_OUI_FROM_DATABASE=Rockwell Automation +OUI:184CAE* + ID_OUI_FROM_DATABASE=CONTINENTAL + OUI:184E16* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -44469,7 +44790,7 @@ OUI:18502A* ID_OUI_FROM_DATABASE=SOARNEX OUI:185207* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:185253* ID_OUI_FROM_DATABASE=Pixord Corporation @@ -44591,8 +44912,23 @@ OUI:1871D5* OUI:18742E* ID_OUI_FROM_DATABASE=Amazon Technologies Inc. +OUI:1874E21* + ID_OUI_FROM_DATABASE=Sartorius Lab Instruments GmbH & Co. KG + +OUI:1874E25* + ID_OUI_FROM_DATABASE=HANGZHOU ZHOUJU ELECTRONIC TECHNOLOGICAL CO.,LTD + +OUI:1874E27* + ID_OUI_FROM_DATABASE=Sansec Technology Co.,Ltd + +OUI:1874E28* + ID_OUI_FROM_DATABASE=Kano Computing Limited + +OUI:1874E2C* + ID_OUI_FROM_DATABASE=NextGen RF Design, Inc. + OUI:187532* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:1878D4* ID_OUI_FROM_DATABASE=Verizon @@ -44864,6 +45200,9 @@ OUI:18B905* OUI:18BB26* ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED +OUI:18BB41* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:18BC5A* ID_OUI_FROM_DATABASE=Zhejiang Tmall Technology Co., Ltd. @@ -44876,6 +45215,9 @@ OUI:18BE92* OUI:18BF1C* ID_OUI_FROM_DATABASE=Jiangsu Huitong Group Co.,Ltd. +OUI:18BFB3* + ID_OUI_FROM_DATABASE=Samsung Electronics Co., Ltd., Memory Division + OUI:18C04D* ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. @@ -44885,6 +45227,9 @@ OUI:18C086* OUI:18C19D* ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. +OUI:18C241* + ID_OUI_FROM_DATABASE=SonicWall + OUI:18C2BF* ID_OUI_FROM_DATABASE=BUFFALO.INC @@ -45341,6 +45686,9 @@ OUI:1C3B8F* OUI:1C3BF3* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:1C3CD4* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:1C3D2F* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -45383,6 +45731,9 @@ OUI:1C4593* OUI:1C45C2* ID_OUI_FROM_DATABASE=Huizhou City Sunsin lntelligent Technology Co.,Ltd +OUI:1C472F* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:1C4840* ID_OUI_FROM_DATABASE=IMS Messsysteme GmbH @@ -45518,6 +45869,9 @@ OUI:1C6E4C* OUI:1C6E76* ID_OUI_FROM_DATABASE=Quarion Technology Inc +OUI:1C6EE6* + ID_OUI_FROM_DATABASE=NHNETWORKS + OUI:1C6F65* ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. @@ -45773,6 +46127,9 @@ OUI:1C8779D* OUI:1C8779E* ID_OUI_FROM_DATABASE=ASSYSTEM France +OUI:1C87E3* + ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED + OUI:1C88790* ID_OUI_FROM_DATABASE=Newps co.,ltd @@ -45836,9 +46193,15 @@ OUI:1C9148* OUI:1C9179* ID_OUI_FROM_DATABASE=Integrated System Technologies Ltd +OUI:1C9180* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:1C919D* ID_OUI_FROM_DATABASE=Dongguan Liesheng Electronic Co., Ltd. +OUI:1C937C* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:1C9492* ID_OUI_FROM_DATABASE=RUAG Schweiz AG @@ -45866,6 +46229,9 @@ OUI:1C98EC* OUI:1C994C* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. +OUI:1C9957* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:1C9C26* ID_OUI_FROM_DATABASE=Zoovel Technologies @@ -45932,12 +46298,60 @@ OUI:1CA0D3D* OUI:1CA0D3E* ID_OUI_FROM_DATABASE=Exicom Tele-Systems Ltd. +OUI:1CA0EF0* + ID_OUI_FROM_DATABASE=Tangshan Liulin Automation Equipment Co., Ltd. + +OUI:1CA0EF1* + ID_OUI_FROM_DATABASE=Wisnu and Supak Co.,Ltd. + +OUI:1CA0EF2* + ID_OUI_FROM_DATABASE=Schneider-Electric(China)Co.Ltd,Shenzhen Branch + +OUI:1CA0EF3* + ID_OUI_FROM_DATABASE=Sequent AG + +OUI:1CA0EF4* + ID_OUI_FROM_DATABASE=Leviathan Solutions Ltd. + +OUI:1CA0EF5* + ID_OUI_FROM_DATABASE=Nanjing Bilin Intelligent Identification Technology Co.,Ltd + +OUI:1CA0EF6* + ID_OUI_FROM_DATABASE=HANJEN.CHIN CO., LTD. + +OUI:1CA0EF7* + ID_OUI_FROM_DATABASE=tec5AG + +OUI:1CA0EF8* + ID_OUI_FROM_DATABASE=Zillnk + +OUI:1CA0EF9* + ID_OUI_FROM_DATABASE=Atlas Aerospace + +OUI:1CA0EFA* + ID_OUI_FROM_DATABASE=Henrich Electronics Corporation + +OUI:1CA0EFB* + ID_OUI_FROM_DATABASE=BMK professional electronics GmbH + +OUI:1CA0EFC* + ID_OUI_FROM_DATABASE=LLC Gagar.In + +OUI:1CA0EFD* + ID_OUI_FROM_DATABASE=Shenzhen Liandian Communication Technology Co.LTD + +OUI:1CA0EFE* + ID_OUI_FROM_DATABASE=RDA Microelectronics Technologies (Shanghai) Co. , Ltd + OUI:1CA2B1* ID_OUI_FROM_DATABASE=ruwido austria gmbh OUI:1CA532* ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT +OUI:1CA681* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:1CA770* ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD @@ -46145,9 +46559,15 @@ OUI:1CCCD6* OUI:1CCDE5* ID_OUI_FROM_DATABASE=Shanghai Wind Technologies Co.,Ltd +OUI:1CD107* + ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd. + OUI:1CD1BA* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:1CD1E0* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:1CD40C* ID_OUI_FROM_DATABASE=Kriwan Industrie-Elektronik GmbH @@ -46196,6 +46616,9 @@ OUI:1CE61D* OUI:1CE62B* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:1CE6AD* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:1CE6C7* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -46293,7 +46716,7 @@ OUI:1CFEA7* ID_OUI_FROM_DATABASE=IDentytech Solutins Ltd. OUI:1CFF59* - ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co., Ltd. + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:20014F* ID_OUI_FROM_DATABASE=Linea Research Ltd @@ -46421,9 +46844,15 @@ OUI:201BC9* OUI:201D03* ID_OUI_FROM_DATABASE=Elatec GmbH +OUI:201E88* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:201F31* ID_OUI_FROM_DATABASE=Inteno Broadband Technology AB +OUI:201F3B* + ID_OUI_FROM_DATABASE=Google, Inc. + OUI:2021A5* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) @@ -46433,6 +46862,9 @@ OUI:202564* OUI:202598* ID_OUI_FROM_DATABASE=Teleview +OUI:2025D2* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:202681* ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED @@ -46496,9 +46928,15 @@ OUI:203A07* OUI:203AEF* ID_OUI_FROM_DATABASE=Sivantos GmbH +OUI:203B69* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:203CAE* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:203CC0* + ID_OUI_FROM_DATABASE=Beijing Tosee Technology Co., Ltd. + OUI:203D66* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -46604,6 +47042,9 @@ OUI:205CFA* OUI:205D47* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:205E64* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:205EF7* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -46625,6 +47066,9 @@ OUI:2064CB* OUI:20658E* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:2066CF* + ID_OUI_FROM_DATABASE=FREEBOX SAS + OUI:20677C* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise @@ -46640,6 +47084,9 @@ OUI:206980* OUI:206A8A* ID_OUI_FROM_DATABASE=Wistron Infocomm (Zhongshan) Corporation +OUI:206A94* + ID_OUI_FROM_DATABASE=Hitron Technologies. Inc + OUI:206AFF* ID_OUI_FROM_DATABASE=Atlas Elektronik UK Limited @@ -46766,6 +47213,9 @@ OUI:208756* OUI:2087AC* ID_OUI_FROM_DATABASE=AES motomation +OUI:2087EC* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:20896F* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -46841,6 +47291,9 @@ OUI:20A783* OUI:20A787* ID_OUI_FROM_DATABASE=Bointec Taiwan Corporation Limited +OUI:20A7F9* + ID_OUI_FROM_DATABASE=SHENZHEN OLANBOA TECHNOLOGY CO., LTD + OUI:20A8B9* ID_OUI_FROM_DATABASE=SIEMENS AG @@ -46880,6 +47333,9 @@ OUI:20B399* OUI:20B5C6* ID_OUI_FROM_DATABASE=Mimosa Networks +OUI:20B730* + ID_OUI_FROM_DATABASE=TeconGroup, Inc + OUI:20B780* ID_OUI_FROM_DATABASE=Toshiba Visual Solutions Corporation Co.,Ltd @@ -46904,6 +47360,9 @@ OUI:20C047* OUI:20C06D* ID_OUI_FROM_DATABASE=SHENZHEN SPACETEK TECHNOLOGY CO.,LTD +OUI:20C19B* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:20C1AF* ID_OUI_FROM_DATABASE=i Wit Digital Co., Limited @@ -46919,6 +47378,9 @@ OUI:20C60D* OUI:20C6EB* ID_OUI_FROM_DATABASE=Panasonic Corporation AVC Networks Company +OUI:20C74F* + ID_OUI_FROM_DATABASE=SensorPush + OUI:20C8B3* ID_OUI_FROM_DATABASE=SHENZHEN BUL-TECH CO.,LTD. @@ -46931,12 +47393,60 @@ OUI:20CD39* OUI:20CD6E* ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd. +OUI:20CE2A0* + ID_OUI_FROM_DATABASE=Annapurna labs + +OUI:20CE2A1* + ID_OUI_FROM_DATABASE=Shanghai Digicube Info&Tech Co.,Ltd. + +OUI:20CE2A2* + ID_OUI_FROM_DATABASE=Jabil + +OUI:20CE2A3* + ID_OUI_FROM_DATABASE=Cuculus GmbH + +OUI:20CE2A4* + ID_OUI_FROM_DATABASE=Annapurna labs + +OUI:20CE2A5* + ID_OUI_FROM_DATABASE=Zaber Technologies Inc. + +OUI:20CE2A6* + ID_OUI_FROM_DATABASE=Radarxense BV + +OUI:20CE2A7* + ID_OUI_FROM_DATABASE=Beijing Huadianzhongxin Tech.Co.,Ltd + +OUI:20CE2A8* + ID_OUI_FROM_DATABASE=Intelligraphics + +OUI:20CE2A9* + ID_OUI_FROM_DATABASE=Rugged Monitoring + +OUI:20CE2AA* + ID_OUI_FROM_DATABASE=MeshPlusPlus, Inc. + +OUI:20CE2AB* + ID_OUI_FROM_DATABASE=Swarovski Optik KG + +OUI:20CE2AC* + ID_OUI_FROM_DATABASE=Ariston Thermo s.p.a. + +OUI:20CE2AD* + ID_OUI_FROM_DATABASE=LAUDA DR R WOBSER GMBH & CO KG + +OUI:20CE2AE* + ID_OUI_FROM_DATABASE=Funkwerk Systems GmbH + OUI:20CEC4* ID_OUI_FROM_DATABASE=Peraso Technologies OUI:20CF30* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:20CFAE* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:20D160* ID_OUI_FROM_DATABASE=Private @@ -46946,6 +47456,9 @@ OUI:20D21F* OUI:20D25F* ID_OUI_FROM_DATABASE=SmartCap Technologies +OUI:20D276* + ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED + OUI:20D390* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -47219,6 +47732,9 @@ OUI:24169D* OUI:24181D* ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND) +OUI:2418C6* + ID_OUI_FROM_DATABASE=HUNAN FN-LINK TECHNOLOGY LIMITED + OUI:241A8C* ID_OUI_FROM_DATABASE=Squarehead Technology AS @@ -47261,6 +47777,9 @@ OUI:24240E* OUI:242642* ID_OUI_FROM_DATABASE=SHARP Corporation. +OUI:2428FD* + ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. + OUI:2429FE* ID_OUI_FROM_DATABASE=KYOCERA Corporation @@ -47318,6 +47837,9 @@ OUI:2443E2* OUI:244427* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:24456B* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:244597* ID_OUI_FROM_DATABASE=GEMUE Gebr. Mueller Apparatebau @@ -47429,6 +47951,51 @@ OUI:245CBF* OUI:245CCB* ID_OUI_FROM_DATABASE=AXIe Consortium, Inc. +OUI:245DFC0* + ID_OUI_FROM_DATABASE=CompanyDeep + +OUI:245DFC1* + ID_OUI_FROM_DATABASE=ARTICONA - Bechtle Logistik & Service GmbH + +OUI:245DFC2* + ID_OUI_FROM_DATABASE=Blue Iris Labs + +OUI:245DFC3* + ID_OUI_FROM_DATABASE=Shenzhen Hailuck Electronic Technology CO.,LTD + +OUI:245DFC4* + ID_OUI_FROM_DATABASE=Suzhou Jiangzhi electronic technology co., Ltd + +OUI:245DFC5* + ID_OUI_FROM_DATABASE=ContactProximity Inc + +OUI:245DFC6* + ID_OUI_FROM_DATABASE=Guangzhou Lango Electronics Technology Co.,Ltd. + +OUI:245DFC7* + ID_OUI_FROM_DATABASE=LTY LLC + +OUI:245DFC8* + ID_OUI_FROM_DATABASE=Cosmicnode + +OUI:245DFC9* + ID_OUI_FROM_DATABASE=TORGOVYY DOM TEHNOLOGIY LLC + +OUI:245DFCA* + ID_OUI_FROM_DATABASE=Tata Sky Limited + +OUI:245DFCB* + ID_OUI_FROM_DATABASE=ONLY + +OUI:245DFCC* + ID_OUI_FROM_DATABASE=Senix Corporation + +OUI:245DFCD* + ID_OUI_FROM_DATABASE=Hunan Honestone lntelligence Technology Co.,Ltd + +OUI:245DFCE* + ID_OUI_FROM_DATABASE=Dodge + OUI:245EBE* ID_OUI_FROM_DATABASE=QNAP Systems, Inc. @@ -47577,7 +48144,7 @@ OUI:248A07* ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc. OUI:248BE0* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:2491BB* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -47606,6 +48173,12 @@ OUI:249504* OUI:2497ED* ID_OUI_FROM_DATABASE=Techvision Intelligent Technology Limited +OUI:249AC8* + ID_OUI_FROM_DATABASE=Shenzhen Skyworth Digital Technology CO., Ltd + +OUI:249AD8* + ID_OUI_FROM_DATABASE=YEALINK(XIAMEN) NETWORK TECHNOLOGY CO.,LTD. + OUI:249EAB* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -47639,6 +48212,12 @@ OUI:24A52C* OUI:24A534* ID_OUI_FROM_DATABASE=SynTrust Tech International Ltd. +OUI:24A65E* + ID_OUI_FROM_DATABASE=zte corporation + +OUI:24A799* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:24A7DC* ID_OUI_FROM_DATABASE=BSkyB Ltd @@ -47805,7 +48384,7 @@ OUI:24DFA7* ID_OUI_FROM_DATABASE=Hangzhou BroadLink Technology Co.,Ltd OUI:24E124* - ID_OUI_FROM_DATABASE=Xiamen Ursalink Technology Co., Ltd. + ID_OUI_FROM_DATABASE=Xiamen Milesight IoT Co., Ltd. OUI:24E271* ID_OUI_FROM_DATABASE=Qingdao Hisense Communications Co.,Ltd. @@ -47825,6 +48404,9 @@ OUI:24E5AA* OUI:24E6BA* ID_OUI_FROM_DATABASE=JSC Zavod im. Kozitsky +OUI:24E853* + ID_OUI_FROM_DATABASE=LG Innotek + OUI:24E927* ID_OUI_FROM_DATABASE=TomTom International BV @@ -47945,6 +48527,9 @@ OUI:280E8B* OUI:280FC5* ID_OUI_FROM_DATABASE=Beijing Leadsec Technology Co., Ltd. +OUI:280FEB* + ID_OUI_FROM_DATABASE=LG Innotek + OUI:28101B* ID_OUI_FROM_DATABASE=MagnaCom @@ -47954,6 +48539,9 @@ OUI:28107B* OUI:2811A5* ID_OUI_FROM_DATABASE=Bose Corporation +OUI:2811A8* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:2811EC* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -48017,6 +48605,9 @@ OUI:2829CC* OUI:2829D9* ID_OUI_FROM_DATABASE=GlobalBeiMing technology (Beijing)Co. Ltd +OUI:282B96* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:282C020* ID_OUI_FROM_DATABASE=SAKATA DENKI Co., Ltd. @@ -48188,6 +48779,9 @@ OUI:284121* OUI:2841C6* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:2841EC* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:284430* ID_OUI_FROM_DATABASE=GenesisTechnical Systems (UK) Ltd @@ -48224,6 +48818,9 @@ OUI:2852E0* OUI:2852F9* ID_OUI_FROM_DATABASE=Zhongxin Intelligent Times (Shenzhen) Co., Ltd. +OUI:28534E* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:285471* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. @@ -48242,6 +48839,9 @@ OUI:2857BE* OUI:285AEB* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:285B0C* + ID_OUI_FROM_DATABASE=Sichuan Jiuzhou Electronic Technology Co., Ltd. + OUI:285F2F* ID_OUI_FROM_DATABASE=RNware Co.,Ltd. @@ -48374,6 +48974,9 @@ OUI:28940F* OUI:2894AF* ID_OUI_FROM_DATABASE=Samhwa Telecom +OUI:2897B8* + ID_OUI_FROM_DATABASE=myenergi Ltd + OUI:28987B* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -48449,6 +49052,9 @@ OUI:28AD3E* OUI:28AF0A* ID_OUI_FROM_DATABASE=Sirius XM Radio Inc +OUI:28AFFD* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:28B0CC* ID_OUI_FROM_DATABASE=Xenya d.o.o. @@ -48563,6 +49169,9 @@ OUI:28C671* OUI:28C68E* ID_OUI_FROM_DATABASE=NETGEAR +OUI:28C709* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:28C718* ID_OUI_FROM_DATABASE=Altierre @@ -48575,6 +49184,9 @@ OUI:28C825* OUI:28C87A* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:28C87C* + ID_OUI_FROM_DATABASE=zte corporation + OUI:28C914* ID_OUI_FROM_DATABASE=Taimag Corporation @@ -48617,6 +49229,9 @@ OUI:28D044* OUI:28D0CB* ID_OUI_FROM_DATABASE=Cambridge Communication Systems Ltd +OUI:28D0EA* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:28D127* ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd @@ -48629,6 +49244,9 @@ OUI:28D1B7* OUI:28D244* ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology Co., Ltd. +OUI:28D3EA* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:28D436* ID_OUI_FROM_DATABASE=Jiangsu dewosi electric co., LTD @@ -48656,6 +49274,9 @@ OUI:28DEE5* OUI:28DEF6* ID_OUI_FROM_DATABASE=bioMerieux Inc. +OUI:28DFEB* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:28E02C* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -48720,7 +49341,7 @@ OUI:28EED3* ID_OUI_FROM_DATABASE=Shenzhen Super D Technology Co., Ltd OUI:28EF01* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. OUI:28F033* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -48737,6 +49358,9 @@ OUI:28F358* OUI:28F366* ID_OUI_FROM_DATABASE=Shenzhen Bilian electronic CO.,LTD +OUI:28F49B* + ID_OUI_FROM_DATABASE=LEETEK + OUI:28F532* ID_OUI_FROM_DATABASE=ADD-Engineering BV @@ -48788,12 +49412,18 @@ OUI:28F537E* OUI:28F606* ID_OUI_FROM_DATABASE=Syes srl +OUI:28FA19* + ID_OUI_FROM_DATABASE=Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd + OUI:28FA7A* ID_OUI_FROM_DATABASE=Zhejiang Tmall Technology Co., Ltd. OUI:28FAA0* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:28FBAE* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:28FBD3* ID_OUI_FROM_DATABASE=Ragentek Technology Group @@ -48875,6 +49505,9 @@ OUI:2C002C* OUI:2C0033* ID_OUI_FROM_DATABASE=EControls, LLC +OUI:2C00AB* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:2C00F7* ID_OUI_FROM_DATABASE=XOS @@ -48899,6 +49532,9 @@ OUI:2C0786* OUI:2C081C* ID_OUI_FROM_DATABASE=OVH +OUI:2C0823* + ID_OUI_FROM_DATABASE=Sercomm France Sarl + OUI:2C088C* ID_OUI_FROM_DATABASE=HUMAX Co., Ltd. @@ -48965,6 +49601,9 @@ OUI:2C16BDD* OUI:2C16BDE* ID_OUI_FROM_DATABASE=Molex Incorporated +OUI:2C17E0* + ID_OUI_FROM_DATABASE=SYSTEMES ET TECHNOLOGIES IDENTIFICATION (STid) + OUI:2C1875* ID_OUI_FROM_DATABASE=Skyworth Digital Technology(Shenzhen) Co.,Ltd @@ -49223,6 +49862,9 @@ OUI:2C4205* OUI:2C431A* ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd +OUI:2C43BE* + ID_OUI_FROM_DATABASE=Sunnovo International Limited + OUI:2C4401* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -49280,6 +49922,9 @@ OUI:2C4835D* OUI:2C4835E* ID_OUI_FROM_DATABASE=IROOTECH TECHNOLOGY CO.,LTD +OUI:2C4881* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:2C4A11* ID_OUI_FROM_DATABASE=Ciena Corporation @@ -49301,6 +49946,9 @@ OUI:2C4F52* OUI:2C5089* ID_OUI_FROM_DATABASE=Shenzhen Kaixuan Visual Technology Co.,Limited +OUI:2C52AF* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:2C534A* ID_OUI_FROM_DATABASE=Shenzhen Winyao Electronic Limited @@ -49386,7 +50034,7 @@ OUI:2C6289* ID_OUI_FROM_DATABASE=Regenersis (Glenrothes) Ltd OUI:2C6373* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:2C641F* ID_OUI_FROM_DATABASE=Vizio, Inc @@ -49454,6 +50102,9 @@ OUI:2C6B7D* OUI:2C6BF5* ID_OUI_FROM_DATABASE=Juniper Networks +OUI:2C6DC1* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:2C6E85* ID_OUI_FROM_DATABASE=Intel Corporate @@ -49466,6 +50117,9 @@ OUI:2C6FC9* OUI:2C7155* ID_OUI_FROM_DATABASE=HiveMotion +OUI:2C71FF* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:2C72C3* ID_OUI_FROM_DATABASE=Soundmatters @@ -49520,6 +50174,9 @@ OUI:2C8A72* OUI:2C8BF2* ID_OUI_FROM_DATABASE=Hitachi Metals America Ltd +OUI:2C8DB1* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:2C9127* ID_OUI_FROM_DATABASE=Eintechno Corporation @@ -49667,6 +50324,9 @@ OUI:2CBE08* OUI:2CBE97* ID_OUI_FROM_DATABASE=Ingenieurbuero Bickele und Buehler GmbH +OUI:2CBEEB* + ID_OUI_FROM_DATABASE=Nothing Technology Limited + OUI:2CC260* ID_OUI_FROM_DATABASE=Oracle Corporation @@ -49682,6 +50342,9 @@ OUI:2CC548* OUI:2CC5D3* ID_OUI_FROM_DATABASE=Ruckus Wireless +OUI:2CC81B* + ID_OUI_FROM_DATABASE=Routerboard.com + OUI:2CCA0C* ID_OUI_FROM_DATABASE=WITHUS PLANET @@ -49703,6 +50366,9 @@ OUI:2CCD43* OUI:2CCD69* ID_OUI_FROM_DATABASE=Aqavi.com +OUI:2CCE1E* + ID_OUI_FROM_DATABASE=Cloudtronics Pty Ltd + OUI:2CCF58* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -49755,7 +50421,7 @@ OUI:2CD141C* ID_OUI_FROM_DATABASE=PIN SHANG LED Co., LTD. OUI:2CD141D* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Square Inc. OUI:2CD141E* ID_OUI_FROM_DATABASE=CITA SMART SOLUTIONS LTD @@ -49799,6 +50465,9 @@ OUI:2CDD95* OUI:2CDDA3* ID_OUI_FROM_DATABASE=Point Grey Research Inc. +OUI:2CDDE9* + ID_OUI_FROM_DATABASE=Arista Networks + OUI:2CE2A8* ID_OUI_FROM_DATABASE=DeviceDesign @@ -49817,6 +50486,9 @@ OUI:2CE871* OUI:2CEA7F* ID_OUI_FROM_DATABASE=Dell Inc. +OUI:2CEADC* + ID_OUI_FROM_DATABASE=ASKEY COMPUTER CORP + OUI:2CEDEB* ID_OUI_FROM_DATABASE=Alpheus Digital Company Limited @@ -49862,6 +50534,9 @@ OUI:2CFDA1* OUI:2CFDAB* ID_OUI_FROM_DATABASE=Motorola (Wuhan) Mobility Technologies Communication Co., Ltd. +OUI:2CFDB3* + ID_OUI_FROM_DATABASE=TCL Technoly Electronics(Huizhou).,Ltd + OUI:2CFF65* ID_OUI_FROM_DATABASE=Oki Electric Industry Co., Ltd. @@ -50123,6 +50798,9 @@ OUI:3035AD* OUI:3037A6* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:3037B3* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:303855* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -50220,7 +50898,7 @@ OUI:304950C* ID_OUI_FROM_DATABASE=Anacove LLC OUI:304950D* - ID_OUI_FROM_DATABASE=Xio Research, Inc + ID_OUI_FROM_DATABASE=Merlyn Mind, Inc. OUI:304950E* ID_OUI_FROM_DATABASE=IoTmaxx GmbH @@ -50354,12 +51032,18 @@ OUI:30786B* OUI:3078C2* ID_OUI_FROM_DATABASE=Innowireless / QUCELL Networks +OUI:3078D3* + ID_OUI_FROM_DATABASE=Virgilant Technologies Ltd. + OUI:307BAC* ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd OUI:307C30* ID_OUI_FROM_DATABASE=RIM +OUI:307C4A* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:307C5E* ID_OUI_FROM_DATABASE=Juniper Networks @@ -50372,12 +51056,18 @@ OUI:307ECB* OUI:30809B* ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd +OUI:308398* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:308454* ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD OUI:3085A9* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:3085EB* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:30862D* ID_OUI_FROM_DATABASE=Arista Network, Inc. @@ -50414,6 +51104,9 @@ OUI:308CFB* OUI:308D99* ID_OUI_FROM_DATABASE=Hewlett Packard +OUI:308E7A* + ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO.,LTD + OUI:309048* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -50435,6 +51128,9 @@ OUI:3093BC* OUI:309435* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:309587* + ID_OUI_FROM_DATABASE=HUNAN FN-LINK TECHNOLOGY LIMITED + OUI:3095E3* ID_OUI_FROM_DATABASE=SHANGHAI SIMCOM LIMITED @@ -50462,6 +51158,9 @@ OUI:309FFB* OUI:30A023* ID_OUI_FROM_DATABASE=ROCK PATH S.R.L +OUI:30A176* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:30A1FA* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -50477,6 +51176,9 @@ OUI:30A2C2* OUI:30A452* ID_OUI_FROM_DATABASE=Arrival Elements BV +OUI:30A612* + ID_OUI_FROM_DATABASE=ShenZhen Hugsun Technology Co.,Ltd. + OUI:30A889* ID_OUI_FROM_DATABASE=DECIMATOR DESIGN @@ -50513,12 +51215,18 @@ OUI:30AFCE* OUI:30B164* ID_OUI_FROM_DATABASE=Power Electronics International Inc. +OUI:30B1B5* + ID_OUI_FROM_DATABASE=Arcadyan Corporation + OUI:30B216* ID_OUI_FROM_DATABASE=Hitachi ABB Power Grids – Grid Automation OUI:30B237* ID_OUI_FROM_DATABASE=GD Midea Air-Conditioning Equipment Co.,Ltd. +OUI:30B346* + ID_OUI_FROM_DATABASE=CJSC NORSI-TRANS + OUI:30B3A2* ID_OUI_FROM_DATABASE=Shenzhen Heguang Measurement & Control Technology Co.,Ltd @@ -50636,6 +51344,9 @@ OUI:30E283* OUI:30E37A* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:30E396* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:30E3D6* ID_OUI_FROM_DATABASE=Spotify USA Inc. @@ -50693,6 +51404,9 @@ OUI:30F7C5* OUI:30F7D7* ID_OUI_FROM_DATABASE=Thread Technology Co., Ltd +OUI:30F94B* + ID_OUI_FROM_DATABASE=Universal Electronics, Inc. + OUI:30F9ED* ID_OUI_FROM_DATABASE=Sony Corporation @@ -51074,6 +51788,9 @@ OUI:3448ED* OUI:34495B* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS +OUI:344AC3* + ID_OUI_FROM_DATABASE=HuNan ZiKun Information Technology CO., Ltd + OUI:344B3D* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -51164,6 +51881,9 @@ OUI:3466EA* OUI:34684A* ID_OUI_FROM_DATABASE=Teraworks Co., Ltd. +OUI:346893* + ID_OUI_FROM_DATABASE=Tecnovideo Srl + OUI:346895* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. @@ -51206,6 +51926,12 @@ OUI:346FED* OUI:347146* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:34732D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + +OUI:34735A* + ID_OUI_FROM_DATABASE=Dell Inc. + OUI:347563* ID_OUI_FROM_DATABASE=SHENZHEN RF-LINK TECHNOLOGY CO.,LTD. @@ -51281,6 +52007,9 @@ OUI:348584* OUI:34862A* ID_OUI_FROM_DATABASE=Heinz Lackmann GmbH & Co KG +OUI:34865D* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:34873D* ID_OUI_FROM_DATABASE=Quectel Wireless Solutions Co., Ltd. @@ -51392,6 +52121,9 @@ OUI:34AAEE* OUI:34AB37* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:34AB95* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:34ADE4* ID_OUI_FROM_DATABASE=Shanghai Chint Power Systems Co., Ltd. @@ -51695,6 +52427,9 @@ OUI:34E894* OUI:34E911* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:34E9FE* + ID_OUI_FROM_DATABASE=Metis Co., Ltd. + OUI:34EA34* ID_OUI_FROM_DATABASE=HangZhou Gubei Electronics Technology Co.,Ltd @@ -51755,6 +52490,9 @@ OUI:34FA9F* OUI:34FC6F* ID_OUI_FROM_DATABASE=ALCEA +OUI:34FCA1* + ID_OUI_FROM_DATABASE=Micronet union Technology(Chengdu)Co., Ltd. + OUI:34FCB9* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise @@ -51785,6 +52523,9 @@ OUI:380197* OUI:38019F* ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD +OUI:3802DE* + ID_OUI_FROM_DATABASE=Sercomm Corporation. + OUI:380546* ID_OUI_FROM_DATABASE=Foctek Photonics, Inc. @@ -51839,6 +52580,9 @@ OUI:3810D5* OUI:3810F0* ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company +OUI:381428* + ID_OUI_FROM_DATABASE=Dell Inc. + OUI:38144E* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -51881,6 +52625,9 @@ OUI:381D14* OUI:381DD9* ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED +OUI:382028* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:382056* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -52064,6 +52811,9 @@ OUI:384FF0* OUI:38521A* ID_OUI_FROM_DATABASE=Nokia +OUI:385247* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:38539C* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -52229,6 +52979,9 @@ OUI:388479* OUI:388602* ID_OUI_FROM_DATABASE=Flexoptix GmbH +OUI:3887D5* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:38881E* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -52304,6 +53057,9 @@ OUI:389F5A* OUI:389F83* ID_OUI_FROM_DATABASE=OTN Systems N.V. +OUI:38A067* + ID_OUI_FROM_DATABASE=Nokia Solutions and Networks GmbH & Co. KG + OUI:38A28C* ID_OUI_FROM_DATABASE=SHENZHEN RF-LINK TECHNOLOGY CO.,LTD. @@ -52344,7 +53100,7 @@ OUI:38AF29* ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd. OUI:38AFD0* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Nevro OUI:38AFD7* ID_OUI_FROM_DATABASE=FUJITSU LIMITED @@ -52400,6 +53156,9 @@ OUI:38B19EE* OUI:38B1DB* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. +OUI:38B3F7* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:38B4D3* ID_OUI_FROM_DATABASE=BSH Hausgeraete GmbH @@ -52440,7 +53199,7 @@ OUI:38B8EB6* ID_OUI_FROM_DATABASE=MATRIXSTREAM TECHNOLOGIES, INC. OUI:38B8EB7* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Sirin Mobile Technologies OUI:38B8EB8* ID_OUI_FROM_DATABASE=CeeNex Inc @@ -52571,6 +53330,9 @@ OUI:38E26E* OUI:38E2DD* ID_OUI_FROM_DATABASE=zte corporation +OUI:38E39F* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company + OUI:38E3C5* ID_OUI_FROM_DATABASE=Taicang T&W Electronics @@ -52634,6 +53396,12 @@ OUI:38F32E* OUI:38F33F* ID_OUI_FROM_DATABASE=TATSUNO CORPORATION +OUI:38F3AB* + ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology co., ltd + +OUI:38F3FB* + ID_OUI_FROM_DATABASE=Asperiq + OUI:38F554* ID_OUI_FROM_DATABASE=HISENSE ELECTRIC CO.,LTD @@ -52793,6 +53561,9 @@ OUI:3C0518* OUI:3C05AB* ID_OUI_FROM_DATABASE=Product Creation Studio +OUI:3C0630* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:3C06A7* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -52841,6 +53612,9 @@ OUI:3C11B2* OUI:3C13CC* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:3C1512* + ID_OUI_FROM_DATABASE=Shenzhen Huanhu Technology Co.,Ltd + OUI:3C15C2* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -52862,6 +53636,9 @@ OUI:3C18A0* OUI:3C1915* ID_OUI_FROM_DATABASE=GFI Chrono Time +OUI:3C195E* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:3C197D* ID_OUI_FROM_DATABASE=Ericsson AB @@ -53000,6 +53777,9 @@ OUI:3C363D* OUI:3C36E4* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:3C3712* + ID_OUI_FROM_DATABASE=AVM Audiovisuelles Marketing und Computersysteme GmbH + OUI:3C3786* ID_OUI_FROM_DATABASE=NETGEAR @@ -53309,6 +54089,12 @@ OUI:3C7873* OUI:3C7A8A* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:3C7AAA* + ID_OUI_FROM_DATABASE=China Dragon Technology Limited + +OUI:3C7AC4* + ID_OUI_FROM_DATABASE=Chemtronics + OUI:3C7C3F* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. @@ -53480,6 +54266,9 @@ OUI:3CA72B* OUI:3CA82A* ID_OUI_FROM_DATABASE=Hewlett Packard +OUI:3CA8ED* + ID_OUI_FROM_DATABASE=smart light technology + OUI:3CA9F4* ID_OUI_FROM_DATABASE=Intel Corporate @@ -53561,6 +54350,9 @@ OUI:3CC243* OUI:3CC2E1* ID_OUI_FROM_DATABASE=XINHUA CONTROL ENGINEERING CO.,LTD +OUI:3CC786* + ID_OUI_FROM_DATABASE=DONGGUAN HUARONG COMMUNICATION TECHNOLOGIES CO.,LTD. + OUI:3CC99E* ID_OUI_FROM_DATABASE=Huiyang Technology Co., Ltd @@ -53642,6 +54434,9 @@ OUI:3CE072* OUI:3CE1A1* ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. +OUI:3CE36B* + ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd. + OUI:3CE3E7* ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. @@ -53765,6 +54560,9 @@ OUI:3CFB96* OUI:3CFDFE* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:3CFFD8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:4000E0* ID_OUI_FROM_DATABASE=Derek(Shaoguan)Limited @@ -53900,6 +54698,9 @@ OUI:4022ED* OUI:402343* ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD. +OUI:4024B2* + ID_OUI_FROM_DATABASE=Sichuan AI-Link Technology Co., Ltd. + OUI:4025C2* ID_OUI_FROM_DATABASE=Intel Corporate @@ -54014,9 +54815,15 @@ OUI:40406B* OUI:4040A7* ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc +OUI:404101* + ID_OUI_FROM_DATABASE=Rockwell Automation + OUI:404229* ID_OUI_FROM_DATABASE=Layer3TV, Inc +OUI:4044FD* + ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd. + OUI:4045DA* ID_OUI_FROM_DATABASE=Spreadtrum Communications (Shanghai) Co., Ltd. @@ -54128,6 +54935,9 @@ OUI:40562D* OUI:405662* ID_OUI_FROM_DATABASE=GuoTengShengHua Electronics LTD. +OUI:405899* + ID_OUI_FROM_DATABASE=Logitech Far East + OUI:405A9B* ID_OUI_FROM_DATABASE=ANOVO @@ -54494,6 +55304,9 @@ OUI:40BD32* OUI:40BD9E* ID_OUI_FROM_DATABASE=Physio-Control, Inc +OUI:40BEEE* + ID_OUI_FROM_DATABASE=Shenzhen Yunding Information Technology Co.,Ltd + OUI:40BF17* ID_OUI_FROM_DATABASE=Digistar Telecom. SA @@ -54503,6 +55316,9 @@ OUI:40C245* OUI:40C3C6* ID_OUI_FROM_DATABASE=SnapRoute +OUI:40C48C* + ID_OUI_FROM_DATABASE=N-iTUS CO.,LTD. + OUI:40C4D6* ID_OUI_FROM_DATABASE=ChongQing Camyu Technology Development Co.,Ltd. @@ -54593,6 +55409,9 @@ OUI:40E230* OUI:40E3D6* ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company +OUI:40E64B* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:40E730* ID_OUI_FROM_DATABASE=DEY Storage Systems, Inc. @@ -54738,7 +55557,7 @@ OUI:40F413* ID_OUI_FROM_DATABASE=Rubezh OUI:40F420* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:40F4EC* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -54951,7 +55770,7 @@ OUI:4434A7* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. OUI:44356F* - ID_OUI_FROM_DATABASE=Neterix + ID_OUI_FROM_DATABASE=Neterix Ltd OUI:443583* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -55059,7 +55878,7 @@ OUI:4456B7* ID_OUI_FROM_DATABASE=Spawn Labs, Inc OUI:4456E2* - ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co., Ltd. + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:445829* ID_OUI_FROM_DATABASE=Cisco SPVTG @@ -55073,6 +55892,9 @@ OUI:44599F* OUI:4459E3* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:445BED* + ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company + OUI:445CE9* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -55118,6 +55940,9 @@ OUI:4466FC* OUI:446747* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:446752* + ID_OUI_FROM_DATABASE=Wistron INFOCOMM (Zhongshan) CORPORATION + OUI:446755* ID_OUI_FROM_DATABASE=Orbit Irrigation @@ -55151,24 +55976,48 @@ OUI:446FD80* OUI:446FD81* ID_OUI_FROM_DATABASE=Shenzhen Furuilian Electronic Co.,Ltd. +OUI:446FD82* + ID_OUI_FROM_DATABASE=BAYKON Endüstriyel Kontrol Sistemleri San. ve Tic. A.Ş. + +OUI:446FD83* + ID_OUI_FROM_DATABASE=Shenzhen Mestechs Technology CO., LTD + OUI:446FD84* ID_OUI_FROM_DATABASE=lb Lautsprecher gmbH OUI:446FD85* ID_OUI_FROM_DATABASE=ZHEJIANG SHIP ELECTRONICS & TECHNOLOGY CO., LTD. +OUI:446FD86* + ID_OUI_FROM_DATABASE=Anhui GuDao Tech + OUI:446FD87* ID_OUI_FROM_DATABASE=ITC OUI:446FD88* ID_OUI_FROM_DATABASE=Global Telecom Engineering, Inc +OUI:446FD89* + ID_OUI_FROM_DATABASE=Annapurna labs + +OUI:446FD8A* + ID_OUI_FROM_DATABASE=ZHEJIANG HIKAILINK TECHNOLOGY Co., Ltd + OUI:446FD8B* ID_OUI_FROM_DATABASE=Beijing gpthink technology co.,LTD. +OUI:446FD8C* + ID_OUI_FROM_DATABASE=Changzhou Haitu Electronic Technology Co.,Ltd + OUI:446FD8D* ID_OUI_FROM_DATABASE=SCAIME +OUI:446FD8E* + ID_OUI_FROM_DATABASE=CTE + +OUI:446FF8* + ID_OUI_FROM_DATABASE=Dyson Limited + OUI:44700B* ID_OUI_FROM_DATABASE=IFFU @@ -55280,6 +56129,9 @@ OUI:44975A* OUI:449B78* ID_OUI_FROM_DATABASE=The Now Factory +OUI:449BC1* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:449CB5* ID_OUI_FROM_DATABASE=Alcomp, Inc @@ -55380,11 +56232,14 @@ OUI:44B994* ID_OUI_FROM_DATABASE=Douglas Lighting Controls OUI:44BA46* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:44BB3B* ID_OUI_FROM_DATABASE=Google, Inc. +OUI:44BDDE* + ID_OUI_FROM_DATABASE=BHTC GmbH + OUI:44BFE3* ID_OUI_FROM_DATABASE=Shenzhen Longtech Electronics Co.,Ltd @@ -55532,6 +56387,9 @@ OUI:44D884* OUI:44D9E7* ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc. +OUI:44DB60* + ID_OUI_FROM_DATABASE=Nanjing Baihezhengliu Technology Co., Ltd + OUI:44DC4E* ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED @@ -55640,6 +56498,9 @@ OUI:480031* OUI:480033* ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. +OUI:48007D* + ID_OUI_FROM_DATABASE=DTS ELEKTRONIK SAN. TIC. LTD. STI. + OUI:4801C5* ID_OUI_FROM_DATABASE=OnePlus Technology (Shenzhen) Co., Ltd @@ -55655,6 +56516,9 @@ OUI:48049F* OUI:4805E2* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:48062B* + ID_OUI_FROM_DATABASE=Private + OUI:48066A* ID_OUI_FROM_DATABASE=Tempered Networks, Inc. @@ -55718,6 +56582,9 @@ OUI:481063* OUI:481249* ID_OUI_FROM_DATABASE=Luxcom Technologies Inc. +OUI:481258* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:48137E* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -55745,12 +56612,18 @@ OUI:481BD2* OUI:481D70* ID_OUI_FROM_DATABASE=Cisco SPVTG +OUI:481F2D* + ID_OUI_FROM_DATABASE=Shenzhen Jie Shi Lian Industrial Co.,LTD + OUI:48210B* ID_OUI_FROM_DATABASE=PEGATRON CORPORATION OUI:48216C* ID_OUI_FROM_DATABASE=China Mobile IOT Company Limited +OUI:482218* + ID_OUI_FROM_DATABASE=Shenzhen Yipingfang Network Technology Co., Ltd. + OUI:482335* ID_OUI_FROM_DATABASE=Dialog Semiconductor Hellas SA @@ -55772,6 +56645,12 @@ OUI:4827EA* OUI:48282F* ID_OUI_FROM_DATABASE=zte corporation +OUI:482952* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + +OUI:4829E4* + ID_OUI_FROM_DATABASE=ZAO NPK Rotek + OUI:482AE3* ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd. @@ -55796,6 +56675,9 @@ OUI:48352E* OUI:48365F* ID_OUI_FROM_DATABASE=Wintecronics Ltd. +OUI:483871* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:483974* ID_OUI_FROM_DATABASE=Proware Technologies Co., Ltd. @@ -55880,6 +56762,9 @@ OUI:4851B7* OUI:4851C5* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:4851CF* + ID_OUI_FROM_DATABASE=Intelbras + OUI:485261* ID_OUI_FROM_DATABASE=SOREEL @@ -55985,6 +56870,9 @@ OUI:4865EEE* OUI:486834* ID_OUI_FROM_DATABASE=Silicon Motion, Inc. +OUI:48684A* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:486B2C* ID_OUI_FROM_DATABASE=BBK EDUCATIONAL ELECTRONICS CORP.,LTD. @@ -56024,6 +56912,9 @@ OUI:487604* OUI:487746* ID_OUI_FROM_DATABASE=Calix Inc. +OUI:48785E* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:48794D* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -56048,6 +56939,9 @@ OUI:487B6B* OUI:487D2E* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:487E48* + ID_OUI_FROM_DATABASE=Earda Technologies co Ltd + OUI:488244* ID_OUI_FROM_DATABASE=Life Fitness / Div. of Brunswick @@ -56075,6 +56969,9 @@ OUI:488803* OUI:48881E* ID_OUI_FROM_DATABASE=EthoSwitch LLC +OUI:488899* + ID_OUI_FROM_DATABASE=Shenzhen SuperElectron Technology Co.,Ltd. + OUI:4888CA* ID_OUI_FROM_DATABASE=Motorola (Wuhan) Mobility Technologies Communication Co., Ltd. @@ -56135,6 +57032,9 @@ OUI:489D24* OUI:489DD1* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:489EBD* + ID_OUI_FROM_DATABASE=HP Inc. + OUI:48A0F8* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -56198,6 +57098,9 @@ OUI:48B02D* OUI:48B253* ID_OUI_FROM_DATABASE=Marketaxess Corporation +OUI:48B25D* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:48B5A7* ID_OUI_FROM_DATABASE=Glory Horse Industries Ltd. @@ -56357,6 +57260,9 @@ OUI:48E695* OUI:48E6C0* ID_OUI_FROM_DATABASE=SIMCom Wireless Solutions Co.,Ltd. +OUI:48E7DA* + ID_OUI_FROM_DATABASE=AzureWave Technology Inc. + OUI:48E9F1* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -56420,6 +57326,9 @@ OUI:48F8DB* OUI:48F8E1* ID_OUI_FROM_DATABASE=Nokia +OUI:48F8FF* + ID_OUI_FROM_DATABASE=CHENGDU KT ELECTRONIC HI-TECH CO.,LTD + OUI:48F925* ID_OUI_FROM_DATABASE=Maestronic @@ -56621,6 +57530,9 @@ OUI:4C3909* OUI:4C3910* ID_OUI_FROM_DATABASE=Newtek Electronics co., Ltd. +OUI:4C3B6C* + ID_OUI_FROM_DATABASE=GARO AB + OUI:4C3B74* ID_OUI_FROM_DATABASE=VOGTEC(H.K.) Co., Ltd @@ -56741,6 +57653,9 @@ OUI:4C56DF* OUI:4C57CA* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:4C5D3C* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:4C5DCD* ID_OUI_FROM_DATABASE=Oy Finnish Electric Vehicle Technologies Ltd @@ -56756,6 +57671,9 @@ OUI:4C60D5* OUI:4C60DE* ID_OUI_FROM_DATABASE=NETGEAR +OUI:4C617E* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:4C6255* ID_OUI_FROM_DATABASE=SANMINA-SCI SYSTEM DE MEXICO S.A. DE C.V. @@ -56840,6 +57758,9 @@ OUI:4C710C* OUI:4C710D* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:4C7167* + ID_OUI_FROM_DATABASE=PoLabs d.o.o. + OUI:4C72B9* ID_OUI_FROM_DATABASE=PEGATRON CORPORATION @@ -56867,6 +57788,9 @@ OUI:4C7625* OUI:4C774F* ID_OUI_FROM_DATABASE=Embedded Wireless Labs +OUI:4C7766* + ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. + OUI:4C776D* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -56876,6 +57800,9 @@ OUI:4C7872* OUI:4C7897* ID_OUI_FROM_DATABASE=Arrowhead Alarm Products Ltd +OUI:4C796E* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:4C79BA* ID_OUI_FROM_DATABASE=Intel Corporate @@ -57134,6 +58061,9 @@ OUI:4CB82C* OUI:4CB8B5* ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd +OUI:4CB910* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:4CB911* ID_OUI_FROM_DATABASE=Raisecom Technology CO.,LTD @@ -57266,6 +58196,12 @@ OUI:4CD0CB* OUI:4CD1A1* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:4CD3AF* + ID_OUI_FROM_DATABASE=HMD Global Oy + +OUI:4CD577* + ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD. + OUI:4CD637* ID_OUI_FROM_DATABASE=Qsono Electronics Co., Ltd @@ -57392,6 +58328,9 @@ OUI:4CF02E* OUI:4CF19E* ID_OUI_FROM_DATABASE=Groupe Atlantic +OUI:4CF202* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:4CF2BF* ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. @@ -57404,6 +58343,9 @@ OUI:4CF55B* OUI:4CF5A0* ID_OUI_FROM_DATABASE=Scalable Network Technologies Inc +OUI:4CF5DC* + ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. + OUI:4CF737* ID_OUI_FROM_DATABASE=SamJi Electronics Co., Ltd @@ -57461,6 +58403,9 @@ OUI:5006AB* OUI:500959* ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. +OUI:5009E5* + ID_OUI_FROM_DATABASE=Drimsys,Inc + OUI:500B32* ID_OUI_FROM_DATABASE=Foxda Technology Industrial(ShenZhen)Co.,LTD @@ -57692,6 +58637,9 @@ OUI:504061* OUI:5041B9* ID_OUI_FROM_DATABASE=I-O DATA DEVICE,INC. +OUI:504348* + ID_OUI_FROM_DATABASE=ThingsMatrix Inc. + OUI:5043B9* ID_OUI_FROM_DATABASE=OktoInform RUS @@ -57707,6 +58655,9 @@ OUI:50465D* OUI:5048EB* ID_OUI_FROM_DATABASE=BEIJING HAIHEJINSHENG NETWORK TECHNOLOGY CO. LTD. +OUI:5049B0* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:504A5E* ID_OUI_FROM_DATABASE=Masimo Corporation @@ -57902,6 +58853,9 @@ OUI:506F9A* OUI:507043* ID_OUI_FROM_DATABASE=BSkyB Ltd +OUI:507097* + ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. + OUI:5070E5* ID_OUI_FROM_DATABASE=He Shan World Fair Electronics Technology Limited @@ -57965,6 +58919,9 @@ OUI:5087B8* OUI:508965* ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. +OUI:508A06* + ID_OUI_FROM_DATABASE=Tuya Smart Inc. + OUI:508A0F* ID_OUI_FROM_DATABASE=SHENZHEN FISE TECHNOLOGY HOLDING CO.,LTD. @@ -58001,12 +58958,18 @@ OUI:50934F* OUI:509551* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:509707* + ID_OUI_FROM_DATABASE=Xiamen Paperang Technology Co.,Ltd. + OUI:509744* ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. OUI:509772* ID_OUI_FROM_DATABASE=Westinghouse Digital +OUI:509839* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:509871* ID_OUI_FROM_DATABASE=Inventum Technologies Private Limited @@ -58016,6 +58979,9 @@ OUI:5098B8* OUI:5098F3* ID_OUI_FROM_DATABASE=Rheem Australia Pty Ltd +OUI:509A46* + ID_OUI_FROM_DATABASE=Safetrust Inc + OUI:509A4C* ID_OUI_FROM_DATABASE=Dell Inc. @@ -58130,6 +59096,9 @@ OUI:50AD92* OUI:50ADD5* ID_OUI_FROM_DATABASE=Dynalec Corporation +OUI:50AE86* + ID_OUI_FROM_DATABASE=Linkintec Co., Ltd + OUI:50AF4D* ID_OUI_FROM_DATABASE=zte corporation @@ -58163,6 +59132,9 @@ OUI:50C006* OUI:50C271* ID_OUI_FROM_DATABASE=SECURETECH INC +OUI:50C2ED* + ID_OUI_FROM_DATABASE=GN Audio A/S + OUI:50C3A2* ID_OUI_FROM_DATABASE=nFore Technology Co.,Ltd. @@ -58313,6 +59285,9 @@ OUI:50E0EF* OUI:50E14A* ID_OUI_FROM_DATABASE=Private +OUI:50E24E* + ID_OUI_FROM_DATABASE=zte corporation + OUI:50E549* ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. @@ -58355,6 +59330,9 @@ OUI:50F14A* OUI:50F43C* ID_OUI_FROM_DATABASE=Leeo Inc +OUI:50F4EB* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:50F520* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -58490,6 +59468,9 @@ OUI:540DF9* OUI:540E2D* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:540E58* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + OUI:541031* ID_OUI_FROM_DATABASE=SMARTO @@ -58511,6 +59492,9 @@ OUI:541379* OUI:541473* ID_OUI_FROM_DATABASE=Wingtech Group (HongKong)Limited +OUI:5414F3* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:5414FD* ID_OUI_FROM_DATABASE=Orbbec 3D Technology International @@ -58610,6 +59594,9 @@ OUI:5435DF* OUI:54369B* ID_OUI_FROM_DATABASE=1Verge Internet Technology (Beijing) Co., Ltd. +OUI:5437BB* + ID_OUI_FROM_DATABASE=Taicang T&W Electronics + OUI:543968* ID_OUI_FROM_DATABASE=Edgewater Networks Inc @@ -58658,6 +59645,9 @@ OUI:54489C* OUI:5448E6* ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd +OUI:5449DF* + ID_OUI_FROM_DATABASE=Peloton Interactive, Inc + OUI:544A00* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -58727,6 +59717,9 @@ OUI:5465DE* OUI:54666C* ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd +OUI:5466F9* + ID_OUI_FROM_DATABASE=ConMet + OUI:546751* ID_OUI_FROM_DATABASE=Compal Broadband Networks, Inc. @@ -58748,6 +59741,9 @@ OUI:5471DD* OUI:54724F* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:54725E* + ID_OUI_FROM_DATABASE=UNIONMAN TECHNOLOGY CO.,LTD + OUI:547398* ID_OUI_FROM_DATABASE=Toyo Electronics Corporation @@ -59015,6 +60011,9 @@ OUI:54AE27* OUI:54AED0* ID_OUI_FROM_DATABASE=DASAN Networks, Inc. +OUI:54AED2* + ID_OUI_FROM_DATABASE=CSL Dualcom Ltd + OUI:54B121* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -59054,6 +60053,9 @@ OUI:54BEF7* OUI:54BF64* ID_OUI_FROM_DATABASE=Dell Inc. +OUI:54C250* + ID_OUI_FROM_DATABASE=Iskratel d.o.o. + OUI:54C33E* ID_OUI_FROM_DATABASE=Ciena Corporation @@ -59090,6 +60092,9 @@ OUI:54D0ED* OUI:54D163* ID_OUI_FROM_DATABASE=MAX-TECH,INC +OUI:54D17D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:54D1B0* ID_OUI_FROM_DATABASE=Universal Laser Systems, Inc @@ -59133,7 +60138,7 @@ OUI:54E032* ID_OUI_FROM_DATABASE=Juniper Networks OUI:54E061* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:54E140* ID_OUI_FROM_DATABASE=INGENICO @@ -59162,6 +60167,9 @@ OUI:54E4A9* OUI:54E4BD* ID_OUI_FROM_DATABASE=FN-LINK TECHNOLOGY LIMITED +OUI:54E61B* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:54E63F* ID_OUI_FROM_DATABASE=ShenZhen LingKeWeiEr Technology Co., Ltd. @@ -59213,6 +60221,9 @@ OUI:54F666* OUI:54F6C5* ID_OUI_FROM_DATABASE=FUJIAN STAR-NET COMMUNICATION CO.,LTD +OUI:54F6E2* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:54F876* ID_OUI_FROM_DATABASE=ABB AG @@ -59273,9 +60284,15 @@ OUI:580A20* OUI:58108C* ID_OUI_FROM_DATABASE=Intelbras +OUI:5810B7* + ID_OUI_FROM_DATABASE=Infinix mobility limited + OUI:581243* ID_OUI_FROM_DATABASE=AcSiP Technology Corp. +OUI:5813D3* + ID_OUI_FROM_DATABASE=Gemtek Technology Co., Ltd. + OUI:581626* ID_OUI_FROM_DATABASE=Avaya Inc @@ -59387,6 +60404,9 @@ OUI:582F40* OUI:582F42* ID_OUI_FROM_DATABASE=Universal Electric Corporation +OUI:582FF7* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + OUI:583112* ID_OUI_FROM_DATABASE=DRUST @@ -59399,6 +60419,9 @@ OUI:58343B* OUI:583526* ID_OUI_FROM_DATABASE=DEEPLET TECHNOLOGY CORP +OUI:58356B* + ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED + OUI:5835D9* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -59426,6 +60449,9 @@ OUI:5842E4* OUI:584498* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd +OUI:58454C* + ID_OUI_FROM_DATABASE=Ericsson AB + OUI:58468F* ID_OUI_FROM_DATABASE=Koncar Electronics and Informatics @@ -59456,6 +60482,9 @@ OUI:584C19* OUI:584CEE* ID_OUI_FROM_DATABASE=Digital One Technologies, Limited +OUI:584D42* + ID_OUI_FROM_DATABASE=Dragos, Inc. + OUI:585076* ID_OUI_FROM_DATABASE=Linear Equipamentos Eletronicos SA @@ -59477,6 +60506,9 @@ OUI:5853C0* OUI:5855CA* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:5856C2* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:5856E8* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -59531,6 +60563,9 @@ OUI:586AB1* OUI:586B14* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:586C25* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:586D8F* ID_OUI_FROM_DATABASE=Cisco-Linksys, LLC @@ -59621,6 +60656,9 @@ OUI:588E81* OUI:589043* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS +OUI:589153* + ID_OUI_FROM_DATABASE=China Mobile IOT Company Limited + OUI:5891CF* ID_OUI_FROM_DATABASE=Intel Corporate @@ -59639,6 +60677,9 @@ OUI:58946B* OUI:5894A2* ID_OUI_FROM_DATABASE=KETEK GmbH +OUI:5894AE* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:5894B2* ID_OUI_FROM_DATABASE=BrainCo @@ -59750,6 +60791,9 @@ OUI:58AE2B* OUI:58AEA8* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:58AEF1* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:58B035* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -59846,6 +60890,9 @@ OUI:58D08F* OUI:58D349* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:58D391* + ID_OUI_FROM_DATABASE=Quectel Wireless Solutions Co., Ltd. + OUI:58D50A* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -59855,6 +60902,9 @@ OUI:58D56E* OUI:58D67A* ID_OUI_FROM_DATABASE=TCPlink +OUI:58D697* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + OUI:58D6D3* ID_OUI_FROM_DATABASE=Dairy Cheq Inc @@ -59999,6 +61049,12 @@ OUI:58F98E* OUI:58FB84* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:58FB96* + ID_OUI_FROM_DATABASE=Ruckus Wireless + +OUI:58FC20* + ID_OUI_FROM_DATABASE=Altice Labs S.A. + OUI:58FC73* ID_OUI_FROM_DATABASE=Arria Live Media, Inc. @@ -60051,7 +61107,10 @@ OUI:58FCDBF* ID_OUI_FROM_DATABASE=Private OUI:58FD20* - ID_OUI_FROM_DATABASE=Bravida Sakerhet AB + ID_OUI_FROM_DATABASE=Systemhouse Solutions AB + +OUI:58FD5D* + ID_OUI_FROM_DATABASE=Hangzhou Xinyun technology Co., Ltd. OUI:58FDB1* ID_OUI_FROM_DATABASE=LG Electronics @@ -60116,6 +61175,9 @@ OUI:5C15E1* OUI:5C16C7* ID_OUI_FROM_DATABASE=Big Switch Networks +OUI:5C1720* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:5C1737* ID_OUI_FROM_DATABASE=I-View Now, LLC. @@ -60243,7 +61305,7 @@ OUI:5C497D* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd OUI:5C4A1F* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:5C4A26* ID_OUI_FROM_DATABASE=Enguity Technology Corp @@ -60311,6 +61373,9 @@ OUI:5C5F67* OUI:5C6199* ID_OUI_FROM_DATABASE=CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. +OUI:5C625A* + ID_OUI_FROM_DATABASE=CANON INC. + OUI:5C63BF* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -60320,6 +61385,9 @@ OUI:5C63C9* OUI:5C647A* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:5C648E* + ID_OUI_FROM_DATABASE=Zyxel Communications Corporation + OUI:5C666C* ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD @@ -60528,7 +61596,7 @@ OUI:5C9AD8* ID_OUI_FROM_DATABASE=FUJITSU LIMITED OUI:5CA176* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:5CA178* ID_OUI_FROM_DATABASE=TableTop Media (dba Ziosk) @@ -60554,6 +61622,9 @@ OUI:5CA5BC* OUI:5CA62D* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:5CA721* + ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd + OUI:5CA86A* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -60575,6 +61646,9 @@ OUI:5CADCF* OUI:5CAF06* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) +OUI:5CB00A* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:5CB066* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -60656,6 +61730,9 @@ OUI:5CC6E9* OUI:5CC7D7* ID_OUI_FROM_DATABASE=AZROAD TECHNOLOGY COMPANY LIMITED +OUI:5CC8E3* + ID_OUI_FROM_DATABASE=Shintec Hozumi co.ltd. + OUI:5CC999* ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd @@ -60764,6 +61841,9 @@ OUI:5CE30E* OUI:5CE3B6* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:5CE42A* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:5CE50C* ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd @@ -60977,6 +62057,48 @@ OUI:601466* OUI:6014B3* ID_OUI_FROM_DATABASE=CyberTAN Technology Inc. +OUI:6015920* + ID_OUI_FROM_DATABASE=S Labs sp. z o.o. + +OUI:6015921* + ID_OUI_FROM_DATABASE=RTDS Technologies Inc. + +OUI:6015922* + ID_OUI_FROM_DATABASE=EDA Technology Co.,LTD + +OUI:6015923* + ID_OUI_FROM_DATABASE=OSI TECHNOLOGY CO.,LTD. + +OUI:6015924* + ID_OUI_FROM_DATABASE=Zaptec + +OUI:6015926* + ID_OUI_FROM_DATABASE=BEIJING KUANGSHI TECHNOLOGY CO., LTD + +OUI:6015927* + ID_OUI_FROM_DATABASE=Faster CZ spol. s r.o. + +OUI:6015928* + ID_OUI_FROM_DATABASE=Yangzhou Wanfang Electronic Technology,CO .,Ltd. + +OUI:6015929* + ID_OUI_FROM_DATABASE=JIANGSU SUNFY TECHNOLOGIES HOLDING CO.,LTD. + +OUI:601592A* + ID_OUI_FROM_DATABASE=insensiv GmbH + +OUI:601592B* + ID_OUI_FROM_DATABASE=Annapurna labs + +OUI:601592C* + ID_OUI_FROM_DATABASE=PSS Co., Ltd + +OUI:601592D* + ID_OUI_FROM_DATABASE=REMOWIRELESS COMMUNICATION INTERNATIONAL CO.,LIMITED + +OUI:601592E* + ID_OUI_FROM_DATABASE=Annapurna labs + OUI:6015C7* ID_OUI_FROM_DATABASE=IdaTech @@ -60989,6 +62111,9 @@ OUI:60182E* OUI:601888* ID_OUI_FROM_DATABASE=zte corporation +OUI:601895* + ID_OUI_FROM_DATABASE=Dell Inc. + OUI:60190C* ID_OUI_FROM_DATABASE=RRAMAC @@ -61028,6 +62153,9 @@ OUI:6023A4* OUI:6024C1* ID_OUI_FROM_DATABASE=Jiangsu Zhongxun Electronic Technology Co., Ltd +OUI:6026EF* + ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company + OUI:60271C* ID_OUI_FROM_DATABASE=VIDEOR E. Hartig GmbH @@ -61088,6 +62216,9 @@ OUI:60391F* OUI:603A7C* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:603AAF* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:603CEE* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) @@ -61166,9 +62297,15 @@ OUI:605661* OUI:605718* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:60577D* + ID_OUI_FROM_DATABASE=eero inc. + OUI:605BB4* ID_OUI_FROM_DATABASE=AzureWave Technology Inc. +OUI:605E4F* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:605F8D* ID_OUI_FROM_DATABASE=eero inc. @@ -61301,6 +62438,9 @@ OUI:6089B1* OUI:6089B7* ID_OUI_FROM_DATABASE=KAEL MÜHENDİSLİK ELEKTRONİK TİCARET SANAYİ LİMİTED ŞİRKETİ +OUI:608A10* + ID_OUI_FROM_DATABASE=Microchip Technology Inc. + OUI:608B0E* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -61409,6 +62549,9 @@ OUI:609AC1* OUI:609B2D* ID_OUI_FROM_DATABASE=JMACS Japan Co., Ltd. +OUI:609BB4* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:609BC8* ID_OUI_FROM_DATABASE=Hipad Intelligent Technology Co., Ltd. @@ -61436,12 +62579,21 @@ OUI:60A423* OUI:60A44C* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:60A4B7* + ID_OUI_FROM_DATABASE=TP-Link Corporation Limited + OUI:60A4D0* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:60A5E2* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:60A730* ID_OUI_FROM_DATABASE=Shenzhen Yipinfang Internet Technology Co.,Ltd +OUI:60A751* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:60A8FE* ID_OUI_FROM_DATABASE=Nokia Solutions and Networks GmbH & Co. KG @@ -61484,6 +62636,9 @@ OUI:60B606* OUI:60B617* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:60B6E1* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:60B76E* ID_OUI_FROM_DATABASE=Google, Inc. @@ -61529,6 +62684,9 @@ OUI:60C5A8* OUI:60C5AD* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:60C5E6* + ID_OUI_FROM_DATABASE=Skullcandy + OUI:60C658* ID_OUI_FROM_DATABASE=PHYTRONIX Co.,Ltd. @@ -61649,6 +62807,9 @@ OUI:60DA23* OUI:60DA83* ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited +OUI:60DB15* + ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd + OUI:60DB2A* ID_OUI_FROM_DATABASE=HNS @@ -61676,6 +62837,9 @@ OUI:60E3AC* OUI:60E6BC* ID_OUI_FROM_DATABASE=Sino-Telecom Technology Co.,Ltd. +OUI:60E6F0* + ID_OUI_FROM_DATABASE=Wistron Neweb Corporation + OUI:60E701* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -61739,6 +62903,9 @@ OUI:60F677* OUI:60F81D* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:60F8F2* + ID_OUI_FROM_DATABASE=Synaptec + OUI:60FA9D* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -61790,6 +62957,9 @@ OUI:6405E4* OUI:6405E9* ID_OUI_FROM_DATABASE=Shenzhen WayOS Technology Crop., Ltd. +OUI:6407F6* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:64094C* ID_OUI_FROM_DATABASE=Beijing Superbee Wireless Technology Co.,Ltd @@ -61805,6 +62975,9 @@ OUI:640B4A* OUI:640BD7* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:640D22* + ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) + OUI:640DCE* ID_OUI_FROM_DATABASE=SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. @@ -61853,6 +63026,9 @@ OUI:64168D* OUI:6416F0* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:641759* + ID_OUI_FROM_DATABASE=Intellivision Holdings, LLC + OUI:641A22* ID_OUI_FROM_DATABASE=Heliospectra AB @@ -61898,6 +63074,9 @@ OUI:642656* OUI:642737* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. +OUI:642753* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:6429ED* ID_OUI_FROM_DATABASE=AO PKK Milandr @@ -61971,7 +63150,7 @@ OUI:64351C* ID_OUI_FROM_DATABASE=e-CON SYSTEMS INDIA PVT LTD OUI:643AB1* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:643AEA* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -62058,7 +63237,7 @@ OUI:645D86* ID_OUI_FROM_DATABASE=Intel Corporate OUI:645D92* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:645DD7* ID_OUI_FROM_DATABASE=Shenzhen Lifesense Medical Electronics Co., Ltd. @@ -62132,6 +63311,9 @@ OUI:646266E* OUI:64628A* ID_OUI_FROM_DATABASE=evon GmbH +OUI:64644A* + ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd + OUI:64649B* ID_OUI_FROM_DATABASE=Juniper Networks @@ -62180,6 +63362,9 @@ OUI:646E6C* OUI:646E97* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:646EE0* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:646EEA* ID_OUI_FROM_DATABASE=Iskratel d.o.o. @@ -62219,6 +63404,9 @@ OUI:647924* OUI:6479A7* ID_OUI_FROM_DATABASE=Phison Electronics Corp. +OUI:6479F0* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:647BCE* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -62267,6 +63455,9 @@ OUI:6490C1* OUI:64956C* ID_OUI_FROM_DATABASE=LG Electronics +OUI:649714* + ID_OUI_FROM_DATABASE=eero inc. + OUI:649829* ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. @@ -62375,6 +63566,9 @@ OUI:64B310* OUI:64B370* ID_OUI_FROM_DATABASE=PowerComm Solutions LLC +OUI:64B379* + ID_OUI_FROM_DATABASE=Private + OUI:64B473* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd @@ -62454,7 +63648,7 @@ OUI:64CFD9* ID_OUI_FROM_DATABASE=Texas Instruments OUI:64D02D* - ID_OUI_FROM_DATABASE=Next Generation Integration (NGI) + ID_OUI_FROM_DATABASE=NEXT GENERATION INTEGRATION LIMITED (NGI) OUI:64D154* ID_OUI_FROM_DATABASE=Routerboard.com @@ -62525,6 +63719,9 @@ OUI:64DFE9* OUI:64E003* ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD +OUI:64E0AB* + ID_OUI_FROM_DATABASE=UNIONMAN TECHNOLOGY CO.,LTD + OUI:64E161* ID_OUI_FROM_DATABASE=DEP Corp. @@ -62757,7 +63954,7 @@ OUI:68234B* ID_OUI_FROM_DATABASE=Nihon Dengyo Kousaku OUI:68262A* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:682719* ID_OUI_FROM_DATABASE=Microchip Technology Inc. @@ -62777,6 +63974,9 @@ OUI:6829DC* OUI:682C7B* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:682D83* + ID_OUI_FROM_DATABASE=SHENZHEN DINGHE COMMUNICATION COMPANY + OUI:682DDC* ID_OUI_FROM_DATABASE=Wuhan Changjiang Electro-Communication Equipment CO.,LTD @@ -62807,6 +64007,9 @@ OUI:683943* OUI:683A1E* ID_OUI_FROM_DATABASE=Cisco Meraki +OUI:683A48* + ID_OUI_FROM_DATABASE=SAMJIN Co., Ltd. + OUI:683B1E* ID_OUI_FROM_DATABASE=Countwise LTD @@ -63188,6 +64391,9 @@ OUI:689E0B* OUI:689E19* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:689E6A* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:689FF0* ID_OUI_FROM_DATABASE=zte corporation @@ -63356,6 +64562,9 @@ OUI:68DCE8* OUI:68DD26* ID_OUI_FROM_DATABASE=Shanghai Focus Vision Security Technology Co.,Ltd +OUI:68DDD9* + ID_OUI_FROM_DATABASE=HMD Global Oy + OUI:68DFDD* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd @@ -63383,6 +64592,9 @@ OUI:68EBC5* OUI:68EC62* ID_OUI_FROM_DATABASE=YODO Technology Corp. Ltd. +OUI:68EC8A* + ID_OUI_FROM_DATABASE=Private + OUI:68ECC5* ID_OUI_FROM_DATABASE=Intel Corporate @@ -63488,6 +64700,9 @@ OUI:6C0EE6* OUI:6C0F6A* ID_OUI_FROM_DATABASE=JDC Tech Co., Ltd. +OUI:6C108B* + ID_OUI_FROM_DATABASE=WeLink Communications + OUI:6C13D5* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -63521,6 +64736,9 @@ OUI:6C19C0* OUI:6C1A75* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:6C1B3F* + ID_OUI_FROM_DATABASE=MiraeSignal Co., Ltd + OUI:6C1C71* ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd. @@ -63560,6 +64778,9 @@ OUI:6C24A6* OUI:6C25B9* ID_OUI_FROM_DATABASE=BBK EDUCATIONAL ELECTRONICS CORP.,LTD. +OUI:6C2636* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:6C2779* ID_OUI_FROM_DATABASE=Microsoft Mobile Oy @@ -63608,6 +64829,9 @@ OUI:6C32DE* OUI:6C33A9* ID_OUI_FROM_DATABASE=Magicjack LP +OUI:6C3491* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:6C3838* ID_OUI_FROM_DATABASE=Marking System Technology Co., Ltd. @@ -63653,6 +64877,9 @@ OUI:6C416A* OUI:6C42AB* ID_OUI_FROM_DATABASE=Subscriber Networks, Inc. +OUI:6C433C* + ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED + OUI:6C4418* ID_OUI_FROM_DATABASE=Zappware @@ -63662,6 +64889,9 @@ OUI:6C442A* OUI:6C4598* ID_OUI_FROM_DATABASE=Antex Electronic Corp. +OUI:6C4760* + ID_OUI_FROM_DATABASE=Sunitec Enterprise Co.,Ltd + OUI:6C49C1* ID_OUI_FROM_DATABASE=o2ones Co., Ltd. @@ -63698,6 +64928,9 @@ OUI:6C54CD* OUI:6C55E8* ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. +OUI:6C5640* + ID_OUI_FROM_DATABASE=BLU Products Inc + OUI:6C5697* ID_OUI_FROM_DATABASE=Amazon Technologies Inc. @@ -63713,6 +64946,9 @@ OUI:6C5976* OUI:6C5A34* ID_OUI_FROM_DATABASE=Shenzhen Haitianxiong Electronic Co., Ltd. +OUI:6C5AB0* + ID_OUI_FROM_DATABASE=TP-Link Corporation Limited + OUI:6C5AB5* ID_OUI_FROM_DATABASE=TCL Technoly Electronics (Huizhou) Co., Ltd. @@ -63845,6 +65081,9 @@ OUI:6C7637* OUI:6C7660* ID_OUI_FROM_DATABASE=KYOCERA CORPORATION +OUI:6C79B8* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:6C81FE* ID_OUI_FROM_DATABASE=Mitsuba Corporation @@ -63890,6 +65129,9 @@ OUI:6C92BF* OUI:6C9354* ID_OUI_FROM_DATABASE=Yaojin Technology (Shenzhen) Co., LTD. +OUI:6C9466* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:6C94F8* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -64094,6 +65336,9 @@ OUI:6CD1B0* OUI:6CD2BA* ID_OUI_FROM_DATABASE=zte corporation +OUI:6CD630* + ID_OUI_FROM_DATABASE=Rootous System Co.,Ltd + OUI:6CD68A* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) @@ -64256,6 +65501,9 @@ OUI:6CFAA7* OUI:6CFDB9* ID_OUI_FROM_DATABASE=Proware Technologies Co Ltd. +OUI:6CFE54* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:6CFFBE* ID_OUI_FROM_DATABASE=MPB Communications Inc. @@ -64889,6 +66137,9 @@ OUI:709383* OUI:7093F8* ID_OUI_FROM_DATABASE=Space Monkey, Inc. +OUI:709741* + ID_OUI_FROM_DATABASE=Arcadyan Corporation + OUI:709756* ID_OUI_FROM_DATABASE=Happyelectronics Co.,Ltd @@ -64934,6 +66185,9 @@ OUI:70A41C* OUI:70A66A* ID_OUI_FROM_DATABASE=Prox Dynamics AS +OUI:70A6CC* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:70A84C* ID_OUI_FROM_DATABASE=MONAD., Inc. @@ -64985,6 +66239,9 @@ OUI:70B3D5002* OUI:70B3D5003* ID_OUI_FROM_DATABASE=ANYROAM +OUI:70B3D5004* + ID_OUI_FROM_DATABASE=LEIDOS + OUI:70B3D5005* ID_OUI_FROM_DATABASE=CT Company @@ -65102,6 +66359,9 @@ OUI:70B3D502A* OUI:70B3D502B* ID_OUI_FROM_DATABASE=Scorpion Precision Industry (HK)CO. Ltd. +OUI:70B3D502C* + ID_OUI_FROM_DATABASE=Iylus Inc. + OUI:70B3D502D* ID_OUI_FROM_DATABASE=NEXTtec srl @@ -65129,6 +66389,9 @@ OUI:70B3D5034* OUI:70B3D5035* ID_OUI_FROM_DATABASE=HKW-Elektronik GmbH +OUI:70B3D5036* + ID_OUI_FROM_DATABASE=Vema Venturi AB + OUI:70B3D5037* ID_OUI_FROM_DATABASE=EIFFAGE ENERGIE ELECTRONIQUE @@ -65318,6 +66581,9 @@ OUI:70B3D5074* OUI:70B3D5075* ID_OUI_FROM_DATABASE=Mo-Sys Engineering Ltd +OUI:70B3D5076* + ID_OUI_FROM_DATABASE=Private Enterprise Scientific and Production Private EnterpriseSparing-Vist Center + OUI:70B3D5077* ID_OUI_FROM_DATABASE=InAccess Networks SA @@ -65639,9 +66905,15 @@ OUI:70B3D50E0* OUI:70B3D50E1* ID_OUI_FROM_DATABASE=MiWave Consulting, LLC +OUI:70B3D50E2* + ID_OUI_FROM_DATABASE=JESE Ltd + OUI:70B3D50E3* ID_OUI_FROM_DATABASE=SinTau SrL +OUI:70B3D50E4* + ID_OUI_FROM_DATABASE=Walter Müller AG + OUI:70B3D50E5* ID_OUI_FROM_DATABASE=Delta Solutions LLC @@ -65714,6 +66986,9 @@ OUI:70B3D50FB* OUI:70B3D50FC* ID_OUI_FROM_DATABASE=vitalcare +OUI:70B3D50FD* + ID_OUI_FROM_DATABASE=JSC Ural Factories + OUI:70B3D50FE* ID_OUI_FROM_DATABASE=Vocality International Ltd @@ -65810,6 +67085,9 @@ OUI:70B3D511C* OUI:70B3D511D* ID_OUI_FROM_DATABASE=Dakton Microlabs LLC +OUI:70B3D511E* + ID_OUI_FROM_DATABASE=KBPR LLC + OUI:70B3D511F* ID_OUI_FROM_DATABASE=Geppetto Electronics @@ -65837,6 +67115,9 @@ OUI:70B3D5126* OUI:70B3D5127* ID_OUI_FROM_DATABASE=VITEC +OUI:70B3D5128* + ID_OUI_FROM_DATABASE=Akse srl + OUI:70B3D5129* ID_OUI_FROM_DATABASE=OOO Microlink-Svyaz @@ -65879,6 +67160,9 @@ OUI:70B3D5135* OUI:70B3D5136* ID_OUI_FROM_DATABASE=Miguel Corporate Services Pte Ltd +OUI:70B3D5137* + ID_OUI_FROM_DATABASE=Subject Link Inc + OUI:70B3D5138* ID_OUI_FROM_DATABASE=SMITEC S.p.A. @@ -65999,6 +67283,9 @@ OUI:70B3D515E* OUI:70B3D515F* ID_OUI_FROM_DATABASE=SAVRONİK ELEKTRONİK +OUI:70B3D5160* + ID_OUI_FROM_DATABASE=European Synchrotron Radiation Facility + OUI:70B3D5161* ID_OUI_FROM_DATABASE=MB connect line GmbH Fernwartungssysteme @@ -66035,6 +67322,9 @@ OUI:70B3D516B* OUI:70B3D516C* ID_OUI_FROM_DATABASE=OCEAN +OUI:70B3D516D* + ID_OUI_FROM_DATABASE=BluB0X Security, Inc. + OUI:70B3D516E* ID_OUI_FROM_DATABASE=Jemac Sweden AB @@ -66155,9 +67445,15 @@ OUI:70B3D5194* OUI:70B3D5195* ID_OUI_FROM_DATABASE=Ci4Rail +OUI:70B3D5196* + ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd + OUI:70B3D5197* ID_OUI_FROM_DATABASE=Lattech Systems Pty Ltd +OUI:70B3D5198* + ID_OUI_FROM_DATABASE=Beijing Muniulinghang Technology Co., Ltd + OUI:70B3D5199* ID_OUI_FROM_DATABASE=Smart Controls LLC @@ -66170,6 +67466,9 @@ OUI:70B3D519B* OUI:70B3D519C* ID_OUI_FROM_DATABASE=Kubu, Inc. +OUI:70B3D519D* + ID_OUI_FROM_DATABASE=Automata GmbH & Co. KG + OUI:70B3D519E* ID_OUI_FROM_DATABASE=J-Factor Embedded Technologies @@ -66218,9 +67517,15 @@ OUI:70B3D51AC* OUI:70B3D51AD* ID_OUI_FROM_DATABASE=Techworld Industries Ltd +OUI:70B3D51AE* + ID_OUI_FROM_DATABASE=EcoG + OUI:70B3D51AF* ID_OUI_FROM_DATABASE=Teenage Engineering AB +OUI:70B3D51B0* + ID_OUI_FROM_DATABASE=NAL Research Corporation + OUI:70B3D51B1* ID_OUI_FROM_DATABASE=Shanghai Danyan Information Technology Co., Ltd. @@ -66254,6 +67559,9 @@ OUI:70B3D51BA* OUI:70B3D51BB* ID_OUI_FROM_DATABASE=EFENTO T P SZYDŁOWSKI K ZARĘBA SPÓŁKA JAWNA +OUI:70B3D51BC* + ID_OUI_FROM_DATABASE=Flextronics International Kft + OUI:70B3D51BD* ID_OUI_FROM_DATABASE=Shenzhen Siera Technology Ltd @@ -66395,6 +67703,9 @@ OUI:70B3D51EA* OUI:70B3D51EB* ID_OUI_FROM_DATABASE=Xavant +OUI:70B3D51ED* + ID_OUI_FROM_DATABASE=SUS Corporation + OUI:70B3D51EE* ID_OUI_FROM_DATABASE=MEGGITT @@ -66419,6 +67730,9 @@ OUI:70B3D51F4* OUI:70B3D51F5* ID_OUI_FROM_DATABASE=Martec S.p.A. +OUI:70B3D51F6* + ID_OUI_FROM_DATABASE=LinkAV Technology Co., Ltd + OUI:70B3D51F7* ID_OUI_FROM_DATABASE=Morgan Schaffer Inc. @@ -66431,6 +67745,9 @@ OUI:70B3D51F9* OUI:70B3D51FA* ID_OUI_FROM_DATABASE=EBZ SysTec GmbH +OUI:70B3D51FB* + ID_OUI_FROM_DATABASE=Crane-elec. Co., LTD. + OUI:70B3D51FC* ID_OUI_FROM_DATABASE=Guan Show Technologe Co., Ltd. @@ -66476,6 +67793,9 @@ OUI:70B3D5209* OUI:70B3D520A* ID_OUI_FROM_DATABASE=Golden Grid Systems +OUI:70B3D520B* + ID_OUI_FROM_DATABASE=KST technology + OUI:70B3D520C* ID_OUI_FROM_DATABASE=Siemens Healthcare Diagnostics @@ -66494,6 +67814,9 @@ OUI:70B3D5210* OUI:70B3D5211* ID_OUI_FROM_DATABASE=Fracarro srl +OUI:70B3D5212* + ID_OUI_FROM_DATABASE=Semiconsoft, inc + OUI:70B3D5213* ID_OUI_FROM_DATABASE=ETON Deutschland Electro Acoustic GmbH @@ -66542,6 +67865,9 @@ OUI:70B3D5221* OUI:70B3D5222* ID_OUI_FROM_DATABASE=Marioff Corporation Oy +OUI:70B3D5223* + ID_OUI_FROM_DATABASE=Research Laboratory of Design Automation, Ltd. + OUI:70B3D5224* ID_OUI_FROM_DATABASE=Urbana Smart Solutions Pte Ltd @@ -66734,6 +68060,9 @@ OUI:70B3D5263* OUI:70B3D5264* ID_OUI_FROM_DATABASE=ifak technology + service GmbH +OUI:70B3D5265* + ID_OUI_FROM_DATABASE=Rapiot + OUI:70B3D5266* ID_OUI_FROM_DATABASE=Spectra Displays Ltd @@ -66767,6 +68096,9 @@ OUI:70B3D526F* OUI:70B3D5270* ID_OUI_FROM_DATABASE=Amazon Technologies Inc. +OUI:70B3D5271* + ID_OUI_FROM_DATABASE=Code Blue Corporation + OUI:70B3D5272* ID_OUI_FROM_DATABASE=TELECOM SANTE @@ -66881,6 +68213,9 @@ OUI:70B3D5296* OUI:70B3D5297* ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG +OUI:70B3D5298* + ID_OUI_FROM_DATABASE=Reflexion Medical + OUI:70B3D5299* ID_OUI_FROM_DATABASE=KMtronic ltd @@ -66968,6 +68303,9 @@ OUI:70B3D52B4* OUI:70B3D52B5* ID_OUI_FROM_DATABASE=Dosepack India LLP +OUI:70B3D52B6* + ID_OUI_FROM_DATABASE=HLT Micro + OUI:70B3D52B7* ID_OUI_FROM_DATABASE=Matrix Orbital Corporation @@ -67010,6 +68348,12 @@ OUI:70B3D52C3* OUI:70B3D52C4* ID_OUI_FROM_DATABASE=Hodwa Co., Ltd +OUI:70B3D52C5* + ID_OUI_FROM_DATABASE=MECT SRL + +OUI:70B3D52C6* + ID_OUI_FROM_DATABASE=AM General Contractor + OUI:70B3D52C7* ID_OUI_FROM_DATABASE=Worldsensing @@ -67097,6 +68441,9 @@ OUI:70B3D52E2* OUI:70B3D52E3* ID_OUI_FROM_DATABASE=Meiknologic GmbH +OUI:70B3D52E4* + ID_OUI_FROM_DATABASE=Schneider Electric Motion USA + OUI:70B3D52E5* ID_OUI_FROM_DATABASE=Fläkt Woods AB @@ -67229,15 +68576,27 @@ OUI:70B3D5310* OUI:70B3D5311* ID_OUI_FROM_DATABASE=Günther Spelsberg GmbH + Co. KG +OUI:70B3D5312* + ID_OUI_FROM_DATABASE=SMITEC S.p.A. + OUI:70B3D5313* ID_OUI_FROM_DATABASE=DIEHL Controls +OUI:70B3D5314* + ID_OUI_FROM_DATABASE=Grau Elektronik GmbH + +OUI:70B3D5315* + ID_OUI_FROM_DATABASE=Private + OUI:70B3D5316* ID_OUI_FROM_DATABASE=Austco Marketing & Service (USA) ltd. OUI:70B3D5317* ID_OUI_FROM_DATABASE=Iotopia Solutions +OUI:70B3D5318* + ID_OUI_FROM_DATABASE=Exemplar Medical, LLC + OUI:70B3D5319* ID_OUI_FROM_DATABASE=ISO/TC 22/SC 31 @@ -67316,6 +68675,9 @@ OUI:70B3D5331* OUI:70B3D5332* ID_OUI_FROM_DATABASE=InnoSenT +OUI:70B3D5333* + ID_OUI_FROM_DATABASE=Orlaco Products B.V. + OUI:70B3D5334* ID_OUI_FROM_DATABASE=Dokuen Co. Ltd. @@ -67334,6 +68696,9 @@ OUI:70B3D5338* OUI:70B3D5339* ID_OUI_FROM_DATABASE=Sierra Nevada Corporation +OUI:70B3D533A* + ID_OUI_FROM_DATABASE=AudioTEC LLC + OUI:70B3D533B* ID_OUI_FROM_DATABASE=Seal Shield, LLC @@ -67499,6 +68864,9 @@ OUI:70B3D5371* OUI:70B3D5372* ID_OUI_FROM_DATABASE=MATELEX +OUI:70B3D5373* + ID_OUI_FROM_DATABASE=Hangzhou Weimu Technology Co.,Ltd. + OUI:70B3D5374* ID_OUI_FROM_DATABASE=OOO NPP Mars-Energo @@ -67577,9 +68945,15 @@ OUI:70B3D538C* OUI:70B3D538D* ID_OUI_FROM_DATABASE=IMP-TELEKOMUNIKACIJE DOO +OUI:70B3D538E* + ID_OUI_FROM_DATABASE=China Telecom Fufu Information Technology CO.,LTD + OUI:70B3D538F* ID_OUI_FROM_DATABASE=Sorynorydotcom Inc +OUI:70B3D5390* + ID_OUI_FROM_DATABASE=TEX COMPUTER SRL + OUI:70B3D5391* ID_OUI_FROM_DATABASE=Changshu Ruite Electric Co.,Ltd. @@ -67682,12 +69056,18 @@ OUI:70B3D53B1* OUI:70B3D53B2* ID_OUI_FROM_DATABASE=Sicon srl +OUI:70B3D53B3* + ID_OUI_FROM_DATABASE=Movicom Electric LLC + OUI:70B3D53B4* ID_OUI_FROM_DATABASE=YOUSUNG OUI:70B3D53B5* ID_OUI_FROM_DATABASE=Preston Industries dba PolyScience +OUI:70B3D53B6* + ID_OUI_FROM_DATABASE=MedRx, Inc + OUI:70B3D53B7* ID_OUI_FROM_DATABASE=Paul Scherrer Institut (PSI) @@ -67799,6 +69179,9 @@ OUI:70B3D53DA* OUI:70B3D53DB* ID_OUI_FROM_DATABASE=KST technology +OUI:70B3D53DC* + ID_OUI_FROM_DATABASE=XIA LLC + OUI:70B3D53DD* ID_OUI_FROM_DATABASE=Kniggendorf + Kögler Security GmbH @@ -67955,6 +69338,9 @@ OUI:70B3D540F* OUI:70B3D5410* ID_OUI_FROM_DATABASE=Avant Technologies, Inc +OUI:70B3D5411* + ID_OUI_FROM_DATABASE=Mi-Fi Networks Pvt Ltd + OUI:70B3D5412* ID_OUI_FROM_DATABASE=TATTILE SRL @@ -68123,6 +69509,9 @@ OUI:70B3D544A* OUI:70B3D544B* ID_OUI_FROM_DATABASE=Open System Solutions Limited +OUI:70B3D544C* + ID_OUI_FROM_DATABASE=ejoin, s.r.o. + OUI:70B3D544D* ID_OUI_FROM_DATABASE=Vessel Technology Ltd @@ -68132,6 +69521,12 @@ OUI:70B3D544E* OUI:70B3D544F* ID_OUI_FROM_DATABASE=Velvac Incorporated +OUI:70B3D5451* + ID_OUI_FROM_DATABASE=Perform3-D LLC + +OUI:70B3D5452* + ID_OUI_FROM_DATABASE=ITALIANA PONTI RADIO SRL + OUI:70B3D5453* ID_OUI_FROM_DATABASE=Foerster-Technik GmbH @@ -68207,6 +69602,9 @@ OUI:70B3D546B* OUI:70B3D546C* ID_OUI_FROM_DATABASE=SHANGHAI CHENZHU INSTRUMENT CO., LTD. +OUI:70B3D546D* + ID_OUI_FROM_DATABASE=Guan Show Technologe Co., Ltd. + OUI:70B3D546E* ID_OUI_FROM_DATABASE=Zamir Recognition Systems Ltd. @@ -68226,7 +69624,7 @@ OUI:70B3D5473* ID_OUI_FROM_DATABASE=KeyProd OUI:70B3D5474* - ID_OUI_FROM_DATABASE=DAYOUPLUS + ID_OUI_FROM_DATABASE=CTROGERS LLC OUI:70B3D5475* ID_OUI_FROM_DATABASE=EWATTCH @@ -68486,6 +69884,9 @@ OUI:70B3D54C9* OUI:70B3D54CA* ID_OUI_FROM_DATABASE=PCB Piezotronics +OUI:70B3D54CB* + ID_OUI_FROM_DATABASE=Cucos Retail Systems GmbH + OUI:70B3D54CC* ID_OUI_FROM_DATABASE=FRESENIUS MEDICAL CARE @@ -68498,6 +69899,9 @@ OUI:70B3D54CE* OUI:70B3D54CF* ID_OUI_FROM_DATABASE=GREEN HOUSE CO., LTD. +OUI:70B3D54D0* + ID_OUI_FROM_DATABASE=Codewerk GmbH + OUI:70B3D54D1* ID_OUI_FROM_DATABASE=Contraves Advanced Devices Sdn. Bhd. @@ -68522,6 +69926,9 @@ OUI:70B3D54D7* OUI:70B3D54D8* ID_OUI_FROM_DATABASE=Versilis Inc. +OUI:70B3D54D9* + ID_OUI_FROM_DATABASE=Coda Octopus Products Limited + OUI:70B3D54DA* ID_OUI_FROM_DATABASE=Private @@ -68558,6 +69965,9 @@ OUI:70B3D54E4* OUI:70B3D54E5* ID_OUI_FROM_DATABASE=viZaar industrial imaging AG +OUI:70B3D54E6* + ID_OUI_FROM_DATABASE=Santa Barbara Imaging Systems + OUI:70B3D54E7* ID_OUI_FROM_DATABASE=Digital Domain @@ -68576,6 +69986,9 @@ OUI:70B3D54EB* OUI:70B3D54EC* ID_OUI_FROM_DATABASE=Hangzhou Youshi Industry Co., Ltd. +OUI:70B3D54ED* + ID_OUI_FROM_DATABASE=Panoramic Power + OUI:70B3D54EE* ID_OUI_FROM_DATABASE=NOA Co., Ltd. @@ -68615,6 +70028,9 @@ OUI:70B3D54F9* OUI:70B3D54FA* ID_OUI_FROM_DATABASE=Thruvision Limited +OUI:70B3D54FB* + ID_OUI_FROM_DATABASE=MAS Elettronica sas di Mascetti Sandro e C. + OUI:70B3D54FC* ID_OUI_FROM_DATABASE=Mettler Toledo @@ -68657,6 +70073,9 @@ OUI:70B3D5508* OUI:70B3D550A* ID_OUI_FROM_DATABASE=AMEDTEC Medizintechnik Aue GmbH +OUI:70B3D550B* + ID_OUI_FROM_DATABASE=Nordson Corporation + OUI:70B3D550C* ID_OUI_FROM_DATABASE=Hangzhou landesker digital technology co. LTD @@ -68717,6 +70136,9 @@ OUI:70B3D551E* OUI:70B3D551F* ID_OUI_FROM_DATABASE=VALEO CDA +OUI:70B3D5520* + ID_OUI_FROM_DATABASE=promedias AG + OUI:70B3D5521* ID_OUI_FROM_DATABASE=Selex ES Inc. @@ -69005,6 +70427,9 @@ OUI:70B3D557F* OUI:70B3D5580* ID_OUI_FROM_DATABASE=Private +OUI:70B3D5581* + ID_OUI_FROM_DATABASE=Thermokon Sensortechnik GmbH + OUI:70B3D5582* ID_OUI_FROM_DATABASE=VAGLER International Sdn Bhd @@ -69017,6 +70442,9 @@ OUI:70B3D5584* OUI:70B3D5585* ID_OUI_FROM_DATABASE=Nefteavtomatika +OUI:70B3D5586* + ID_OUI_FROM_DATABASE=Aliter Technologies + OUI:70B3D5587* ID_OUI_FROM_DATABASE=INCAA Computers @@ -69089,6 +70517,9 @@ OUI:70B3D559D* OUI:70B3D559E* ID_OUI_FROM_DATABASE=i2-electronics +OUI:70B3D559F* + ID_OUI_FROM_DATABASE=Megger Germany GmbH + OUI:70B3D55A0* ID_OUI_FROM_DATABASE=Ascon Tecnologic S.r.l. @@ -69146,6 +70577,9 @@ OUI:70B3D55B1* OUI:70B3D55B2* ID_OUI_FROM_DATABASE=Peter Huber Kaeltemaschinenbau AG +OUI:70B3D55B3* + ID_OUI_FROM_DATABASE=STENTORIUS by ADI + OUI:70B3D55B4* ID_OUI_FROM_DATABASE=Systems Technologies @@ -69155,9 +70589,15 @@ OUI:70B3D55B5* OUI:70B3D55B6* ID_OUI_FROM_DATABASE=Ethical Lighting and Sensor Solutions Limited +OUI:70B3D55B7* + ID_OUI_FROM_DATABASE=on-systems limited + OUI:70B3D55B8* ID_OUI_FROM_DATABASE=Hella Gutmann Solutions GmbH +OUI:70B3D55B9* + ID_OUI_FROM_DATABASE=EIZO RUGGED SOLUTIONS + OUI:70B3D55BA* ID_OUI_FROM_DATABASE=INFRASAFE/ ADVANTOR SYSTEMS @@ -69182,6 +70622,12 @@ OUI:70B3D55C0* OUI:70B3D55C1* ID_OUI_FROM_DATABASE=Shanghai JaWay Information Technology Co., Ltd. +OUI:70B3D55C2* + ID_OUI_FROM_DATABASE=Sono-Tek Corporation + +OUI:70B3D55C3* + ID_OUI_FROM_DATABASE=DIC Corporation + OUI:70B3D55C4* ID_OUI_FROM_DATABASE=TATTILE SRL @@ -69212,6 +70658,9 @@ OUI:70B3D55CC* OUI:70B3D55CD* ID_OUI_FROM_DATABASE=MVT Video Technologies R + H Maedler GbR +OUI:70B3D55CE* + ID_OUI_FROM_DATABASE=IP Devices + OUI:70B3D55CF* ID_OUI_FROM_DATABASE=PROEL TSI s.r.l. @@ -69371,6 +70820,9 @@ OUI:70B3D5602* OUI:70B3D5603* ID_OUI_FROM_DATABASE=EGISTECH CO.,LTD. +OUI:70B3D5604* + ID_OUI_FROM_DATABASE=Foxtrot Research Corp + OUI:70B3D5605* ID_OUI_FROM_DATABASE=Aplex Technology Inc. @@ -69539,6 +70991,9 @@ OUI:70B3D563B* OUI:70B3D563C* ID_OUI_FROM_DATABASE=Pivothead +OUI:70B3D563D* + ID_OUI_FROM_DATABASE=Topic Embedded Products B.V. + OUI:70B3D563E* ID_OUI_FROM_DATABASE=RIKEN OPTECH CORPORATION @@ -69683,6 +71138,9 @@ OUI:70B3D566C* OUI:70B3D566D* ID_OUI_FROM_DATABASE=Sanmina Israel +OUI:70B3D566E* + ID_OUI_FROM_DATABASE=SIAME + OUI:70B3D566F* ID_OUI_FROM_DATABASE=Simplified MFG @@ -69737,6 +71195,9 @@ OUI:70B3D567F* OUI:70B3D5680* ID_OUI_FROM_DATABASE=BASF Corporation +OUI:70B3D5681* + ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH + OUI:70B3D5682* ID_OUI_FROM_DATABASE=Rosslare Enterprises Limited @@ -69746,6 +71207,9 @@ OUI:70B3D5683* OUI:70B3D5684* ID_OUI_FROM_DATABASE=LECO Corporation +OUI:70B3D5685* + ID_OUI_FROM_DATABASE=LDA Audiotech + OUI:70B3D5686* ID_OUI_FROM_DATABASE=Access Protocol Pty Ltd @@ -69776,6 +71240,9 @@ OUI:70B3D568E* OUI:70B3D568F* ID_OUI_FROM_DATABASE=PEEK TRAFFIC +OUI:70B3D5690* + ID_OUI_FROM_DATABASE=Sicon srl + OUI:70B3D5691* ID_OUI_FROM_DATABASE=PEEK TRAFFIC @@ -69797,6 +71264,9 @@ OUI:70B3D5696* OUI:70B3D5697* ID_OUI_FROM_DATABASE=Alazar Technologies Inc. +OUI:70B3D5698* + ID_OUI_FROM_DATABASE=ZIEHL-ABEGG SE + OUI:70B3D5699* ID_OUI_FROM_DATABASE=Flextronics International Kft @@ -69804,7 +71274,7 @@ OUI:70B3D569A* ID_OUI_FROM_DATABASE=Altaneos OUI:70B3D569B* - ID_OUI_FROM_DATABASE=TAIYO SEIKI CO.,LTD. + ID_OUI_FROM_DATABASE=HORIZON.INC OUI:70B3D569C* ID_OUI_FROM_DATABASE=Keepen @@ -69878,6 +71348,9 @@ OUI:70B3D56B2* OUI:70B3D56B3* ID_OUI_FROM_DATABASE=DuraComm Corporation +OUI:70B3D56B4* + ID_OUI_FROM_DATABASE=Nudron IoT Solutions LLP + OUI:70B3D56B5* ID_OUI_FROM_DATABASE=ART SPA @@ -69911,6 +71384,9 @@ OUI:70B3D56BE* OUI:70B3D56BF* ID_OUI_FROM_DATABASE=Otto Bihler Maschinenfabrik GmbH & Co. KG +OUI:70B3D56C0* + ID_OUI_FROM_DATABASE=LLC NTZ Mekhanotronika + OUI:70B3D56C1* ID_OUI_FROM_DATABASE=Labtronik s.r.l. @@ -69968,6 +71444,12 @@ OUI:70B3D56D2* OUI:70B3D56D3* ID_OUI_FROM_DATABASE=DEUTA-WERKE GmbH +OUI:70B3D56D4* + ID_OUI_FROM_DATABASE=Telerob Gesellschaft für Fernhantierungs + +OUI:70B3D56D5* + ID_OUI_FROM_DATABASE=Potter Electric Signal Co. LLC + OUI:70B3D56D6* ID_OUI_FROM_DATABASE=KMtronic ltd @@ -70133,6 +71615,9 @@ OUI:70B3D570B* OUI:70B3D570C* ID_OUI_FROM_DATABASE=Potter Electric Signal Co. LLC +OUI:70B3D570D* + ID_OUI_FROM_DATABASE=OMNISENSING PHOTONICS LLC + OUI:70B3D570E* ID_OUI_FROM_DATABASE=Wuhan Xingtuxinke ELectronic Co.,Ltd @@ -70148,6 +71633,9 @@ OUI:70B3D5711* OUI:70B3D5712* ID_OUI_FROM_DATABASE=APG Cash Drawer, LLC +OUI:70B3D5713* + ID_OUI_FROM_DATABASE=Coloet S.r.l. + OUI:70B3D5714* ID_OUI_FROM_DATABASE=Alturna Networks @@ -70166,6 +71654,9 @@ OUI:70B3D5718* OUI:70B3D5719* ID_OUI_FROM_DATABASE=2M Technology +OUI:70B3D571A* + ID_OUI_FROM_DATABASE=MB connect line GmbH Fernwartungssysteme + OUI:70B3D571B* ID_OUI_FROM_DATABASE=elsys @@ -70178,8 +71669,11 @@ OUI:70B3D571D* OUI:70B3D571E* ID_OUI_FROM_DATABASE=Motec Pty Ltd +OUI:70B3D571F* + ID_OUI_FROM_DATABASE=Grayshift + OUI:70B3D5720* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Jeio Tech OUI:70B3D5721* ID_OUI_FROM_DATABASE=Zoe Medical @@ -70193,6 +71687,9 @@ OUI:70B3D5723* OUI:70B3D5724* ID_OUI_FROM_DATABASE=Quan International Co., Ltd. +OUI:70B3D5725* + ID_OUI_FROM_DATABASE=Swiss Timing LTD + OUI:70B3D5726* ID_OUI_FROM_DATABASE=ATGS @@ -70208,6 +71705,9 @@ OUI:70B3D5729* OUI:70B3D572A* ID_OUI_FROM_DATABASE=MRC Systems GmbH +OUI:70B3D572B* + ID_OUI_FROM_DATABASE=Medipense Inc. + OUI:70B3D572C* ID_OUI_FROM_DATABASE=NuRi&G Engineering co,.Ltd. @@ -70239,7 +71739,7 @@ OUI:70B3D5735* ID_OUI_FROM_DATABASE=Swiss Audio OUI:70B3D5736* - ID_OUI_FROM_DATABASE=Jabil, Inc. + ID_OUI_FROM_DATABASE=Jabil OUI:70B3D5737* ID_OUI_FROM_DATABASE=SD Biosensor @@ -70286,6 +71786,9 @@ OUI:70B3D5744* OUI:70B3D5745* ID_OUI_FROM_DATABASE=TMSI LLC +OUI:70B3D5746* + ID_OUI_FROM_DATABASE=Smart Systems LLC + OUI:70B3D5747* ID_OUI_FROM_DATABASE=Eva Automation @@ -70526,6 +72029,9 @@ OUI:70B3D5796* OUI:70B3D5797* ID_OUI_FROM_DATABASE=Mitsubishi Electric India Pvt. Ltd. +OUI:70B3D5798* + ID_OUI_FROM_DATABASE=TIAMA + OUI:70B3D5799* ID_OUI_FROM_DATABASE=Vitec System Engineering Inc. @@ -70679,6 +72185,9 @@ OUI:70B3D57CA* OUI:70B3D57CB* ID_OUI_FROM_DATABASE=KeyW Corporation +OUI:70B3D57CC* + ID_OUI_FROM_DATABASE=MITSUBISHI HEAVY INDUSTRIES THERMAL SYSTEMS, LTD. + OUI:70B3D57CD* ID_OUI_FROM_DATABASE=Molekuler Goruntuleme A.S. @@ -70754,6 +72263,9 @@ OUI:70B3D57E4* OUI:70B3D57E5* ID_OUI_FROM_DATABASE=Megaflex Oy +OUI:70B3D57E6* + ID_OUI_FROM_DATABASE=11811347 CANADA Inc. + OUI:70B3D57E7* ID_OUI_FROM_DATABASE=Atessa, Inc. @@ -70799,6 +72311,9 @@ OUI:70B3D57F4* OUI:70B3D57F5* ID_OUI_FROM_DATABASE=Incusense +OUI:70B3D57F6* + ID_OUI_FROM_DATABASE=IDZ Ltd + OUI:70B3D57F7* ID_OUI_FROM_DATABASE=JASCO Applied Sciences Canada Ltd @@ -70808,6 +72323,9 @@ OUI:70B3D57F8* OUI:70B3D57F9* ID_OUI_FROM_DATABASE=Communication Systems Solutions +OUI:70B3D57FA* + ID_OUI_FROM_DATABASE=meoENERGY + OUI:70B3D57FB* ID_OUI_FROM_DATABASE=db Broadcast Products Ltd @@ -70877,6 +72395,9 @@ OUI:70B3D5810* OUI:70B3D5811* ID_OUI_FROM_DATABASE=CJSC «INTERSET» +OUI:70B3D5812* + ID_OUI_FROM_DATABASE=TESCAN Brno, s.r.o. + OUI:70B3D5813* ID_OUI_FROM_DATABASE=Wavemed srl @@ -70913,6 +72434,9 @@ OUI:70B3D581D* OUI:70B3D581E* ID_OUI_FROM_DATABASE=Novathings +OUI:70B3D581F* + ID_OUI_FROM_DATABASE=CAR-connect GmbH + OUI:70B3D5820* ID_OUI_FROM_DATABASE=Becker Nachrichtentechnik GmbH @@ -70940,6 +72464,9 @@ OUI:70B3D5827* OUI:70B3D5828* ID_OUI_FROM_DATABASE=Xacti Corporation +OUI:70B3D5829* + ID_OUI_FROM_DATABASE=Guan Show Technologe Co., Ltd. + OUI:70B3D582A* ID_OUI_FROM_DATABASE=C W F Hamilton & Co Ltd @@ -71414,6 +72941,9 @@ OUI:70B3D58C7* OUI:70B3D58C8* ID_OUI_FROM_DATABASE=KRONOTECH SRL +OUI:70B3D58C9* + ID_OUI_FROM_DATABASE=Arwin Technology Limited + OUI:70B3D58CA* ID_OUI_FROM_DATABASE=Allied Data Systems @@ -71450,6 +72980,9 @@ OUI:70B3D58D4* OUI:70B3D58D5* ID_OUI_FROM_DATABASE=Guangzhou Wanglu +OUI:70B3D58D6* + ID_OUI_FROM_DATABASE=Beijing Xiansheng Technology Co., Ltd + OUI:70B3D58D7* ID_OUI_FROM_DATABASE=Schneider Electric Motion USA @@ -71492,6 +73025,9 @@ OUI:70B3D58E3* OUI:70B3D58E4* ID_OUI_FROM_DATABASE=Aplex Technology Inc. +OUI:70B3D58E5* + ID_OUI_FROM_DATABASE=Shanghai Armour Technology Co., Ltd. + OUI:70B3D58E6* ID_OUI_FROM_DATABASE=Mothonic AB @@ -71501,6 +73037,9 @@ OUI:70B3D58E7* OUI:70B3D58E8* ID_OUI_FROM_DATABASE=PREO INDUSTRIES FAR EAST LTD +OUI:70B3D58E9* + ID_OUI_FROM_DATABASE=COONTROL Tecnologia em Combustão LTDA EPP + OUI:70B3D58EA* ID_OUI_FROM_DATABASE=JLCooper Electronics @@ -71558,6 +73097,9 @@ OUI:70B3D58FB* OUI:70B3D58FC* ID_OUI_FROM_DATABASE=Mianjie Technology +OUI:70B3D58FD* + ID_OUI_FROM_DATABASE=sonatest + OUI:70B3D58FE* ID_OUI_FROM_DATABASE=Selmatec AS @@ -71615,12 +73157,18 @@ OUI:70B3D5910* OUI:70B3D5911* ID_OUI_FROM_DATABASE=Equatel +OUI:70B3D5912* + ID_OUI_FROM_DATABASE=VERTEL DIGITAL PRIVATE LIMITED + OUI:70B3D5913* ID_OUI_FROM_DATABASE=Shenzhen Riitek Technology Co.,Ltd OUI:70B3D5914* ID_OUI_FROM_DATABASE=Contec Americas Inc. +OUI:70B3D5915* + ID_OUI_FROM_DATABASE=DHK Storage, LLC + OUI:70B3D5916* ID_OUI_FROM_DATABASE=Techno Mathematical Co.,Ltd @@ -71675,6 +73223,9 @@ OUI:70B3D5926* OUI:70B3D5927* ID_OUI_FROM_DATABASE=LG Electronics +OUI:70B3D5928* + ID_OUI_FROM_DATABASE=Done Design Inc + OUI:70B3D5929* ID_OUI_FROM_DATABASE=OutSys @@ -71855,6 +73406,9 @@ OUI:70B3D5963* OUI:70B3D5964* ID_OUI_FROM_DATABASE=Visility +OUI:70B3D5965* + ID_OUI_FROM_DATABASE=LINEAGE POWER PVT LTD., + OUI:70B3D5966* ID_OUI_FROM_DATABASE=dA Tomato Limited @@ -71867,9 +73421,15 @@ OUI:70B3D5968* OUI:70B3D5969* ID_OUI_FROM_DATABASE=Emtel System Sp. z o.o. +OUI:70B3D596A* + ID_OUI_FROM_DATABASE=Anello Photonics + OUI:70B3D596B* ID_OUI_FROM_DATABASE=FOCAL-JMLab +OUI:70B3D596C* + ID_OUI_FROM_DATABASE=Weble Sàrl + OUI:70B3D596D* ID_OUI_FROM_DATABASE=MSB Elektronik und Gerätebau GmbH @@ -72107,6 +73667,9 @@ OUI:70B3D59BA* OUI:70B3D59BB* ID_OUI_FROM_DATABASE=Jinga-hi, Inc. +OUI:70B3D59BC* + ID_OUI_FROM_DATABASE=Radian Research, Inc. + OUI:70B3D59BD* ID_OUI_FROM_DATABASE=Signal Processing Devices Sweden AB @@ -72188,6 +73751,9 @@ OUI:70B3D59D6* OUI:70B3D59D7* ID_OUI_FROM_DATABASE=KM OptoElektronik GmbH +OUI:70B3D59D8* + ID_OUI_FROM_DATABASE=JOLANYEE Technology Co., Ltd. + OUI:70B3D59D9* ID_OUI_FROM_DATABASE=ATX Networks Corp @@ -72252,7 +73818,7 @@ OUI:70B3D59ED* ID_OUI_FROM_DATABASE=Benchmark Electronics BV OUI:70B3D59EE* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Lockheed Martin - THAAD OUI:70B3D59EF* ID_OUI_FROM_DATABASE=Cottonwood Creek Technologies, Inc. @@ -72302,12 +73868,18 @@ OUI:70B3D59FD* OUI:70B3D59FE* ID_OUI_FROM_DATABASE=SURUGA SEIKI CO., LTD. +OUI:70B3D59FF* + ID_OUI_FROM_DATABASE=Network Integrity Systems + OUI:70B3D5A00* ID_OUI_FROM_DATABASE=ATX NETWORKS LTD OUI:70B3D5A01* ID_OUI_FROM_DATABASE=FeldTech GmbH +OUI:70B3D5A02* + ID_OUI_FROM_DATABASE=GreenFlux + OUI:70B3D5A03* ID_OUI_FROM_DATABASE=Proemion GmbH @@ -72335,6 +73907,9 @@ OUI:70B3D5A0A* OUI:70B3D5A0B* ID_OUI_FROM_DATABASE=ambiHome GmbH +OUI:70B3D5A0C* + ID_OUI_FROM_DATABASE=Lumiplan Duhamel + OUI:70B3D5A0D* ID_OUI_FROM_DATABASE=Globalcom Engineering SPA @@ -72356,6 +73931,9 @@ OUI:70B3D5A12* OUI:70B3D5A13* ID_OUI_FROM_DATABASE=Uplevel Systems Inc +OUI:70B3D5A14* + ID_OUI_FROM_DATABASE=aelettronica group srl + OUI:70B3D5A15* ID_OUI_FROM_DATABASE=Intercore GmbH @@ -72383,6 +73961,9 @@ OUI:70B3D5A1C* OUI:70B3D5A1D* ID_OUI_FROM_DATABASE=Fluid Components International +OUI:70B3D5A1E* + ID_OUI_FROM_DATABASE=Monnit Corporation + OUI:70B3D5A1F* ID_OUI_FROM_DATABASE=GlobalTest LLC @@ -72587,6 +74168,9 @@ OUI:70B3D5A61* OUI:70B3D5A62* ID_OUI_FROM_DATABASE=Environexus +OUI:70B3D5A63* + ID_OUI_FROM_DATABASE=DesignA Electronics Limited + OUI:70B3D5A64* ID_OUI_FROM_DATABASE=Newshine @@ -72716,6 +74300,9 @@ OUI:70B3D5A8D* OUI:70B3D5A8E* ID_OUI_FROM_DATABASE=OMESH CITY GROUP +OUI:70B3D5A8F* + ID_OUI_FROM_DATABASE=VK Integrated Systems + OUI:70B3D5A90* ID_OUI_FROM_DATABASE=ERA a.s. @@ -72762,7 +74349,7 @@ OUI:70B3D5A9E* ID_OUI_FROM_DATABASE=Argon ST OUI:70B3D5A9F* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Master Meter Inc. OUI:70B3D5AA0* ID_OUI_FROM_DATABASE=Simple Works, Inc. @@ -72899,9 +74486,15 @@ OUI:70B3D5ACC* OUI:70B3D5ACD* ID_OUI_FROM_DATABASE=CRDE +OUI:70B3D5ACE* + ID_OUI_FROM_DATABASE=FARHO DOMOTICA SL + OUI:70B3D5ACF* ID_OUI_FROM_DATABASE=APG Cash Drawer, LLC +OUI:70B3D5AD0* + ID_OUI_FROM_DATABASE=REO AG + OUI:70B3D5AD1* ID_OUI_FROM_DATABASE=Sensile Technologies SA @@ -73034,6 +74627,9 @@ OUI:70B3D5AFB* OUI:70B3D5AFC* ID_OUI_FROM_DATABASE=BAE Systems +OUI:70B3D5AFD* + ID_OUI_FROM_DATABASE=dongsheng + OUI:70B3D5AFE* ID_OUI_FROM_DATABASE=MESOTECHNIC @@ -73043,6 +74639,9 @@ OUI:70B3D5AFF* OUI:70B3D5B00* ID_OUI_FROM_DATABASE=HORIBA ABX SAS +OUI:70B3D5B01* + ID_OUI_FROM_DATABASE=G.S.D GROUP INC. + OUI:70B3D5B02* ID_OUI_FROM_DATABASE=Nordic Automation Systems AS @@ -73088,6 +74687,9 @@ OUI:70B3D5B10* OUI:70B3D5B11* ID_OUI_FROM_DATABASE=CAB S.R.L. +OUI:70B3D5B12* + ID_OUI_FROM_DATABASE=VTEQ + OUI:70B3D5B13* ID_OUI_FROM_DATABASE=Omwave @@ -73256,6 +74858,9 @@ OUI:70B3D5B4A* OUI:70B3D5B4B* ID_OUI_FROM_DATABASE=Network Customizing Technologies Inc +OUI:70B3D5B4C* + ID_OUI_FROM_DATABASE=AmericanPharma Technologies + OUI:70B3D5B4D* ID_OUI_FROM_DATABASE=Avidbots Corporation @@ -73358,6 +74963,9 @@ OUI:70B3D5B6E* OUI:70B3D5B6F* ID_OUI_FROM_DATABASE=Integra Metering SAS +OUI:70B3D5B70* + ID_OUI_FROM_DATABASE=Torion Plasma Corporation + OUI:70B3D5B71* ID_OUI_FROM_DATABASE=Optiver Pty Ltd @@ -73382,6 +74990,9 @@ OUI:70B3D5B77* OUI:70B3D5B78* ID_OUI_FROM_DATABASE=HOERMANN GmbH +OUI:70B3D5B79* + ID_OUI_FROM_DATABASE=Dadacon GmbH + OUI:70B3D5B7A* ID_OUI_FROM_DATABASE=MAHLE @@ -73493,6 +75104,9 @@ OUI:70B3D5B9E* OUI:70B3D5B9F* ID_OUI_FROM_DATABASE=Yuksek Kapasite Radyolink Sistemleri San. ve Tic. A.S. +OUI:70B3D5BA0* + ID_OUI_FROM_DATABASE=Season Electronics Ltd + OUI:70B3D5BA1* ID_OUI_FROM_DATABASE=Cathwell AS @@ -73610,6 +75224,9 @@ OUI:70B3D5BC6* OUI:70B3D5BC7* ID_OUI_FROM_DATABASE=Autonomic Controls, Inc. +OUI:70B3D5BC8* + ID_OUI_FROM_DATABASE=Loma Systems s.r.o. + OUI:70B3D5BC9* ID_OUI_FROM_DATABASE=Yite technology @@ -73652,6 +75269,9 @@ OUI:70B3D5BD5* OUI:70B3D5BD6* ID_OUI_FROM_DATABASE=Consarc Corporation +OUI:70B3D5BD7* + ID_OUI_FROM_DATABASE=TT Group SRL + OUI:70B3D5BD8* ID_OUI_FROM_DATABASE=MB connect line GmbH Fernwartungssysteme @@ -73745,6 +75365,9 @@ OUI:70B3D5BF5* OUI:70B3D5BF6* ID_OUI_FROM_DATABASE=comtac AG +OUI:70B3D5BF7* + ID_OUI_FROM_DATABASE=Fischer Connectors + OUI:70B3D5BF8* ID_OUI_FROM_DATABASE=RCH ITALIA SPA @@ -73844,6 +75467,9 @@ OUI:70B3D5C17* OUI:70B3D5C18* ID_OUI_FROM_DATABASE=Sanmina Israel +OUI:70B3D5C19* + ID_OUI_FROM_DATABASE=Zumbach Electronic AG + OUI:70B3D5C1A* ID_OUI_FROM_DATABASE=Xylon @@ -74087,6 +75713,9 @@ OUI:70B3D5C69* OUI:70B3D5C6A* ID_OUI_FROM_DATABASE=Private +OUI:70B3D5C6B* + ID_OUI_FROM_DATABASE=Herholdt Controls srl + OUI:70B3D5C6C* ID_OUI_FROM_DATABASE=McQ Inc @@ -74102,6 +75731,9 @@ OUI:70B3D5C6F* OUI:70B3D5C70* ID_OUI_FROM_DATABASE=Magnetek +OUI:70B3D5C71* + ID_OUI_FROM_DATABASE=The Engineerix Group + OUI:70B3D5C72* ID_OUI_FROM_DATABASE=Scharco Elektronik GmbH @@ -74240,6 +75872,9 @@ OUI:70B3D5C9E* OUI:70B3D5C9F* ID_OUI_FROM_DATABASE=Triax A/S +OUI:70B3D5CA0* + ID_OUI_FROM_DATABASE=Xirgo Technologies LLC + OUI:70B3D5CA1* ID_OUI_FROM_DATABASE=Waldo System @@ -74255,6 +75890,9 @@ OUI:70B3D5CA4* OUI:70B3D5CA5* ID_OUI_FROM_DATABASE=PTS Technologies Pte Ltd +OUI:70B3D5CA6* + ID_OUI_FROM_DATABASE=AXING AG + OUI:70B3D5CA7* ID_OUI_FROM_DATABASE=i-View Communication Inc. @@ -74273,6 +75911,9 @@ OUI:70B3D5CAB* OUI:70B3D5CAC* ID_OUI_FROM_DATABASE=CRDE +OUI:70B3D5CAD* + ID_OUI_FROM_DATABASE=YUYAMA MFG Co.,Ltd + OUI:70B3D5CAE* ID_OUI_FROM_DATABASE=THEMA @@ -74294,6 +75935,9 @@ OUI:70B3D5CB3* OUI:70B3D5CB4* ID_OUI_FROM_DATABASE=Planewave Instruments +OUI:70B3D5CB5* + ID_OUI_FROM_DATABASE=Atlas Lighting Products + OUI:70B3D5CB6* ID_OUI_FROM_DATABASE=Kuebrich Ingeniergesellschaft mbh & Co. KG @@ -74324,6 +75968,9 @@ OUI:70B3D5CBE* OUI:70B3D5CBF* ID_OUI_FROM_DATABASE=Cubic ITS, Inc. dba GRIDSMART Technologies +OUI:70B3D5CC0* + ID_OUI_FROM_DATABASE=Avionica + OUI:70B3D5CC1* ID_OUI_FROM_DATABASE=BEEcube Inc. @@ -74417,6 +76064,9 @@ OUI:70B3D5CDE* OUI:70B3D5CDF* ID_OUI_FROM_DATABASE=3D Printing Specialists +OUI:70B3D5CE0* + ID_OUI_FROM_DATABASE=M.S. CONTROL + OUI:70B3D5CE1* ID_OUI_FROM_DATABASE=EA Elektroautomatik GmbH & Co. KG @@ -74432,15 +76082,24 @@ OUI:70B3D5CE4* OUI:70B3D5CE5* ID_OUI_FROM_DATABASE=GridBridge Inc +OUI:70B3D5CE6* + ID_OUI_FROM_DATABASE=Dynim Oy + OUI:70B3D5CE7* ID_OUI_FROM_DATABASE=June Automation Singapore Pte. Ltd. +OUI:70B3D5CE8* + ID_OUI_FROM_DATABASE=Grossenbacher Systeme AG + OUI:70B3D5CE9* ID_OUI_FROM_DATABASE=KINEMETRICS OUI:70B3D5CEA* ID_OUI_FROM_DATABASE=Computerwise, Inc. +OUI:70B3D5CEB* + ID_OUI_FROM_DATABASE=Xirgo Technologies LLC + OUI:70B3D5CEC* ID_OUI_FROM_DATABASE=Deltronic Security AB @@ -74480,6 +76139,12 @@ OUI:70B3D5CF7* OUI:70B3D5CF8* ID_OUI_FROM_DATABASE=Idneo Technologies S.A.U. +OUI:70B3D5CF9* + ID_OUI_FROM_DATABASE=Breas Medical AB + +OUI:70B3D5CFA* + ID_OUI_FROM_DATABASE=SCHEIBER + OUI:70B3D5CFB* ID_OUI_FROM_DATABASE=Screen Innovations @@ -74507,6 +76172,9 @@ OUI:70B3D5D02* OUI:70B3D5D03* ID_OUI_FROM_DATABASE=Digitella Inc. +OUI:70B3D5D04* + ID_OUI_FROM_DATABASE=Plenty Unlimited Inc + OUI:70B3D5D05* ID_OUI_FROM_DATABASE=Colmek @@ -74546,6 +76214,9 @@ OUI:70B3D5D11* OUI:70B3D5D12* ID_OUI_FROM_DATABASE=FIDELTRONIK POLAND SP. Z O.O. +OUI:70B3D5D13* + ID_OUI_FROM_DATABASE=IRT Technologies + OUI:70B3D5D14* ID_OUI_FROM_DATABASE=LIGPT @@ -74573,6 +76244,9 @@ OUI:70B3D5D1B* OUI:70B3D5D1C* ID_OUI_FROM_DATABASE=Specialised Imaging Limited +OUI:70B3D5D1D* + ID_OUI_FROM_DATABASE=Stuyts Engineering Haarlem BV + OUI:70B3D5D1E* ID_OUI_FROM_DATABASE=Houston Radar LLC @@ -74582,6 +76256,9 @@ OUI:70B3D5D1F* OUI:70B3D5D20* ID_OUI_FROM_DATABASE=Rheonics GmbH +OUI:70B3D5D21* + ID_OUI_FROM_DATABASE=biosilver .co.,ltd + OUI:70B3D5D22* ID_OUI_FROM_DATABASE=DEK Technologies @@ -74612,6 +76289,9 @@ OUI:70B3D5D2A* OUI:70B3D5D2B* ID_OUI_FROM_DATABASE=StreamPlay Oy Ltd +OUI:70B3D5D2C* + ID_OUI_FROM_DATABASE=microWerk GmbH + OUI:70B3D5D2D* ID_OUI_FROM_DATABASE=Evolute Systems Private Limited @@ -74684,6 +76364,9 @@ OUI:70B3D5D43* OUI:70B3D5D44* ID_OUI_FROM_DATABASE=ic-automation GmbH +OUI:70B3D5D45* + ID_OUI_FROM_DATABASE=Vemco Sp. z o. o. + OUI:70B3D5D46* ID_OUI_FROM_DATABASE=Contineo s.r.o. @@ -74720,6 +76403,9 @@ OUI:70B3D5D50* OUI:70B3D5D51* ID_OUI_FROM_DATABASE=Azcom Technology S.r.l. +OUI:70B3D5D52* + ID_OUI_FROM_DATABASE=Sensoronic Co.,Ltd + OUI:70B3D5D53* ID_OUI_FROM_DATABASE=BeiLi eTek (Zhangjiagang) Co., Ltd. @@ -74750,6 +76436,9 @@ OUI:70B3D5D5B* OUI:70B3D5D5C* ID_OUI_FROM_DATABASE=Critical Link LLC +OUI:70B3D5D5D* + ID_OUI_FROM_DATABASE=SEASONS 4 INC + OUI:70B3D5D5E* ID_OUI_FROM_DATABASE=Barcelona Smart Technologies @@ -74795,6 +76484,9 @@ OUI:70B3D5D6B* OUI:70B3D5D6C* ID_OUI_FROM_DATABASE=GP Systems GmbH +OUI:70B3D5D6D* + ID_OUI_FROM_DATABASE=ACD Elekronik GmbH + OUI:70B3D5D6E* ID_OUI_FROM_DATABASE=ard sa @@ -74858,6 +76550,9 @@ OUI:70B3D5D81* OUI:70B3D5D82* ID_OUI_FROM_DATABASE=SUN ELECTRONICS CO.,LTD. +OUI:70B3D5D83* + ID_OUI_FROM_DATABASE=AKASAKATEC INC. + OUI:70B3D5D84* ID_OUI_FROM_DATABASE=Sentry360 @@ -74942,6 +76637,9 @@ OUI:70B3D5D9E* OUI:70B3D5D9F* ID_OUI_FROM_DATABASE=Digital Solutions JSC +OUI:70B3D5DA0* + ID_OUI_FROM_DATABASE=Jiangsu Etern Compamy Limited + OUI:70B3D5DA1* ID_OUI_FROM_DATABASE=Qprel srl @@ -75083,6 +76781,9 @@ OUI:70B3D5DCE* OUI:70B3D5DCF* ID_OUI_FROM_DATABASE=KLS Netherlands B.V. +OUI:70B3D5DD0* + ID_OUI_FROM_DATABASE=Deep Secure Limited + OUI:70B3D5DD1* ID_OUI_FROM_DATABASE=em-tec GmbH @@ -75110,6 +76811,9 @@ OUI:70B3D5DD8* OUI:70B3D5DD9* ID_OUI_FROM_DATABASE=MaNima Technologies BV +OUI:70B3D5DDA* + ID_OUI_FROM_DATABASE=Hubbell Power Systems + OUI:70B3D5DDB* ID_OUI_FROM_DATABASE=Intra Corporation @@ -75158,6 +76862,9 @@ OUI:70B3D5DE9* OUI:70B3D5DEA* ID_OUI_FROM_DATABASE=Advanced Ventilation Applications, Inc. +OUI:70B3D5DEB* + ID_OUI_FROM_DATABASE=DORLET SAU + OUI:70B3D5DEC* ID_OUI_FROM_DATABASE=Condev-Automation GmbH @@ -75167,6 +76874,9 @@ OUI:70B3D5DED* OUI:70B3D5DEE* ID_OUI_FROM_DATABASE=CRDE +OUI:70B3D5DEF* + ID_OUI_FROM_DATABASE=ISG Nordic AB + OUI:70B3D5DF0* ID_OUI_FROM_DATABASE=astozi consulting Tomasz Zieba @@ -75189,7 +76899,7 @@ OUI:70B3D5DF6* ID_OUI_FROM_DATABASE=Tiab Limited OUI:70B3D5DF7* - ID_OUI_FROM_DATABASE=Refecor Oy + ID_OUI_FROM_DATABASE=ScopeSensor Oy OUI:70B3D5DF8* ID_OUI_FROM_DATABASE=RMA Mess- und Regeltechnik GmbH & Co.KG @@ -75224,9 +76934,15 @@ OUI:70B3D5E01* OUI:70B3D5E02* ID_OUI_FROM_DATABASE=YEHL & JORDAN LLC +OUI:70B3D5E03* + ID_OUI_FROM_DATABASE=MBJ + OUI:70B3D5E04* ID_OUI_FROM_DATABASE=Combilent +OUI:70B3D5E05* + ID_OUI_FROM_DATABASE=Lobaro GmbH + OUI:70B3D5E06* ID_OUI_FROM_DATABASE=System West dba ICS Electronics @@ -75251,6 +76967,9 @@ OUI:70B3D5E0C* OUI:70B3D5E0D* ID_OUI_FROM_DATABASE=Sigma Connectivity AB +OUI:70B3D5E0E* + ID_OUI_FROM_DATABASE=VulcanForms + OUI:70B3D5E0F* ID_OUI_FROM_DATABASE=Vtron Pty Ltd @@ -75281,6 +77000,9 @@ OUI:70B3D5E17* OUI:70B3D5E18* ID_OUI_FROM_DATABASE=Plasmapp Co.,Ltd. +OUI:70B3D5E19* + ID_OUI_FROM_DATABASE=BAB TECHNOLOGIE GmbH + OUI:70B3D5E1A* ID_OUI_FROM_DATABASE=BIZERBA LUCEO @@ -75398,6 +77120,9 @@ OUI:70B3D5E3F* OUI:70B3D5E40* ID_OUI_FROM_DATABASE=Siemens Mobility GmbH - MO TI SPA +OUI:70B3D5E42* + ID_OUI_FROM_DATABASE=Neusoft Reach Automotive Technology (Shenyang) Co.,Ltd + OUI:70B3D5E43* ID_OUI_FROM_DATABASE=SL Audio A/S @@ -75482,6 +77207,12 @@ OUI:70B3D5E5D* OUI:70B3D5E5E* ID_OUI_FROM_DATABASE=Critical Link LLC +OUI:70B3D5E5F* + ID_OUI_FROM_DATABASE=CesiumAstro Inc. + +OUI:70B3D5E60* + ID_OUI_FROM_DATABASE=Davitor AB + OUI:70B3D5E61* ID_OUI_FROM_DATABASE=Adeli @@ -75701,6 +77432,9 @@ OUI:70B3D5EA8* OUI:70B3D5EA9* ID_OUI_FROM_DATABASE=Zhuhai Lonl electric Co.,Ltd. +OUI:70B3D5EAA* + ID_OUI_FROM_DATABASE=Druck Ltd. + OUI:70B3D5EAB* ID_OUI_FROM_DATABASE=APEN GROUP SpA (VAT IT08767740155) @@ -75764,6 +77498,9 @@ OUI:70B3D5EBE* OUI:70B3D5EBF* ID_OUI_FROM_DATABASE=AUTOMATICA Y REGULACION S.A. +OUI:70B3D5EC0* + ID_OUI_FROM_DATABASE=ProtoConvert Pty Ltd + OUI:70B3D5EC1* ID_OUI_FROM_DATABASE=Xafax Nederland bv @@ -75827,6 +77564,9 @@ OUI:70B3D5ED4* OUI:70B3D5ED5* ID_OUI_FROM_DATABASE=hangzhou battle link technology Co.,Ltd +OUI:70B3D5ED6* + ID_OUI_FROM_DATABASE=Metrasens Limited + OUI:70B3D5ED7* ID_OUI_FROM_DATABASE=WAVE @@ -75854,6 +77594,9 @@ OUI:70B3D5EDE* OUI:70B3D5EDF* ID_OUI_FROM_DATABASE=GridNavigator +OUI:70B3D5EE0* + ID_OUI_FROM_DATABASE=Stecomp + OUI:70B3D5EE1* ID_OUI_FROM_DATABASE=allora Factory BVBA @@ -75899,6 +77642,9 @@ OUI:70B3D5EEE* OUI:70B3D5EEF* ID_OUI_FROM_DATABASE=TATTILE SRL +OUI:70B3D5EF0* + ID_OUI_FROM_DATABASE=PNETWORKS + OUI:70B3D5EF1* ID_OUI_FROM_DATABASE=Nanotok LLC @@ -76025,6 +77771,9 @@ OUI:70B3D5F19* OUI:70B3D5F1A* ID_OUI_FROM_DATABASE=Sator Controls s.r.o. +OUI:70B3D5F1B* + ID_OUI_FROM_DATABASE=RoyalShield Technologies India Private Limited + OUI:70B3D5F1C* ID_OUI_FROM_DATABASE=Bavaria Digital Technik GmbH @@ -76052,6 +77801,9 @@ OUI:70B3D5F24* OUI:70B3D5F25* ID_OUI_FROM_DATABASE=JSC “Scientific Industrial Enterprise Rubin +OUI:70B3D5F26* + ID_OUI_FROM_DATABASE=XJ ELECTRIC CO., LTD. + OUI:70B3D5F27* ID_OUI_FROM_DATABASE=NIRIT- Xinwei Telecom Technology Co., Ltd. @@ -76082,6 +77834,9 @@ OUI:70B3D5F2F* OUI:70B3D5F30* ID_OUI_FROM_DATABASE=ADE Technology Inc. +OUI:70B3D5F31* + ID_OUI_FROM_DATABASE=The-Box Development + OUI:70B3D5F32* ID_OUI_FROM_DATABASE=Elektronik Art @@ -76124,6 +77879,9 @@ OUI:70B3D5F3E* OUI:70B3D5F3F* ID_OUI_FROM_DATABASE=comtac AG +OUI:70B3D5F40* + ID_OUI_FROM_DATABASE=HORIZON.INC + OUI:70B3D5F41* ID_OUI_FROM_DATABASE=DUEVI SRL @@ -76277,6 +78035,9 @@ OUI:70B3D5F72* OUI:70B3D5F73* ID_OUI_FROM_DATABASE=ASL Holdings +OUI:70B3D5F74* + ID_OUI_FROM_DATABASE=TESSA AGRITECH SRL + OUI:70B3D5F75* ID_OUI_FROM_DATABASE=Enlaps @@ -76299,7 +78060,7 @@ OUI:70B3D5F7B* ID_OUI_FROM_DATABASE=KST technology OUI:70B3D5F7C* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Medicomp, Inc OUI:70B3D5F7D* ID_OUI_FROM_DATABASE=2M Technology @@ -76466,6 +78227,9 @@ OUI:70B3D5FB2* OUI:70B3D5FB3* ID_OUI_FROM_DATABASE=3PS Inc +OUI:70B3D5FB4* + ID_OUI_FROM_DATABASE=Array Technologies Inc. + OUI:70B3D5FB5* ID_OUI_FROM_DATABASE=Orange Tree Technologies Ltd @@ -76595,6 +78359,12 @@ OUI:70B3D5FDE* OUI:70B3D5FDF* ID_OUI_FROM_DATABASE=NARA CONTROLS INC. +OUI:70B3D5FE0* + ID_OUI_FROM_DATABASE=Blueprint Lab + +OUI:70B3D5FE1* + ID_OUI_FROM_DATABASE=Shenzhen Zhiting Technology Co.,Ltd + OUI:70B3D5FE2* ID_OUI_FROM_DATABASE=Galileo Tıp Teknolojileri San. ve Tic. A.S. @@ -76694,6 +78464,9 @@ OUI:70B7E2* OUI:70B921* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:70B950* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:70BAEF* ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited @@ -76802,6 +78575,9 @@ OUI:70DEF9* OUI:70DF2F* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:70DFF7* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:70E027* ID_OUI_FROM_DATABASE=HONGYU COMMUNICATION TECHNOLOGY LIMITED @@ -76850,6 +78626,9 @@ OUI:70EF00* OUI:70F087* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:70F088* + ID_OUI_FROM_DATABASE=Nintendo Co.,Ltd + OUI:70F096* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -76964,6 +78743,9 @@ OUI:7404F0* OUI:7405A5* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:7409AC* + ID_OUI_FROM_DATABASE=Quext, LLC + OUI:740ABC* ID_OUI_FROM_DATABASE=LightwaveRF Technology Ltd @@ -76982,6 +78764,9 @@ OUI:7412BB* OUI:741489* ID_OUI_FROM_DATABASE=SRT Wireless +OUI:741575* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:7415E2* ID_OUI_FROM_DATABASE=Tri-Sen Systems Corporation @@ -77309,6 +79094,9 @@ OUI:745C4B* OUI:745C9F* ID_OUI_FROM_DATABASE=TCT mobile ltd +OUI:745D68* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:745E1C* ID_OUI_FROM_DATABASE=PIONEER CORPORATION @@ -77588,6 +79376,9 @@ OUI:74AC5F* OUI:74ACB9* ID_OUI_FROM_DATABASE=Ubiquiti Networks Inc. +OUI:74AD98* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:74ADB7* ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. @@ -77678,6 +79469,9 @@ OUI:74CD0C* OUI:74CE56* ID_OUI_FROM_DATABASE=Packet Force Technology Limited Company +OUI:74CF00* + ID_OUI_FROM_DATABASE=Shenzhen SuperElectron Technology Co.,Ltd. + OUI:74D02B* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. @@ -77687,6 +79481,9 @@ OUI:74D0DC* OUI:74D21D* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:74D285* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:74D435* ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. @@ -77795,6 +79592,9 @@ OUI:74E19A* OUI:74E1B6* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:74E20C* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:74E277* ID_OUI_FROM_DATABASE=Vizmonet Pte Ltd @@ -78005,6 +79805,9 @@ OUI:780ED1* OUI:780F77* ID_OUI_FROM_DATABASE=HangZhou Gubei Electronics Technology Co.,Ltd +OUI:781053* + ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. + OUI:781100* ID_OUI_FROM_DATABASE=Quantumsolution @@ -78026,6 +79829,9 @@ OUI:7817BE* OUI:781881* ID_OUI_FROM_DATABASE=AzureWave Technology Inc. +OUI:7818A8* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:78192E* ID_OUI_FROM_DATABASE=NASCENT Technology @@ -78195,7 +80001,7 @@ OUI:78471D* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd OUI:7847E3* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOM CO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:784859* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -78284,9 +80090,15 @@ OUI:78617C* OUI:786256* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:7864C0* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:7864E6* ID_OUI_FROM_DATABASE=Green Motive Technology Limited +OUI:78653B* + ID_OUI_FROM_DATABASE=Shaoxing Ourten Electronics Co., Ltd. + OUI:786559* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -78326,6 +80138,9 @@ OUI:78719C* OUI:78725D* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:787A6F* + ID_OUI_FROM_DATABASE=Juice Technology AG + OUI:787B8A* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -78365,6 +80180,9 @@ OUI:7884EE* OUI:7885F4* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:7886B6* + ID_OUI_FROM_DATABASE=Shenzhen YOUHUA Technology Co., Ltd + OUI:78870D* ID_OUI_FROM_DATABASE=Unifiedgateways India Private Limited @@ -78488,6 +80306,9 @@ OUI:78A5DD* OUI:78A683* ID_OUI_FROM_DATABASE=Precidata +OUI:78A6A0* + ID_OUI_FROM_DATABASE=Hangzhou Ezviz Software Co.,Ltd. + OUI:78A6BD* ID_OUI_FROM_DATABASE=DAEYEON Control&Instrument Co,.Ltd @@ -78545,6 +80366,9 @@ OUI:78B3CE* OUI:78B46A* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:78B554* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:78B5D2* ID_OUI_FROM_DATABASE=Ever Treasure Industrial Limited @@ -78558,7 +80382,7 @@ OUI:78B81A* ID_OUI_FROM_DATABASE=INTER SALES A/S OUI:78B84B* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:78B8D6* ID_OUI_FROM_DATABASE=Zebra Technologies Inc. @@ -78569,6 +80393,9 @@ OUI:78BAD0* OUI:78BAF9* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:78BB88* + ID_OUI_FROM_DATABASE=Maxio Technology (Hangzhou) Ltd. + OUI:78BC1A* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -78603,7 +80430,7 @@ OUI:78C2C05* ID_OUI_FROM_DATABASE=ShenZhen TuLing Robot CO.,LTD OUI:78C2C06* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:78C2C07* ID_OUI_FROM_DATABASE=Guangzhou Hongcai Stage Equipment co.,ltd @@ -78731,6 +80558,9 @@ OUI:78CD8E* OUI:78CF2F* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:78CFF9* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:78D004* ID_OUI_FROM_DATABASE=Neousys Technology Inc. @@ -78806,6 +80636,9 @@ OUI:78D66F* OUI:78D6B2* ID_OUI_FROM_DATABASE=Toshiba +OUI:78D6DC* + ID_OUI_FROM_DATABASE=Motorola (Wuhan) Mobility Technologies Communication Co., Ltd. + OUI:78D6F0* ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO., LTD. @@ -78866,6 +80699,9 @@ OUI:78D800E* OUI:78D99F* ID_OUI_FROM_DATABASE=NuCom HK Ltd. +OUI:78D9E9* + ID_OUI_FROM_DATABASE=MOMENTUM IOT + OUI:78DA07* ID_OUI_FROM_DATABASE=Zhejiang Tmall Technology Co., Ltd. @@ -78905,6 +80741,9 @@ OUI:78E22C* OUI:78E2BD* ID_OUI_FROM_DATABASE=Vodafone Automotive S.p.A. +OUI:78E36D* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:78E3B5* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -78941,6 +80780,9 @@ OUI:78EF4C* OUI:78F09B* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:78F235* + ID_OUI_FROM_DATABASE=Sichuan AI-Link Technology Co., Ltd. + OUI:78F29E* ID_OUI_FROM_DATABASE=PEGATRON CORPORATION @@ -78992,6 +80834,9 @@ OUI:78FF57* OUI:78FFCA* ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED +OUI:7C004D* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:7C010A* ID_OUI_FROM_DATABASE=Texas Instruments @@ -79037,6 +80882,9 @@ OUI:7C08D9* OUI:7C092B* ID_OUI_FROM_DATABASE=Bekey A/S +OUI:7C0A3F* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:7C0A50* ID_OUI_FROM_DATABASE=J-MEX Inc. @@ -79076,6 +80924,9 @@ OUI:7C1A03* OUI:7C1AFC* ID_OUI_FROM_DATABASE=Dalian Co-Edifice Video Technology Co., Ltd +OUI:7C1B93* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:7C1C4E* ID_OUI_FROM_DATABASE=LG Innotek @@ -79133,6 +80984,9 @@ OUI:7C2634* OUI:7C2664* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS +OUI:7C27BC* + ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD + OUI:7C2A31* ID_OUI_FROM_DATABASE=Intel Corporate @@ -79187,6 +81041,12 @@ OUI:7C3BD5* OUI:7C3CB6* ID_OUI_FROM_DATABASE=Shenzhen Homecare Technology Co.,Ltd. +OUI:7C3D2B* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + +OUI:7C3E74* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:7C3E9D* ID_OUI_FROM_DATABASE=PATECH @@ -79298,6 +81158,9 @@ OUI:7C5259* OUI:7C534A* ID_OUI_FROM_DATABASE=Metamako +OUI:7C55A7* + ID_OUI_FROM_DATABASE=Kastle Systems + OUI:7C55E7* ID_OUI_FROM_DATABASE=YSI, Inc. @@ -79436,6 +81299,9 @@ OUI:7C70BCE* OUI:7C70BCF* ID_OUI_FROM_DATABASE=Private +OUI:7C70DB* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:7C7176* ID_OUI_FROM_DATABASE=Wuxi iData Technology Company Ltd. @@ -79496,6 +81362,9 @@ OUI:7C8274* OUI:7C8306* ID_OUI_FROM_DATABASE=Glen Dimplex Nordic as +OUI:7C8530* + ID_OUI_FROM_DATABASE=Nokia + OUI:7C8956* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -79553,6 +81422,9 @@ OUI:7C9A9B* OUI:7C9EBD* ID_OUI_FROM_DATABASE=Espressif Inc. +OUI:7C9F07* + ID_OUI_FROM_DATABASE=CIG SHANGHAI CO LTD + OUI:7CA15D* ID_OUI_FROM_DATABASE=GN ReSound A/S @@ -79637,6 +81509,9 @@ OUI:7CB733* OUI:7CB77B* ID_OUI_FROM_DATABASE=Paradigm Electronics Inc +OUI:7CB94C* + ID_OUI_FROM_DATABASE=Bouffalo Lab (Nanjing) Co., Ltd. + OUI:7CB960* ID_OUI_FROM_DATABASE=Shanghai X-Cheng telecom LTD @@ -79836,7 +81711,7 @@ OUI:7CCBE2E* ID_OUI_FROM_DATABASE=Aplex Technology Inc. OUI:7CCC1F* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:7CCCB8* ID_OUI_FROM_DATABASE=Intel Corporate @@ -79874,6 +81749,9 @@ OUI:7CD95C* OUI:7CD9A0* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:7CD9F4* + ID_OUI_FROM_DATABASE=UAB Teltonika Telematics + OUI:7CD9FE* ID_OUI_FROM_DATABASE=New Cosmos Electric Co., Ltd. @@ -79970,9 +81848,18 @@ OUI:7CF31B* OUI:7CF429* ID_OUI_FROM_DATABASE=NUUO Inc. +OUI:7CF462* + ID_OUI_FROM_DATABASE=BEIJING HUAWOO TECHNOLOGIES CO.LTD + +OUI:7CF666* + ID_OUI_FROM_DATABASE=Tuya Smart Inc. + OUI:7CF854* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:7CF880* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:7CF90E* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -80036,6 +81923,9 @@ OUI:800588* OUI:8005DF* ID_OUI_FROM_DATABASE=Montage Technology Group Limited +OUI:80071B* + ID_OUI_FROM_DATABASE=VSOLUTION TELECOMMUNICATION TECHNOLOGY CO.,LTD. + OUI:8007A2* ID_OUI_FROM_DATABASE=Esson Technology Inc. @@ -80150,6 +82040,9 @@ OUI:802278* OUI:8022A7* ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. +OUI:802511* + ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED + OUI:802689* ID_OUI_FROM_DATABASE=D-Link International @@ -80192,6 +82085,9 @@ OUI:8031F0* OUI:803253* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:803428* + ID_OUI_FROM_DATABASE=Microchip Technology Inc. + OUI:803457* ID_OUI_FROM_DATABASE=OT Systems Limited @@ -80252,11 +82148,20 @@ OUI:80414E* OUI:80427C* ID_OUI_FROM_DATABASE=Adolf Tedsen GmbH & Co. KG +OUI:8044FD* + ID_OUI_FROM_DATABASE=China Mobile (Hangzhou) Information Technology Co., Ltd. + +OUI:8045DD* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:804731* ID_OUI_FROM_DATABASE=Packet Design, Inc. +OUI:804786* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:8048A5* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:804971* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -80339,6 +82244,9 @@ OUI:806459* OUI:80647A* ID_OUI_FROM_DATABASE=Ola Sense Inc +OUI:806559* + ID_OUI_FROM_DATABASE=EM Microelectronic + OUI:80656D* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -80381,6 +82289,9 @@ OUI:80717A* OUI:807215* ID_OUI_FROM_DATABASE=BSkyB Ltd +OUI:807264* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:80739F* ID_OUI_FROM_DATABASE=KYOCERA CORPORATION @@ -80507,6 +82418,9 @@ OUI:808917* OUI:808A8B* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:808AF7* + ID_OUI_FROM_DATABASE=Nanoleaf + OUI:808B5C* ID_OUI_FROM_DATABASE=Shenzhen Runhuicheng Technology Co., Ltd @@ -80624,6 +82538,9 @@ OUI:80B575* OUI:80B624* ID_OUI_FROM_DATABASE=IVS +OUI:80B655* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:80B686* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -80693,6 +82610,9 @@ OUI:80CA4B* OUI:80CC12* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:80CC9C* + ID_OUI_FROM_DATABASE=NETGEAR + OUI:80CE62* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -80852,6 +82772,9 @@ OUI:80F1F1* OUI:80F25E* ID_OUI_FROM_DATABASE=Kyynel +OUI:80F3EF* + ID_OUI_FROM_DATABASE=Facebook Technologies, LLC + OUI:80F503* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -80900,6 +82823,9 @@ OUI:840328* OUI:8404D2* ID_OUI_FROM_DATABASE=Kirale Technologies SL +OUI:8406FA* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:840B2D* ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO., LTD. @@ -81002,6 +82928,9 @@ OUI:841C70* OUI:841E26* ID_OUI_FROM_DATABASE=KERNEL-I Co.,LTD +OUI:841EA3* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + OUI:842096* ID_OUI_FROM_DATABASE=SHENZHEN RF-LINK TECHNOLOGY CO.,LTD. @@ -81014,6 +82943,9 @@ OUI:8421F1* OUI:84225E* ID_OUI_FROM_DATABASE=SHENZHEN TECHNEWCHIP TECHNOLOGY CO.,LTD. +OUI:842388* + ID_OUI_FROM_DATABASE=Ruckus Wireless + OUI:84248D* ID_OUI_FROM_DATABASE=Zebra Technologies Inc @@ -81035,6 +82967,9 @@ OUI:842615* OUI:84262B* ID_OUI_FROM_DATABASE=Nokia +OUI:84267A* + ID_OUI_FROM_DATABASE=GUANGDONG TAIDE ZHILIAN TECHNOLOGY CO.,LTD + OUI:842690* ID_OUI_FROM_DATABASE=BEIJING THOUGHT SCIENCE CO.,LTD. @@ -81143,6 +83078,12 @@ OUI:8439BED* OUI:843A4B* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:843A5B* + ID_OUI_FROM_DATABASE=Inventec(Chongqing) Corporation + +OUI:843B10* + ID_OUI_FROM_DATABASE=Lv switch Inc. + OUI:843DC6* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -81311,6 +83252,9 @@ OUI:847973* OUI:847A88* ID_OUI_FROM_DATABASE=HTC Corporation +OUI:847AB6* + ID_OUI_FROM_DATABASE=AltoBeam (China) Inc. + OUI:847BEB* ID_OUI_FROM_DATABASE=Dell Inc. @@ -81455,6 +83399,9 @@ OUI:848BCDD* OUI:848BCDE* ID_OUI_FROM_DATABASE=Emotiv Inc +OUI:848C8D* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:848D84* ID_OUI_FROM_DATABASE=Rajant Corporation @@ -81474,7 +83421,7 @@ OUI:848F69* ID_OUI_FROM_DATABASE=Dell Inc. OUI:849000* - ID_OUI_FROM_DATABASE=Arnold & Richter Cine Technik + ID_OUI_FROM_DATABASE=Arnold&Richter Cine Technik GmbH & Co. Betriebs KG OUI:84930C* ID_OUI_FROM_DATABASE=InCoax Networks Europe AB @@ -81566,6 +83513,9 @@ OUI:84AA9C* OUI:84AB1A* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:84AB26* + ID_OUI_FROM_DATABASE=Tiinlab Corporation + OUI:84ACA4* ID_OUI_FROM_DATABASE=Beijing Novel Super Digital TV Technology Co., Ltd @@ -81639,7 +83589,7 @@ OUI:84C727* ID_OUI_FROM_DATABASE=Gnodal Ltd OUI:84C78F* - ID_OUI_FROM_DATABASE=STORDIS GmbH + ID_OUI_FROM_DATABASE=APS Networks GmbH OUI:84C7A9* ID_OUI_FROM_DATABASE=C3PO S.A. @@ -81689,6 +83639,9 @@ OUI:84D47E* OUI:84D4C8* ID_OUI_FROM_DATABASE=Widex A/S +OUI:84D608* + ID_OUI_FROM_DATABASE=Wingtech Mobile Communications Co., Ltd. + OUI:84D6C5* ID_OUI_FROM_DATABASE=SolarEdge Technologies @@ -81803,6 +83756,9 @@ OUI:84E714* OUI:84E892* ID_OUI_FROM_DATABASE=Actiontec Electronics, Inc +OUI:84E986* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:84EA97* ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO.,LTD @@ -81818,6 +83774,9 @@ OUI:84EB18* OUI:84EB3E* ID_OUI_FROM_DATABASE=Vivint Smart Home +OUI:84EBEF* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:84ED33* ID_OUI_FROM_DATABASE=BBMC Co.,Ltd @@ -81851,6 +83810,9 @@ OUI:84FCAC* OUI:84FCFE* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:84FD27* + ID_OUI_FROM_DATABASE=Silicon Laboratories + OUI:84FDD1* ID_OUI_FROM_DATABASE=Intel Corporate @@ -81968,6 +83930,9 @@ OUI:882950* OUI:88299C* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:882A5E* + ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd + OUI:882B94* ID_OUI_FROM_DATABASE=MADOKA SYSTEM Co.,Ltd. @@ -82061,6 +84026,9 @@ OUI:884477* OUI:8844F6* ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:884604* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:88462A* ID_OUI_FROM_DATABASE=Telechips Inc. @@ -82355,6 +84323,9 @@ OUI:888C19* OUI:888E68* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:889009* + ID_OUI_FROM_DATABASE=Juniper Networks + OUI:88908D* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -82433,6 +84404,9 @@ OUI:889FFA* OUI:88A084* ID_OUI_FROM_DATABASE=Formation Data Systems +OUI:88A0BE* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:88A25E* ID_OUI_FROM_DATABASE=Juniper Networks @@ -82523,6 +84497,9 @@ OUI:88AE07* OUI:88AE1D* ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. +OUI:88AEDD* + ID_OUI_FROM_DATABASE=EliteGroup Computer Systems Co., LTD + OUI:88B111* ID_OUI_FROM_DATABASE=Intel Corporate @@ -82592,12 +84569,60 @@ OUI:88C397* OUI:88C3B3* ID_OUI_FROM_DATABASE=SOVICO +OUI:88C3E5* + ID_OUI_FROM_DATABASE=Betop Techonologies + OUI:88C626* ID_OUI_FROM_DATABASE=Logitech, Inc OUI:88C663* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:88C9B30* + ID_OUI_FROM_DATABASE=ADOPT NETTECH PVT LTD + +OUI:88C9B31* + ID_OUI_FROM_DATABASE=Cervoz Technology Co; Ltd. + +OUI:88C9B32* + ID_OUI_FROM_DATABASE=shenzhen franklin ESS technology CO.,Ltd + +OUI:88C9B33* + ID_OUI_FROM_DATABASE=Fortive Setra-ICG(Tianjin)Co.,Ltd + +OUI:88C9B34* + ID_OUI_FROM_DATABASE=Hasbro Inc + +OUI:88C9B35* + ID_OUI_FROM_DATABASE=Brabender Technologie GmbH & Co, KG + +OUI:88C9B36* + ID_OUI_FROM_DATABASE=Hugo Techno + +OUI:88C9B37* + ID_OUI_FROM_DATABASE=Robert Bosch JuP1 + +OUI:88C9B38* + ID_OUI_FROM_DATABASE=Divelbiss Corporation + +OUI:88C9B39* + ID_OUI_FROM_DATABASE=Richbeam (Beijing) Technology Co., Ltd. + +OUI:88C9B3A* + ID_OUI_FROM_DATABASE=Gefran Drive & Motion srl + +OUI:88C9B3B* + ID_OUI_FROM_DATABASE=Shenzhen MMUI Co.,Ltd + +OUI:88C9B3C* + ID_OUI_FROM_DATABASE=Shenzhen Viewsmart Technology Co.,Ltd + +OUI:88C9B3D* + ID_OUI_FROM_DATABASE=Origins Technology Limited + +OUI:88C9B3E* + ID_OUI_FROM_DATABASE=Sercomm Corporation. + OUI:88C9D0* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) @@ -82679,6 +84704,9 @@ OUI:88DF9E* OUI:88E034* ID_OUI_FROM_DATABASE=Shinwa industries(China) ltd. +OUI:88E056* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:88E0A0* ID_OUI_FROM_DATABASE=Shenzhen VisionSTOR Technologies Co., Ltd @@ -82754,6 +84782,9 @@ OUI:88F7C7* OUI:88F872* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:88FCA6* + ID_OUI_FROM_DATABASE=devolo AG + OUI:88FD15* ID_OUI_FROM_DATABASE=LINEEYE CO., LTD @@ -82928,6 +84959,9 @@ OUI:8C192DD* OUI:8C192DE* ID_OUI_FROM_DATABASE=Elcon AB +OUI:8C19B5* + ID_OUI_FROM_DATABASE=Arcadyan Corporation + OUI:8C1ABF* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -82994,6 +85028,9 @@ OUI:8C278A* OUI:8C2937* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:8C2A8E* + ID_OUI_FROM_DATABASE=DongGuan Ramaxel Memory Technology + OUI:8C2DAA* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -83003,6 +85040,9 @@ OUI:8C2F39* OUI:8C2FA6* ID_OUI_FROM_DATABASE=Solid Optics B.V. +OUI:8C31E2* + ID_OUI_FROM_DATABASE=DAYOUPLUS + OUI:8C3330* ID_OUI_FROM_DATABASE=EmFirst Co., Ltd. @@ -83012,12 +85052,18 @@ OUI:8C3357* OUI:8C3401* ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +OUI:8C3446* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:8C34FD* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:8C3579* ID_OUI_FROM_DATABASE=QDIQO Sp. z o.o. +OUI:8C367A* + ID_OUI_FROM_DATABASE=Palo Alto Networks + OUI:8C395C* ID_OUI_FROM_DATABASE=Bit4id Srl @@ -83048,6 +85094,9 @@ OUI:8C41F4* OUI:8C426D* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:8C4361* + ID_OUI_FROM_DATABASE=Hailo Digital Hub GmbH & Co. KG + OUI:8C4435* ID_OUI_FROM_DATABASE=Shanghai BroadMobi Communication Technology Co., Ltd. @@ -83273,6 +85322,9 @@ OUI:8C640B* OUI:8C6422* ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc +OUI:8C64A2* + ID_OUI_FROM_DATABASE=OnePlus Technology (Shenzhen) Co., Ltd + OUI:8C64D4* ID_OUI_FROM_DATABASE=Hyeco Smart Tech Co.,Ltd @@ -83285,6 +85337,9 @@ OUI:8C6878* OUI:8C68C8* ID_OUI_FROM_DATABASE=zte corporation +OUI:8C6A8D* + ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. + OUI:8C6AE4* ID_OUI_FROM_DATABASE=Viogem Limited @@ -83309,6 +85364,9 @@ OUI:8C71F8* OUI:8C736E* ID_OUI_FROM_DATABASE=FUJITSU LIMITED +OUI:8C73A0* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:8C76C1* ID_OUI_FROM_DATABASE=Goden Tech Limited @@ -83366,6 +85424,9 @@ OUI:8C83DF* OUI:8C83E1* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:8C83FC* + ID_OUI_FROM_DATABASE=Axioma Metering UAB + OUI:8C8401* ID_OUI_FROM_DATABASE=Private @@ -83441,6 +85502,9 @@ OUI:8C9351* OUI:8C941F* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:8C94CC* + ID_OUI_FROM_DATABASE=SFR + OUI:8C94CF* ID_OUI_FROM_DATABASE=Encell Technology, Inc. @@ -83462,6 +85526,9 @@ OUI:8CA048* OUI:8CA2FD* ID_OUI_FROM_DATABASE=Starry, Inc. +OUI:8CA399* + ID_OUI_FROM_DATABASE=SERVERCOM (INDIA) PRIVATE LIMITED + OUI:8CA5A1* ID_OUI_FROM_DATABASE=Oregano Systems - Design & Consulting GmbH @@ -83477,6 +85544,9 @@ OUI:8CA982* OUI:8CAAB5* ID_OUI_FROM_DATABASE=Espressif Inc. +OUI:8CAACE* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:8CAB8E* ID_OUI_FROM_DATABASE=Shanghai Feixun Communication Co.,Ltd. @@ -83681,6 +85751,9 @@ OUI:8CD628* OUI:8CD67F* ID_OUI_FROM_DATABASE=EM Microelectronic +OUI:8CD9D6* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:8CDB25* ID_OUI_FROM_DATABASE=ESG Solutions @@ -83730,7 +85803,7 @@ OUI:8CE5EF* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:8CE748* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Hangzhou Hikvision Digital Technology Co.,Ltd. OUI:8CE78C* ID_OUI_FROM_DATABASE=DK Networks @@ -83792,6 +85865,9 @@ OUI:8CFABA* OUI:8CFCA0* ID_OUI_FROM_DATABASE=Shenzhen Smart Device Technology Co., LTD. +OUI:8CFD15* + ID_OUI_FROM_DATABASE=Imagine Marketing Private Limited + OUI:8CFD18* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -83954,6 +86030,9 @@ OUI:902155* OUI:902181* ID_OUI_FROM_DATABASE=Shanghai Huaqin Telecom Technology Co.,Ltd +OUI:9023B4* + ID_OUI_FROM_DATABASE=New H3C Technologies Co., Ltd + OUI:9023EC* ID_OUI_FROM_DATABASE=Availink, Inc. @@ -84197,6 +86276,9 @@ OUI:9067F3* OUI:9068C3* ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company +OUI:906976* + ID_OUI_FROM_DATABASE=Withrobot Inc. + OUI:906CAC* ID_OUI_FROM_DATABASE=Fortinet, Inc. @@ -84272,6 +86354,9 @@ OUI:907EBA* OUI:907F61* ID_OUI_FROM_DATABASE=Chicony Electronics Co., Ltd. +OUI:908060* + ID_OUI_FROM_DATABASE=Nilfisk A/S + OUI:90808F* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. @@ -84300,7 +86385,7 @@ OUI:90848B* ID_OUI_FROM_DATABASE=HDR10+ Technologies, LLC OUI:908674* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:90869B* ID_OUI_FROM_DATABASE=zte corporation @@ -84356,6 +86441,9 @@ OUI:909497* OUI:9094E4* ID_OUI_FROM_DATABASE=D-Link International +OUI:9096F3* + ID_OUI_FROM_DATABASE=BUFFALO.INC + OUI:9097D5* ID_OUI_FROM_DATABASE=Espressif Inc. @@ -84425,6 +86513,9 @@ OUI:90A783* OUI:90A7C1* ID_OUI_FROM_DATABASE=Pakedge Device and Software Inc. +OUI:90A822* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:90A935* ID_OUI_FROM_DATABASE=JWEntertainment @@ -84467,6 +86558,9 @@ OUI:90B21F* OUI:90B4DD* ID_OUI_FROM_DATABASE=Private +OUI:90B67A* + ID_OUI_FROM_DATABASE=Shenzhen Skyworth Digital Technology CO., Ltd + OUI:90B686* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -84491,6 +86585,9 @@ OUI:90BDE6* OUI:90C115* ID_OUI_FROM_DATABASE=Sony Mobile Communications Inc +OUI:90C119* + ID_OUI_FROM_DATABASE=Nokia + OUI:90C1C6* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -84734,6 +86831,9 @@ OUI:90F72F* OUI:90F891* ID_OUI_FROM_DATABASE=Kaonmedia CO., LTD. +OUI:90F9B7* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:90FB5B* ID_OUI_FROM_DATABASE=Avaya Inc @@ -84789,7 +86889,7 @@ OUI:9405BB2* ID_OUI_FROM_DATABASE=Dongguan CXWE Technology Co.,Ltd. OUI:9405BB3* - ID_OUI_FROM_DATABASE=Neurik AG + ID_OUI_FROM_DATABASE=Neutrik AG OUI:9405BB4* ID_OUI_FROM_DATABASE=Shenzhen Baolijie Technology Co., Ltd. @@ -84950,6 +87050,9 @@ OUI:9437F7* OUI:9439E5* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. +OUI:943A91* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:943AF0* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -84959,6 +87062,9 @@ OUI:943BB0* OUI:943BB1* ID_OUI_FROM_DATABASE=Kaonmedia CO., LTD. +OUI:943CC6* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:943DC9* ID_OUI_FROM_DATABASE=Asahi Net, Inc. @@ -85169,6 +87275,9 @@ OUI:948FCF* OUI:948FEE* ID_OUI_FROM_DATABASE=Verizon Telematics +OUI:949010* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:949034* ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD @@ -85232,6 +87341,9 @@ OUI:94A3CA* OUI:94A40C* ID_OUI_FROM_DATABASE=Diehl Metering GmbH +OUI:94A4F9* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:94A67E* ID_OUI_FROM_DATABASE=NETGEAR @@ -85241,6 +87353,9 @@ OUI:94A7B7* OUI:94A7BC* ID_OUI_FROM_DATABASE=BodyMedia, Inc. +OUI:94AA0A* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:94AAB8* ID_OUI_FROM_DATABASE=Joview(Beijing) Technology Co. Ltd. @@ -85499,6 +87614,9 @@ OUI:94E1AC* OUI:94E226* ID_OUI_FROM_DATABASE=D. ORtiz Consulting, LLC +OUI:94E23C* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:94E2FD* ID_OUI_FROM_DATABASE=Boge Kompressoren OTTO Boge GmbH & Co. KG @@ -85541,6 +87659,9 @@ OUI:94E98C* OUI:94E9EE* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:94EA32* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:94EAEA* ID_OUI_FROM_DATABASE=TELLESCOM INDUSTRIA E COMERCIO EM TELECOMUNICACAO @@ -85829,6 +87950,9 @@ OUI:9816EC* OUI:981888* ID_OUI_FROM_DATABASE=Cisco Meraki +OUI:981A35* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:981BB5* ID_OUI_FROM_DATABASE=ASSA ABLOY Korea Co., Ltd iRevo @@ -85856,6 +87980,51 @@ OUI:98234E* OUI:98262A* ID_OUI_FROM_DATABASE=Applied Research Associates, Inc +OUI:9827820* + ID_OUI_FROM_DATABASE=SHENZHEN HEROFUN BIO-TECH CO., LTD + +OUI:9827821* + ID_OUI_FROM_DATABASE=INFODAS GmbH + +OUI:9827822* + ID_OUI_FROM_DATABASE=Anhui Shengren Electronic Technology Co., Ltd + +OUI:9827823* + ID_OUI_FROM_DATABASE=Danfoss Power Solutions + +OUI:9827824* + ID_OUI_FROM_DATABASE=Dspread Technology (Beijing) Inc. + +OUI:9827825* + ID_OUI_FROM_DATABASE=Guangzhou Wuzhou Technology Co, Ltd. + +OUI:9827826* + ID_OUI_FROM_DATABASE=WESTERN SECURITY SOLUTIONS + +OUI:9827827* + ID_OUI_FROM_DATABASE=KORTEK CORPORATION + +OUI:9827828* + ID_OUI_FROM_DATABASE=CATS Power design + +OUI:9827829* + ID_OUI_FROM_DATABASE=Wuxi GuoYiHaiJu Technology Co.,Ltd. + +OUI:982782A* + ID_OUI_FROM_DATABASE=Nanjing BianYu Future Home Technology Co.Ltd + +OUI:982782B* + ID_OUI_FROM_DATABASE=RayTron, INC. + +OUI:982782C* + ID_OUI_FROM_DATABASE=KRISTECH Krzysztof Kajstura + +OUI:982782D* + ID_OUI_FROM_DATABASE=Thorlabs GmbH + +OUI:982782E* + ID_OUI_FROM_DATABASE=SureFlap Ltd + OUI:9828A6* ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. @@ -85910,6 +88079,9 @@ OUI:9835ED* OUI:983713* ID_OUI_FROM_DATABASE=PT.Navicom Indonesia +OUI:98387D* + ID_OUI_FROM_DATABASE=ITRONIC TECHNOLOGY CO . , LTD . + OUI:98398E* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -85922,6 +88094,9 @@ OUI:983B8F* OUI:983F60* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:983F66* + ID_OUI_FROM_DATABASE=Wuhan Funshion Online Technologies Co.,Ltd + OUI:983F9F* ID_OUI_FROM_DATABASE=China SSJ (Suzhou) Network Technology Inc. @@ -85934,9 +88109,15 @@ OUI:98415C* OUI:984246* ID_OUI_FROM_DATABASE=SOL INDUSTRY PTE., LTD +OUI:984265* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + OUI:9843DA* ID_OUI_FROM_DATABASE=INTERTECH +OUI:9843FA* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:9844B6* ID_OUI_FROM_DATABASE=INFRANOR SAS @@ -85955,9 +88136,15 @@ OUI:98473C* OUI:984827* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:984874* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:984914* ID_OUI_FROM_DATABASE=Wistron Neweb Corporation +OUI:98499F* + ID_OUI_FROM_DATABASE=Domo Tactical Communications + OUI:9849E1* ID_OUI_FROM_DATABASE=Boeing Defence Australia @@ -86111,6 +88298,9 @@ OUI:98743D* OUI:9874DA* ID_OUI_FROM_DATABASE=Infinix mobility limited +OUI:98751A* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:9876B6* ID_OUI_FROM_DATABASE=Adafruit @@ -86129,6 +88319,9 @@ OUI:987A14* OUI:987BF3* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:987DDD* + ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. + OUI:987E46* ID_OUI_FROM_DATABASE=Emizon Networks Limited @@ -86282,6 +88475,9 @@ OUI:98AAFCD* OUI:98AAFCE* ID_OUI_FROM_DATABASE=Comarch S.A. +OUI:98AD1D* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:98AE71* ID_OUI_FROM_DATABASE=VVDN Technologies Pvt Ltd @@ -86330,6 +88526,9 @@ OUI:98BEDC* OUI:98C0EB* ID_OUI_FROM_DATABASE=Global Regency Ltd +OUI:98C3D2* + ID_OUI_FROM_DATABASE=Ningbo Sanxing Medical Electric Co.,Ltd + OUI:98C5DB* ID_OUI_FROM_DATABASE=Ericsson AB @@ -86357,6 +88556,9 @@ OUI:98CBA4* OUI:98CC4D* ID_OUI_FROM_DATABASE=Shenzhen mantunsci co., LTD +OUI:98CDAC* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:98CDB4* ID_OUI_FROM_DATABASE=Virident Systems, Inc. @@ -86456,6 +88658,9 @@ OUI:98EF9B* OUI:98F058* ID_OUI_FROM_DATABASE=Lynxspring, Incl. +OUI:98F083* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:98F0AB* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -86468,6 +88673,9 @@ OUI:98F181* OUI:98F199* ID_OUI_FROM_DATABASE=NEC Platforms, Ltd. +OUI:98F217* + ID_OUI_FROM_DATABASE=Castlenet Technology Inc. + OUI:98F2B3* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise @@ -86672,6 +88880,9 @@ OUI:9C19C2* OUI:9C1C12* ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company +OUI:9C1C37* + ID_OUI_FROM_DATABASE=AltoBeam (China) Inc. + OUI:9C1D36* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -86754,7 +88965,7 @@ OUI:9C31C3* ID_OUI_FROM_DATABASE=BSkyB Ltd OUI:9C32A9* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:9C32CE* ID_OUI_FROM_DATABASE=CANON INC. @@ -86861,6 +89072,9 @@ OUI:9C4E8E* OUI:9C4EBF* ID_OUI_FROM_DATABASE=BoxCast +OUI:9C4F5F* + ID_OUI_FROM_DATABASE=TAP Sound System + OUI:9C4FCF* ID_OUI_FROM_DATABASE=TCT mobile ltd @@ -86897,6 +89111,9 @@ OUI:9C57AD* OUI:9C5A44* ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. +OUI:9C5A81* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:9C5B96* ID_OUI_FROM_DATABASE=NMR Corporation @@ -86928,7 +89145,7 @@ OUI:9C611D* ID_OUI_FROM_DATABASE=Panasonic Corporation of North America OUI:9C6121* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:9C62AB* ID_OUI_FROM_DATABASE=Sumavision Technologies Co.,Ltd @@ -87041,6 +89258,12 @@ OUI:9C746F* OUI:9C7514* ID_OUI_FROM_DATABASE=Wildix srl +OUI:9C760E* + ID_OUI_FROM_DATABASE=Apple, Inc. + +OUI:9C7613* + ID_OUI_FROM_DATABASE=Ring LLC + OUI:9C77AA* ID_OUI_FROM_DATABASE=NADASNV @@ -87062,6 +89285,9 @@ OUI:9C7DA3* OUI:9C7F57* ID_OUI_FROM_DATABASE=UNIC Memory Technology Co Ltd +OUI:9C7F81* + ID_OUI_FROM_DATABASE=SHENZHEN FAST TECHNOLOGIES CO.,LTD + OUI:9C807D* ID_OUI_FROM_DATABASE=SYSCABLE Korea Inc. @@ -87074,6 +89300,9 @@ OUI:9C823F* OUI:9C8275* ID_OUI_FROM_DATABASE=Yichip Microelectronics (Hangzhou) Co.,Ltd +OUI:9C8281* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:9C83BF* ID_OUI_FROM_DATABASE=PRO-VISION, Inc. @@ -87134,6 +89363,9 @@ OUI:9C93B0* OUI:9C93E4* ID_OUI_FROM_DATABASE=Private +OUI:9C9567* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:9C95F8* ID_OUI_FROM_DATABASE=SmartDoor Systems, LLC @@ -87162,7 +89394,7 @@ OUI:9C9C1F* ID_OUI_FROM_DATABASE=Espressif Inc. OUI:9C9C40* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:9C9D5D* ID_OUI_FROM_DATABASE=Raden Inc @@ -87170,6 +89402,9 @@ OUI:9C9D5D* OUI:9C9D7E* ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd +OUI:9C9E71* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:9CA10A* ID_OUI_FROM_DATABASE=SCLE SFE @@ -87335,6 +89570,9 @@ OUI:9CDA3E* OUI:9CDB07* ID_OUI_FROM_DATABASE=Thum+Mahr GmbH +OUI:9CDBCB* + ID_OUI_FROM_DATABASE=Wuhan Funshion Online Technologies Co.,Ltd + OUI:9CDC71* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise @@ -87803,6 +90041,9 @@ OUI:A03299* OUI:A0341B* ID_OUI_FROM_DATABASE=Adero Inc +OUI:A03679* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:A0369F* ID_OUI_FROM_DATABASE=Intel Corporate @@ -87929,6 +90170,9 @@ OUI:A047D7* OUI:A0481C* ID_OUI_FROM_DATABASE=Hewlett Packard +OUI:A04A5E* + ID_OUI_FROM_DATABASE=Microsoft Corporation + OUI:A04C5B* ID_OUI_FROM_DATABASE=Shenzhen TINNO Mobile Technology Corp. @@ -88046,6 +90290,9 @@ OUI:A06FAA* OUI:A07099* ID_OUI_FROM_DATABASE=Beijing Huacan Electronics Co., Ltd +OUI:A070B7* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:A071A9* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -88196,6 +90443,9 @@ OUI:A09E1A* OUI:A09F10* ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD +OUI:A0A0DC* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:A0A130* ID_OUI_FROM_DATABASE=DLI Taiwan Branch office @@ -88247,6 +90497,9 @@ OUI:A0AFBD* OUI:A0B045* ID_OUI_FROM_DATABASE=Halong Mining +OUI:A0B086* + ID_OUI_FROM_DATABASE=Hirschmann Automation and Control GmbH + OUI:A0B100* ID_OUI_FROM_DATABASE=ShenZhen Cando Electronics Co.,Ltd @@ -88442,9 +90695,15 @@ OUI:A0D3C1* OUI:A0D635* ID_OUI_FROM_DATABASE=WBS Technology +OUI:A0D722* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:A0D795* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:A0D7A0* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:A0D807* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. @@ -88505,6 +90764,9 @@ OUI:A0E617* OUI:A0E6F8* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:A0E70B* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:A0E9DB* ID_OUI_FROM_DATABASE=Ningbo FreeWings Technologies Co.,Ltd @@ -88586,6 +90848,9 @@ OUI:A402B9* OUI:A40450* ID_OUI_FROM_DATABASE=nFore Technology Inc. +OUI:A4056E* + ID_OUI_FROM_DATABASE=Tiinlab Corporation + OUI:A4059E* ID_OUI_FROM_DATABASE=STA Infinity LLP @@ -88712,6 +90977,9 @@ OUI:A41875* OUI:A41908* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:A41B34* + ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. + OUI:A41BC0* ID_OUI_FROM_DATABASE=Fastec Imaging Corporation @@ -88754,6 +91022,9 @@ OUI:A42985* OUI:A429B7* ID_OUI_FROM_DATABASE=bluesky +OUI:A42A71* + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD + OUI:A42B8C* ID_OUI_FROM_DATABASE=NETGEAR @@ -88790,6 +91061,9 @@ OUI:A434F1* OUI:A43523* ID_OUI_FROM_DATABASE=Guangdong Donyan Network Technologies Co.,Ltd. +OUI:A4352D* + ID_OUI_FROM_DATABASE=TRIZ Networks corp. + OUI:A43831* ID_OUI_FROM_DATABASE=RF elements s.r.o. @@ -88799,6 +91073,9 @@ OUI:A438CC* OUI:A438FC* ID_OUI_FROM_DATABASE=Plastic Logic +OUI:A439B6* + ID_OUI_FROM_DATABASE=SHENZHEN PEIZHE MICROELECTRONICS CO .LTD + OUI:A43A69* ID_OUI_FROM_DATABASE=Vers Inc @@ -88898,6 +91175,9 @@ OUI:A44BD5* OUI:A44C11* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:A44C62* + ID_OUI_FROM_DATABASE=Hangzhou Microimage Software Co., Ltd + OUI:A44CC8* ID_OUI_FROM_DATABASE=Dell Inc. @@ -88998,7 +91278,7 @@ OUI:A453EE5* ID_OUI_FROM_DATABASE=Foshan Yisihang Electrical Technology Co., Ltd. OUI:A453EE6* - ID_OUI_FROM_DATABASE=Aura Home, Inc. + ID_OUI_FROM_DATABASE=Shenzhen Xunqi Interconnet Technology Co., Ltd OUI:A453EE7* ID_OUI_FROM_DATABASE=Beijing Lanke Science and Technology Co.,LTd. @@ -89018,6 +91298,9 @@ OUI:A453EEC* OUI:A453EED* ID_OUI_FROM_DATABASE=SSK CORPORATION +OUI:A45590* + ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd + OUI:A45602* ID_OUI_FROM_DATABASE=fenglian Technology Co.,Ltd. @@ -89030,6 +91313,9 @@ OUI:A45630* OUI:A456CC* ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. +OUI:A45802* + ID_OUI_FROM_DATABASE=SHIN-IL TECH + OUI:A4580F0* ID_OUI_FROM_DATABASE=INNOPRO @@ -89150,6 +91436,9 @@ OUI:A47758* OUI:A47760* ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:A47806* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:A47886* ID_OUI_FROM_DATABASE=Avaya Inc @@ -89162,6 +91451,9 @@ OUI:A47AA4* OUI:A47ACF* ID_OUI_FROM_DATABASE=VIBICOM COMMUNICATIONS INC. +OUI:A47B1A* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:A47B2C* ID_OUI_FROM_DATABASE=Nokia @@ -89183,6 +91475,9 @@ OUI:A47CC9* OUI:A47D9F* ID_OUI_FROM_DATABASE=Shenzhen iComm Semiconductor CO.,LTD +OUI:A47E36* + ID_OUI_FROM_DATABASE=EM Microelectronic + OUI:A47E39* ID_OUI_FROM_DATABASE=zte corporation @@ -89276,6 +91571,9 @@ OUI:A49B13* OUI:A49B4F* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:A49BCD* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:A49BF5* ID_OUI_FROM_DATABASE=Hybridserver Tec GmbH @@ -89303,6 +91601,9 @@ OUI:A4A1E4* OUI:A4A24A* ID_OUI_FROM_DATABASE=Cisco SPVTG +OUI:A4A46B* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:A4A4D3* ID_OUI_FROM_DATABASE=Bluebank Communication Technology Co.Ltd @@ -89447,6 +91748,9 @@ OUI:A4CCB9* OUI:A4CD23* ID_OUI_FROM_DATABASE=Shenzhenshi Xinzhongxin Co., Ltd +OUI:A4CEDA* + ID_OUI_FROM_DATABASE=Arcadyan Corporation + OUI:A4CF12* ID_OUI_FROM_DATABASE=Espressif Inc. @@ -89454,7 +91758,7 @@ OUI:A4CFD2* ID_OUI_FROM_DATABASE=Ubee Interactive Co., Limited OUI:A4D094* - ID_OUI_FROM_DATABASE=Erwin Peters Systemtechnik GmbH + ID_OUI_FROM_DATABASE=VIVAVIS AG OUI:A4D18C* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -89477,6 +91781,12 @@ OUI:A4D4B2* OUI:A4D578* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:A4D73C* + ID_OUI_FROM_DATABASE=Seiko Epson Corporation + +OUI:A4D795* + ID_OUI_FROM_DATABASE=Wingtech Mobile Communications Co.,Ltd + OUI:A4D856* ID_OUI_FROM_DATABASE=Gimbal, Inc @@ -89543,6 +91853,9 @@ OUI:A4DA32* OUI:A4DA3F* ID_OUI_FROM_DATABASE=Bionics Corp. +OUI:A4DAD4* + ID_OUI_FROM_DATABASE=Yamato Denki Co.,Ltd. + OUI:A4DB2E* ID_OUI_FROM_DATABASE=Kingspan Environmental Ltd @@ -89777,6 +92090,9 @@ OUI:A81FAF* OUI:A82066* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:A82316* + ID_OUI_FROM_DATABASE=Nokia + OUI:A823FE* ID_OUI_FROM_DATABASE=LG Electronics @@ -89903,6 +92219,9 @@ OUI:A84122* OUI:A842A7* ID_OUI_FROM_DATABASE=Jiangsu Huitong Group Co.,Ltd. +OUI:A84397* + ID_OUI_FROM_DATABASE=Innogrit Corporation + OUI:A84481* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -89930,6 +92249,9 @@ OUI:A84D4A* OUI:A84E3F* ID_OUI_FROM_DATABASE=Hitron Technologies. Inc +OUI:A85081* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:A8515B* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -89937,7 +92259,7 @@ OUI:A854B2* ID_OUI_FROM_DATABASE=Wistron Neweb Corporation OUI:A8556A* - ID_OUI_FROM_DATABASE=Pocketnet Technology Inc. + ID_OUI_FROM_DATABASE=3S System Technology Inc. OUI:A8574E* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -89984,6 +92306,9 @@ OUI:A861AA* OUI:A862A2* ID_OUI_FROM_DATABASE=JIWUMEDIA CO., LTD. +OUI:A8637D* + ID_OUI_FROM_DATABASE=D-Link International + OUI:A863DF* ID_OUI_FROM_DATABASE=DISPLAIRE CORPORATION @@ -89993,6 +92318,9 @@ OUI:A863F2* OUI:A86405* ID_OUI_FROM_DATABASE=nimbus 9, Inc +OUI:A864F1* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:A865B2* ID_OUI_FROM_DATABASE=DONGGUAN YISHANG ELECTRONIC TECHNOLOGY CO., LIMITED @@ -90047,9 +92375,15 @@ OUI:A875D6* OUI:A875E2* ID_OUI_FROM_DATABASE=Aventura Technologies, Inc. +OUI:A87650* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:A8776F* ID_OUI_FROM_DATABASE=Zonoff +OUI:A877E5* + ID_OUI_FROM_DATABASE=SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD + OUI:A87B39* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -90122,6 +92456,9 @@ OUI:A8913D* OUI:A8922C* ID_OUI_FROM_DATABASE=LG Electronics (Mobile Communications) +OUI:A8934A* + ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD. + OUI:A89352* ID_OUI_FROM_DATABASE=SHANGHAI ZHONGMI COMMUNICATION TECHNOLOGY CO.,LTD @@ -90356,6 +92693,9 @@ OUI:A8E705* OUI:A8E77D* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:A8E81E* + ID_OUI_FROM_DATABASE=ATW TECHNOLOGY, INC. + OUI:A8E824* ID_OUI_FROM_DATABASE=INIM ELECTRONICS S.R.L. @@ -90371,6 +92711,9 @@ OUI:A8EF26* OUI:A8F038* ID_OUI_FROM_DATABASE=SHEN ZHEN SHI JIN HUA TAI ELECTRONICS CO.,LTD +OUI:A8F266* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:A8F274* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -90467,6 +92810,9 @@ OUI:AC1203* OUI:AC122F* ID_OUI_FROM_DATABASE=Fantasia Trading LLC +OUI:AC139C* + ID_OUI_FROM_DATABASE=Adtran Inc + OUI:AC1461* ID_OUI_FROM_DATABASE=ATAW Co., Ltd. @@ -90551,6 +92897,9 @@ OUI:AC1ED0* OUI:AC1F09* ID_OUI_FROM_DATABASE=shenzhen RAKwireless technology Co.,Ltd +OUI:AC1F0F* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:AC1F6B* ID_OUI_FROM_DATABASE=Super Micro Computer, Inc. @@ -90575,6 +92924,9 @@ OUI:AC2205* OUI:AC220B* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:AC2316* + ID_OUI_FROM_DATABASE=Mist Systems, Inc. + OUI:AC2334* ID_OUI_FROM_DATABASE=Infinix mobility limited @@ -90743,6 +93095,9 @@ OUI:AC5A14* OUI:AC5AEE* ID_OUI_FROM_DATABASE=China Mobile Group Device Co.,Ltd. +OUI:AC5AFC* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:AC5D10* ID_OUI_FROM_DATABASE=Pace Americas @@ -90884,6 +93239,12 @@ OUI:AC7289* OUI:AC7409* ID_OUI_FROM_DATABASE=Hangzhou H3C Technologies Co., Limited +OUI:AC74B1* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:AC74C4* + ID_OUI_FROM_DATABASE=Maytronics Ltd. + OUI:AC751D* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -90989,6 +93350,12 @@ OUI:AC9403* OUI:AC9572* ID_OUI_FROM_DATABASE=Jovision Technology Co., Ltd. +OUI:AC976C* + ID_OUI_FROM_DATABASE=Greenliant + +OUI:AC9929* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:AC9A22* ID_OUI_FROM_DATABASE=NXP Semiconductors @@ -91169,9 +93536,15 @@ OUI:ACD364* OUI:ACD564* ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD. +OUI:ACD618* + ID_OUI_FROM_DATABASE=OnePlus Technology (Shenzhen) Co., Ltd + OUI:ACD657* ID_OUI_FROM_DATABASE=Shaanxi GuoLian Digital TV Technology Co.,Ltd. +OUI:ACD829* + ID_OUI_FROM_DATABASE=Bouffalo Lab (Nanjing) Co., Ltd. + OUI:ACD9D6* ID_OUI_FROM_DATABASE=tci GmbH @@ -91196,6 +93569,9 @@ OUI:ACE010* OUI:ACE069* ID_OUI_FROM_DATABASE=ISAAC Instruments +OUI:ACE14F* + ID_OUI_FROM_DATABASE=Autonomic Controls, Inc. + OUI:ACE215* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -91221,7 +93597,7 @@ OUI:ACE64B* ID_OUI_FROM_DATABASE=Shenzhen Baojia Battery Technology Co., Ltd. OUI:ACE77B* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:ACE87B* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -91421,6 +93797,12 @@ OUI:B01F81E* OUI:B01F81F* ID_OUI_FROM_DATABASE=Private +OUI:B0227A* + ID_OUI_FROM_DATABASE=HP Inc. + +OUI:B02491* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:B024F3* ID_OUI_FROM_DATABASE=Progeny Systems @@ -91433,6 +93815,9 @@ OUI:B02628* OUI:B02680* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:B027CF* + ID_OUI_FROM_DATABASE=Extreme Networks, Inc. + OUI:B02A1F* ID_OUI_FROM_DATABASE=Wingtech Group (HongKong)Limited @@ -91472,9 +93857,15 @@ OUI:B03850* OUI:B03956* ID_OUI_FROM_DATABASE=NETGEAR +OUI:B03ACE* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:B03D96* ID_OUI_FROM_DATABASE=Vision Valley FZ LLC +OUI:B03DC2* + ID_OUI_FROM_DATABASE=Wasp artificial intelligence(Shenzhen) Co.,ltd + OUI:B03E51* ID_OUI_FROM_DATABASE=BSkyB Ltd @@ -91538,6 +93929,9 @@ OUI:B04C05* OUI:B04E26* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:B04F13* + ID_OUI_FROM_DATABASE=Dell Inc. + OUI:B04FC3* ID_OUI_FROM_DATABASE=Shenzhen NVC Cloud Technology Co., Ltd. @@ -91580,6 +93974,9 @@ OUI:B05CDA* OUI:B05CE5* ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:B05DD4* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:B06088* ID_OUI_FROM_DATABASE=Intel Corporate @@ -91799,6 +94196,9 @@ OUI:B0A72A* OUI:B0A737* ID_OUI_FROM_DATABASE=Roku, Inc. +OUI:B0A7B9* + ID_OUI_FROM_DATABASE=TP-Link Corporation Limited + OUI:B0A86E* ID_OUI_FROM_DATABASE=Juniper Networks @@ -92018,6 +94418,9 @@ OUI:B0C83F* OUI:B0C8AD* ID_OUI_FROM_DATABASE=People Power Company +OUI:B0C952* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + OUI:B0C95B* ID_OUI_FROM_DATABASE=Beijing Symtech CO.,LTD @@ -92054,6 +94457,9 @@ OUI:B0D7C5* OUI:B0D7CC* ID_OUI_FROM_DATABASE=Tridonic GmbH & Co KG +OUI:B0D888* + ID_OUI_FROM_DATABASE=Panasonic Corporation Automotive + OUI:B0DA00* ID_OUI_FROM_DATABASE=CERA ELECTRONIQUE @@ -92270,9 +94676,15 @@ OUI:B40F3B* OUI:B40FB3* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:B4107B* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:B41489* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:B414E6* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:B41513* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -92558,6 +94970,9 @@ OUI:B45D50* OUI:B46077* ID_OUI_FROM_DATABASE=Sichuan Changhong Electric Ltd. +OUI:B4608C* + ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD + OUI:B460ED* ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd @@ -92669,9 +95084,15 @@ OUI:B485E1* OUI:B48655* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:B48901* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:B48910* ID_OUI_FROM_DATABASE=Coster T.E. S.P.A. +OUI:B48A5F* + ID_OUI_FROM_DATABASE=Juniper Networks + OUI:B48B19* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -92714,6 +95135,9 @@ OUI:B49EAC* OUI:B49EE6* ID_OUI_FROM_DATABASE=SHENZHEN TECHNOLOGY CO LTD +OUI:B4A25C* + ID_OUI_FROM_DATABASE=Cambium Networks Limited + OUI:B4A2EB0* ID_OUI_FROM_DATABASE=QKM Technology(Dongguan)Co.,Ltd @@ -92990,6 +95414,9 @@ OUI:B4E1C4* OUI:B4E1EB* ID_OUI_FROM_DATABASE=Private +OUI:B4E3F9* + ID_OUI_FROM_DATABASE=Silicon Laboratories + OUI:B4E62A* ID_OUI_FROM_DATABASE=LG Innotek @@ -93074,6 +95501,9 @@ OUI:B4F81E* OUI:B4F949* ID_OUI_FROM_DATABASE=optilink networks pvt ltd +OUI:B4FA48* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:B4FBE3* ID_OUI_FROM_DATABASE=AltoBeam (China) Inc. @@ -93131,12 +95561,21 @@ OUI:B810D4* OUI:B8114B* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:B81332* + ID_OUI_FROM_DATABASE=AMPAK Technology,Inc. + OUI:B813E9* ID_OUI_FROM_DATABASE=Trace Live Network OUI:B81413* ID_OUI_FROM_DATABASE=Keen High Holding(HK) Ltd. +OUI:B8145C* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + +OUI:B814DB* + ID_OUI_FROM_DATABASE=OHSUNG + OUI:B81619* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -93165,7 +95604,7 @@ OUI:B820E7* ID_OUI_FROM_DATABASE=Guangzhou Horizontal Information & Network Integration Co. Ltd OUI:B8224F* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:B82410* ID_OUI_FROM_DATABASE=Magneti Marelli Slovakia s.r.o. @@ -93179,6 +95618,9 @@ OUI:B824F0* OUI:B8259A* ID_OUI_FROM_DATABASE=Thalmic Labs +OUI:B825B5* + ID_OUI_FROM_DATABASE=Trakm8 Ltd + OUI:B8266C* ID_OUI_FROM_DATABASE=ANOV France @@ -93200,6 +95642,9 @@ OUI:B829F7* OUI:B82A72* ID_OUI_FROM_DATABASE=Dell Inc. +OUI:B82AA9* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:B82ADC* ID_OUI_FROM_DATABASE=EFR Europäische Funk-Rundsteuerung GmbH @@ -93260,6 +95705,9 @@ OUI:B841A4* OUI:B843E4* ID_OUI_FROM_DATABASE=Vlatacom +OUI:B844AE* + ID_OUI_FROM_DATABASE=TCT mobile ltd + OUI:B844D9* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -93419,6 +95867,9 @@ OUI:B8804F* OUI:B88198* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:B881FA* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:B88303* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise @@ -93536,9 +95987,15 @@ OUI:B89BE4* OUI:B89F09* ID_OUI_FROM_DATABASE=Wistron Neweb Corporation +OUI:B8A14A* + ID_OUI_FROM_DATABASE=Raisecom Technology CO.,LTD + OUI:B8A175* ID_OUI_FROM_DATABASE=Roku, Inc. +OUI:B8A377* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:B8A386* ID_OUI_FROM_DATABASE=D-Link International @@ -93587,6 +96044,9 @@ OUI:B8B3DC* OUI:B8B42E* ID_OUI_FROM_DATABASE=Gionee Communication Equipment Co,Ltd.ShenZhen +OUI:B8B77D* + ID_OUI_FROM_DATABASE=Guangdong Transtek Medical Electronics CO.,Ltd + OUI:B8B7D7* ID_OUI_FROM_DATABASE=2GIG Technologies @@ -93701,6 +96161,9 @@ OUI:B8D06F* OUI:B8D309* ID_OUI_FROM_DATABASE=Cox Communications, Inc +OUI:B8D43E* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:B8D49D* ID_OUI_FROM_DATABASE=M Seven System Ltd. @@ -93713,6 +96176,12 @@ OUI:B8D50B* OUI:B8D526* ID_OUI_FROM_DATABASE=Zyxel Communications Corporation +OUI:B8D56B* + ID_OUI_FROM_DATABASE=Mirka Ltd. + +OUI:B8D6F6* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:B8D7AF* ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. @@ -94541,6 +97010,9 @@ OUI:BCA042* OUI:BCA13A* ID_OUI_FROM_DATABASE=SES-imagotag +OUI:BCA37F* + ID_OUI_FROM_DATABASE=Rail-Mil Sp. z o.o. Sp. K. + OUI:BCA4E1* ID_OUI_FROM_DATABASE=Nabto @@ -94733,9 +97205,15 @@ OUI:BCEC23* OUI:BCEC5D* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:BCECA0* + ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. + OUI:BCEE7B* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. +OUI:BCF171* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:BCF1F2* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -94766,6 +97244,9 @@ OUI:BCF811* OUI:BCF9F2* ID_OUI_FROM_DATABASE=TEKO +OUI:BCFAB8* + ID_OUI_FROM_DATABASE=Guangzhou Shiyuan Electronic Technology Company Limited + OUI:BCFE8C* ID_OUI_FROM_DATABASE=Altronic, LLC @@ -94775,6 +97256,9 @@ OUI:BCFED9* OUI:BCFF21* ID_OUI_FROM_DATABASE=Smart Code(shenzhen)Technology Co.,Ltd +OUI:BCFF4D* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:BCFFAC* ID_OUI_FROM_DATABASE=TOPCON CORPORATION @@ -94790,6 +97274,9 @@ OUI:C00380* OUI:C005C2* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:C006C3* + ID_OUI_FROM_DATABASE=TP-Link Corporation Limited + OUI:C0074A* ID_OUI_FROM_DATABASE=Brita GmbH @@ -94836,7 +97323,7 @@ OUI:C01ADA* ID_OUI_FROM_DATABASE=Apple, Inc. OUI:C01B23* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOM CO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:C01C30* ID_OUI_FROM_DATABASE=Shenzhen WIFI-3L Technology Co.,Ltd @@ -94850,6 +97337,9 @@ OUI:C0210D* OUI:C02250* ID_OUI_FROM_DATABASE=Koss Corporation +OUI:C0238D* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:C02506* ID_OUI_FROM_DATABASE=AVM GmbH @@ -94937,6 +97427,9 @@ OUI:C0395A* OUI:C03B8F* ID_OUI_FROM_DATABASE=Minicom Digital Signage +OUI:C03C04* + ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS + OUI:C03C59* ID_OUI_FROM_DATABASE=Intel Corporate @@ -94985,6 +97478,9 @@ OUI:C04301* OUI:C044E3* ID_OUI_FROM_DATABASE=Shenzhen Sinkna Electronics Co., LTD +OUI:C04754* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:C048E6* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -95000,6 +97496,9 @@ OUI:C04A00* OUI:C04A09* ID_OUI_FROM_DATABASE=Zhejiang Everbright Communication Equip. Co,. Ltd +OUI:C04B13* + ID_OUI_FROM_DATABASE=WonderSound Technology Co., Ltd + OUI:C04DF7* ID_OUI_FROM_DATABASE=SERELEC @@ -95237,6 +97736,9 @@ OUI:C09132* OUI:C09134* ID_OUI_FROM_DATABASE=ProCurve Networking by HP +OUI:C09296* + ID_OUI_FROM_DATABASE=zte corporation + OUI:C09435* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -95378,6 +97880,9 @@ OUI:C0AA68* OUI:C0AC54* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS +OUI:C0AEFD* + ID_OUI_FROM_DATABASE=Shenzhen HC-WLAN Technology Co.,Ltd + OUI:C0B101* ID_OUI_FROM_DATABASE=zte corporation @@ -95469,7 +97974,7 @@ OUI:C0CBF1* ID_OUI_FROM_DATABASE=Mobiwire Mobiles (NingBo) Co., LTD OUI:C0CC42* - ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co., Ltd. + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:C0CCF8* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -95549,6 +98054,9 @@ OUI:C0D391E* OUI:C0D3C0* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:C0D46B* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C0D682* ID_OUI_FROM_DATABASE=Arista Networks @@ -95567,6 +98075,9 @@ OUI:C0DA74* OUI:C0DC6A* ID_OUI_FROM_DATABASE=Qingdao Eastsoft Communication Technology Co.,LTD +OUI:C0DCD7* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C0DCDA* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -95576,6 +98087,9 @@ OUI:C0DF77* OUI:C0E018* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:C0E1BE* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:C0E3A0* ID_OUI_FROM_DATABASE=Renesas Electronics (Penang) Sdn. Bhd. @@ -95642,6 +98156,54 @@ OUI:C0F945* OUI:C0F991* ID_OUI_FROM_DATABASE=GME Standard Communications P/L +OUI:C0F9B0* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + +OUI:C0FBF90* + ID_OUI_FROM_DATABASE=Xerox Corporation + +OUI:C0FBF91* + ID_OUI_FROM_DATABASE=LIXIL Corporation + +OUI:C0FBF92* + ID_OUI_FROM_DATABASE=Dongguan Chuan OptoElectronics Limited + +OUI:C0FBF93* + ID_OUI_FROM_DATABASE=SHENZHEN HEQIANG ELECTRONICS LIMITED + +OUI:C0FBF94* + ID_OUI_FROM_DATABASE=Minato Advanced Technologies inc + +OUI:C0FBF95* + ID_OUI_FROM_DATABASE=HAGUENET + +OUI:C0FBF96* + ID_OUI_FROM_DATABASE=IVT corporation + +OUI:C0FBF97* + ID_OUI_FROM_DATABASE=LongSung Technology (Shanghai) Co.,Ltd. + +OUI:C0FBF98* + ID_OUI_FROM_DATABASE=Dongmengling + +OUI:C0FBF99* + ID_OUI_FROM_DATABASE=zxsolution + +OUI:C0FBF9A* + ID_OUI_FROM_DATABASE=Tiandi(Changzhou) Automation Co., Ltd. + +OUI:C0FBF9B* + ID_OUI_FROM_DATABASE=SHENZHEN COMIX HST CLOUD COMPUTING CO., LTD. + +OUI:C0FBF9C* + ID_OUI_FROM_DATABASE=SHENZHEN ELSKY TECHNOLOGY CO., LTD + +OUI:C0FBF9D* + ID_OUI_FROM_DATABASE=Dropbeats Technology Co., Ltd. + +OUI:C0FBF9E* + ID_OUI_FROM_DATABASE=Navitas Digital Safety Ltd + OUI:C0FD84* ID_OUI_FROM_DATABASE=zte corporation @@ -95768,6 +98330,9 @@ OUI:C41ECE* OUI:C421C8* ID_OUI_FROM_DATABASE=KYOCERA CORPORATION +OUI:C42360* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:C4237A* ID_OUI_FROM_DATABASE=WhizNets Inc. @@ -95966,6 +98531,9 @@ OUI:C45976* OUI:C45A86* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:C45BBE* + ID_OUI_FROM_DATABASE=Espressif Inc. + OUI:C45BF7* ID_OUI_FROM_DATABASE=ants @@ -95975,6 +98543,9 @@ OUI:C45D83* OUI:C45DD8* ID_OUI_FROM_DATABASE=HDMI Forum +OUI:C45E5C* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:C46044* ID_OUI_FROM_DATABASE=Everex Electronics Limited @@ -96041,6 +98612,9 @@ OUI:C46E7B* OUI:C4700B* ID_OUI_FROM_DATABASE=GUANGZHOU CHIP TECHNOLOGIES CO.,LTD +OUI:C470AB* + ID_OUI_FROM_DATABASE=Ruijie Networks Co.,LTD + OUI:C47130* ID_OUI_FROM_DATABASE=Fon Technology S.L. @@ -96059,6 +98633,9 @@ OUI:C4731E* OUI:C4741E* ID_OUI_FROM_DATABASE=zte corporation +OUI:C47469* + ID_OUI_FROM_DATABASE=BT9 + OUI:C474F8* ID_OUI_FROM_DATABASE=Hot Pepper, Inc. @@ -96068,6 +98645,9 @@ OUI:C477AB* OUI:C477AF* ID_OUI_FROM_DATABASE=Advanced Digital Broadcast SA +OUI:C478A2* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C47B2F* ID_OUI_FROM_DATABASE=Beijing JoinHope Image Technology Ltd. @@ -96134,6 +98714,12 @@ OUI:C47DFE* OUI:C47F51* ID_OUI_FROM_DATABASE=Inventek Systems +OUI:C48025* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + +OUI:C4808A* + ID_OUI_FROM_DATABASE=Cloud Diagnostics Canada ULC + OUI:C4823F* ID_OUI_FROM_DATABASE=Fujian Newland Auto-ID Tech. Co,.Ltd. @@ -96176,6 +98762,9 @@ OUI:C4910C* OUI:C4913A* ID_OUI_FROM_DATABASE=Shenzhen Sanland Electronic Co., ltd. +OUI:C491CF* + ID_OUI_FROM_DATABASE=Luxul + OUI:C4924C* ID_OUI_FROM_DATABASE=KEISOKUKI CENTER CO.,LTD. @@ -96273,7 +98862,7 @@ OUI:C49FF3* ID_OUI_FROM_DATABASE=Mciao Technologies, Inc. OUI:C4A151* - ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co., Ltd. + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:C4A366* ID_OUI_FROM_DATABASE=zte corporation @@ -96338,6 +98927,9 @@ OUI:C4BB4C* OUI:C4BBEA* ID_OUI_FROM_DATABASE=Pakedge Device and Software Inc +OUI:C4BCD7* + ID_OUI_FROM_DATABASE=New Ryatek + OUI:C4BD6A* ID_OUI_FROM_DATABASE=SKF GmbH @@ -96389,6 +98981,9 @@ OUI:C4CD45* OUI:C4CD82* ID_OUI_FROM_DATABASE=Hangzhou Lowan Information Technology Co., Ltd. +OUI:C4D0E3* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:C4D197* ID_OUI_FROM_DATABASE=Ventia Utility Services @@ -96482,6 +99077,9 @@ OUI:C4F081* OUI:C4F0EC* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD +OUI:C4F174* + ID_OUI_FROM_DATABASE=eero inc. + OUI:C4F1D1* ID_OUI_FROM_DATABASE=BEIJING SOGOU TECHNOLOGY DEVELOPMENT CO., LTD. @@ -96521,6 +99119,9 @@ OUI:C4FEE2* OUI:C4FF1F* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:C4FF22* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C4FFBC0* ID_OUI_FROM_DATABASE=Danego BV @@ -96584,6 +99185,9 @@ OUI:C802A6* OUI:C803F5* ID_OUI_FROM_DATABASE=Ruckus Wireless +OUI:C8059E* + ID_OUI_FROM_DATABASE=Hefei Symboltek Co.,Ltd + OUI:C80718* ID_OUI_FROM_DATABASE=TDSi @@ -96620,6 +99224,9 @@ OUI:C80E95* OUI:C81073* ID_OUI_FROM_DATABASE=CENTURY OPTICOMM CO.,LTD +OUI:C8138B* + ID_OUI_FROM_DATABASE=Shenzhen Skyworth Digital Technology CO., Ltd + OUI:C81451* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -96749,6 +99356,9 @@ OUI:C83232* OUI:C8334B* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:C833E5* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:C8348E* ID_OUI_FROM_DATABASE=Intel Corporate @@ -96818,6 +99428,9 @@ OUI:C848F5* OUI:C84C75* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:C84D34* + ID_OUI_FROM_DATABASE=LIONS Taiwan Technology Inc. + OUI:C84F0E* ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. @@ -96830,6 +99443,9 @@ OUI:C850CE* OUI:C850E9* ID_OUI_FROM_DATABASE=Raisecom Technology CO., LTD +OUI:C85142* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:C85195* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -96968,6 +99584,9 @@ OUI:C87765* OUI:C8778B* ID_OUI_FROM_DATABASE=Mercury Systems – Trusted Mission Solutions, Inc. +OUI:C87B23* + ID_OUI_FROM_DATABASE=Bose Corporation + OUI:C87B5B* ID_OUI_FROM_DATABASE=zte corporation @@ -97082,6 +99701,9 @@ OUI:C89346* OUI:C89383* ID_OUI_FROM_DATABASE=Embedded Automation, Inc. +OUI:C89402* + ID_OUI_FROM_DATABASE=CHONGQING FUGUI ELECTRONICS CO.,LTD. + OUI:C894BB* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -97091,6 +99713,9 @@ OUI:C894D2* OUI:C8979F* ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:C89BAD* + ID_OUI_FROM_DATABASE=Honor Device Co., Ltd. + OUI:C89C13* ID_OUI_FROM_DATABASE=Inspiremobile @@ -97100,6 +99725,9 @@ OUI:C89C1D* OUI:C89CDC* ID_OUI_FROM_DATABASE=Elitegroup Computer Systems Co.,Ltd. +OUI:C89D18* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C89F1D* ID_OUI_FROM_DATABASE=SHENZHEN COMMUNICATION TECHNOLOGIES CO.,LTD @@ -97190,6 +99818,9 @@ OUI:C8BA94* OUI:C8BAE9* ID_OUI_FROM_DATABASE=QDIS +OUI:C8BB81* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C8BBD3* ID_OUI_FROM_DATABASE=Embrane @@ -97202,9 +99833,15 @@ OUI:C8BCC8* OUI:C8BCE5* ID_OUI_FROM_DATABASE=Sense Things Japan INC. +OUI:C8BD69* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:C8BE19* ID_OUI_FROM_DATABASE=D-Link International +OUI:C8BFFE* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:C8C126* ID_OUI_FROM_DATABASE=ZPM Industria e Comercio Ltda @@ -97295,6 +99932,9 @@ OUI:C8D779* OUI:C8D7B0* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:C8D884* + ID_OUI_FROM_DATABASE=Universal Electronics, Inc. + OUI:C8D9D2* ID_OUI_FROM_DATABASE=Hewlett Packard @@ -97373,6 +100013,51 @@ OUI:C8F386* OUI:C8F406* ID_OUI_FROM_DATABASE=Avaya Inc +OUI:C8F5D60* + ID_OUI_FROM_DATABASE=MEIRYO TECHNICA CORPORATION + +OUI:C8F5D61* + ID_OUI_FROM_DATABASE=Valeo Interior Controls (Shenzhen) Co.,Ltd + +OUI:C8F5D62* + ID_OUI_FROM_DATABASE=Qbic Technology Co., Ltd + +OUI:C8F5D63* + ID_OUI_FROM_DATABASE=BBPOS International Limited + +OUI:C8F5D64* + ID_OUI_FROM_DATABASE=EVOTOR LLC + +OUI:C8F5D65* + ID_OUI_FROM_DATABASE=Pinmicro K K + +OUI:C8F5D66* + ID_OUI_FROM_DATABASE=Jabil + +OUI:C8F5D67* + ID_OUI_FROM_DATABASE=Oscars Pro + +OUI:C8F5D68* + ID_OUI_FROM_DATABASE=Yarward Electronics Co., Ltd. + +OUI:C8F5D69* + ID_OUI_FROM_DATABASE=Shanghai Mo xiang Network Technology CO.,Ltd + +OUI:C8F5D6A* + ID_OUI_FROM_DATABASE=HENAN FOXSTAR DIGITAL DISPLAY Co.,Ltd. + +OUI:C8F5D6B* + ID_OUI_FROM_DATABASE=United Barcode Systems + +OUI:C8F5D6C* + ID_OUI_FROM_DATABASE=Eltako GmbH + +OUI:C8F5D6D* + ID_OUI_FROM_DATABASE=Volansys technologies pvt ltd + +OUI:C8F5D6E* + ID_OUI_FROM_DATABASE=HEITEC AG + OUI:C8F650* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -97478,6 +100163,9 @@ OUI:CC09C8* OUI:CC0CDA* ID_OUI_FROM_DATABASE=Miljovakt AS +OUI:CC0DE7* + ID_OUI_FROM_DATABASE=B METERS S.R.L. + OUI:CC0DEC* ID_OUI_FROM_DATABASE=Cisco SPVTG @@ -97490,6 +100178,9 @@ OUI:CC10A3* OUI:CC14A6* ID_OUI_FROM_DATABASE=Yichun MyEnergy Domain, Inc +OUI:CC1531* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:CC167E* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -97613,6 +100304,9 @@ OUI:CC2237D* OUI:CC2237E* ID_OUI_FROM_DATABASE=MANUFACTURAS Y TRANSFORMADOS AB, S.L. +OUI:CC242E* + ID_OUI_FROM_DATABASE=Shenzhen SuperElectron Technology Co.,Ltd. + OUI:CC25EF* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -97652,9 +100346,15 @@ OUI:CC2F71* OUI:CC3080* ID_OUI_FROM_DATABASE=VAIO Corporation +OUI:CC3296* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:CC32E5* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:CC3331* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:CC33BB* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -97680,7 +100380,7 @@ OUI:CC3A61* ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO MECHANICS CO., LTD. OUI:CC3ADF* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Neptune Technology Group Inc. OUI:CC3B27* ID_OUI_FROM_DATABASE=TECNO MOBILE LIMITED @@ -97868,6 +100568,9 @@ OUI:CC660A* OUI:CC66B2* ID_OUI_FROM_DATABASE=Nokia +OUI:CC68B6* + ID_OUI_FROM_DATABASE=TP-Link Corporation Limited + OUI:CC69B0* ID_OUI_FROM_DATABASE=Global Traffic Technologies, LLC @@ -97877,6 +100580,9 @@ OUI:CC69FA* OUI:CC6A10* ID_OUI_FROM_DATABASE=The Chamberlain Group, Inc +OUI:CC6B1E* + ID_OUI_FROM_DATABASE=CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. + OUI:CC6B98* ID_OUI_FROM_DATABASE=Minetec Wireless Technologies @@ -97946,6 +100652,9 @@ OUI:CC7F75* OUI:CC7F76* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:CC812A* + ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. + OUI:CC81DA* ID_OUI_FROM_DATABASE=Phicomm (Shanghai) Co., Ltd. @@ -97955,12 +100664,21 @@ OUI:CC82EB* OUI:CC856C* ID_OUI_FROM_DATABASE=SHENZHEN MDK DIGITAL TECHNOLOGY CO.,LTD +OUI:CC86EC* + ID_OUI_FROM_DATABASE=Silicon Laboratories + OUI:CC874A* ID_OUI_FROM_DATABASE=Nokia OUI:CC8826* ID_OUI_FROM_DATABASE=LG Innotek +OUI:CC88C7* + ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company + +OUI:CC895E* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:CC89FD* ID_OUI_FROM_DATABASE=Nokia Corporation @@ -98012,6 +100730,9 @@ OUI:CC9891* OUI:CC9916* ID_OUI_FROM_DATABASE=Integrated Device Technology (Malaysia) Sdn. Bhd. +OUI:CC9C3E* + ID_OUI_FROM_DATABASE=Cisco Meraki + OUI:CC9E00* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. @@ -98040,7 +100761,7 @@ OUI:CCA223* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:CCA260* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:CCA374* ID_OUI_FROM_DATABASE=Guangdong Guanglian Electronic Technology Co.Ltd @@ -98087,6 +100808,9 @@ OUI:CCB3F8* OUI:CCB55A* ID_OUI_FROM_DATABASE=Fraunhofer ITWM +OUI:CCB5D1* + ID_OUI_FROM_DATABASE=Beijing Xiaomi Mobile Software Co., Ltd + OUI:CCB691* ID_OUI_FROM_DATABASE=NECMagnusCommunications @@ -98342,6 +101066,9 @@ OUI:CCD9AC* OUI:CCD9E9* ID_OUI_FROM_DATABASE=SCR Engineers Ltd. +OUI:CCDB04* + ID_OUI_FROM_DATABASE=DataRemote Inc. + OUI:CCDB93* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -98375,6 +101102,9 @@ OUI:CCE8AC* OUI:CCEA1C* ID_OUI_FROM_DATABASE=DCONWORKS Co., Ltd +OUI:CCED21* + ID_OUI_FROM_DATABASE=Nokia Shanghai Bell Co., Ltd. + OUI:CCEDDC* ID_OUI_FROM_DATABASE=MitraStar Technology Corp. @@ -98555,6 +101285,9 @@ OUI:D015A6* OUI:D016B4* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:D01769* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + OUI:D0176A* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -98573,6 +101306,9 @@ OUI:D01C3C* OUI:D01CBB* ID_OUI_FROM_DATABASE=Beijing Ctimes Digital Technology Co., Ltd. +OUI:D01E1D* + ID_OUI_FROM_DATABASE=SaiNXT Technologies LLP + OUI:D021AC* ID_OUI_FROM_DATABASE=Yo Labs LLC @@ -98666,6 +101402,9 @@ OUI:D03169* OUI:D03311* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:D035E5* + ID_OUI_FROM_DATABASE=EM Microelectronic + OUI:D03742* ID_OUI_FROM_DATABASE=Yulong Computer Telecommunication Scientific (Shenzhen) Co.,Ltd @@ -98696,6 +101435,9 @@ OUI:D03DC3* OUI:D03E5C* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:D03E7D* + ID_OUI_FROM_DATABASE=CHIPSEA TECHNOLOGIES (SHENZHEN) CORP. + OUI:D03FAA* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -98711,6 +101453,9 @@ OUI:D0431E* OUI:D046DC* ID_OUI_FROM_DATABASE=Southwest Research Institute +OUI:D047C1* + ID_OUI_FROM_DATABASE=Elma Electronic AG + OUI:D048F3* ID_OUI_FROM_DATABASE=DATTUS Inc @@ -98747,6 +101492,9 @@ OUI:D05349* OUI:D0542D* ID_OUI_FROM_DATABASE=Cambridge Industries(Group) Co.,Ltd. +OUI:D05475* + ID_OUI_FROM_DATABASE=SAVI Controls + OUI:D05509* ID_OUI_FROM_DATABASE=Nintendo Co.,Ltd @@ -98993,6 +101741,9 @@ OUI:D07AB5* OUI:D07C2D* ID_OUI_FROM_DATABASE=Leie IOT technology Co., Ltd +OUI:D07D33* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:D07DE5* ID_OUI_FROM_DATABASE=Forward Pay Systems, Inc. @@ -99059,6 +101810,9 @@ OUI:D095C7* OUI:D096FB* ID_OUI_FROM_DATABASE=DASAN Network Solutions +OUI:D097FE* + ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd. + OUI:D099D5* ID_OUI_FROM_DATABASE=Alcatel-Lucent @@ -99077,6 +101831,51 @@ OUI:D09D0A* OUI:D09DAB* ID_OUI_FROM_DATABASE=TCT mobile ltd +OUI:D09FD90* + ID_OUI_FROM_DATABASE=Lemei Intelligent IOT (Shenzhen) Co., Ltd + +OUI:D09FD91* + ID_OUI_FROM_DATABASE=elecgator bvba + +OUI:D09FD92* + ID_OUI_FROM_DATABASE=Westar Display Technologies + +OUI:D09FD93* + ID_OUI_FROM_DATABASE=Sanken-Densetsu Co.,LTD. + +OUI:D09FD94* + ID_OUI_FROM_DATABASE=Poten (Shanghai) Technology Co.,Ltd. + +OUI:D09FD95* + ID_OUI_FROM_DATABASE=Carbon Mobile GmbH + +OUI:D09FD96* + ID_OUI_FROM_DATABASE=Elevoc Technology Co., Ltd. + +OUI:D09FD97* + ID_OUI_FROM_DATABASE=Raymax Technology Ltd. + +OUI:D09FD98* + ID_OUI_FROM_DATABASE=Queclink Wireless Solutions Co., Ltd. + +OUI:D09FD99* + ID_OUI_FROM_DATABASE=ENTTEC Pty Ltd. + +OUI:D09FD9A* + ID_OUI_FROM_DATABASE=Eurolan Ltd + +OUI:D09FD9B* + ID_OUI_FROM_DATABASE=Cablewireless Laboratory Co., Ltd + +OUI:D09FD9C* + ID_OUI_FROM_DATABASE=Fujian Newland Auto-ID Tech. Co,.Ltd. + +OUI:D09FD9D* + ID_OUI_FROM_DATABASE=Shenzhen eloT Technology Co.,Ltd + +OUI:D09FD9E* + ID_OUI_FROM_DATABASE=Minibems Ltd + OUI:D0A0D6* ID_OUI_FROM_DATABASE=Chengdu TD Tech Ltd. @@ -99242,6 +102041,9 @@ OUI:D0CDE1* OUI:D0CF5E* ID_OUI_FROM_DATABASE=Energy Micro AS +OUI:D0CFD8* + ID_OUI_FROM_DATABASE=Huizhou Boshijie Technology Co.,Ltd + OUI:D0D003* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,LTD @@ -99341,6 +102143,9 @@ OUI:D0DFB2* OUI:D0DFC7* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:D0E042* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:D0E140* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -99422,6 +102227,9 @@ OUI:D404FF* OUI:D40598* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. +OUI:D40868* + ID_OUI_FROM_DATABASE=Beijing Lanxum Computer Technology CO.,LTD. + OUI:D40AA9* ID_OUI_FROM_DATABASE=ARRIS Group, Inc. @@ -99633,7 +102441,7 @@ OUI:D440F0* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:D44165* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:D443A8* ID_OUI_FROM_DATABASE=Changzhou Haojie Electric Co., Ltd. @@ -99647,6 +102455,9 @@ OUI:D44649* OUI:D446E1* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:D4475A* + ID_OUI_FROM_DATABASE=ScreenBeam, Inc. + OUI:D4482D* ID_OUI_FROM_DATABASE=Shenzhen Deejoy Lighting Technology Co.,Ltd. @@ -99701,6 +102512,9 @@ OUI:D45383* OUI:D453AF* ID_OUI_FROM_DATABASE=VIGO System S.A. +OUI:D4548B* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:D45556* ID_OUI_FROM_DATABASE=Fiber Mountain Inc. @@ -99842,6 +102656,9 @@ OUI:D476EA* OUI:D4772B* ID_OUI_FROM_DATABASE=Nanjing Ztlink Network Technology Co.,Ltd +OUI:D47798* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:D477B2* ID_OUI_FROM_DATABASE=Netix Global B.V. @@ -100577,6 +103394,9 @@ OUI:D857EF* OUI:D858D7* ID_OUI_FROM_DATABASE=CZ.NIC, z.s.p.o. +OUI:D85982* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:D85B2A* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -100595,6 +103415,9 @@ OUI:D85DEF* OUI:D85DFB* ID_OUI_FROM_DATABASE=Private +OUI:D85ED3* + ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. + OUI:D85F77* ID_OUI_FROM_DATABASE=Telink Semiconductor (Shanghai) Co., Ltd. @@ -100814,6 +103637,9 @@ OUI:D897BA* OUI:D89A34* ID_OUI_FROM_DATABASE=Beijing SHENQI Technology Co., Ltd. +OUI:D89AC1* + ID_OUI_FROM_DATABASE=Nokia + OUI:D89B3B* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -100838,6 +103664,9 @@ OUI:D89ED4* OUI:D89EF3* ID_OUI_FROM_DATABASE=Dell Inc. +OUI:D8A011* + ID_OUI_FROM_DATABASE=WiZ + OUI:D8A01D* ID_OUI_FROM_DATABASE=Espressif Inc. @@ -100850,6 +103679,9 @@ OUI:D8A25E* OUI:D8A315* ID_OUI_FROM_DATABASE=vivo Mobile Communication Co., Ltd. +OUI:D8A35C* + ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd + OUI:D8A491* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. @@ -100922,6 +103754,9 @@ OUI:D8B90E* OUI:D8BB2C* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:D8BBC1* + ID_OUI_FROM_DATABASE=Micro-Star INTL CO., LTD. + OUI:D8BC59* ID_OUI_FROM_DATABASE=Shenzhen DAPU Microelectronics Co., Ltd @@ -100982,6 +103817,9 @@ OUI:D8CB8A* OUI:D8CC98* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:D8CD2C* + ID_OUI_FROM_DATABASE=WUXI NEIHUA NETWORK TECHNOLOGY CO., LTD + OUI:D8CE3A* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd @@ -101067,7 +103905,7 @@ OUI:D8E56D* ID_OUI_FROM_DATABASE=TCT mobile ltd OUI:D8E72B* - ID_OUI_FROM_DATABASE=NetAlly + ID_OUI_FROM_DATABASE=NETSCOUT SYSTEMS INC OUI:D8E743* ID_OUI_FROM_DATABASE=Wush, Inc @@ -101075,9 +103913,18 @@ OUI:D8E743* OUI:D8E952* ID_OUI_FROM_DATABASE=KEOPSYS +OUI:D8EB46* + ID_OUI_FROM_DATABASE=Google, Inc. + OUI:D8EB97* ID_OUI_FROM_DATABASE=TRENDnet, Inc. +OUI:D8EC5E* + ID_OUI_FROM_DATABASE=Belkin International Inc. + +OUI:D8ECE5* + ID_OUI_FROM_DATABASE=Zyxel Communications Corporation + OUI:D8ED1C* ID_OUI_FROM_DATABASE=Magna Technology SL @@ -101150,6 +103997,9 @@ OUI:DC0265* OUI:DC028E* ID_OUI_FROM_DATABASE=zte corporation +OUI:DC0398* + ID_OUI_FROM_DATABASE=LG Innotek + OUI:DC052F* ID_OUI_FROM_DATABASE=National Products Inc. @@ -101192,6 +104042,9 @@ OUI:DC0D30* OUI:DC0EA1* ID_OUI_FROM_DATABASE=COMPAL INFORMATION (KUNSHAN) CO., LTD. +OUI:DC15C8* + ID_OUI_FROM_DATABASE=AVM Audiovisuelles Marketing und Computersysteme GmbH + OUI:DC15DB* ID_OUI_FROM_DATABASE=Ge Ruili Intelligent Technology ( Beijing ) Co., Ltd. @@ -101228,6 +104081,12 @@ OUI:DC1EA3* OUI:DC2008* ID_OUI_FROM_DATABASE=ASD Electronics Ltd +OUI:DC2148* + ID_OUI_FROM_DATABASE=Intel Corporate + +OUI:DC215C* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:DC21B9* ID_OUI_FROM_DATABASE=Sentec Co.Ltd @@ -101267,6 +104126,9 @@ OUI:DC2BCA* OUI:DC2C26* ID_OUI_FROM_DATABASE=Iton Technology Limited +OUI:DC2D3C* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:DC2DCB* ID_OUI_FROM_DATABASE=Beijing Unis HengYue Technology Co., Ltd. @@ -101597,6 +104459,9 @@ OUI:DC85DE* OUI:DC86D8* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:DC87CB* + ID_OUI_FROM_DATABASE=Beijing Perfectek Technologies Co., Ltd. + OUI:DC8983* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -101711,6 +104576,9 @@ OUI:DCB058* OUI:DCB082* ID_OUI_FROM_DATABASE=Nokia +OUI:DCB131* + ID_OUI_FROM_DATABASE=SHENZHEN HUARUIAN TECHNOLOGY CO.,LTD + OUI:DCB3B4* ID_OUI_FROM_DATABASE=Honeywell Environmental & Combustion Controls (Tianjin) Co., Ltd. @@ -101901,7 +104769,7 @@ OUI:DCE5339* ID_OUI_FROM_DATABASE=Tiertime Corporation OUI:DCE533A* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Amazinglayer Network Co., Ltd. OUI:DCE533B* ID_OUI_FROM_DATABASE=Tintel Hongkong Co.Ltd @@ -102026,6 +104894,9 @@ OUI:E00B28* OUI:E00C7F* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. +OUI:E00CE5* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E00DB9* ID_OUI_FROM_DATABASE=Cree, Inc. @@ -102243,7 +105114,7 @@ OUI:E04F43* ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. OUI:E04FBD* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:E0508B* ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd. @@ -102291,7 +105162,7 @@ OUI:E05A9F7* ID_OUI_FROM_DATABASE=OMB Guitars LLC OUI:E05A9F8* - ID_OUI_FROM_DATABASE=Fujian Newland Auto-ID Tech. Co.,Ltd. + ID_OUI_FROM_DATABASE=Fujian Newland Auto-ID Tech. Co,.Ltd. OUI:E05A9F9* ID_OUI_FROM_DATABASE=Gemalto Document Readers @@ -102455,6 +105326,9 @@ OUI:E09153* OUI:E091F5* ID_OUI_FROM_DATABASE=NETGEAR +OUI:E0925C* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:E092A7* ID_OUI_FROM_DATABASE=Feitian Technologies Co., Ltd @@ -102654,7 +105528,7 @@ OUI:E0C3F3* ID_OUI_FROM_DATABASE=zte corporation OUI:E0C63C* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:E0C6B3* ID_OUI_FROM_DATABASE=MilDef AB @@ -102746,6 +105620,9 @@ OUI:E0D9A2* OUI:E0D9E3* ID_OUI_FROM_DATABASE=Eltex Enterprise Ltd. +OUI:E0DA90* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E0DADC* ID_OUI_FROM_DATABASE=JVC KENWOOD Corporation @@ -102758,6 +105635,9 @@ OUI:E0DB55* OUI:E0DB88* ID_OUI_FROM_DATABASE=Open Standard Digital-IF Interface for SATCOM Systems +OUI:E0DBD1* + ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. + OUI:E0DCA0* ID_OUI_FROM_DATABASE=Siemens Industrial Automation Products Ltd Chengdu @@ -102779,6 +105659,9 @@ OUI:E0E1A9* OUI:E0E2E6* ID_OUI_FROM_DATABASE=Espressif Inc. +OUI:E0E37C* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:E0E5CF* ID_OUI_FROM_DATABASE=Texas Instruments @@ -102788,12 +105671,18 @@ OUI:E0E62E* OUI:E0E631* ID_OUI_FROM_DATABASE=SNB TECHNOLOGIES LIMITED +OUI:E0E656* + ID_OUI_FROM_DATABASE=Nethesis srl + OUI:E0E751* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. OUI:E0E7BB* ID_OUI_FROM_DATABASE=Nureva, Inc. +OUI:E0E8BB* + ID_OUI_FROM_DATABASE=Unicom Vsens Telecommunications Co., Ltd. + OUI:E0E8E6* ID_OUI_FROM_DATABASE=Shenzhen C-Data Technology Co., Ltd. @@ -102855,7 +105744,13 @@ OUI:E40439* ID_OUI_FROM_DATABASE=TomTom Software Ltd OUI:E405F8* - ID_OUI_FROM_DATABASE=Delta Innovation Technology Co., Ltd. + ID_OUI_FROM_DATABASE=Bytedance + +OUI:E408E7* + ID_OUI_FROM_DATABASE=Quectel Wireless Solutions Co.,Ltd. + +OUI:E40CFD* + ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD OUI:E40EEE* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -102974,6 +105869,9 @@ OUI:E42761* OUI:E42771* ID_OUI_FROM_DATABASE=Smartlabs +OUI:E428A4* + ID_OUI_FROM_DATABASE=Prama India Private Limited + OUI:E42AD3* ID_OUI_FROM_DATABASE=Magneti Marelli S.p.A. Powertrain @@ -103055,6 +105953,9 @@ OUI:E440E2* OUI:E44122* ID_OUI_FROM_DATABASE=OnePlus Technology (Shenzhen) Co., Ltd +OUI:E44164* + ID_OUI_FROM_DATABASE=Nokia + OUI:E441E6* ID_OUI_FROM_DATABASE=Ottec Technology GmbH @@ -103133,6 +106034,9 @@ OUI:E44CC7E* OUI:E44E18* ID_OUI_FROM_DATABASE=Gardasoft VisionLimited +OUI:E44E2D* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:E44E76* ID_OUI_FROM_DATABASE=CHAMPIONTECH ENTERPRISE (SHENZHEN) INC @@ -103151,6 +106055,9 @@ OUI:E450EB* OUI:E454E8* ID_OUI_FROM_DATABASE=Dell Inc. +OUI:E455A8* + ID_OUI_FROM_DATABASE=Cisco Meraki + OUI:E455EA* ID_OUI_FROM_DATABASE=Dedicated Computing @@ -103244,6 +106151,9 @@ OUI:E47684* OUI:E47723* ID_OUI_FROM_DATABASE=zte corporation +OUI:E47727* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E4776B* ID_OUI_FROM_DATABASE=AARTESYS AG @@ -103529,6 +106439,9 @@ OUI:E4C801* OUI:E4C806* ID_OUI_FROM_DATABASE=Ceiec Electric Technology Inc. +OUI:E4C90B* + ID_OUI_FROM_DATABASE=Radwin + OUI:E4CA12* ID_OUI_FROM_DATABASE=zte corporation @@ -103640,6 +106553,9 @@ OUI:E4F3F5* OUI:E4F4C6* ID_OUI_FROM_DATABASE=NETGEAR +OUI:E4F75B* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:E4F7A1* ID_OUI_FROM_DATABASE=Datafox GmbH @@ -103670,6 +106586,9 @@ OUI:E4FB8F* OUI:E4FC82* ID_OUI_FROM_DATABASE=Juniper Networks +OUI:E4FD45* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:E4FDA1* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -103703,6 +106622,9 @@ OUI:E804F3* OUI:E8056D* ID_OUI_FROM_DATABASE=Nortel Networks +OUI:E805DC* + ID_OUI_FROM_DATABASE=Verifone Inc. + OUI:E80688* ID_OUI_FROM_DATABASE=Apple, Inc. @@ -103826,6 +106748,9 @@ OUI:E81B69* OUI:E81CBA* ID_OUI_FROM_DATABASE=Fortinet, Inc. +OUI:E81CD8* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:E81DA8* ID_OUI_FROM_DATABASE=Ruckus Wireless @@ -103931,6 +106856,9 @@ OUI:E84943* OUI:E84C56* ID_OUI_FROM_DATABASE=INTERCEPT SERVICES LIMITED +OUI:E84D74* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E84DD0* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -103943,6 +106871,9 @@ OUI:E84E84* OUI:E84ECE* ID_OUI_FROM_DATABASE=Nintendo Co., Ltd. +OUI:E84F25* + ID_OUI_FROM_DATABASE=Murata Manufacturing Co., Ltd. + OUI:E84F4B* ID_OUI_FROM_DATABASE=Shenzhen Delos Electronic Co., Ltd @@ -103985,6 +106916,9 @@ OUI:E85BB7* OUI:E85BF0* ID_OUI_FROM_DATABASE=Imaging Diagnostics +OUI:E85C0A* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:E85D6B* ID_OUI_FROM_DATABASE=Luminate Wireless @@ -104024,6 +106958,51 @@ OUI:E868E7* OUI:E86A64* ID_OUI_FROM_DATABASE=LCFC(HeFei) Electronics Technology co., ltd +OUI:E86CC70* + ID_OUI_FROM_DATABASE=Trapeze Switzerland GmbH + +OUI:E86CC71* + ID_OUI_FROM_DATABASE=ASSA ABLOY(GuangZhou) Smart Technology Co., Ltd + +OUI:E86CC72* + ID_OUI_FROM_DATABASE=Xirgo Technologies LLC + +OUI:E86CC73* + ID_OUI_FROM_DATABASE=Shenzhen Yibaifen Industrial Co.,Ltd. + +OUI:E86CC74* + ID_OUI_FROM_DATABASE=Koal Software Co., Ltd + +OUI:E86CC75* + ID_OUI_FROM_DATABASE=Shenzhen Rongda Computer Co.,Ltd + +OUI:E86CC76* + ID_OUI_FROM_DATABASE=KLAB + +OUI:E86CC77* + ID_OUI_FROM_DATABASE=Huaqin Technology Co.,Ltd + +OUI:E86CC78* + ID_OUI_FROM_DATABASE=Lighthouse EIP + +OUI:E86CC79* + ID_OUI_FROM_DATABASE=Hangzhou Lanxum Security Technology Co., Ltd + +OUI:E86CC7A* + ID_OUI_FROM_DATABASE=CoxSpace + +OUI:E86CC7B* + ID_OUI_FROM_DATABASE=MORNSUN Guangzhou Science & Technology Co., Ltd. + +OUI:E86CC7C* + ID_OUI_FROM_DATABASE=Limited Liability Company M.S.Korp + +OUI:E86CC7D* + ID_OUI_FROM_DATABASE=z-max mediasolution + +OUI:E86CC7E* + ID_OUI_FROM_DATABASE=Annapurna labs + OUI:E86CDA* ID_OUI_FROM_DATABASE=Supercomputers and Neurocomputers Research Center @@ -104163,11 +107142,14 @@ OUI:E89D87* ID_OUI_FROM_DATABASE=Toshiba OUI:E89E0C* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=MAX8USA DISTRIBUTORS INC. OUI:E89EB4* ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co.,Ltd. +OUI:E89F39* + ID_OUI_FROM_DATABASE=Nokia + OUI:E89F80* ID_OUI_FROM_DATABASE=Belkin International Inc. @@ -104189,6 +107171,9 @@ OUI:E8A364* OUI:E8A4C1* ID_OUI_FROM_DATABASE=Deep Sea Electronics Ltd +OUI:E8A660* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E8A788* ID_OUI_FROM_DATABASE=XIAMEN LEELEN TECHNOLOGY CO., LTD @@ -104297,6 +107282,9 @@ OUI:E8C1B8* OUI:E8C1D7* ID_OUI_FROM_DATABASE=Philips +OUI:E8C1E8* + ID_OUI_FROM_DATABASE=Shenzhen Xiao Bi En Culture Education Technology Co.,Ltd. + OUI:E8C229* ID_OUI_FROM_DATABASE=H-Displays (MSC) Bhd @@ -104366,6 +107354,9 @@ OUI:E8D819* OUI:E8D8D1* ID_OUI_FROM_DATABASE=HP Inc. +OUI:E8DA00* + ID_OUI_FROM_DATABASE=Kivo Technology, Inc. + OUI:E8DA20* ID_OUI_FROM_DATABASE=Nintendo Co.,Ltd @@ -104432,6 +107423,9 @@ OUI:E8E8B7* OUI:E8E98E* ID_OUI_FROM_DATABASE=SOLAR controls s.r.o. +OUI:E8EA4D* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E8EA6A* ID_OUI_FROM_DATABASE=StarTech.com @@ -104474,6 +107468,9 @@ OUI:E8F2E3* OUI:E8F408* ID_OUI_FROM_DATABASE=Intel Corporate +OUI:E8F654* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:E8F724* ID_OUI_FROM_DATABASE=Hewlett Packard Enterprise @@ -104492,6 +107489,9 @@ OUI:E8FC60* OUI:E8FCAF* ID_OUI_FROM_DATABASE=NETGEAR +OUI:E8FD35* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:E8FD72* ID_OUI_FROM_DATABASE=SHANGHAI LINGUO TECHNOLOGY CO., LTD. @@ -104510,12 +107510,21 @@ OUI:EC01E2* OUI:EC01EE* ID_OUI_FROM_DATABASE=GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +OUI:EC0273* + ID_OUI_FROM_DATABASE=Aruba, a Hewlett Packard Enterprise Company + OUI:EC0441* ID_OUI_FROM_DATABASE=ShenZhen TIGO Semiconductor Co., Ltd. OUI:EC086B* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. +OUI:EC08E5* + ID_OUI_FROM_DATABASE=Motorola Mobility LLC, a Lenovo Company + +OUI:EC0BAE* + ID_OUI_FROM_DATABASE=Hangzhou BroadLink Technology Co.,Ltd + OUI:EC0D9A* ID_OUI_FROM_DATABASE=Mellanox Technologies, Inc. @@ -104546,6 +107555,9 @@ OUI:EC13DB* OUI:EC14F6* ID_OUI_FROM_DATABASE=BioControl AS +OUI:EC153D* + ID_OUI_FROM_DATABASE=Beijing Yaxunhongda Technology Co., Ltd. + OUI:EC172F* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -104612,6 +107624,9 @@ OUI:EC2CE2* OUI:EC2E4E* ID_OUI_FROM_DATABASE=HITACHI-LG DATA STORAGE INC +OUI:EC2E98* + ID_OUI_FROM_DATABASE=AzureWave Technology Inc. + OUI:EC3091* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -104747,6 +107762,9 @@ OUI:EC60E0* OUI:EC6264* ID_OUI_FROM_DATABASE=Global411 Internet Services, LLC +OUI:EC63D7* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:EC63E5* ID_OUI_FROM_DATABASE=ePBoard Design LLC @@ -104858,6 +107876,9 @@ OUI:EC89F5* OUI:EC8A4C* ID_OUI_FROM_DATABASE=zte corporation +OUI:EC8AC4* + ID_OUI_FROM_DATABASE=Amazon Technologies Inc. + OUI:EC8AC7* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -105008,6 +108029,9 @@ OUI:ECB1D7* OUI:ECB313* ID_OUI_FROM_DATABASE=SHENZHEN GONGJIN ELECTRONICS CO.,LT +OUI:ECB4E8* + ID_OUI_FROM_DATABASE=Wistron Mexico SA de CV + OUI:ECB541* ID_OUI_FROM_DATABASE=SHINANO E and E Co.Ltd. @@ -105020,6 +108044,9 @@ OUI:ECB870* OUI:ECB907* ID_OUI_FROM_DATABASE=CloudGenix Inc +OUI:ECB970* + ID_OUI_FROM_DATABASE=Ruijie Networks Co.,LTD + OUI:ECBAFE* ID_OUI_FROM_DATABASE=GIROPTIC @@ -105056,6 +108083,9 @@ OUI:ECC40D* OUI:ECC57F* ID_OUI_FROM_DATABASE=Suzhou Pairlink Network Technology +OUI:ECC5D2* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:ECC882* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -105177,7 +108207,7 @@ OUI:ECF72B* ID_OUI_FROM_DATABASE=HD DIGITAL TECH CO., LTD. OUI:ECF8EB* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:ECFA03* ID_OUI_FROM_DATABASE=FCA @@ -105203,6 +108233,9 @@ OUI:ECFE7E* OUI:F0007F* ID_OUI_FROM_DATABASE=Janz - Contadores de Energia, SA +OUI:F0016E* + ID_OUI_FROM_DATABASE=Tianyi Telecom Terminals Company Limited + OUI:F0022B* ID_OUI_FROM_DATABASE=Chrontel @@ -105287,6 +108320,9 @@ OUI:F01FAF* OUI:F0219D* ID_OUI_FROM_DATABASE=Cal-Comp Electronics & Communications Company Ltd. +OUI:F021E0* + ID_OUI_FROM_DATABASE=eero inc. + OUI:F0224E* ID_OUI_FROM_DATABASE=Esan electronic co. @@ -105336,7 +108372,7 @@ OUI:F023B9C* ID_OUI_FROM_DATABASE=Shenzhen Lachesis Mhealth Co., Ltd. OUI:F023B9D* - ID_OUI_FROM_DATABASE=Private + ID_OUI_FROM_DATABASE=Shenyang Ali Technology Company Limited OUI:F023B9E* ID_OUI_FROM_DATABASE=Domotz Ltd @@ -105386,6 +108422,9 @@ OUI:F02A61* OUI:F02E51* ID_OUI_FROM_DATABASE=Casa Systems +OUI:F02F4B* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:F02F74* ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. @@ -105503,6 +108542,9 @@ OUI:F045DA* OUI:F0463B* ID_OUI_FROM_DATABASE=Comcast Cable Corporation +OUI:F04A02* + ID_OUI_FROM_DATABASE=Cisco Systems, Inc + OUI:F04A2B* ID_OUI_FROM_DATABASE=PYRAMID Computer GmbH @@ -105569,6 +108611,9 @@ OUI:F06130* OUI:F0620D* ID_OUI_FROM_DATABASE=Shenzhen Egreat Tech Corp.,Ltd +OUI:F0625A* + ID_OUI_FROM_DATABASE=Realme Chongqing Mobile Telecommunications Corp.,Ltd. + OUI:F06281* ID_OUI_FROM_DATABASE=ProCurve Networking by HP @@ -105632,6 +108677,9 @@ OUI:F0766F* OUI:F07765* ID_OUI_FROM_DATABASE=Sourcefire, Inc +OUI:F077C3* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:F077D0* ID_OUI_FROM_DATABASE=Xcellen @@ -105708,7 +108756,7 @@ OUI:F0921C* ID_OUI_FROM_DATABASE=Hewlett Packard OUI:F092B4* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO., LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:F0933A* ID_OUI_FROM_DATABASE=NxtConect @@ -105752,6 +108800,9 @@ OUI:F09CD7* OUI:F09CE9* ID_OUI_FROM_DATABASE=Extreme Networks, Inc. +OUI:F09E4A* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:F09E63* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -105767,6 +108818,9 @@ OUI:F0A225* OUI:F0A35A* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:F0A3B2* + ID_OUI_FROM_DATABASE=Hui Zhou Gaoshengda Technology Co.,LTD + OUI:F0A764* ID_OUI_FROM_DATABASE=GST Co., Ltd. @@ -105857,6 +108911,9 @@ OUI:F0B0E7* OUI:F0B107* ID_OUI_FROM_DATABASE=Ericsson AB +OUI:F0B11D* + ID_OUI_FROM_DATABASE=Nokia + OUI:F0B2E5* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -105920,6 +108977,9 @@ OUI:F0C42F* OUI:F0C77F* ID_OUI_FROM_DATABASE=Texas Instruments +OUI:F0C814* + ID_OUI_FROM_DATABASE=SHENZHEN BILIAN ELECTRONIC CO.,LTD + OUI:F0C850* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -105932,6 +108992,9 @@ OUI:F0C9D1* OUI:F0CBA1* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:F0D08C* + ID_OUI_FROM_DATABASE=TCT mobile ltd + OUI:F0D14F* ID_OUI_FROM_DATABASE=LINEAR LLC @@ -106151,6 +109214,12 @@ OUI:F0FE6B* OUI:F0FEE7* ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. +OUI:F40223* + ID_OUI_FROM_DATABASE=PAX Computer Technology(Shenzhen) Ltd. + +OUI:F40228* + ID_OUI_FROM_DATABASE=SAMSUNG ELECTRO-MECHANICS(THAILAND) + OUI:F40270* ID_OUI_FROM_DATABASE=Dell Inc. @@ -106373,6 +109442,9 @@ OUI:F43E9D* OUI:F44156* ID_OUI_FROM_DATABASE=Arrikto Inc. +OUI:F4419E* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:F44227* ID_OUI_FROM_DATABASE=S & S Research Inc. @@ -106382,6 +109454,9 @@ OUI:F4428F* OUI:F44450* ID_OUI_FROM_DATABASE=BND Co., Ltd. +OUI:F44588* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:F445ED* ID_OUI_FROM_DATABASE=Portable Innovation Technology Ltd. @@ -106418,6 +109493,12 @@ OUI:F44D30* OUI:F44E05* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:F44E38* + ID_OUI_FROM_DATABASE=Olibra LLC + +OUI:F44EE3* + ID_OUI_FROM_DATABASE=Intel Corporate + OUI:F44EFD* ID_OUI_FROM_DATABASE=Actions Semiconductor Co.,Ltd.(Cayman Islands) @@ -106472,6 +109553,9 @@ OUI:F45FF7* OUI:F4600D* ID_OUI_FROM_DATABASE=Panoptic Technology, Inc +OUI:F46077* + ID_OUI_FROM_DATABASE=Texas Instruments + OUI:F460E2* ID_OUI_FROM_DATABASE=Xiaomi Communications Co Ltd @@ -106484,6 +109568,9 @@ OUI:F4631F* OUI:F46349* ID_OUI_FROM_DATABASE=Diffon Corporation +OUI:F463E7* + ID_OUI_FROM_DATABASE=Nanjing Maxon O.E. Tech. Co., LTD + OUI:F4645D* ID_OUI_FROM_DATABASE=Toshiba @@ -106544,6 +109631,12 @@ OUI:F46A92* OUI:F46ABC* ID_OUI_FROM_DATABASE=Adonit Corp. Ltd. +OUI:F46AD7* + ID_OUI_FROM_DATABASE=Microsoft Corporation + +OUI:F46B8C* + ID_OUI_FROM_DATABASE=Hon Hai Precision Ind. Co., Ltd. + OUI:F46BEF* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS @@ -106562,6 +109655,9 @@ OUI:F46E95* OUI:F46F4E* ID_OUI_FROM_DATABASE=Echowell +OUI:F46FA4* + ID_OUI_FROM_DATABASE=Physik Instrumente GmbH & Co. KG + OUI:F46FED* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -106748,6 +109844,9 @@ OUI:F4A59D* OUI:F4A739* ID_OUI_FROM_DATABASE=Juniper Networks +OUI:F4A80D* + ID_OUI_FROM_DATABASE=Wistron InfoComm(Kunshan)Co.,Ltd. + OUI:F4A997* ID_OUI_FROM_DATABASE=CANON INC. @@ -106760,6 +109859,9 @@ OUI:F4AFE7* OUI:F4B164* ID_OUI_FROM_DATABASE=Lightning Telecommunications Technology Co. Ltd +OUI:F4B1C2* + ID_OUI_FROM_DATABASE=Zhejiang Dahua Technology Co., Ltd. + OUI:F4B301* ID_OUI_FROM_DATABASE=Intel Corporate @@ -106817,12 +109919,18 @@ OUI:F4BD7C* OUI:F4BD9E* ID_OUI_FROM_DATABASE=Cisco Systems, Inc +OUI:F4BEEC* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:F4BF80* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:F4BFA8* ID_OUI_FROM_DATABASE=Juniper Networks +OUI:F4C02F* + ID_OUI_FROM_DATABASE=BlueBite + OUI:F4C114* ID_OUI_FROM_DATABASE=Technicolor CH USA Inc. @@ -106845,7 +109953,10 @@ OUI:F4C714* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD OUI:F4C795* - ID_OUI_FROM_DATABASE=WEY Elektronik AG + ID_OUI_FROM_DATABASE=WEY Technology AG + +OUI:F4C7AA* + ID_OUI_FROM_DATABASE=Marvell Semiconductors OUI:F4C7C8* ID_OUI_FROM_DATABASE=Kelvin Inc. @@ -106943,6 +110054,9 @@ OUI:F4E204* OUI:F4E3FB* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:F4E451* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:F4E4AD* ID_OUI_FROM_DATABASE=zte corporation @@ -107021,6 +110135,9 @@ OUI:F4F646* OUI:F4F951* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:F4FBB8* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:F4FC32* ID_OUI_FROM_DATABASE=Texas Instruments @@ -107159,6 +110276,9 @@ OUI:F81654* OUI:F81897* ID_OUI_FROM_DATABASE=2Wire Inc +OUI:F81A2B* + ID_OUI_FROM_DATABASE=Google, Inc. + OUI:F81A67* ID_OUI_FROM_DATABASE=TP-LINK TECHNOLOGIES CO.,LTD. @@ -107339,6 +110459,9 @@ OUI:F83D4E* OUI:F83DFF* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:F83E95* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:F83F51* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -107351,6 +110474,9 @@ OUI:F844E3* OUI:F845AD* ID_OUI_FROM_DATABASE=Konka Group Co., Ltd. +OUI:F845C4* + ID_OUI_FROM_DATABASE=Shenzhen Netforward Micro-Electronic Co., Ltd. + OUI:F8461C* ID_OUI_FROM_DATABASE=Sony Interactive Entertainment Inc. @@ -107375,6 +110501,9 @@ OUI:F84A7F* OUI:F84ABF* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD +OUI:F84CDA* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:F84D33* ID_OUI_FROM_DATABASE=Fiberhome Telecommunication Technologies Co.,LTD @@ -107537,6 +110666,9 @@ OUI:F8769B* OUI:F877B8* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:F8790A* + ID_OUI_FROM_DATABASE=ARRIS Group, Inc. + OUI:F87A41* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -107570,12 +110702,18 @@ OUI:F88479* OUI:F884F2* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd +OUI:F885F9* + ID_OUI_FROM_DATABASE=Calix Inc. + OUI:F887F1* ID_OUI_FROM_DATABASE=Apple, Inc. OUI:F8893C* ID_OUI_FROM_DATABASE=Inventec Appliances Corp. +OUI:F889D2* + ID_OUI_FROM_DATABASE=CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. + OUI:F88A3C0* ID_OUI_FROM_DATABASE=ART SPA @@ -107639,6 +110777,9 @@ OUI:F88DEF* OUI:F88E85* ID_OUI_FROM_DATABASE=Comtrend Corporation +OUI:F88EA1* + ID_OUI_FROM_DATABASE=Edgecore Networks Corporation + OUI:F88F07* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -107669,6 +110810,9 @@ OUI:F895C7* OUI:F895EA* ID_OUI_FROM_DATABASE=Apple, Inc. +OUI:F89753* + ID_OUI_FROM_DATABASE=Huawei Device Co., Ltd. + OUI:F897CF* ID_OUI_FROM_DATABASE=DAESHIN-INFORMATION TECHNOLOGY CO., LTD. @@ -107744,12 +110888,18 @@ OUI:F8A9D0* OUI:F8A9DE* ID_OUI_FROM_DATABASE=PUISSANCE PLUS +OUI:F8AA3F* + ID_OUI_FROM_DATABASE=DWnet Technologies(Suzhou) Corporation + OUI:F8AA8A* ID_OUI_FROM_DATABASE=Axview Technology (Shenzhen) Co.,Ltd OUI:F8AB05* ID_OUI_FROM_DATABASE=Sagemcom Broadband SAS +OUI:F8ABE5* + ID_OUI_FROM_DATABASE=shenzhen worldelite electronics co., LTD + OUI:F8AC65* ID_OUI_FROM_DATABASE=Intel Corporate @@ -107837,6 +110987,9 @@ OUI:F8B7E2* OUI:F8B95A* ID_OUI_FROM_DATABASE=LG Innotek +OUI:F8BAE6* + ID_OUI_FROM_DATABASE=Nokia + OUI:F8BBBF* ID_OUI_FROM_DATABASE=eero inc. @@ -108128,6 +111281,9 @@ OUI:FC1186* OUI:FC1349* ID_OUI_FROM_DATABASE=Global Apps Corp. +OUI:FC13F0* + ID_OUI_FROM_DATABASE=Bouffalo Lab (Nanjing) Co., Ltd. + OUI:FC1499* ID_OUI_FROM_DATABASE=Aimore Acoustics Incorporation @@ -108236,6 +111392,9 @@ OUI:FC3342* OUI:FC335F* ID_OUI_FROM_DATABASE=Polyera +OUI:FC3497* + ID_OUI_FROM_DATABASE=ASUSTek COMPUTER INC. + OUI:FC3598* ID_OUI_FROM_DATABASE=Favite Inc. @@ -108243,7 +111402,7 @@ OUI:FC35E6* ID_OUI_FROM_DATABASE=Visteon corp OUI:FC372B* - ID_OUI_FROM_DATABASE=SICHUAN TIANYI COMHEART TELECOMCO.,LTD + ID_OUI_FROM_DATABASE=Sichuan Tianyi Comheart Telecom Co.,LTD OUI:FC3964* ID_OUI_FROM_DATABASE=ITEL MOBILE LIMITED @@ -108266,6 +111425,9 @@ OUI:FC3FAB* OUI:FC3FDB* ID_OUI_FROM_DATABASE=Hewlett Packard +OUI:FC4009* + ID_OUI_FROM_DATABASE=zte corporation + OUI:FC4203* ID_OUI_FROM_DATABASE=Samsung Electronics Co.,Ltd @@ -108311,9 +111473,15 @@ OUI:FC4BBC* OUI:FC4D8C* ID_OUI_FROM_DATABASE=SHENZHEN PANTE ELECTRONICS TECHNOLOGY CO., LTD +OUI:FC4DA6* + ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD + OUI:FC4DD4* ID_OUI_FROM_DATABASE=Universal Global Scientific Industrial Co., Ltd. +OUI:FC4EA4* + ID_OUI_FROM_DATABASE=Apple, Inc. + OUI:FC5090* ID_OUI_FROM_DATABASE=SIMEX Sp. z o.o. @@ -108332,6 +111500,9 @@ OUI:FC539E* OUI:FC55DC* ID_OUI_FROM_DATABASE=Baltic Latvian Universal Electronics LLC +OUI:FC584A* + ID_OUI_FROM_DATABASE=xiamenshi c-chip technology co., ltd + OUI:FC589A* ID_OUI_FROM_DATABASE=Cisco Systems, Inc @@ -108491,6 +111662,9 @@ OUI:FC9114* OUI:FC923B* ID_OUI_FROM_DATABASE=Nokia Corporation +OUI:FC9257* + ID_OUI_FROM_DATABASE=Renesas Electronics (Penang) Sdn. Bhd. + OUI:FC9435* ID_OUI_FROM_DATABASE=HUAWEI TECHNOLOGIES CO.,LTD @@ -108518,6 +111692,9 @@ OUI:FC9AFA* OUI:FC9BC6* ID_OUI_FROM_DATABASE=Sumavision Technologies Co.,Ltd +OUI:FC9C98* + ID_OUI_FROM_DATABASE=Arlo Technology + OUI:FC9DD8* ID_OUI_FROM_DATABASE=Beijing TongTongYiLian Science and Technology Ltd. @@ -108605,6 +111782,9 @@ OUI:FCA89A* OUI:FCA9B0* ID_OUI_FROM_DATABASE=MIARTECH (SHANGHAI),INC. +OUI:FCA9DC* + ID_OUI_FROM_DATABASE=Renesas Electronics (Penang) Sdn. Bhd. + OUI:FCAA14* ID_OUI_FROM_DATABASE=GIGA-BYTE TECHNOLOGY CO.,LTD. @@ -108860,6 +112040,9 @@ OUI:FCE557* OUI:FCE66A* ID_OUI_FROM_DATABASE=Industrial Software Co +OUI:FCE806* + ID_OUI_FROM_DATABASE=Edifier International + OUI:FCE892* ID_OUI_FROM_DATABASE=Hangzhou Lancable Technology Co.,Ltd diff --git a/hwdb.d/20-acpi-vendor.hwdb b/hwdb.d/20-acpi-vendor.hwdb index ac8710870..c6d3798e1 100644 --- a/hwdb.d/20-acpi-vendor.hwdb +++ b/hwdb.d/20-acpi-vendor.hwdb @@ -51,6 +51,9 @@ acpi:ATML*: acpi:AUTH*: ID_VENDOR_FROM_DATABASE=AuthenTec +acpi:BABA*: + ID_VENDOR_FROM_DATABASE=Alibaba Co., Ltd. + acpi:BOOT*: ID_VENDOR_FROM_DATABASE=Coreboot Project @@ -93,6 +96,9 @@ acpi:ESSX*: acpi:EXAR*: ID_VENDOR_FROM_DATABASE=Exar Corporation +acpi:FRMW*: + ID_VENDOR_FROM_DATABASE=Framework Computer LLC + acpi:FRSC*: ID_VENDOR_FROM_DATABASE=Freescale, Inc @@ -168,6 +174,9 @@ acpi:IP3T*: acpi:IPHI*: ID_VENDOR_FROM_DATABASE=Inphi Corporation +acpi:JSYS*: + ID_VENDOR_FROM_DATABASE=Juniper Systems, Inc. + acpi:KIOX*: ID_VENDOR_FROM_DATABASE=Kionix, Inc. @@ -228,6 +237,9 @@ acpi:PHYT*: acpi:PIXA*: ID_VENDOR_FROM_DATABASE=PixArt imaging inc. +acpi:PNSO*: + ID_VENDOR_FROM_DATABASE=Pensando Systems, Inc. + acpi:QCOM*: ID_VENDOR_FROM_DATABASE=Qualcomm Inc @@ -243,6 +255,9 @@ acpi:RKCP*: acpi:RZSN*: ID_VENDOR_FROM_DATABASE=Rozsnyó, s.r.o. +acpi:SECC*: + ID_VENDOR_FROM_DATABASE=Seiko Epson Corporation + acpi:SHRP*: ID_VENDOR_FROM_DATABASE=Sharp Corporation @@ -592,7 +607,7 @@ acpi:ALO*: ID_VENDOR_FROM_DATABASE=Algolith Inc. acpi:ALP*: - ID_VENDOR_FROM_DATABASE=Alps Electric Company Ltd + ID_VENDOR_FROM_DATABASE=ALPS ALPINE CO., LTD. acpi:ALR*: ID_VENDOR_FROM_DATABASE=Advanced Logic @@ -718,7 +733,7 @@ acpi:APD*: ID_VENDOR_FROM_DATABASE=AppliAdata acpi:APE*: - ID_VENDOR_FROM_DATABASE=Alpine Electronics, Inc. + ID_VENDOR_FROM_DATABASE=ALPS ALPINE CO., LTD. acpi:APG*: ID_VENDOR_FROM_DATABASE=Horner Electric Inc @@ -883,7 +898,7 @@ acpi:AUG*: ID_VENDOR_FROM_DATABASE=August Home, Inc. acpi:AUI*: - ID_VENDOR_FROM_DATABASE=Alps Electric Inc + ID_VENDOR_FROM_DATABASE=ALPS ALPINE CO., LTD. acpi:AUO*: ID_VENDOR_FROM_DATABASE=AU Optronics @@ -1473,6 +1488,9 @@ acpi:CLM*: acpi:CLO*: ID_VENDOR_FROM_DATABASE=Clone Computers +acpi:CLR*: + ID_VENDOR_FROM_DATABASE=Clover Electronics + acpi:CLT*: ID_VENDOR_FROM_DATABASE=automated computer control systems @@ -1521,6 +1539,9 @@ acpi:CNB*: acpi:CNC*: ID_VENDOR_FROM_DATABASE=Alvedon Computers Ltd +acpi:CND*: + ID_VENDOR_FROM_DATABASE=Micro-Star Int'l Co., Ltd. + acpi:CNE*: ID_VENDOR_FROM_DATABASE=Cine-tal @@ -1620,6 +1641,9 @@ acpi:CRI*: acpi:CRL*: ID_VENDOR_FROM_DATABASE=Creative Logic +acpi:CRM*: + ID_VENDOR_FROM_DATABASE=CORSAIR MEMORY Inc. + acpi:CRN*: ID_VENDOR_FROM_DATABASE=Cornerstone Imaging @@ -3891,6 +3915,9 @@ acpi:KTK*: acpi:KTN*: ID_VENDOR_FROM_DATABASE=Katron Tech Inc +acpi:KTS*: + ID_VENDOR_FROM_DATABASE=Kyokko Communication System Co., Ltd. + acpi:KUR*: ID_VENDOR_FROM_DATABASE=Kurta Corporation @@ -4986,6 +5013,9 @@ acpi:NVT*: acpi:NWC*: ID_VENDOR_FROM_DATABASE=NW Computer Engineering +acpi:NWL*: + ID_VENDOR_FROM_DATABASE=Newline Interactive Inc. + acpi:NWP*: ID_VENDOR_FROM_DATABASE=NovaWeb Technologies Inc @@ -6732,6 +6762,9 @@ acpi:TGS*: acpi:TGV*: ID_VENDOR_FROM_DATABASE=Grass Valley Germany GmbH +acpi:TGW*: + ID_VENDOR_FROM_DATABASE=TECHNOGYM S.p.A. + acpi:THN*: ID_VENDOR_FROM_DATABASE=Thundercom Holdings Sdn. Bhd. @@ -6813,6 +6846,9 @@ acpi:TMI*: acpi:TMM*: ID_VENDOR_FROM_DATABASE=Time Management, Inc. +acpi:TMO*: + ID_VENDOR_FROM_DATABASE=Terumo Corporation + acpi:TMR*: ID_VENDOR_FROM_DATABASE=Taicom International Inc diff --git a/hwdb.d/20-acpi-vendor.hwdb.patch b/hwdb.d/20-acpi-vendor.hwdb.patch index cdfe663c2..a5f1dacda 100644 --- a/hwdb.d/20-acpi-vendor.hwdb.patch +++ b/hwdb.d/20-acpi-vendor.hwdb.patch @@ -1,5 +1,5 @@ ---- 20-acpi-vendor.hwdb.base 2020-11-26 13:49:35.243482590 +0100 -+++ 20-acpi-vendor.hwdb 2020-11-26 13:49:35.260482675 +0100 +--- 20-acpi-vendor.hwdb.base 2021-03-30 13:03:54.632421502 +0200 ++++ 20-acpi-vendor.hwdb 2021-03-30 13:03:54.650421692 +0200 @@ -3,6 +3,8 @@ # Data imported from: # https://uefi.org/uefi-pnp-export @@ -19,7 +19,7 @@ acpi:AMDI*: ID_VENDOR_FROM_DATABASE=AMD -@@ -295,6 +294,9 @@ +@@ -310,6 +309,9 @@ acpi:AAA*: ID_VENDOR_FROM_DATABASE=Avolites Ltd @@ -29,7 +29,7 @@ acpi:AAE*: ID_VENDOR_FROM_DATABASE=Anatek Electronics Inc. -@@ -322,6 +324,9 @@ +@@ -337,6 +339,9 @@ acpi:ABO*: ID_VENDOR_FROM_DATABASE=D-Link Systems Inc @@ -39,7 +39,7 @@ acpi:ABS*: ID_VENDOR_FROM_DATABASE=Abaco Systems, Inc. -@@ -367,7 +372,7 @@ +@@ -382,7 +387,7 @@ acpi:ACO*: ID_VENDOR_FROM_DATABASE=Allion Computer Inc. @@ -48,7 +48,7 @@ ID_VENDOR_FROM_DATABASE=Aspen Tech Inc acpi:ACR*: -@@ -640,6 +645,9 @@ +@@ -655,6 +660,9 @@ acpi:AMT*: ID_VENDOR_FROM_DATABASE=AMT International Industry @@ -58,7 +58,7 @@ acpi:AMX*: ID_VENDOR_FROM_DATABASE=AMX LLC -@@ -688,6 +696,9 @@ +@@ -703,6 +711,9 @@ acpi:AOA*: ID_VENDOR_FROM_DATABASE=AOpen Inc. @@ -68,7 +68,7 @@ acpi:AOE*: ID_VENDOR_FROM_DATABASE=Advanced Optics Electronics, Inc. -@@ -697,6 +708,9 @@ +@@ -712,6 +723,9 @@ acpi:AOT*: ID_VENDOR_FROM_DATABASE=Alcatel @@ -78,8 +78,8 @@ acpi:APC*: ID_VENDOR_FROM_DATABASE=American Power Conversion -@@ -872,7 +886,7 @@ - ID_VENDOR_FROM_DATABASE=Alps Electric Inc +@@ -887,7 +901,7 @@ + ID_VENDOR_FROM_DATABASE=ALPS ALPINE CO., LTD. acpi:AUO*: - ID_VENDOR_FROM_DATABASE=DO NOT USE - AUO @@ -87,7 +87,7 @@ acpi:AUR*: ID_VENDOR_FROM_DATABASE=Aureal Semiconductor -@@ -952,6 +966,9 @@ +@@ -967,6 +981,9 @@ acpi:AXE*: ID_VENDOR_FROM_DATABASE=Axell Corporation @@ -97,7 +97,7 @@ acpi:AXI*: ID_VENDOR_FROM_DATABASE=American Magnetics -@@ -1102,6 +1119,9 @@ +@@ -1117,6 +1134,9 @@ acpi:BML*: ID_VENDOR_FROM_DATABASE=BIOMED Lab @@ -107,7 +107,7 @@ acpi:BMS*: ID_VENDOR_FROM_DATABASE=BIOMEDISYS -@@ -1114,6 +1134,9 @@ +@@ -1129,6 +1149,9 @@ acpi:BNO*: ID_VENDOR_FROM_DATABASE=Bang & Olufsen @@ -117,7 +117,7 @@ acpi:BNS*: ID_VENDOR_FROM_DATABASE=Boulder Nonlinear Systems -@@ -1357,6 +1380,9 @@ +@@ -1372,6 +1395,9 @@ acpi:CHA*: ID_VENDOR_FROM_DATABASE=Chase Research PLC @@ -127,7 +127,7 @@ acpi:CHD*: ID_VENDOR_FROM_DATABASE=ChangHong Electric Co.,Ltd -@@ -1513,6 +1539,9 @@ +@@ -1534,6 +1560,9 @@ acpi:COD*: ID_VENDOR_FROM_DATABASE=CODAN Pty. Ltd. @@ -137,7 +137,7 @@ acpi:COI*: ID_VENDOR_FROM_DATABASE=Codec Inc. -@@ -1919,7 +1948,7 @@ +@@ -1943,7 +1972,7 @@ ID_VENDOR_FROM_DATABASE=Dragon Information Technology acpi:DJE*: @@ -146,7 +146,7 @@ acpi:DJP*: ID_VENDOR_FROM_DATABASE=Maygay Machines, Ltd -@@ -2251,6 +2280,9 @@ +@@ -2275,6 +2304,9 @@ acpi:EIN*: ID_VENDOR_FROM_DATABASE=Elegant Invention @@ -156,7 +156,7 @@ acpi:EKA*: ID_VENDOR_FROM_DATABASE=MagTek Inc. -@@ -2512,6 +2544,9 @@ +@@ -2536,6 +2568,9 @@ acpi:FCG*: ID_VENDOR_FROM_DATABASE=First International Computer Ltd @@ -166,7 +166,7 @@ acpi:FCS*: ID_VENDOR_FROM_DATABASE=Focus Enhancements, Inc. -@@ -2885,7 +2920,7 @@ +@@ -2909,7 +2944,7 @@ ID_VENDOR_FROM_DATABASE=General Standards Corporation acpi:GSM*: @@ -175,7 +175,7 @@ acpi:GSN*: ID_VENDOR_FROM_DATABASE=Grandstream Networks, Inc. -@@ -2986,6 +3021,9 @@ +@@ -3010,6 +3045,9 @@ acpi:HEC*: ID_VENDOR_FROM_DATABASE=Hisense Electric Co., Ltd. @@ -185,7 +185,7 @@ acpi:HEL*: ID_VENDOR_FROM_DATABASE=Hitachi Micro Systems Europe Ltd -@@ -3115,6 +3153,9 @@ +@@ -3139,6 +3177,9 @@ acpi:HSD*: ID_VENDOR_FROM_DATABASE=HannStar Display Corp @@ -195,7 +195,7 @@ acpi:HSM*: ID_VENDOR_FROM_DATABASE=AT&T Microelectronics -@@ -3238,6 +3279,9 @@ +@@ -3262,6 +3303,9 @@ acpi:ICI*: ID_VENDOR_FROM_DATABASE=Infotek Communication Inc @@ -205,7 +205,7 @@ acpi:ICM*: ID_VENDOR_FROM_DATABASE=Intracom SA -@@ -3334,6 +3378,9 @@ +@@ -3358,6 +3402,9 @@ acpi:IKE*: ID_VENDOR_FROM_DATABASE=Ikegami Tsushinki Co. Ltd. @@ -215,7 +215,7 @@ acpi:IKS*: ID_VENDOR_FROM_DATABASE=Ikos Systems Inc -@@ -3379,6 +3426,9 @@ +@@ -3403,6 +3450,9 @@ acpi:IMT*: ID_VENDOR_FROM_DATABASE=Inmax Technology Corporation @@ -225,7 +225,7 @@ acpi:INA*: ID_VENDOR_FROM_DATABASE=Inventec Corporation -@@ -3886,6 +3936,9 @@ +@@ -3913,6 +3963,9 @@ acpi:LAN*: ID_VENDOR_FROM_DATABASE=Sodeman Lancom Inc @@ -235,7 +235,7 @@ acpi:LAS*: ID_VENDOR_FROM_DATABASE=LASAT Comm. A/S -@@ -3931,6 +3984,9 @@ +@@ -3958,6 +4011,9 @@ acpi:LED*: ID_VENDOR_FROM_DATABASE=Long Engineering Design Inc @@ -245,7 +245,7 @@ acpi:LEG*: ID_VENDOR_FROM_DATABASE=Legerity, Inc -@@ -3946,6 +4002,9 @@ +@@ -3973,6 +4029,9 @@ acpi:LGC*: ID_VENDOR_FROM_DATABASE=Logic Ltd @@ -255,7 +255,7 @@ acpi:LGI*: ID_VENDOR_FROM_DATABASE=Logitech Inc -@@ -4000,6 +4059,9 @@ +@@ -4027,6 +4086,9 @@ acpi:LND*: ID_VENDOR_FROM_DATABASE=Land Computer Company Ltd @@ -265,7 +265,7 @@ acpi:LNK*: ID_VENDOR_FROM_DATABASE=Link Tech Inc -@@ -4034,7 +4096,7 @@ +@@ -4061,7 +4123,7 @@ ID_VENDOR_FROM_DATABASE=Design Technology acpi:LPL*: @@ -274,7 +274,7 @@ acpi:LSC*: ID_VENDOR_FROM_DATABASE=LifeSize Communications -@@ -4210,6 +4272,9 @@ +@@ -4237,6 +4299,9 @@ acpi:MCX*: ID_VENDOR_FROM_DATABASE=Millson Custom Solutions Inc. @@ -284,7 +284,7 @@ acpi:MDA*: ID_VENDOR_FROM_DATABASE=Media4 Inc -@@ -4450,6 +4515,9 @@ +@@ -4477,6 +4542,9 @@ acpi:MOM*: ID_VENDOR_FROM_DATABASE=Momentum Data Systems @@ -294,7 +294,7 @@ acpi:MOS*: ID_VENDOR_FROM_DATABASE=Moses Corporation -@@ -4678,6 +4746,9 @@ +@@ -4705,6 +4773,9 @@ acpi:NAL*: ID_VENDOR_FROM_DATABASE=Network Alchemy @@ -304,7 +304,7 @@ acpi:NAT*: ID_VENDOR_FROM_DATABASE=NaturalPoint Inc. -@@ -5185,6 +5256,9 @@ +@@ -5215,6 +5286,9 @@ acpi:PCX*: ID_VENDOR_FROM_DATABASE=PC Xperten @@ -314,7 +314,7 @@ acpi:PDM*: ID_VENDOR_FROM_DATABASE=Psion Dacom Plc. -@@ -5248,9 +5322,6 @@ +@@ -5278,9 +5352,6 @@ acpi:PHE*: ID_VENDOR_FROM_DATABASE=Philips Medical Systems Boeblingen GmbH @@ -324,7 +324,7 @@ acpi:PHL*: ID_VENDOR_FROM_DATABASE=Philips Consumer Electronics Company -@@ -5338,9 +5409,6 @@ +@@ -5368,9 +5439,6 @@ acpi:PNL*: ID_VENDOR_FROM_DATABASE=Panelview, Inc. @@ -334,7 +334,7 @@ acpi:PNR*: ID_VENDOR_FROM_DATABASE=Planar Systems, Inc. -@@ -5476,15 +5544,9 @@ +@@ -5506,15 +5574,9 @@ acpi:PTS*: ID_VENDOR_FROM_DATABASE=Plain Tree Systems Inc @@ -350,7 +350,7 @@ acpi:PVG*: ID_VENDOR_FROM_DATABASE=Proview Global Co., Ltd -@@ -5800,9 +5862,6 @@ +@@ -5830,9 +5892,6 @@ acpi:RTI*: ID_VENDOR_FROM_DATABASE=Rancho Tech Inc @@ -360,7 +360,7 @@ acpi:RTL*: ID_VENDOR_FROM_DATABASE=Realtek Semiconductor Company Ltd -@@ -5968,9 +6027,6 @@ +@@ -5998,9 +6057,6 @@ acpi:SEE*: ID_VENDOR_FROM_DATABASE=SeeColor Corporation @@ -370,7 +370,7 @@ acpi:SEI*: ID_VENDOR_FROM_DATABASE=Seitz & Associates Inc -@@ -6430,6 +6486,9 @@ +@@ -6460,6 +6516,9 @@ acpi:SVD*: ID_VENDOR_FROM_DATABASE=SVD Computer @@ -380,7 +380,7 @@ acpi:SVI*: ID_VENDOR_FROM_DATABASE=Sun Microsystems -@@ -6514,6 +6573,9 @@ +@@ -6544,6 +6603,9 @@ acpi:SZM*: ID_VENDOR_FROM_DATABASE=Shenzhen MTC Co., Ltd @@ -390,7 +390,7 @@ acpi:TAA*: ID_VENDOR_FROM_DATABASE=Tandberg -@@ -6604,6 +6666,9 @@ +@@ -6634,6 +6696,9 @@ acpi:TDG*: ID_VENDOR_FROM_DATABASE=Six15 Technologies @@ -400,7 +400,7 @@ acpi:TDM*: ID_VENDOR_FROM_DATABASE=Tandem Computer Europe Inc -@@ -6646,6 +6711,9 @@ +@@ -6676,6 +6741,9 @@ acpi:TEV*: ID_VENDOR_FROM_DATABASE=Televés, S.A. @@ -410,7 +410,7 @@ acpi:TEZ*: ID_VENDOR_FROM_DATABASE=Tech Source Inc. -@@ -6760,9 +6828,6 @@ +@@ -6796,9 +6864,6 @@ acpi:TNC*: ID_VENDOR_FROM_DATABASE=TNC Industrial Company Ltd @@ -420,7 +420,7 @@ acpi:TNM*: ID_VENDOR_FROM_DATABASE=TECNIMAGEN SA -@@ -7069,14 +7134,14 @@ +@@ -7105,14 +7170,14 @@ acpi:UNC*: ID_VENDOR_FROM_DATABASE=Unisys Corporation @@ -441,7 +441,7 @@ acpi:UNI*: ID_VENDOR_FROM_DATABASE=Uniform Industry Corp. -@@ -7111,6 +7176,9 @@ +@@ -7147,6 +7212,9 @@ acpi:USA*: ID_VENDOR_FROM_DATABASE=Utimaco Safeware AG @@ -451,7 +451,7 @@ acpi:USD*: ID_VENDOR_FROM_DATABASE=U.S. Digital Corporation -@@ -7357,9 +7425,6 @@ +@@ -7393,9 +7461,6 @@ acpi:WAL*: ID_VENDOR_FROM_DATABASE=Wave Access @@ -461,7 +461,7 @@ acpi:WAV*: ID_VENDOR_FROM_DATABASE=Wavephore -@@ -7484,7 +7549,7 @@ +@@ -7520,7 +7585,7 @@ ID_VENDOR_FROM_DATABASE=WyreStorm Technologies LLC acpi:WYS*: @@ -470,7 +470,7 @@ acpi:WYT*: ID_VENDOR_FROM_DATABASE=Wooyoung Image & Information Co.,Ltd. -@@ -7498,9 +7563,6 @@ +@@ -7534,9 +7599,6 @@ acpi:XDM*: ID_VENDOR_FROM_DATABASE=XDM Ltd. @@ -480,7 +480,7 @@ acpi:XES*: ID_VENDOR_FROM_DATABASE=Extreme Engineering Solutions, Inc. -@@ -7531,9 +7593,6 @@ +@@ -7567,9 +7629,6 @@ acpi:XNT*: ID_VENDOR_FROM_DATABASE=XN Technologies, Inc. @@ -490,7 +490,7 @@ acpi:XQU*: ID_VENDOR_FROM_DATABASE=SHANGHAI SVA-DAV ELECTRONICS CO., LTD -@@ -7600,6 +7659,9 @@ +@@ -7636,6 +7695,9 @@ acpi:ZBX*: ID_VENDOR_FROM_DATABASE=Zebax Technologies diff --git a/hwdb.d/20-dmi-id.hwdb b/hwdb.d/20-dmi-id.hwdb new file mode 100644 index 000000000..a614473bd --- /dev/null +++ b/hwdb.d/20-dmi-id.hwdb @@ -0,0 +1,6 @@ +# This file is part of systemd + +# Fix "Lenovo" capitalization in /sys/class/dmi/id/sys_vendor +dmi:bvnLENOVO* + ID_SYSFS_ATTRIBUTE_MODEL=product_version + ID_VENDOR_FROM_DATABASE=Lenovo diff --git a/hwdb.d/20-pci-vendor-model.hwdb b/hwdb.d/20-pci-vendor-model.hwdb index 21defccc8..269f6959f 100644 --- a/hwdb.d/20-pci-vendor-model.hwdb +++ b/hwdb.d/20-pci-vendor-model.hwdb @@ -1466,6 +1466,9 @@ pci:v00001000d00000072sv00001000sd00003080* pci:v00001000d00000072sv00001000sd000030B0* ID_MODEL_FROM_DATABASE=SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon] (9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA]) +pci:v00001000d00000072sv00001014sd000003CA* + ID_MODEL_FROM_DATABASE=SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon] (IBM 6Gb SAS HBA [9212-4i4e]) + pci:v00001000d00000072sv00001028sd00001F1C* ID_MODEL_FROM_DATABASE=SAS2008 PCI-Express Fusion-MPT SAS-2 [Falcon] (6Gbps SAS HBA Adapter) @@ -1998,7 +2001,10 @@ pci:v00001000d000000AFsv00001D49sd00000204* ID_MODEL_FROM_DATABASE=SAS3408 Fusion-MPT Tri-Mode I/O Controller Chip (IOC) (ThinkSystem 430-8i SAS/SATA 12Gb Dense HBA) pci:v00001000d000000B2* - ID_MODEL_FROM_DATABASE=PEX880xx PCIe Gen 4 Switch SES management endpoint + ID_MODEL_FROM_DATABASE=PCIe Switch management endpoint + +pci:v00001000d000000B2sv00001D49sd00000003* + ID_MODEL_FROM_DATABASE=PCIe Switch management endpoint (ThinkSystem 1611-8P PCIe Gen4 NVMe Switch Adapter) pci:v00001000d000000BE* ID_MODEL_FROM_DATABASE=SAS3504 Fusion-MPT Tri-Mode RAID On Chip (ROC) @@ -2447,6 +2453,18 @@ pci:v00001000d000010E1sv00001D49sd0000060F* pci:v00001000d000010E2* ID_MODEL_FROM_DATABASE=MegaRAID 12GSAS/PCIe Secure SAS39xx +pci:v00001000d000010E2sv00001000sd00004000* + ID_MODEL_FROM_DATABASE=MegaRAID 12GSAS/PCIe Secure SAS39xx (MegaRAID 9560-16i) + +pci:v00001000d000010E2sv00001000sd00004010* + ID_MODEL_FROM_DATABASE=MegaRAID 12GSAS/PCIe Secure SAS39xx (MegaRAID 9560-8i) + +pci:v00001000d000010E2sv00001000sd00004020* + ID_MODEL_FROM_DATABASE=MegaRAID 12GSAS/PCIe Secure SAS39xx (MegaRAID 9580-8i8e) + +pci:v00001000d000010E2sv00001000sd000040B0* + ID_MODEL_FROM_DATABASE=MegaRAID 12GSAS/PCIe Secure SAS39xx (MegaRAID 9562-16i) + pci:v00001000d000010E2sv00001028sd00001AE0* ID_MODEL_FROM_DATABASE=MegaRAID 12GSAS/PCIe Secure SAS39xx (PERC H755 Adapter) @@ -2549,6 +2567,12 @@ pci:v00001000d00003050* pci:v00001000d00006001* ID_MODEL_FROM_DATABASE=DX1 Multiformat Broadcast HD/SD Encoder/Decoder +pci:v00001000d0000C012* + ID_MODEL_FROM_DATABASE=PEX880xx PCIe Gen 4 Switch + +pci:v00001000d0000C012sv00001D49sd00000003* + ID_MODEL_FROM_DATABASE=PEX880xx PCIe Gen 4 Switch (ThinkSystem 1611-8P PCIe Gen4 NVMe Switch Adapter) + pci:v00001001* ID_VENDOR_FROM_DATABASE=Kolter Electronic @@ -2675,6 +2699,9 @@ pci:v00001002d00001479* pci:v00001002d0000154C* ID_MODEL_FROM_DATABASE=Kryptos [Radeon RX 350] +pci:v00001002d0000154Csv00001462sd00007C28* + ID_MODEL_FROM_DATABASE=Kryptos [Radeon RX 350] (MS-7C28 Motherboard) + pci:v00001002d0000154E* ID_MODEL_FROM_DATABASE=Garfield @@ -2693,33 +2720,54 @@ pci:v00001002d000015D8* pci:v00001002d000015D8sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Picasso (Pavilion Laptop 15-cw1xxx) +pci:v00001002d000015D8sv000017AAsd00003181* + ID_MODEL_FROM_DATABASE=Picasso (ThinkCentre M75n IoT) + pci:v00001002d000015D8sv000017AAsd00005124* ID_MODEL_FROM_DATABASE=Picasso (ThinkPad E595) +pci:v00001002d000015D8sv0000EA50sd0000CC10* + ID_MODEL_FROM_DATABASE=Picasso (RXi2-BP) + pci:v00001002d000015DD* ID_MODEL_FROM_DATABASE=Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] pci:v00001002d000015DDsv0000103Csd000083C6* ID_MODEL_FROM_DATABASE=Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] (Radeon Vega 8 Mobile) +pci:v00001002d000015DDsv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] (PRIME Motherboard) + pci:v00001002d000015DDsv00001458sd0000D000* ID_MODEL_FROM_DATABASE=Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] (Radeon RX Vega 11) +pci:v00001002d000015DDsv0000EA50sd0000CC10* + ID_MODEL_FROM_DATABASE=Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] (RXi2-BP) + pci:v00001002d000015DE* ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang HDMI/DP Audio Controller pci:v00001002d000015DEsv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang HDMI/DP Audio Controller (Pavilion Laptop 15-cw1xxx) +pci:v00001002d000015DEsv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang HDMI/DP Audio Controller (PRIME B450M-A Motherboard) + pci:v00001002d000015DEsv000017AAsd00005124* ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang HDMI/DP Audio Controller (ThinkPad E595) +pci:v00001002d000015DEsv0000EA50sd0000CC10* + ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang HDMI/DP Audio Controller (RXi2-BP) + pci:v00001002d000015DF* ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang/Renoir Cryptographic Coprocessor pci:v00001002d000015DFsv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang/Renoir Cryptographic Coprocessor (Pavilion Laptop 15-cw1xxx) +pci:v00001002d000015DFsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Raven/Raven2/Fenghuang/Renoir Cryptographic Coprocessor (mCOM10-L1900) + pci:v00001002d000015FF* ID_MODEL_FROM_DATABASE=Fenghuang [Zhongshan Subor Z+] @@ -2729,6 +2777,15 @@ pci:v00001002d00001607* pci:v00001002d00001636* ID_MODEL_FROM_DATABASE=Renoir +pci:v00001002d00001638* + ID_MODEL_FROM_DATABASE=Cezanne + +pci:v00001002d0000163F* + ID_MODEL_FROM_DATABASE=VanGogh + +pci:v00001002d0000164C* + ID_MODEL_FROM_DATABASE=Lucienne + pci:v00001002d00001714* ID_MODEL_FROM_DATABASE=BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series] @@ -3275,6 +3332,9 @@ pci:v00001002d00004383sv00001458sd0000A022* pci:v00001002d00004383sv00001458sd0000A102* ID_MODEL_FROM_DATABASE=SBx00 Azalia (Intel HDA) (GA-880GMA-USB3) +pci:v00001002d00004383sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SBx00 Azalia (Intel HDA) (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004383sv000017F2sd00005000* ID_MODEL_FROM_DATABASE=SBx00 Azalia (Intel HDA) (KI690-AM2 Motherboard) @@ -3311,6 +3371,9 @@ pci:v00001002d00004385sv00001458sd00004385* pci:v00001002d00004385sv00001462sd00007368* ID_MODEL_FROM_DATABASE=SBx00 SMBus Controller (K9AG Neo2) +pci:v00001002d00004385sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SBx00 SMBus Controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004385sv000015D9sd0000A811* ID_MODEL_FROM_DATABASE=SBx00 SMBus Controller (H8DGU) @@ -3461,6 +3524,9 @@ pci:v00001002d00004390sv0000105Bsd00000E13* pci:v00001002d00004390sv00001458sd0000B002* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [IDE mode] (GA-MA770-DS3rev2.0 Motherboard) +pci:v00001002d00004390sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [IDE mode] (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004390sv00001849sd00004390* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 SATA Controller [IDE mode] (Motherboard (one of many)) @@ -3530,6 +3596,9 @@ pci:v00001002d00004396sv0000105Bsd00000E13* pci:v00001002d00004396sv00001458sd00005004* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB EHCI Controller (GA-880GMA-USB3) +pci:v00001002d00004396sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB EHCI Controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004396sv000015D9sd0000A811* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB EHCI Controller (H8DGU) @@ -3560,6 +3629,9 @@ pci:v00001002d00004397sv0000105Bsd00000E13* pci:v00001002d00004397sv00001458sd00005004* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI0 Controller (GA-880GMA-USB3) +pci:v00001002d00004397sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI0 Controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004397sv000015D9sd0000A811* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI0 Controller (H8DGU) @@ -3578,6 +3650,9 @@ pci:v00001002d00004398sv00001043sd000082EF* pci:v00001002d00004398sv0000105Bsd00000E13* ID_MODEL_FROM_DATABASE=SB7x0 USB OHCI1 Controller (N15235/A74MX mainboard / AMD SB700) +pci:v00001002d00004398sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0 USB OHCI1 Controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004398sv000015D9sd0000A811* ID_MODEL_FROM_DATABASE=SB7x0 USB OHCI1 Controller (H8DGU) @@ -3599,6 +3674,9 @@ pci:v00001002d00004399sv0000105Bsd00000E13* pci:v00001002d00004399sv00001458sd00005004* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI2 Controller (GA-880GMA-USB3) +pci:v00001002d00004399sv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI2 Controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00004399sv0000174Bsd00001001* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 USB OHCI2 Controller (PURE Fusion Mini) @@ -3620,6 +3698,9 @@ pci:v00001002d0000439Csv00001043sd000082EF* pci:v00001002d0000439Csv0000105Bsd00000E13* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 IDE Controller (N15235/A74MX mainboard / AMD SB700) +pci:v00001002d0000439Csv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 IDE Controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d0000439D* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 LPC host controller @@ -3641,6 +3722,9 @@ pci:v00001002d0000439Dsv00001043sd00008443* pci:v00001002d0000439Dsv0000105Bsd00000E13* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 LPC host controller (N15235/A74MX mainboard / AMD SB700) +pci:v00001002d0000439Dsv00001462sd00007596* + ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 LPC host controller (760GM-E51(MS-7596) Motherboard) + pci:v00001002d0000439Dsv0000174Bsd00001001* ID_MODEL_FROM_DATABASE=SB7x0/SB8x0/SB9x0 LPC host controller (PURE Fusion Mini) @@ -5094,7 +5178,7 @@ pci:v00001002d00005964sv00001043sd0000C006* ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Radeon 9200 SE / TD / 128M) pci:v00001002d00005964sv00001458sd00004018* - ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Radeon 9200 SE) + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (R92S128T (Radeon 9200 SE 128MB)) pci:v00001002d00005964sv00001458sd00004032* ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Radeon 9200 SE 128MB) @@ -5358,7 +5442,7 @@ pci:v00001002d00005D44* ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Secondary) pci:v00001002d00005D44sv00001458sd00004019* - ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Secondary) (Radeon 9200 SE (Secondary)) + ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Secondary) (R92S128T (Radeon 9200 SE 128MB Secondary)) pci:v00001002d00005D44sv00001458sd00004032* ID_MODEL_FROM_DATABASE=RV280 [Radeon 9200 SE] (Secondary) (Radeon 9200 SE 128MB) @@ -5469,10 +5553,10 @@ pci:v00001002d00005F57* ID_MODEL_FROM_DATABASE=R423 [Radeon X800 XT] pci:v00001002d00006600* - ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8670A/8670M/8750M] + ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8670A/8670M/8750M / R7 M370] pci:v00001002d00006600sv0000103Csd00001952* - ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8670A/8670M/8750M] (ProBook 455 G1) + ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8670A/8670M/8750M / R7 M370] (ProBook 455 G1) pci:v00001002d00006601* ID_MODEL_FROM_DATABASE=Mars [Radeon HD 8730M] @@ -5519,42 +5603,66 @@ pci:v00001002d00006608* pci:v00001002d00006608sv000013CCsd00003D28* ID_MODEL_FROM_DATABASE=Oland GL [FirePro W2100] (MXRT-2600) +pci:v00001002d00006609* + ID_MODEL_FROM_DATABASE=Oland GL [FirePro W2100 / Barco MXRT 2600] + pci:v00001002d00006610* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] pci:v00001002d00006610sv00001019sd00000030* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon HD 8670) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon HD 8670) + +pci:v00001002d00006610sv00001028sd00000081* + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon R7 350X OEM) + +pci:v00001002d00006610sv00001028sd00000083* + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon R5 340X OEM) pci:v00001002d00006610sv00001028sd00002120* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon R7 250) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon R7 250) pci:v00001002d00006610sv00001028sd00002322* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon R7 250) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon R7 250) pci:v00001002d00006610sv00001462sd00002910* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon HD 8670) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon HD 8670) pci:v00001002d00006610sv00001462sd00002911* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon HD 8670) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon HD 8670) pci:v00001002d00006610sv0000148Csd00007350* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon R7 350) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon R7 350) pci:v00001002d00006610sv00001642sd00003C81* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon HD 8670) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon HD 8670) pci:v00001002d00006610sv00001642sd00003C91* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon HD 8670) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon HD 8670) pci:v00001002d00006610sv00001642sd00003F09* - ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R7 250/350] (Radeon R7 350) + ID_MODEL_FROM_DATABASE=Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] (Radeon R7 350) pci:v00001002d00006611* ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] +pci:v00001002d00006611sv00001028sd00001001* + ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R5 430 OEM (1024 MByte)) + +pci:v00001002d00006611sv00001028sd00001002* + ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R5 430 OEM (2048 MByte)) + +pci:v00001002d00006611sv00001028sd00001711* + ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (R5 430 OEM (2048 MByte)) + pci:v00001002d00006611sv00001028sd0000210B* ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon R5 240 OEM) +pci:v00001002d00006611sv00001028sd00002121* + ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon HD 8570 OEM) + +pci:v00001002d00006611sv000010CFsd00001889* + ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon HD 8570 OEM) + pci:v00001002d00006611sv00001642sd00001869* ID_MODEL_FROM_DATABASE=Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] (Radeon 520 OEM) @@ -5766,13 +5874,13 @@ pci:v00001002d000066A0* ID_MODEL_FROM_DATABASE=Vega 20 [Radeon Instinct] pci:v00001002d000066A1* - ID_MODEL_FROM_DATABASE=Vega 20 + ID_MODEL_FROM_DATABASE=Vega 20 WKS GL-XE [Radeon Pro VII] pci:v00001002d000066A2* ID_MODEL_FROM_DATABASE=Vega 20 pci:v00001002d000066A3* - ID_MODEL_FROM_DATABASE=Vega 20 + ID_MODEL_FROM_DATABASE=Vega 20 [Radeon Pro Vega II/Radeon Pro Vega II Duo] pci:v00001002d000066A7* ID_MODEL_FROM_DATABASE=Vega 20 [Radeon Pro Vega 20] @@ -6351,7 +6459,7 @@ pci:v00001002d00006749* ID_MODEL_FROM_DATABASE=Turks GL [FirePro V4900] pci:v00001002d00006749sv000015C3sd00002B06* - ID_MODEL_FROM_DATABASE=Turks GL [FirePro V4900] (MED-X4900) + ID_MODEL_FROM_DATABASE=Turks GL [FirePro V4900] (MED-X4900 (EIZO)) pci:v00001002d0000674A* ID_MODEL_FROM_DATABASE=Turks GL [FirePro V3900] @@ -6438,61 +6546,79 @@ pci:v00001002d00006758sv00001787sd00002309* ID_MODEL_FROM_DATABASE=Turks XT [Radeon HD 6670/7670] (Radeon HD 6670) pci:v00001002d00006759* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] pci:v00001002d00006759sv0000103Csd00003130* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001043sd00000403* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001462sd00002500* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001462sd00002509* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 7570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 7570) pci:v00001002d00006759sv0000148Csd00007570* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 7570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 7570) pci:v00001002d00006759sv00001642sd00003A67* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001682sd00003280* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 7570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 7570) pci:v00001002d00006759sv00001682sd00003530* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 8550) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 8550) + +pci:v00001002d00006759sv00001682sd00005230* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon R5 230 series) + +pci:v00001002d00006759sv00001682sd00006450* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6450 series) pci:v00001002d00006759sv0000174Bsd00007570* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 7570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 7570) + +pci:v00001002d00006759sv0000174Bsd00008550* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD8550 OEM) + +pci:v00001002d00006759sv0000174Bsd00008570* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD8550 OEM) pci:v00001002d00006759sv0000174Bsd0000E142* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv0000174Bsd0000E181* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) + +pci:v00001002d00006759sv00001787sd0000A230* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon R5 230 series) + +pci:v00001002d00006759sv00001787sd0000A450* + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6450 series) pci:v00001002d00006759sv00001B0Asd0000908F* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001B0Asd00009090* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001B0Asd00009091* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001B0Asd00009092* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001B0Asd0000909E* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 6570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 6570) pci:v00001002d00006759sv00001B0Asd000090B5* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 7570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 7570) pci:v00001002d00006759sv00001B0Asd000090B6* - ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550] (Radeon HD 7570) + ID_MODEL_FROM_DATABASE=Turks PRO [Radeon HD 6570/7570/8550 / R5 230] (Radeon HD 7570) pci:v00001002d0000675B* ID_MODEL_FROM_DATABASE=Turks [Radeon HD 7600 Series] @@ -7535,6 +7661,9 @@ pci:v00001002d000067B1sv0000148Csd00002358* pci:v00001002d000067B1sv0000174Bsd0000E324* ID_MODEL_FROM_DATABASE=Hawaii PRO [Radeon R9 290/390] (Sapphire Nitro R9 390) +pci:v00001002d000067B8* + ID_MODEL_FROM_DATABASE=Hawaii XT [Radeon R9 290X Engineering Sample] + pci:v00001002d000067B9* ID_MODEL_FROM_DATABASE=Vesuvius [Radeon R9 295X2] @@ -7637,6 +7766,9 @@ pci:v00001002d000067DFsv00001462sd0000341B* pci:v00001002d000067DFsv00001462sd0000341E* ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 570 Armor 4G OC) +pci:v00001002d000067DFsv00001462sd0000809E* + ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 480 4GB) + pci:v00001002d000067DFsv00001462sd00008A92* ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 580) @@ -7661,6 +7793,9 @@ pci:v00001002d000067DFsv00001682sd00009470* pci:v00001002d000067DFsv00001682sd00009480* ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 480) +pci:v00001002d000067DFsv00001682sd00009587* + ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 590 FATBOY 8GB) + pci:v00001002d000067DFsv00001682sd00009588* ID_MODEL_FROM_DATABASE=Ellesmere [Radeon RX 470/480/570/570X/580/580X/590] (Radeon RX 580 XTR) @@ -8474,9 +8609,24 @@ pci:v00001002d00006867* pci:v00001002d00006868* ID_MODEL_FROM_DATABASE=Vega 10 [Radeon PRO WX 8100/8200] +pci:v00001002d00006869* + ID_MODEL_FROM_DATABASE=Vega 10 XGA [Radeon Pro Vega 48] + +pci:v00001002d0000686A* + ID_MODEL_FROM_DATABASE=Vega 10 LEA + +pci:v00001002d0000686B* + ID_MODEL_FROM_DATABASE=Vega 10 XTXA [Radeon Pro Vega 64X] + pci:v00001002d0000686C* ID_MODEL_FROM_DATABASE=Vega 10 [Radeon Instinct MI25 MxGPU] +pci:v00001002d0000686D* + ID_MODEL_FROM_DATABASE=Vega 10 GLXTA + +pci:v00001002d0000686E* + ID_MODEL_FROM_DATABASE=Vega 10 GLXLA + pci:v00001002d0000687F* ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] @@ -8489,6 +8639,9 @@ pci:v00001002d0000687Fsv00001002sd00006B76* pci:v00001002d0000687Fsv00001458sd0000230C* ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] (Radeon RX VEGA 56 GAMING OC 8G) +pci:v00001002d0000687Fsv00001DA2sd0000E376* + ID_MODEL_FROM_DATABASE=Vega 10 XL/XT [Radeon RX Vega 56/64] (Radeon RX VEGA 56 Pulse 8GB OC HBM2) + pci:v00001002d00006880* ID_MODEL_FROM_DATABASE=Lexington [Radeon HD 6550M] @@ -9218,6 +9371,9 @@ pci:v00001002d000068D9sv000017AFsd00003010* pci:v00001002d000068DA* ID_MODEL_FROM_DATABASE=Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570] +pci:v00001002d000068DAsv00001462sd00008071* + ID_MODEL_FROM_DATABASE=Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570] (VR5550-MD1G (Radeon HD 5550)) + pci:v00001002d000068DAsv0000148Csd00003000* ID_MODEL_FROM_DATABASE=Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570] (Radeon HD 6390) @@ -10529,12 +10685,18 @@ pci:v00001002d00007310* pci:v00001002d00007312* ID_MODEL_FROM_DATABASE=Navi 10 [Radeon Pro W5700] +pci:v00001002d00007314* + ID_MODEL_FROM_DATABASE=Navi 10 USB + pci:v00001002d0000731F* ID_MODEL_FROM_DATABASE=Navi 10 [Radeon RX 5600 OEM/5600 XT / 5700/5700 XT] pci:v00001002d0000731Fsv00001458sd00002313* ID_MODEL_FROM_DATABASE=Navi 10 [Radeon RX 5600 OEM/5600 XT / 5700/5700 XT] (Radeon RX 5700 XT Gaming OC) +pci:v00001002d0000731Fsv00001682sd00005701* + ID_MODEL_FROM_DATABASE=Navi 10 [Radeon RX 5600 OEM/5600 XT / 5700/5700 XT] (RX 5700 XT RAW II) + pci:v00001002d0000731Fsv00001DA2sd0000E411* ID_MODEL_FROM_DATABASE=Navi 10 [Radeon RX 5600 OEM/5600 XT / 5700/5700 XT] (Radeon RX 5600 XT) @@ -10551,19 +10713,52 @@ pci:v00001002d0000734F* ID_MODEL_FROM_DATABASE=Navi 14 [Radeon Pro W5300M] pci:v00001002d00007360* - ID_MODEL_FROM_DATABASE=Navi 12 [Radeon Pro 5600M] + ID_MODEL_FROM_DATABASE=Navi 12 [Radeon Pro 5600M / V520] + +pci:v00001002d00007362* + ID_MODEL_FROM_DATABASE=Navi 12 [Radeon Pro V520] + +pci:v00001002d00007388* + ID_MODEL_FROM_DATABASE=Arcturus GL-XL + +pci:v00001002d0000738C* + ID_MODEL_FROM_DATABASE=Arcturus GL-XL [AMD Instinct MI100] + +pci:v00001002d0000738E* + ID_MODEL_FROM_DATABASE=Arcturus GL-XL + +pci:v00001002d000073A4* + ID_MODEL_FROM_DATABASE=Navi 21 USB + +pci:v00001002d000073AF* + ID_MODEL_FROM_DATABASE=Navi 21 [Radeon RX 6900 XT] pci:v00001002d000073BF* ID_MODEL_FROM_DATABASE=Navi 21 [Radeon RX 6800/6800 XT / 6900 XT] +pci:v00001002d000073BFsv00001EAEsd00006701* + ID_MODEL_FROM_DATABASE=Navi 21 [Radeon RX 6800/6800 XT / 6900 XT] (XFX Speedster MERC 319 AMD Radeon RX 6800 XT Black) + pci:v00001002d000073C3* ID_MODEL_FROM_DATABASE=Navi 22 +pci:v00001002d000073C4* + ID_MODEL_FROM_DATABASE=Navi 22 USB + pci:v00001002d000073DF* - ID_MODEL_FROM_DATABASE=Navi 22 + ID_MODEL_FROM_DATABASE=Navi 22 [Radeon RX 6700/6700 XT / 6800M] + +pci:v00001002d000073E0* + ID_MODEL_FROM_DATABASE=Navi 23 + +pci:v00001002d000073E1* + ID_MODEL_FROM_DATABASE=Navi 23 + +pci:v00001002d000073E4* + ID_MODEL_FROM_DATABASE=Navi 23 USB pci:v00001002d000073FF* - ID_MODEL_FROM_DATABASE=Navi 23 + ID_MODEL_FROM_DATABASE=Navi 23 [Radeon RX 6600/6600 XT] pci:v00001002d00007833* ID_MODEL_FROM_DATABASE=RS350 Host Bridge @@ -11171,6 +11366,9 @@ pci:v00001002d000095CF* pci:v00001002d0000960F* ID_MODEL_FROM_DATABASE=RS780 HDMI Audio [Radeon 3000/3100 / HD 3200/3300] +pci:v00001002d0000960Fsv00001462sd00007596* + ID_MODEL_FROM_DATABASE=RS780 HDMI Audio [Radeon 3000/3100 / HD 3200/3300] (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00009610* ID_MODEL_FROM_DATABASE=RS780 [Radeon HD 3200] @@ -11195,6 +11393,9 @@ pci:v00001002d00009615* pci:v00001002d00009616* ID_MODEL_FROM_DATABASE=RS780L [Radeon 3000] +pci:v00001002d00009616sv00001462sd00007501* + ID_MODEL_FROM_DATABASE=RS780L [Radeon 3000] (760GM-E51(MS-7596) Motherboard) + pci:v00001002d00009640* ID_MODEL_FROM_DATABASE=Sumo [Radeon HD 6550D] @@ -11309,6 +11510,9 @@ pci:v00001002d0000980A* pci:v00001002d00009830* ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8400 / R3 Series] +pci:v00001002d00009830sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8400 / R3 Series] (AM1I-A Motherboard) + pci:v00001002d00009831* ID_MODEL_FROM_DATABASE=Kabini [Radeon HD 8400E] @@ -11345,6 +11549,9 @@ pci:v00001002d0000983D* pci:v00001002d00009840* ID_MODEL_FROM_DATABASE=Kabini HDMI/DP Audio +pci:v00001002d00009840sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=Kabini HDMI/DP Audio (AM1I-A Motherboard) + pci:v00001002d00009840sv00001849sd00009840* ID_MODEL_FROM_DATABASE=Kabini HDMI/DP Audio (QC5000-ITX/PH) @@ -12180,13 +12387,13 @@ pci:v00001011d0000000D* ID_MODEL_FROM_DATABASE=PBXGB [TGA2] pci:v00001011d0000000F* - ID_MODEL_FROM_DATABASE=DEFPA FDDI PCI-to-PDQ Interface Chip [PFI] + ID_MODEL_FROM_DATABASE=PCI-to-PDQ Interface Chip [PFI] FDDI (DEFPA) pci:v00001011d0000000Fsv00001011sd0000DEF1* - ID_MODEL_FROM_DATABASE=DEFPA FDDI PCI-to-PDQ Interface Chip [PFI] (FDDI controller (DEFPA)) + ID_MODEL_FROM_DATABASE=PCI-to-PDQ Interface Chip [PFI] FDDI (DEFPA) (FDDIcontroller/PCI (DEFPA)) pci:v00001011d0000000Fsv0000103Csd0000DEF1* - ID_MODEL_FROM_DATABASE=DEFPA FDDI PCI-to-PDQ Interface Chip [PFI] (FDDI controller (3X-DEFPA)) + ID_MODEL_FROM_DATABASE=PCI-to-PDQ Interface Chip [PFI] FDDI (DEFPA) (FDDIcontroller/PCI (3X-DEFPA)) pci:v00001011d00000014* ID_MODEL_FROM_DATABASE=DECchip 21041 [Tulip Pass 3] @@ -12195,7 +12402,7 @@ pci:v00001011d00000014sv00001186sd00000100* ID_MODEL_FROM_DATABASE=DECchip 21041 [Tulip Pass 3] (DE-530+) pci:v00001011d00000016* - ID_MODEL_FROM_DATABASE=DGLPB [OPPO] + ID_MODEL_FROM_DATABASE=ATMworks 350 Adapter [OPPO] (DGLPB) pci:v00001011d00000017* ID_MODEL_FROM_DATABASE=PV-PCI Graphics Controller (ZLXp-L) @@ -13574,6 +13781,9 @@ pci:v00001022d00001451* pci:v00001022d00001452* ID_MODEL_FROM_DATABASE=Family 17h (Models 00h-1fh) PCIe Dummy Host Bridge +pci:v00001022d00001452sv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Family 17h (Models 00h-1fh) PCIe Dummy Host Bridge (mCOM10-L1900) + pci:v00001022d00001453* ID_MODEL_FROM_DATABASE=Family 17h (Models 00h-0fh) PCIe GPP Bridge @@ -13736,6 +13946,9 @@ pci:v00001022d0000149C* pci:v00001022d0000149Csv00001462sd00007C37* ID_MODEL_FROM_DATABASE=Matisse USB 3.0 Host Controller (X570-A PRO motherboard) +pci:v00001022d0000149D* + ID_MODEL_FROM_DATABASE=Vangogh CVIP + pci:v00001022d00001510* ID_MODEL_FROM_DATABASE=Family 14h Processor Root Complex @@ -13778,6 +13991,9 @@ pci:v00001022d00001535* pci:v00001022d00001536* ID_MODEL_FROM_DATABASE=Family 16h Processor Root Complex +pci:v00001022d00001536sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=Family 16h Processor Root Complex (AM1I-A Motherboard) + pci:v00001022d00001536sv00001849sd00001536* ID_MODEL_FROM_DATABASE=Family 16h Processor Root Complex (QC5000-ITX/PH) @@ -13988,12 +14204,21 @@ pci:v00001022d000015D0* pci:v00001022d000015D0sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Raven/Raven2 Root Complex (Pavilion Laptop 15-cw1xxx) +pci:v00001022d000015D0sv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Raven/Raven2 Root Complex (PRIME B450M-A Motherboard) + pci:v00001022d000015D1* ID_MODEL_FROM_DATABASE=Raven/Raven2 IOMMU pci:v00001022d000015D1sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Raven/Raven2 IOMMU (Pavilion Laptop 15-cw1xxx) +pci:v00001022d000015D1sv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Raven/Raven2 IOMMU (PRIME B450M-A Motherboard) + +pci:v00001022d000015D1sv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Raven/Raven2 IOMMU (mCOM10-L1900) + pci:v00001022d000015D2* ID_MODEL_FROM_DATABASE=Raven/Raven2 PCIe Dummy Host Bridge @@ -14012,36 +14237,60 @@ pci:v00001022d000015DA* pci:v00001022d000015DB* ID_MODEL_FROM_DATABASE=Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus A +pci:v00001022d000015DBsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus A (mCOM10-L1900) + pci:v00001022d000015DC* ID_MODEL_FROM_DATABASE=Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus B +pci:v00001022d000015DCsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus B (mCOM10-L1900) + pci:v00001022d000015DE* ID_MODEL_FROM_DATABASE=Raven/Raven2/FireFlight HD Audio Controller pci:v00001022d000015DF* ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) Platform Security Processor +pci:v00001022d000015DFsv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) Platform Security Processor (PRIME Motherboard) + pci:v00001022d000015DFsv000017AAsd00005124* ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) Platform Security Processor (ThinkPad E595) +pci:v00001022d000015DFsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) Platform Security Processor (mCOM10-L1900) + pci:v00001022d000015E0* ID_MODEL_FROM_DATABASE=Raven USB 3.1 pci:v00001022d000015E0sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Raven USB 3.1 (Pavilion Laptop 15-cw1xxx) +pci:v00001022d000015E0sv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Raven USB 3.1 (PRIME Motherboard) + pci:v00001022d000015E0sv000017AAsd00005124* ID_MODEL_FROM_DATABASE=Raven USB 3.1 (ThinkPad E595) +pci:v00001022d000015E0sv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Raven USB 3.1 (mCOM10-L1900) + pci:v00001022d000015E1* ID_MODEL_FROM_DATABASE=Raven USB 3.1 pci:v00001022d000015E1sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Raven USB 3.1 (Pavilion Laptop 15-cw1xxx) +pci:v00001022d000015E1sv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=Raven USB 3.1 (PRIME Motherboard) + pci:v00001022d000015E1sv000017AAsd00005124* ID_MODEL_FROM_DATABASE=Raven USB 3.1 (ThinkPad E595) +pci:v00001022d000015E1sv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=Raven USB 3.1 (mCOM10-L1900) + pci:v00001022d000015E2* ID_MODEL_FROM_DATABASE=Raven/Raven2/FireFlight/Renoir Audio Processor @@ -14054,6 +14303,9 @@ pci:v00001022d000015E3* pci:v00001022d000015E3sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) HD Audio Controller (Pavilion Laptop 15-cw1xxx) +pci:v00001022d000015E3sv00001043sd000086C7* + ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) HD Audio Controller (PRIME B450M-A Motherboard) + pci:v00001022d000015E3sv000017AAsd00005124* ID_MODEL_FROM_DATABASE=Family 17h (Models 10h-1fh) HD Audio Controller (ThinkPad E595) @@ -14258,6 +14510,12 @@ pci:v00001022d00001643* pci:v00001022d00001644* ID_MODEL_FROM_DATABASE=Renoir I2S +pci:v00001022d00001648* + ID_MODEL_FROM_DATABASE=VanGogh Root Complex + +pci:v00001022d00001649* + ID_MODEL_FROM_DATABASE=VanGogh PSP/CCP + pci:v00001022d00001700* ID_MODEL_FROM_DATABASE=Family 12h/14h Processor Function 0 @@ -14379,13 +14637,13 @@ pci:v00001022d00002000sv00004C53sd00001060* ID_MODEL_FROM_DATABASE=79c970 [PCnet32 LANCE] (PC7 mainboard) pci:v00001022d00002001* - ID_MODEL_FROM_DATABASE=79c978 [HomePNA] + ID_MODEL_FROM_DATABASE=Am79C978 PCnet Home (HomePNA) 1/10 PCI Ethernet Adapter [Am79C971 PHY] pci:v00001022d00002001sv00001092sd00000A78* - ID_MODEL_FROM_DATABASE=79c978 [HomePNA] (Multimedia Home Network Adapter) + ID_MODEL_FROM_DATABASE=Am79C978 PCnet Home (HomePNA) 1/10 PCI Ethernet Adapter [Am79C971 PHY] (Multimedia Home Network Adapter) pci:v00001022d00002001sv00001668sd00000299* - ID_MODEL_FROM_DATABASE=79c978 [HomePNA] (ActionLink Home Network Adapter) + ID_MODEL_FROM_DATABASE=Am79C978 PCnet Home (HomePNA) 1/10 PCI Ethernet Adapter [Am79C971 PHY] (ActionLink Home Network Adapter) pci:v00001022d00002003* ID_MODEL_FROM_DATABASE=Am 1771 MBW [Alchemy] @@ -14435,6 +14693,12 @@ pci:v00001022d00002097* pci:v00001022d0000209A* ID_MODEL_FROM_DATABASE=CS5536 [Geode companion] IDE +pci:v00001022d00002625* + ID_MODEL_FROM_DATABASE=Am79C973 [Lance/PCI PCNet/32] + +pci:v00001022d00002627* + ID_MODEL_FROM_DATABASE=Am79C975 [Lance/PCI PCNet/32] + pci:v00001022d00003000* ID_MODEL_FROM_DATABASE=ELanSC520 Microcontroller @@ -14681,6 +14945,9 @@ pci:v00001022d00007801sv0000103Csd0000168B* pci:v00001022d00007801sv0000103Csd0000194E* ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (ProBook 455 G1 Notebook) +pci:v00001022d00007801sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (AM1I-A Motherboard) + pci:v00001022d00007801sv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (Z50-75) @@ -14714,6 +14981,9 @@ pci:v00001022d00007807sv0000103Csd0000194E* pci:v00001022d00007807sv0000103Csd00001985* ID_MODEL_FROM_DATABASE=FCH USB OHCI Controller (Pavilion 17-e163sg Notebook PC) +pci:v00001022d00007807sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=FCH USB OHCI Controller (AM1I-A Motherboard) + pci:v00001022d00007807sv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH USB OHCI Controller (Z50-75) @@ -14729,6 +14999,9 @@ pci:v00001022d00007808sv0000103Csd0000194E* pci:v00001022d00007808sv0000103Csd00001985* ID_MODEL_FROM_DATABASE=FCH USB EHCI Controller (Pavilion 17-e163sg Notebook PC) +pci:v00001022d00007808sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=FCH USB EHCI Controller (AM1I-A Motherboard) + pci:v00001022d00007808sv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH USB EHCI Controller (Z50-75) @@ -14756,6 +15029,9 @@ pci:v00001022d0000780Bsv0000103Csd0000194E* pci:v00001022d0000780Bsv0000103Csd00001985* ID_MODEL_FROM_DATABASE=FCH SMBus Controller (Pavilion 17-e163sg Notebook PC) +pci:v00001022d0000780Bsv00001043sd00008623* + ID_MODEL_FROM_DATABASE=FCH SMBus Controller (AM1I-A Motherboard) + pci:v00001022d0000780Bsv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH SMBus Controller (Z50-75) @@ -14777,6 +15053,9 @@ pci:v00001022d0000780Dsv0000103Csd00001985* pci:v00001022d0000780Dsv00001043sd00008444* ID_MODEL_FROM_DATABASE=FCH Azalia Controller (F2A85-M Series) +pci:v00001022d0000780Dsv00001043sd00008576* + ID_MODEL_FROM_DATABASE=FCH Azalia Controller (AM1I-A Motherboard) + pci:v00001022d0000780Dsv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH Azalia Controller (Z50-75) @@ -14792,6 +15071,9 @@ pci:v00001022d0000780Esv0000103Csd0000194E* pci:v00001022d0000780Esv0000103Csd00001985* ID_MODEL_FROM_DATABASE=FCH LPC Bridge (Pavilion 17-e163sg Notebook PC) +pci:v00001022d0000780Esv00001043sd00008623* + ID_MODEL_FROM_DATABASE=FCH LPC Bridge (AM1I-A Motherboard) + pci:v00001022d0000780Esv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH LPC Bridge (Z50-75) @@ -14816,6 +15098,9 @@ pci:v00001022d00007814sv0000103Csd0000194E* pci:v00001022d00007814sv0000103Csd00001985* ID_MODEL_FROM_DATABASE=FCH USB XHCI Controller (Pavilion 17-e163sg Notebook PC) +pci:v00001022d00007814sv00001043sd00008623* + ID_MODEL_FROM_DATABASE=FCH USB XHCI Controller (AM1I-A Motherboard) + pci:v00001022d00007814sv000017AAsd00003988* ID_MODEL_FROM_DATABASE=FCH USB XHCI Controller (Z50-75) @@ -14831,9 +15116,15 @@ pci:v00001022d00007901* pci:v00001022d00007901sv0000103Csd00008615* ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (Pavilion Laptop 15-cw1xxx) +pci:v00001022d00007901sv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (PRIME Motherboard) + pci:v00001022d00007901sv00001462sd00007C37* ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (X570-A PRO motherboard) +pci:v00001022d00007901sv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=FCH SATA Controller [AHCI mode] (mCOM10-L1900) + pci:v00001022d00007902* ID_MODEL_FROM_DATABASE=FCH SATA Controller [RAID mode] @@ -14855,24 +15146,36 @@ pci:v00001022d0000790B* pci:v00001022d0000790Bsv0000103Csd00008615* ID_MODEL_FROM_DATABASE=FCH SMBus Controller (Pavilion Laptop 15-cw1xxx) +pci:v00001022d0000790Bsv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=FCH SMBus Controller (PRIME Motherboard) + pci:v00001022d0000790Bsv00001462sd00007C37* ID_MODEL_FROM_DATABASE=FCH SMBus Controller (X570-A PRO motherboard) pci:v00001022d0000790Bsv000017AAsd00005124* ID_MODEL_FROM_DATABASE=FCH SMBus Controller (ThinkPad E595) +pci:v00001022d0000790Bsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=FCH SMBus Controller (mCOM10-L1900) + pci:v00001022d0000790E* ID_MODEL_FROM_DATABASE=FCH LPC Bridge pci:v00001022d0000790Esv0000103Csd00008615* ID_MODEL_FROM_DATABASE=FCH LPC Bridge (Pavilion Laptop 15-cw1xxx) +pci:v00001022d0000790Esv00001043sd0000876B* + ID_MODEL_FROM_DATABASE=FCH LPC Bridge (PRIME B450M-A Motherboard) + pci:v00001022d0000790Esv00001462sd00007C37* ID_MODEL_FROM_DATABASE=FCH LPC Bridge (X570-A PRO motherboard) pci:v00001022d0000790Esv000017AAsd00005124* ID_MODEL_FROM_DATABASE=FCH LPC Bridge (ThinkPad E595) +pci:v00001022d0000790Esv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=FCH LPC Bridge (mCOM10-L1900) + pci:v00001022d0000790F* ID_MODEL_FROM_DATABASE=FCH PCI Bridge @@ -16610,6 +16913,9 @@ pci:v00001033d00000035sv00001931sd0000000B* pci:v00001033d00000035sv0000807Dsd00000035* ID_MODEL_FROM_DATABASE=OHCI USB Controller (PCI-USB2 (OHCI subsystem)) +pci:v00001033d00000035sv00008086sd00004D44* + ID_MODEL_FROM_DATABASE=OHCI USB Controller (D850EMV2 motherboard) + pci:v00001033d0000003B* ID_MODEL_FROM_DATABASE=PCI to C-bus Bridge @@ -16700,6 +17006,9 @@ pci:v00001033d000000E0sv00001799sd00000002* pci:v00001033d000000E0sv0000807Dsd00001043* ID_MODEL_FROM_DATABASE=uPD72010x USB 2.0 Controller (PCI-USB2 (EHCI subsystem)) +pci:v00001033d000000E0sv00008086sd00004D44* + ID_MODEL_FROM_DATABASE=uPD72010x USB 2.0 Controller (D850EMV2 motherboard) + pci:v00001033d000000E7* ID_MODEL_FROM_DATABASE=uPD72873 [Firewarden] IEEE1394a OHCI 1.1 Link/2-port PHY Controller @@ -20189,6 +20498,9 @@ pci:v0000106Bd00000004* pci:v0000106Bd00000007* ID_MODEL_FROM_DATABASE=O'Hare I/O +pci:v0000106Bd0000000B* + ID_MODEL_FROM_DATABASE=Apple Camera + pci:v0000106Bd0000000C* ID_MODEL_FROM_DATABASE=DOS on Mac @@ -20696,6 +21008,9 @@ pci:v00001077d00002031sv0000103Csd00001939* pci:v00001077d00002031sv0000103Csd00008002* ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter (3830C 16G Fibre Channel Host Bus Adapter) +pci:v00001077d00002031sv00001077sd00000241* + ID_MODEL_FROM_DATABASE=ISP8324-based 16Gb Fibre Channel to PCI Express Adapter (QLE2670 16Gb Single Port Fibre Channel Adapter) + pci:v00001077d00002071* ID_MODEL_FROM_DATABASE=ISP2714-based 16/32Gb Fibre Channel to PCIe Adapter @@ -20720,6 +21035,15 @@ pci:v00001077d00002081sv00001077sd000002E1* pci:v00001077d00002081sv00001077sd000002E3* ID_MODEL_FROM_DATABASE=ISP2814-based 64/32G Fibre Channel to PCIe Controller (QLE2774 Quad Port 32GFC PCIe Gen4 x16 Adapter) +pci:v00001077d00002089* + ID_MODEL_FROM_DATABASE=ISP2854-based 64/32G Fibre Channel to PCIe Controller with StorCryption + +pci:v00001077d00002089sv00001077sd000002E8* + ID_MODEL_FROM_DATABASE=ISP2854-based 64/32G Fibre Channel to PCIe Controller with StorCryption (QLE2884 Quad Port 64GFC PCIe Gen4 x16 Adapter with StorCryption) + +pci:v00001077d00002089sv00001077sd000002EA* + ID_MODEL_FROM_DATABASE=ISP2854-based 64/32G Fibre Channel to PCIe Controller with StorCryption (QLE2784 Quad Port 32GFC PCIe Gen4 x16 Adapter with StorCryption) + pci:v00001077d00002100* ID_MODEL_FROM_DATABASE=QLA2100 64-bit Fibre Channel Adapter @@ -20780,6 +21104,9 @@ pci:v00001077d00002261sv00001590sd00000204* pci:v00001077d00002261sv00001590sd0000022D* ID_MODEL_FROM_DATABASE=ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter (5830C 32Gb Dual Port Fibre Channel Adapter) +pci:v00001077d00002261sv0000193Dsd0000100D* + ID_MODEL_FROM_DATABASE=ISP2722-based 16/32Gb Fibre Channel to PCIe Adapter (NIC-FC680i-Mb-2x16G) + pci:v00001077d00002281* ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller @@ -20807,6 +21134,21 @@ pci:v00001077d00002281sv00001590sd000002D3* pci:v00001077d00002281sv00001590sd000002D4* ID_MODEL_FROM_DATABASE=ISP2812-based 64/32G Fibre Channel to PCIe Controller (SN1610Q – 2P Enhanced 32GFC Dual Port Fibre Channel Host Bus Adapter) +pci:v00001077d00002289* + ID_MODEL_FROM_DATABASE=ISP2852-based 64/32G Fibre Channel to PCIe Controller with StorCryption + +pci:v00001077d00002289sv00001077sd000002E9* + ID_MODEL_FROM_DATABASE=ISP2852-based 64/32G Fibre Channel to PCIe Controller with StorCryption (QLE2882 Dual Port 64GFC PCIe Gen4 x8 Adapter with StorCryption) + +pci:v00001077d00002289sv00001077sd000002EB* + ID_MODEL_FROM_DATABASE=ISP2852-based 64/32G Fibre Channel to PCIe Controller with StorCryption (QLE2782 Dual Port 32GFC PCIe Gen4 x8 Adapter with StorCryption) + +pci:v00001077d00002289sv00001077sd000002EF* + ID_MODEL_FROM_DATABASE=ISP2852-based 64/32G Fibre Channel to PCIe Controller with StorCryption (QLE2880 Single Port 64GFC PCIe Gen4 x8 Adapter with StorCryption) + +pci:v00001077d00002289sv00001077sd000002F1* + ID_MODEL_FROM_DATABASE=ISP2852-based 64/32G Fibre Channel to PCIe Controller with StorCryption (QLE2780 Single Port 32GFC PCIe Gen4 x8 Adapter with StorCryption) + pci:v00001077d00002300* ID_MODEL_FROM_DATABASE=QLA2300 64-bit Fibre Channel Adapter @@ -21083,6 +21425,12 @@ pci:v00001077d00008070sv00001590sd00000220* pci:v00001077d00008070sv00001590sd000002BD* ID_MODEL_FROM_DATABASE=FastLinQ QL41000 Series 10/25/40/50GbE Controller (10Gb 2P 524SFP+ NIC) +pci:v00001077d00008070sv0000193Dsd00001030* + ID_MODEL_FROM_DATABASE=FastLinQ QL41000 Series 10/25/40/50GbE Controller (NIC-ETH681i-Mb-2x25G) + +pci:v00001077d00008070sv0000193Dsd00001032* + ID_MODEL_FROM_DATABASE=FastLinQ QL41000 Series 10/25/40/50GbE Controller (NIC-ETH682i-Mb-2x25G) + pci:v00001077d00008080* ID_MODEL_FROM_DATABASE=FastLinQ QL41000 Series 10/25/40/50GbE Controller (FCoE) @@ -25331,6 +25679,9 @@ pci:v000010B5d00009050sv000010B5sd00003196* pci:v000010B5d00009050sv000010B5sd00009050* ID_MODEL_FROM_DATABASE=PCI <-> IOBus Bridge (PCI-I04 PCI Passive PC/CAN Interface) +pci:v000010B5d00009050sv000012FEsd00000001* + ID_MODEL_FROM_DATABASE=PCI <-> IOBus Bridge (CAN-PCI/331 CAN bus controller) + pci:v000010B5d00009050sv00001369sd00008901* ID_MODEL_FROM_DATABASE=PCI <-> IOBus Bridge (PCX11+ PCI) @@ -29532,7 +29883,7 @@ pci:v000010DEd00000332* ID_MODEL_FROM_DATABASE=NV35 [GeForce FX 5900XT] pci:v000010DEd00000333* - ID_MODEL_FROM_DATABASE=NV38 [GeForce FX 5950 Ultra] + ID_MODEL_FROM_DATABASE=NV38 [GeForce FX 5950 Ultra / PCX 5950] pci:v000010DEd00000334* ID_MODEL_FROM_DATABASE=NV35 [GeForce FX 5900ZT] @@ -31808,6 +32159,9 @@ pci:v000010DEd00000A22* pci:v000010DEd00000A23* ID_MODEL_FROM_DATABASE=GT216 [GeForce 210] +pci:v000010DEd00000A24* + ID_MODEL_FROM_DATABASE=GT216 [GeForce 405] + pci:v000010DEd00000A26* ID_MODEL_FROM_DATABASE=GT216 [GeForce 405] @@ -35177,6 +35531,9 @@ pci:v000010DEd00001AEC* pci:v000010DEd00001AED* ID_MODEL_FROM_DATABASE=TU116 USB Type-C UCSI Controller +pci:v000010DEd00001AEF* + ID_MODEL_FROM_DATABASE=GA102 High Definition Audio Controller + pci:v000010DEd00001B00* ID_MODEL_FROM_DATABASE=GP102 [TITAN X] @@ -35201,6 +35558,9 @@ pci:v000010DEd00001B30* pci:v000010DEd00001B38* ID_MODEL_FROM_DATABASE=GP102GL [Tesla P40] +pci:v000010DEd00001B39* + ID_MODEL_FROM_DATABASE=GP102GL [Tesla P10] + pci:v000010DEd00001B70* ID_MODEL_FROM_DATABASE=GP102GL @@ -35364,10 +35724,10 @@ pci:v000010DEd00001C31* ID_MODEL_FROM_DATABASE=GP106GL [Quadro P2200] pci:v000010DEd00001C35* - ID_MODEL_FROM_DATABASE=GP106 + ID_MODEL_FROM_DATABASE=GP106M [Quadro P2000 Mobile] pci:v000010DEd00001C36* - ID_MODEL_FROM_DATABASE=GP106 + ID_MODEL_FROM_DATABASE=GP106 [P106M] pci:v000010DEd00001C60* ID_MODEL_FROM_DATABASE=GP106BM [GeForce GTX 1060 Mobile 6GB] @@ -35729,6 +36089,9 @@ pci:v000010DEd00001F09* pci:v000010DEd00001F0A* ID_MODEL_FROM_DATABASE=TU106 [GeForce GTX 1650] +pci:v000010DEd00001F0B* + ID_MODEL_FROM_DATABASE=TU106 [CMP 40HX] + pci:v000010DEd00001F10* ID_MODEL_FROM_DATABASE=TU106M [GeForce RTX 2070 Mobile] @@ -35804,6 +36167,9 @@ pci:v000010DEd00001F99* pci:v000010DEd00001F9C* ID_MODEL_FROM_DATABASE=TU117M [GeForce MX450] +pci:v000010DEd00001F9D* + ID_MODEL_FROM_DATABASE=TU117M [GeForce GTX 1650 Mobile / Max-Q] + pci:v000010DEd00001FAE* ID_MODEL_FROM_DATABASE=TU117GL @@ -35813,6 +36179,9 @@ pci:v000010DEd00001FB8* pci:v000010DEd00001FB9* ID_MODEL_FROM_DATABASE=TU117GLM [Quadro T1000 Mobile] +pci:v000010DEd00001FBB* + ID_MODEL_FROM_DATABASE=TU117GLM [Quadro T500 Mobile] + pci:v000010DEd00001FBF* ID_MODEL_FROM_DATABASE=TU117GL @@ -35828,6 +36197,9 @@ pci:v000010DEd000020B0* pci:v000010DEd000020B1* ID_MODEL_FROM_DATABASE=GA100 [A100 PCIe 40GB] +pci:v000010DEd000020B2* + ID_MODEL_FROM_DATABASE=GA100 [A100 SXM4 80GB] + pci:v000010DEd000020BE* ID_MODEL_FROM_DATABASE=GA100 [GRID A100A] @@ -35852,6 +36224,9 @@ pci:v000010DEd00002187* pci:v000010DEd00002188* ID_MODEL_FROM_DATABASE=TU116 [GeForce GTX 1650] +pci:v000010DEd00002189* + ID_MODEL_FROM_DATABASE=TU116 [CMP 30HX] + pci:v000010DEd00002191* ID_MODEL_FROM_DATABASE=TU116M [GeForce GTX 1660 Ti Mobile] @@ -35864,24 +36239,39 @@ pci:v000010DEd000021AE* pci:v000010DEd000021BF* ID_MODEL_FROM_DATABASE=TU116GL +pci:v000010DEd000021C2* + ID_MODEL_FROM_DATABASE=TU116 + pci:v000010DEd000021C4* ID_MODEL_FROM_DATABASE=TU116 [GeForce GTX 1660 SUPER] pci:v000010DEd000021D1* ID_MODEL_FROM_DATABASE=TU116BM [GeForce GTX 1660 Ti Mobile] +pci:v000010DEd00002200* + ID_MODEL_FROM_DATABASE=GA102 + pci:v000010DEd00002204* ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3090] +pci:v000010DEd00002205* + ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080 20GB] + pci:v000010DEd00002206* ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080] +pci:v000010DEd00002206sv000010DEsd00001467* + ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080] + pci:v000010DEd00002206sv000010DEsd0000146D* ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080] (GA102 [GeForce RTX 3080 20GB]) pci:v000010DEd00002206sv00001462sd00003892* ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080] (RTX 3080 10GB GAMING X TRIO) +pci:v000010DEd00002208* + ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3080 Ti] + pci:v000010DEd0000222B* ID_MODEL_FROM_DATABASE=GA102 [GeForce RTX 3090 Engineering Sample] @@ -35891,9 +36281,30 @@ pci:v000010DEd0000222F* pci:v000010DEd00002230* ID_MODEL_FROM_DATABASE=GA102GL [RTX A6000] +pci:v000010DEd00002231* + ID_MODEL_FROM_DATABASE=GA102GL + +pci:v000010DEd00002235* + ID_MODEL_FROM_DATABASE=GA102GL [RTX A40] + +pci:v000010DEd00002236* + ID_MODEL_FROM_DATABASE=GA102GL + +pci:v000010DEd00002237* + ID_MODEL_FROM_DATABASE=GA102GL + pci:v000010DEd0000223F* ID_MODEL_FROM_DATABASE=GA102GL +pci:v000010DEd0000228B* + ID_MODEL_FROM_DATABASE=GA104 High Definition Audio Controller + +pci:v000010DEd00002302* + ID_MODEL_FROM_DATABASE=GA103 + +pci:v000010DEd00002321* + ID_MODEL_FROM_DATABASE=GA103 + pci:v000010DEd00002482* ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070 Ti] @@ -35910,11 +36321,14 @@ pci:v000010DEd00002486* ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3060 Ti] pci:v000010DEd0000249C* - ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3070 Mobile / Max-Q 8GB/16GB] + ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3080 Mobile / Max-Q 8GB/16GB] pci:v000010DEd0000249D* ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3070 Mobile / Max-Q] +pci:v000010DEd0000249F* + ID_MODEL_FROM_DATABASE=GA104M + pci:v000010DEd000024AC* ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 30x0 Engineering Sample] @@ -35924,18 +36338,51 @@ pci:v000010DEd000024AD* pci:v000010DEd000024AF* ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070 Engineering Sample] +pci:v000010DEd000024B6* + ID_MODEL_FROM_DATABASE=GA104 + +pci:v000010DEd000024B8* + ID_MODEL_FROM_DATABASE=GA104 + pci:v000010DEd000024BF* ID_MODEL_FROM_DATABASE=GA104 [GeForce RTX 3070 Engineering Sample] pci:v000010DEd000024DC* - ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3070 Mobile 16GB] + ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3080 Mobile / Max-Q 8GB/16GB] pci:v000010DEd000024DD* ID_MODEL_FROM_DATABASE=GA104M [GeForce RTX 3070 Mobile / Max-Q] +pci:v000010DEd00002501* + ID_MODEL_FROM_DATABASE=GA106 [GeForce RTX 3060] + +pci:v000010DEd00002503* + ID_MODEL_FROM_DATABASE=GA106 [GeForce RTX 3060] + +pci:v000010DEd00002505* + ID_MODEL_FROM_DATABASE=GA106 + +pci:v000010DEd00002520* + ID_MODEL_FROM_DATABASE=GA106M [GeForce RTX 3060 Mobile / Max-Q] + pci:v000010DEd0000252F* ID_MODEL_FROM_DATABASE=GA106 [GeForce RTX 3060 Engineering Sample] +pci:v000010DEd00002560* + ID_MODEL_FROM_DATABASE=GA106M [GeForce RTX 3060 Mobile / Max-Q] + +pci:v000010DEd00002583* + ID_MODEL_FROM_DATABASE=GA107 [GeForce RTX 3050] + +pci:v000010DEd000025A0* + ID_MODEL_FROM_DATABASE=GA107M [GeForce RTX 3050 Ti Mobile] + +pci:v000010DEd000025A2* + ID_MODEL_FROM_DATABASE=GA107M [GeForce RTX 3050 Mobile] + +pci:v000010DEd000025A4* + ID_MODEL_FROM_DATABASE=GA107 + pci:v000010DEd000025AF* ID_MODEL_FROM_DATABASE=GA107 [GeForce RTX 3050 Engineering Sample] @@ -36119,6 +36566,9 @@ pci:v000010DFd0000E300sv00001590sd00000214* pci:v000010DFd0000E300sv00001590sd0000022E* ID_MODEL_FROM_DATABASE=LPe31000/LPe32000 Series 16Gb/32Gb Fibre Channel Adapter (Synergy 5330C 2-Port 32Gb Fibre Channel Mezz Card) +pci:v000010DFd0000E300sv0000193Dsd00001060* + ID_MODEL_FROM_DATABASE=LPe31000/LPe32000 Series 16Gb/32Gb Fibre Channel Adapter (NIC-FC730i-Mb-2P) + pci:v000010DFd0000F011* ID_MODEL_FROM_DATABASE=Saturn: LightPulse Fibre Channel Host Adapter @@ -36221,6 +36671,9 @@ pci:v000010DFd0000F400sv00001590sd000002D5* pci:v000010DFd0000F400sv00001590sd000002D6* ID_MODEL_FROM_DATABASE=LPe35000/LPe36000 Series 32Gb/64Gb Fibre Channel Adapter (StoreFabric SN1610E 2-Port 32Gb Fibre Channel Adapter) +pci:v000010DFd0000F500* + ID_MODEL_FROM_DATABASE=LPe37000/LPe38000 Series 32Gb/64Gb Fibre Channel Adapter + pci:v000010DFd0000F700* ID_MODEL_FROM_DATABASE=LP7000 Fibre Channel Host Adapter @@ -36536,6 +36989,9 @@ pci:v000010EC* pci:v000010ECd00000139* ID_MODEL_FROM_DATABASE=RTL-8139/8139C/8139C+ Ethernet Controller +pci:v000010ECd00003000* + ID_MODEL_FROM_DATABASE=Killer E3000 2.5GbE Controller + pci:v000010ECd00005208* ID_MODEL_FROM_DATABASE=RTS5208 PCI Express Card Reader @@ -36602,6 +37058,9 @@ pci:v000010ECd0000525Asv00001028sd000006DC* pci:v000010ECd0000525Asv00001028sd000006E4* ID_MODEL_FROM_DATABASE=RTS525A PCI Express Card Reader (XPS 15 9550) +pci:v000010ECd0000525Asv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=RTS525A PCI Express Card Reader (Latitude 11 5175 2-in-1) + pci:v000010ECd0000525Asv000017AAsd0000224F* ID_MODEL_FROM_DATABASE=RTS525A PCI Express Card Reader (ThinkPad X1 Carbon 5th Gen) @@ -36845,6 +37304,12 @@ pci:v000010ECd00008139sv00008E2Esd00007100* pci:v000010ECd00008139sv0000A0A0sd00000007* ID_MODEL_FROM_DATABASE=RTL-8100/8101L/8139 PCI Fast Ethernet Adapter (ALN-325C) +pci:v000010ECd00008161* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller + +pci:v000010ECd00008161sv000010ECsd00008168* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (TP-Link TG-3468 v4.0 Gigabit PCI Express Network Adapter) + pci:v000010ECd00008167* ID_MODEL_FROM_DATABASE=RTL-8110SC/8169SC Gigabit Ethernet @@ -36878,6 +37343,9 @@ pci:v000010ECd00008168sv00001028sd000004B2* pci:v000010ECd00008168sv00001028sd000004DA* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Vostro 3750) +pci:v000010ECd00008168sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Alienware X51 R2) + pci:v000010ECd00008168sv00001028sd000006F2* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Latitude 3470) @@ -36923,6 +37391,15 @@ pci:v000010ECd00008168sv00001043sd00008432* pci:v000010ECd00008168sv00001043sd00008505* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (P8 series motherboard) +pci:v000010ECd00008168sv00001043sd00008554* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (H81M-C Motherboard) + +pci:v000010ECd00008168sv00001043sd0000859E* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (AM1I-A Motherboard) + +pci:v000010ECd00008168sv00001043sd00008677* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (PRIME B450M-A Motherboard) + pci:v000010ECd00008168sv0000105Bsd00000D7C* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (D270S/D250S Motherboard) @@ -36956,6 +37433,9 @@ pci:v000010ECd00008168sv00001462sd00007C37* pci:v000010ECd00008168sv00001775sd000011CC* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (CC11/CL11) +pci:v000010ECd00008168sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (ThinkCentre E73) + pci:v000010ECd00008168sv000017AAsd00003814* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Z50-75) @@ -36977,6 +37457,9 @@ pci:v000010ECd00008168sv00008086sd00002055* pci:v000010ECd00008168sv00008086sd0000D615* ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (Desktop Board D510MO/D525MW) +pci:v000010ECd00008168sv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller (mCOM10-L1900) + pci:v000010ECd00008169* ID_MODEL_FROM_DATABASE=RTL8169 PCI Gigabit Ethernet Controller @@ -37025,6 +37508,30 @@ pci:v000010ECd00008169sv00001734sd00001091* pci:v000010ECd00008169sv0000A0A0sd00000449* ID_MODEL_FROM_DATABASE=RTL8169 PCI Gigabit Ethernet Controller (AK86-L motherboard) +pci:v000010ECd0000816A* + ID_MODEL_FROM_DATABASE=RTL8111xP UART #1 + +pci:v000010ECd0000816Asv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=RTL8111xP UART #1 (mCOM10-L1900) + +pci:v000010ECd0000816B* + ID_MODEL_FROM_DATABASE=RTL8111xP UART #2 + +pci:v000010ECd0000816Bsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=RTL8111xP UART #2 (mCOM10-L1900) + +pci:v000010ECd0000816C* + ID_MODEL_FROM_DATABASE=RTL8111xP IPMI interface + +pci:v000010ECd0000816Csv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=RTL8111xP IPMI interface (mCOM10-L1900) + +pci:v000010ECd0000816D* + ID_MODEL_FROM_DATABASE=RTL811x EHCI host controller + +pci:v000010ECd0000816Dsv0000EA50sd0000CE19* + ID_MODEL_FROM_DATABASE=RTL811x EHCI host controller (mCOM10-L1900) + pci:v000010ECd00008171* ID_MODEL_FROM_DATABASE=RTL8191SEvA Wireless LAN Controller @@ -37211,6 +37718,9 @@ pci:v000010EEd00007038* pci:v000010EEd00007038sv000017AAsd0000402F* ID_MODEL_FROM_DATABASE=FPGA Card XC7VX690T (FPGA XC7VX690T-3FFG1157E) +pci:v000010EEd00008019* + ID_MODEL_FROM_DATABASE=Memory controller + pci:v000010EEd00008380* ID_MODEL_FROM_DATABASE=Ellips ProfiXpress Profibus Master @@ -38034,7 +38544,7 @@ pci:v00001106d00000351* ID_MODEL_FROM_DATABASE=K8T890CF Host Bridge pci:v00001106d00000353* - ID_MODEL_FROM_DATABASE=VX800 Host Bridge + ID_MODEL_FROM_DATABASE=VX800/820-Series Chipset Host-Bridge Controller pci:v00001106d00000364* ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge @@ -38049,7 +38559,7 @@ pci:v00001106d00000409* ID_MODEL_FROM_DATABASE=VX855/VX875 Host Bridge: Host Control pci:v00001106d00000410* - ID_MODEL_FROM_DATABASE=VX900 Host Bridge: Host Control + ID_MODEL_FROM_DATABASE=VX900 Series Host Bridge: Host Control pci:v00001106d00000415* ID_MODEL_FROM_DATABASE=VT6415 PATA IDE Host Controller @@ -38124,10 +38634,10 @@ pci:v00001106d00000576* ID_MODEL_FROM_DATABASE=VT82C576 3V [Apollo Master] pci:v00001106d00000581* - ID_MODEL_FROM_DATABASE=CX700/VX700 RAID Controller + ID_MODEL_FROM_DATABASE=CX700/VX700/VX800/820-Series Serial ATA RAID-Controller pci:v00001106d00000581sv00001106sd00000581* - ID_MODEL_FROM_DATABASE=CX700/VX700 RAID Controller (Wrong IDE ID) + ID_MODEL_FROM_DATABASE=CX700/VX700/VX800/820-Series Serial ATA RAID-Controller (Wrong IDE ID) pci:v00001106d00000585* ID_MODEL_FROM_DATABASE=VT82C585VP [Apollo VP1/VPX] @@ -38295,7 +38805,7 @@ pci:v00001106d00001314* ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge pci:v00001106d00001324* - ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + ID_MODEL_FROM_DATABASE=CX700/VX700-Series Error Reporting pci:v00001106d00001327* ID_MODEL_FROM_DATABASE=P4M890 Host Bridge @@ -38319,7 +38829,7 @@ pci:v00001106d00001409* ID_MODEL_FROM_DATABASE=VX855/VX875 Error Reporting pci:v00001106d00001410* - ID_MODEL_FROM_DATABASE=VX900 Error Reporting + ID_MODEL_FROM_DATABASE=VX900 Series Error Reporting pci:v00001106d00001571* ID_MODEL_FROM_DATABASE=VT82C576M/VT82C586 @@ -38370,7 +38880,7 @@ pci:v00001106d00002314* ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge pci:v00001106d00002324* - ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + ID_MODEL_FROM_DATABASE=CX700/VX700-Series Host Interface Control pci:v00001106d00002327* ID_MODEL_FROM_DATABASE=P4M890 Host Bridge @@ -38394,7 +38904,7 @@ pci:v00001106d00002409* ID_MODEL_FROM_DATABASE=VX855/VX875 Host Bus Control pci:v00001106d00002410* - ID_MODEL_FROM_DATABASE=VX900 CPU Bus Controller + ID_MODEL_FROM_DATABASE=VX900 Series CPU Bus Controller pci:v00001106d0000287A* ID_MODEL_FROM_DATABASE=VT8251 PCI to PCI Bridge @@ -38415,64 +38925,67 @@ pci:v00001106d00003022* ID_MODEL_FROM_DATABASE=CLE266 pci:v00001106d00003038* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller pci:v00001106d00003038sv00000925sd00001234* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (onboard UHCI USB 1.1 Controller) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (onboard UHCI USB 1.1 Controller) pci:v00001106d00003038sv00001019sd00000985* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (P6VXA Motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (P6VXA Motherboard) pci:v00001106d00003038sv00001019sd00000A81* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (L7VTA v1.0 Motherboard (KT400-8235)) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (L7VTA v1.0 Motherboard (KT400-8235)) pci:v00001106d00003038sv00001043sd00008080* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (A7V333 motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (A7V333 motherboard) pci:v00001106d00003038sv00001043sd0000808C* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (VT6202 USB2.0 4 port controller) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (VT62xx USB1.1 4 port controller) pci:v00001106d00003038sv00001043sd000080A1* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (A7V8X-X motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (A7V8X-X motherboard) pci:v00001106d00003038sv00001043sd000080ED* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (A7V600/K8V-X/A8V Deluxe motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (A7V600/K8V-X/A8V Deluxe motherboard) pci:v00001106d00003038sv00001179sd00000001* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (Magnia Z310) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (Magnia Z310) + +pci:v00001106d00003038sv00001234sd00000925* + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (MVP3 USB Controller) pci:v00001106d00003038sv00001458sd00005004* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (GA-7VAX Mainboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (GA-7VAX Mainboard) pci:v00001106d00003038sv00001462sd00005901* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (KT6 Delta-FIS2R (MS-6590)) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (KT6 Delta-FIS2R (MS-6590)) pci:v00001106d00003038sv00001462sd00007020* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (K8T NEO 2 motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (K8T NEO 2 motherboard) pci:v00001106d00003038sv00001462sd00007094* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (K8T Neo2-F V2.0) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (K8T Neo2-F V2.0) pci:v00001106d00003038sv00001462sd00007120* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (KT4AV motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (KT4AV motherboard) pci:v00001106d00003038sv00001462sd00007181* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (K8MM3-V mainboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (K8MM3-V mainboard) pci:v00001106d00003038sv0000147Bsd00001407* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (KV8-MAX3 motherboard) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (KV8-MAX3 motherboard) pci:v00001106d00003038sv0000182Dsd0000201D* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (CN-029 USB2.0 4 port PCI Card) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (CN-029 USB2.0 4 port PCI Card) pci:v00001106d00003038sv00001849sd00003038* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (K7VT series Motherboards) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (K7VT series Motherboards) pci:v00001106d00003038sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (ZBOX nano VD01) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (ZBOX nano VD01) pci:v00001106d00003038sv00001AF4sd00001100* - ID_MODEL_FROM_DATABASE=VT82xx/62xx UHCI USB 1.1 Controller (QEMU Virtual Machine) + ID_MODEL_FROM_DATABASE=VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller (QEMU Virtual Machine) pci:v00001106d00003040* ID_MODEL_FROM_DATABASE=VT82C586B ACPI @@ -38781,58 +39294,58 @@ pci:v00001106d00003103* ID_MODEL_FROM_DATABASE=VT8615 Host Bridge pci:v00001106d00003104* - ID_MODEL_FROM_DATABASE=USB 2.0 + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller pci:v00001106d00003104sv00000925sd00001234* - ID_MODEL_FROM_DATABASE=USB 2.0 (onboard EHCI USB 2.0 Controller) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (onboard EHCI USB 2.0 Controller) pci:v00001106d00003104sv00001019sd00000A81* - ID_MODEL_FROM_DATABASE=USB 2.0 (L7VTA v1.0 Motherboard (KT400-8235)) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (L7VTA v1.0 Motherboard (KT400-8235)) pci:v00001106d00003104sv00001043sd0000808C* - ID_MODEL_FROM_DATABASE=USB 2.0 (A7V8X motherboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (A7V8X motherboard) pci:v00001106d00003104sv00001043sd000080A1* - ID_MODEL_FROM_DATABASE=USB 2.0 (A7V8X-X motherboard rev 1.01) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (A7V8X-X motherboard rev 1.01) pci:v00001106d00003104sv00001043sd000080ED* - ID_MODEL_FROM_DATABASE=USB 2.0 (A7V600/K8V-X/A8V Deluxe motherboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (A7V600/K8V-X/A8V Deluxe motherboard) pci:v00001106d00003104sv00001106sd00003104* - ID_MODEL_FROM_DATABASE=USB 2.0 (Controller) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (USB 2.0 Controller) pci:v00001106d00003104sv00001297sd0000F641* - ID_MODEL_FROM_DATABASE=USB 2.0 (FX41 motherboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (FX41 motherboard) pci:v00001106d00003104sv00001458sd00005004* - ID_MODEL_FROM_DATABASE=USB 2.0 (GA-7VAX Mainboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (GA-7VAX Mainboard) pci:v00001106d00003104sv00001462sd00005901* - ID_MODEL_FROM_DATABASE=USB 2.0 (KT6 Delta-FIS2R (MS-6590)) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (KT6 Delta-FIS2R (MS-6590)) pci:v00001106d00003104sv00001462sd00007020* - ID_MODEL_FROM_DATABASE=USB 2.0 (K8T NEO 2 motherboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (K8T NEO 2 motherboard) pci:v00001106d00003104sv00001462sd00007094* - ID_MODEL_FROM_DATABASE=USB 2.0 (K8T Neo2-F V2.0) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (K8T Neo2-F V2.0) pci:v00001106d00003104sv00001462sd00007120* - ID_MODEL_FROM_DATABASE=USB 2.0 (KT4AV motherboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (KT4AV motherboard) pci:v00001106d00003104sv00001462sd00007181* - ID_MODEL_FROM_DATABASE=USB 2.0 (K8MM3-V mainboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (K8MM3-V mainboard) pci:v00001106d00003104sv0000147Bsd00001407* - ID_MODEL_FROM_DATABASE=USB 2.0 (KV8-MAX3 motherboard) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (KV8-MAX3 motherboard) pci:v00001106d00003104sv0000182Dsd0000201D* - ID_MODEL_FROM_DATABASE=USB 2.0 (CN-029 USB 2.0 4 port PCI Card) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (CN-029 USB 2.0 4 port PCI Card) pci:v00001106d00003104sv00001849sd00003104* - ID_MODEL_FROM_DATABASE=USB 2.0 (K7VT series Motherboards) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (K7VT series Motherboards) pci:v00001106d00003104sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=USB 2.0 (ZBOX nano VD01) + ID_MODEL_FROM_DATABASE=USB 2.0 EHCI-Compliant Host-Controller (ZBOX nano VD01) pci:v00001106d00003106* ID_MODEL_FROM_DATABASE=VT6105/VT6106S [Rhine-III] @@ -39111,10 +39624,10 @@ pci:v00001106d00003287* ID_MODEL_FROM_DATABASE=VT8251 PCI to ISA Bridge pci:v00001106d00003288* - ID_MODEL_FROM_DATABASE=VT8237A/VT8251 HDA Controller + ID_MODEL_FROM_DATABASE=VX900/VT8xxx High Definition Audio Controller pci:v00001106d00003288sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VT8237A/VT8251 HDA Controller (ZBOX VD01) + ID_MODEL_FROM_DATABASE=VX900/VT8xxx High Definition Audio Controller (ZBOX VD01) pci:v00001106d00003290* ID_MODEL_FROM_DATABASE=K8M890 Host Bridge @@ -39123,7 +39636,7 @@ pci:v00001106d00003296* ID_MODEL_FROM_DATABASE=P4M800 Host Bridge pci:v00001106d00003324* - ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + ID_MODEL_FROM_DATABASE=CX700/VX700-Series DRAM Bus Control pci:v00001106d00003327* ID_MODEL_FROM_DATABASE=P4M890 Host Bridge @@ -39150,11 +39663,14 @@ pci:v00001106d00003351* ID_MODEL_FROM_DATABASE=VT3351 Host Bridge pci:v00001106d00003353* - ID_MODEL_FROM_DATABASE=VX800 PCI to PCI Bridge + ID_MODEL_FROM_DATABASE=VX800/820 PCI to PCI Bridge pci:v00001106d00003364* ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 Host Bridge +pci:v00001106d00003365* + ID_MODEL_FROM_DATABASE=VT630x IEEE 1394 Host Controller [Fire II/M] + pci:v00001106d00003371* ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 [Chrome 9 HC] @@ -39180,13 +39696,13 @@ pci:v00001106d00003409* ID_MODEL_FROM_DATABASE=VX855/VX875 DRAM Bus Control pci:v00001106d00003410* - ID_MODEL_FROM_DATABASE=VX900 DRAM Bus Control + ID_MODEL_FROM_DATABASE=VX900 Series DRAM Bus Control pci:v00001106d00003410sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VX900 DRAM Bus Control (ZBOX nano VD01) + ID_MODEL_FROM_DATABASE=VX900 Series DRAM Bus Control (ZBOX nano VD01) pci:v00001106d00003432* - ID_MODEL_FROM_DATABASE=VL80x xHCI USB 3.0 Controller + ID_MODEL_FROM_DATABASE=VL800/801 xHCI USB 3.0 Controller pci:v00001106d00003456* ID_MODEL_FROM_DATABASE=VX11 Standard Host Bridge @@ -39195,7 +39711,7 @@ pci:v00001106d0000345B* ID_MODEL_FROM_DATABASE=VX11 Miscellaneous Bus pci:v00001106d00003483* - ID_MODEL_FROM_DATABASE=VL805 USB 3.0 Host Controller + ID_MODEL_FROM_DATABASE=VL805/806 xHCI USB 3.0 Controller pci:v00001106d00003A01* ID_MODEL_FROM_DATABASE=VX11 Graphics [Chrome 645/640] @@ -39240,7 +39756,7 @@ pci:v00001106d00004314* ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge pci:v00001106d00004324* - ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + ID_MODEL_FROM_DATABASE=CX700/VX700-Series Power Management and Testing Control pci:v00001106d00004327* ID_MODEL_FROM_DATABASE=P4M890 Host Bridge @@ -39264,10 +39780,10 @@ pci:v00001106d00004409* ID_MODEL_FROM_DATABASE=VX855/VX875 Power Management Control pci:v00001106d00004410* - ID_MODEL_FROM_DATABASE=VX900 Power Management and Chip Testing Control + ID_MODEL_FROM_DATABASE=VX900 Series Power Management and Chip Testing Control pci:v00001106d00004410sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VX900 Power Management and Chip Testing Control (ZBOX nano VD01) + ID_MODEL_FROM_DATABASE=VX900 Series Power Management and Chip Testing Control (ZBOX nano VD01) pci:v00001106d00005030* ID_MODEL_FROM_DATABASE=VT82C596 ACPI [Apollo PRO] @@ -39291,7 +39807,7 @@ pci:v00001106d00005308* ID_MODEL_FROM_DATABASE=PT894 I/O APIC Interrupt Controller pci:v00001106d00005324* - ID_MODEL_FROM_DATABASE=VX800 Serial ATA and EIDE Controller + ID_MODEL_FROM_DATABASE=CX700M2/VX700/VX800/820-Series Serial ATA & EIDE-Controller pci:v00001106d00005327* ID_MODEL_FROM_DATABASE=P4M890 I/O APIC Interrupt Controller @@ -39318,7 +39834,7 @@ pci:v00001106d00005409* ID_MODEL_FROM_DATABASE=VX855/VX875 APIC and Central Traffic Control pci:v00001106d00005410* - ID_MODEL_FROM_DATABASE=VX900 APIC and Central Traffic Control + ID_MODEL_FROM_DATABASE=VX900 Series APIC and Central Traffic Control pci:v00001106d00006100* ID_MODEL_FROM_DATABASE=VT85C100A [Rhine II] @@ -39342,10 +39858,10 @@ pci:v00001106d00006409* ID_MODEL_FROM_DATABASE=VX855/VX875 Scratch Registers pci:v00001106d00006410* - ID_MODEL_FROM_DATABASE=VX900 Scratch Registers + ID_MODEL_FROM_DATABASE=VX900 Series Scratch Registers pci:v00001106d00006410sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VX900 Scratch Registers (ZBOX nano VD01) + ID_MODEL_FROM_DATABASE=VX900 Series Scratch Registers (ZBOX nano VD01) pci:v00001106d00007122* ID_MODEL_FROM_DATABASE=VX900 Graphics [Chrome9 HD] @@ -39396,7 +39912,7 @@ pci:v00001106d00007314* ID_MODEL_FROM_DATABASE=CN700/VN800/P4M800CE/Pro Host Bridge pci:v00001106d00007324* - ID_MODEL_FROM_DATABASE=CX700/VX700 Host Bridge + ID_MODEL_FROM_DATABASE=CX700/VX700-Series North-South Module Interface Control pci:v00001106d00007327* ID_MODEL_FROM_DATABASE=P4M890 Host Bridge @@ -39420,10 +39936,10 @@ pci:v00001106d00007409* ID_MODEL_FROM_DATABASE=VX855/VX875 North-South Module Interface Control pci:v00001106d00007410* - ID_MODEL_FROM_DATABASE=VX900 North-South Module Interface Control + ID_MODEL_FROM_DATABASE=VX900 Series North-South Module Interface Control pci:v00001106d00007410sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VX900 North-South Module Interface Control (ZBOX nano VD01) + ID_MODEL_FROM_DATABASE=VX900 Series North-South Module Interface Control (ZBOX nano VD01) pci:v00001106d00008231* ID_MODEL_FROM_DATABASE=VT8231 [PCI-to-ISA Bridge] @@ -39435,7 +39951,7 @@ pci:v00001106d00008305* ID_MODEL_FROM_DATABASE=VT8363/8365 [KT133/KM133 AGP] pci:v00001106d00008324* - ID_MODEL_FROM_DATABASE=CX700/VX700 PCI to ISA Bridge + ID_MODEL_FROM_DATABASE=CX700/VX700-Series Bus Control and Power Management pci:v00001106d00008353* ID_MODEL_FROM_DATABASE=VX800/VX820 Bus Control and Power Management @@ -39450,10 +39966,10 @@ pci:v00001106d00008409* ID_MODEL_FROM_DATABASE=VX855/VX875 Bus Control and Power Management pci:v00001106d00008410* - ID_MODEL_FROM_DATABASE=VX900 Bus Control and Power Management + ID_MODEL_FROM_DATABASE=VX900 Series Bus Control and Power Management pci:v00001106d00008410sv000019DAsd0000A179* - ID_MODEL_FROM_DATABASE=VX900 Bus Control and Power Management (ZBOX VD01) + ID_MODEL_FROM_DATABASE=VX900 Series Bus Control and Power Management (ZBOX VD01) pci:v00001106d00008500* ID_MODEL_FROM_DATABASE=KLE133/PLE133/PLE133T @@ -39498,7 +40014,7 @@ pci:v00001106d00008D04* ID_MODEL_FROM_DATABASE=KM266/P4M266/P4M266A/P4N266 [S3 ProSavageDDR] pci:v00001106d00009001* - ID_MODEL_FROM_DATABASE=VX900 Serial ATA Controller + ID_MODEL_FROM_DATABASE=VX900 Series Serial-ATA Controller pci:v00001106d00009082* ID_MODEL_FROM_DATABASE=Standard AHCI 1.0 SATA Controller @@ -39510,10 +40026,10 @@ pci:v00001106d00009201* ID_MODEL_FROM_DATABASE=USB3.0 Controller pci:v00001106d00009530* - ID_MODEL_FROM_DATABASE=Secure Digital Memory Card Controller + ID_MODEL_FROM_DATABASE=VX800/820/900 Series Secure Digital Memory Card Controller pci:v00001106d000095D0* - ID_MODEL_FROM_DATABASE=SDIO Host Controller + ID_MODEL_FROM_DATABASE=VX800/820/900 Series SDIO Host Controller pci:v00001106d0000A208* ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller @@ -39525,16 +40041,16 @@ pci:v00001106d0000A327* ID_MODEL_FROM_DATABASE=P4M890 PCI to PCI Bridge Controller pci:v00001106d0000A353* - ID_MODEL_FROM_DATABASE=VX8xx South-North Module Interface Control + ID_MODEL_FROM_DATABASE=VX8xx/900 Series South-North Module Interface Control pci:v00001106d0000A364* ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 PCI to PCI Bridge Controller pci:v00001106d0000A409* - ID_MODEL_FROM_DATABASE=VX855/VX875 USB Device Controller + ID_MODEL_FROM_DATABASE=VX855/VX875/VX900 Series USB Device Controller pci:v00001106d0000A410* - ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 0 + ID_MODEL_FROM_DATABASE=VX900 Series PCI Express Root Port 0 pci:v00001106d0000B091* ID_MODEL_FROM_DATABASE=VT8633 [Apollo Pro266 AGP] @@ -39570,7 +40086,7 @@ pci:v00001106d0000B188sv0000147Bsd00001407* ID_MODEL_FROM_DATABASE=VT8237/8251 PCI bridge [K8M890/K8T800/K8T890 South] (KV8-MAX3 motherboard) pci:v00001106d0000B198* - ID_MODEL_FROM_DATABASE=VT8237/VX700 PCI Bridge + ID_MODEL_FROM_DATABASE=VT8237/CX700/VX700-Series PCI to PCI Bridge pci:v00001106d0000B213* ID_MODEL_FROM_DATABASE=VPX/VPX2 I/O APIC Interrupt Controller @@ -39579,7 +40095,7 @@ pci:v00001106d0000B353* ID_MODEL_FROM_DATABASE=VX855/VX875/VX900 PCI to PCI Bridge pci:v00001106d0000B410* - ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 1 + ID_MODEL_FROM_DATABASE=VX900 Series PCI Express Root Port 1 pci:v00001106d0000B999* ID_MODEL_FROM_DATABASE=[K8T890 North / VT8237 South] PCI Bridge @@ -39597,7 +40113,7 @@ pci:v00001106d0000C340* ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller pci:v00001106d0000C353* - ID_MODEL_FROM_DATABASE=VX800/VX820 PCI Express Root Port + ID_MODEL_FROM_DATABASE=VX800/820-Series PCI-Express Root (PCI-to-PCI Virtual Bridge) pci:v00001106d0000C364* ID_MODEL_FROM_DATABASE=CN896/VN896/P4M900 PCI to PCI Bridge Controller @@ -39606,7 +40122,7 @@ pci:v00001106d0000C409* ID_MODEL_FROM_DATABASE=VX855/VX875 EIDE Controller pci:v00001106d0000C410* - ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 2 + ID_MODEL_FROM_DATABASE=VX900 Series PCI Express Root Port 2 pci:v00001106d0000D104* ID_MODEL_FROM_DATABASE=VT8237R USB UDCI Controller @@ -39624,7 +40140,7 @@ pci:v00001106d0000D340* ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller pci:v00001106d0000D410* - ID_MODEL_FROM_DATABASE=VX900 PCI Express Root Port 3 + ID_MODEL_FROM_DATABASE=VX900 Series PCI Express Root Port 3 pci:v00001106d0000E208* ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller @@ -39636,10 +40152,10 @@ pci:v00001106d0000E340* ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller pci:v00001106d0000E353* - ID_MODEL_FROM_DATABASE=VX800/VX820 PCI Express Root Port + ID_MODEL_FROM_DATABASE=VX800/820-Series PCI-Express Root Port 0 pci:v00001106d0000E410* - ID_MODEL_FROM_DATABASE=VX900 PCI Express Physical Layer Electrical Sub-block + ID_MODEL_FROM_DATABASE=VX900 Series PCI Express Physical Layer Electrical Sub-block pci:v00001106d0000F208* ID_MODEL_FROM_DATABASE=PT890 PCI to PCI Bridge Controller @@ -39651,7 +40167,10 @@ pci:v00001106d0000F340* ID_MODEL_FROM_DATABASE=PT900 PCI to PCI Bridge Controller pci:v00001106d0000F353* - ID_MODEL_FROM_DATABASE=VX800/VX820 PCI Express Root Port + ID_MODEL_FROM_DATABASE=VX800/820-Series PCI-Express Root Port 1 + +pci:v00001106d0000F410* + ID_MODEL_FROM_DATABASE=VX900 Series PCI UART Port 0-3 pci:v00001107* ID_VENDOR_FROM_DATABASE=Stratus Computers @@ -41532,7 +42051,7 @@ pci:v00001134d0000000D* ID_MODEL_FROM_DATABASE=POET PSDMS Device pci:v00001135* - ID_VENDOR_FROM_DATABASE=Fuji Xerox Co Ltd + ID_VENDOR_FROM_DATABASE=FUJIFILM Business Innovation Corp. pci:v00001135d00000001* ID_MODEL_FROM_DATABASE=Printer controller @@ -42938,6 +43457,9 @@ pci:v00001172d000000A7* pci:v00001172d00000530* ID_MODEL_FROM_DATABASE=Stratix IV +pci:v00001172d0000646C* + ID_MODEL_FROM_DATABASE=KT-500/KT-521 board + pci:v00001173* ID_VENDOR_FROM_DATABASE=Adobe Systems, Inc @@ -42968,6 +43490,9 @@ pci:v00001179d00000102* pci:v00001179d00000103* ID_MODEL_FROM_DATABASE=EX-IDE Type-B +pci:v00001179d0000010E* + ID_MODEL_FROM_DATABASE=PXP04 NVMe SSD + pci:v00001179d0000010F* ID_MODEL_FROM_DATABASE=NVMe Controller @@ -43001,9 +43526,15 @@ pci:v00001179d00000110sv00001D49sd0000403A* pci:v00001179d00000113* ID_MODEL_FROM_DATABASE=BG3 NVMe SSD Controller +pci:v00001179d00000113sv00001179sd00000001* + ID_MODEL_FROM_DATABASE=BG3 NVMe SSD Controller (Toshiba KBG30ZMS128G 128GB NVMe SSD) + pci:v00001179d00000115* ID_MODEL_FROM_DATABASE=XG4 NVMe SSD Controller +pci:v00001179d0000011A* + ID_MODEL_FROM_DATABASE=XG6 NVMe SSD Controller + pci:v00001179d00000404* ID_MODEL_FROM_DATABASE=DVD Decoder card @@ -44069,6 +44600,9 @@ pci:v000011AA* pci:v000011AB* ID_VENDOR_FROM_DATABASE=Marvell Technology Group Ltd. +pci:v000011ABd00000100* + ID_MODEL_FROM_DATABASE=88F3700 [Armada 3700 Family] ARM SoC + pci:v000011ABd00000146* ID_MODEL_FROM_DATABASE=GT-64010/64010A System Controller @@ -44708,6 +45242,12 @@ pci:v000011ABd00006480sv00001775sd0000C200* pci:v000011ABd00006485* ID_MODEL_FROM_DATABASE=MV64460/64461/64462 System Controller, Revision B +pci:v000011ABd00006820* + ID_MODEL_FROM_DATABASE=88F6820 [Armada 385] ARM SoC + +pci:v000011ABd00006828* + ID_MODEL_FROM_DATABASE=88F6828 [Armada 388] ARM SoC + pci:v000011ABd00007042* ID_MODEL_FROM_DATABASE=88SX7042 PCI-e 4-port SATA-II @@ -44754,7 +45294,7 @@ pci:v000011ADd00000002sv000011ADsd0000FFFF* ID_MODEL_FROM_DATABASE=LNE100TX pci:v000011ADd00000002sv00001385sd0000F004* - ID_MODEL_FROM_DATABASE=LNE100TX (FA310TX) + ID_MODEL_FROM_DATABASE=LNE100TX (FA310/TX LAN 10/100 PCI Ethernet Adapter) pci:v000011ADd00000002sv00002646sd0000F002* ID_MODEL_FROM_DATABASE=LNE100TX (KNE110TX EtheRx Fast Ethernet) @@ -45695,6 +46235,9 @@ pci:v000011F8d00008531* pci:v000011F8d00008546* ID_MODEL_FROM_DATABASE=PM8546 B-FEIP PSX 96xG3 PCIe Storage Switch +pci:v000011F8d00008562* + ID_MODEL_FROM_DATABASE=PM8562 Switchtec PFX-L 32xG3 Fanout-Lite PCIe Gen3 Switch + pci:v000011F9* ID_VENDOR_FROM_DATABASE=I-Cube Inc @@ -46841,6 +47384,9 @@ pci:v0000125Bd00009100sv0000A000sd00006000* pci:v0000125Bd00009100sv0000A000sd00007000* ID_MODEL_FROM_DATABASE=AX99100 PCIe to Multi I/O Controller (Local Bus) +pci:v0000125Bd00009100sv0000EA50sd00001C10* + ID_MODEL_FROM_DATABASE=AX99100 PCIe to Multi I/O Controller (RXi2-BP) + pci:v0000125C* ID_VENDOR_FROM_DATABASE=Aurora Technologies, Inc. @@ -47222,6 +47768,9 @@ pci:v0000126Fd00000910* pci:v0000126Fd00002262* ID_MODEL_FROM_DATABASE=SM2262/SM2262EN SSD Controller +pci:v0000126Fd00002263* + ID_MODEL_FROM_DATABASE=SM2263EN/SM2263XT SSD Controller + pci:v00001270* ID_VENDOR_FROM_DATABASE=Olympus Optical Co., Ltd. @@ -47874,16 +48423,16 @@ pci:v00001282d00006585* ID_MODEL_FROM_DATABASE=DM562P V90 Modem pci:v00001282d00009009* - ID_MODEL_FROM_DATABASE=Ethernet 100/10 MBit + ID_MODEL_FROM_DATABASE=DM9009 Ethernet Controller pci:v00001282d00009100* ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet pci:v00001282d00009102* - ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet + ID_MODEL_FROM_DATABASE=DM9102 Fast Ethernet Controller pci:v00001282d00009102sv00000291sd00008212* - ID_MODEL_FROM_DATABASE=21x4x DEC-Tulip compatible 10/100 Ethernet (DM9102A (DM9102AE, SM9102AF) Ethernet 100/10 MBit) + ID_MODEL_FROM_DATABASE=DM9102 Fast Ethernet Controller (DM9102A (DM9102AE, SM9102AF) Ethernet 100/10 MBit) pci:v00001282d00009132* ID_MODEL_FROM_DATABASE=Ethernet 100/10 MBit @@ -47930,6 +48479,9 @@ pci:v00001283d00008889* pci:v00001283d00008892* ID_MODEL_FROM_DATABASE=IT8892E PCIe to PCI Bridge +pci:v00001283d00008892sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=IT8892E PCIe to PCI Bridge (DH61CR motherboard) + pci:v00001283d00008893* ID_MODEL_FROM_DATABASE=IT8893E PCIe to PCI Bridge @@ -48596,6 +49148,9 @@ pci:v000012D8d00002404* pci:v000012D8d00002608* ID_MODEL_FROM_DATABASE=PI7C9X2G608GP PCIe2 6-Port/8-Lane Packet Switch +pci:v000012D8d00002608sv0000EA50sd0000CC10* + ID_MODEL_FROM_DATABASE=PI7C9X2G608GP PCIe2 6-Port/8-Lane Packet Switch (RXi2-BP) + pci:v000012D8d0000400A* ID_MODEL_FROM_DATABASE=PI7C9X442SL PCI Express Bridge Port @@ -48626,6 +49181,9 @@ pci:v000012D8d00008152* pci:v000012D8d00008154* ID_MODEL_FROM_DATABASE=PI7C8154A/PI7C8154B/PI7C8154BI PCI-to-PCI Bridge +pci:v000012D8d00008619* + ID_MODEL_FROM_DATABASE=PI7C9X2G1616PR PCIe2 16-Port/16-Lane Packet Switch + pci:v000012D8d0000E110* ID_MODEL_FROM_DATABASE=PI7C9X110 PCI Express to PCI bridge @@ -48728,6 +49286,9 @@ pci:v000012EB* pci:v000012EBd00000001* ID_MODEL_FROM_DATABASE=Vortex 1 +pci:v000012EBd00000001sv00000000sd00000300* + ID_MODEL_FROM_DATABASE=Vortex 1 (Terasound A3D PCI) + pci:v000012EBd00000001sv0000104Dsd00008036* ID_MODEL_FROM_DATABASE=Vortex 1 (AU8820 Vortex Digital Audio Processor) @@ -48744,7 +49305,7 @@ pci:v000012EBd00000001sv00001092sd00002200* ID_MODEL_FROM_DATABASE=Vortex 1 (Sonic Impact A3D) pci:v000012EBd00000001sv0000122Dsd00001002* - ID_MODEL_FROM_DATABASE=Vortex 1 (AU8820 Vortex Digital Audio Processor) + ID_MODEL_FROM_DATABASE=Vortex 1 (SC 338-A3D) pci:v000012EBd00000001sv000012EBsd00000001* ID_MODEL_FROM_DATABASE=Vortex 1 (AU8820 Vortex Digital Audio Processor) @@ -49602,7 +50163,7 @@ pci:v00001351* ID_VENDOR_FROM_DATABASE=Sonix Inc pci:v00001353* - ID_VENDOR_FROM_DATABASE=Vierling Communication SAS + ID_VENDOR_FROM_DATABASE=dbeeSet Technology pci:v00001353d00000002* ID_MODEL_FROM_DATABASE=Proserver @@ -49616,6 +50177,12 @@ pci:v00001353d00000004* pci:v00001353d00000005* ID_MODEL_FROM_DATABASE=PCI-FUT-S0 +pci:v00001353d00000006* + ID_MODEL_FROM_DATABASE=OTDU-1U (FPGA Zynq-7000) + +pci:v00001353d00000007* + ID_MODEL_FROM_DATABASE=OTDU-EX + pci:v00001354* ID_VENDOR_FROM_DATABASE=Dwave System Inc @@ -51716,6 +52283,9 @@ pci:v00001414d00000001* pci:v00001414d00000002* ID_MODEL_FROM_DATABASE=MN-130 (ADMtek Centaur-P based) +pci:v00001414d0000008C* + ID_MODEL_FROM_DATABASE=Basic Render Driver + pci:v00001414d00005353* ID_MODEL_FROM_DATABASE=Hyper-V virtual VGA @@ -54101,8 +54671,14 @@ pci:v0000144Dd0000A800* pci:v0000144Dd0000A802* ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM951/PM951 +pci:v0000144Dd0000A802sv0000144Dsd0000A801* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM951/PM951 (PM963 2.5" NVMe PCIe SSD) + pci:v0000144Dd0000A804* - ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM961/PM961 + ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM961/PM961/SM963 + +pci:v0000144Dd0000A804sv0000144Dsd0000A801* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM961/PM961/SM963 (SM963 2.5" NVMe PCIe SSD) pci:v0000144Dd0000A808* ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM981/PM981/PM983 @@ -54110,6 +54686,9 @@ pci:v0000144Dd0000A808* pci:v0000144Dd0000A808sv00001D49sd0000403B* ID_MODEL_FROM_DATABASE=NVMe SSD Controller SM981/PM981/PM983 (Thinksystem U.2 PM983 NVMe SSD) +pci:v0000144Dd0000A80A* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM9A1/980PRO + pci:v0000144Dd0000A820* ID_MODEL_FROM_DATABASE=NVMe SSD Controller 171X @@ -54299,6 +54878,54 @@ pci:v0000144Dd0000A824sv00001028sd00002098* pci:v0000144Dd0000A824sv00001028sd00002099* ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 7.68TB) +pci:v0000144Dd0000A824sv00001028sd00002118* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS MU U.2 1.6TB) + +pci:v0000144Dd0000A824sv00001028sd00002119* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN MU U.2 1.6TB) + +pci:v0000144Dd0000A824sv00001028sd00002120* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS MU U.2 3.2T) + +pci:v0000144Dd0000A824sv00001028sd00002121* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN MU U.2 3.2TB) + +pci:v0000144Dd0000A824sv00001028sd00002122* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS MU U.2 6.4TB) + +pci:v0000144Dd0000A824sv00001028sd00002123* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN MU U.2 6.4TB) + +pci:v0000144Dd0000A824sv00001028sd00002124* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS MU U.2 6.4TB) + +pci:v0000144Dd0000A824sv00001028sd00002125* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN MU U.2 12.8TB) + +pci:v0000144Dd0000A824sv00001028sd00002126* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS RI U.2 1.92TB) + +pci:v0000144Dd0000A824sv00001028sd00002127* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN RI U.2 1.92TB) + +pci:v0000144Dd0000A824sv00001028sd00002128* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS RI U.2 3.84TB) + +pci:v0000144Dd0000A824sv00001028sd00002129* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN RI U.2 3.84TB) + +pci:v0000144Dd0000A824sv00001028sd00002130* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS RI U.2 7.68TB) + +pci:v0000144Dd0000A824sv00001028sd00002131* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN RI U.2 7.68TB) + +pci:v0000144Dd0000A824sv00001028sd00002132* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN FIPS RI U.2 15.36TB) + +pci:v0000144Dd0000A824sv00001028sd00002133* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller PM173X (Ent NVMe v2 AGN RI U.2 15.36TB) + pci:v0000144Dd0000ECEC* ID_MODEL_FROM_DATABASE=Exynos 8895 PCIe Root Complex @@ -54332,6 +54959,9 @@ pci:v00001457* pci:v00001458* ID_VENDOR_FROM_DATABASE=Gigabyte Technology Co., Ltd +pci:v00001458d00003483* + ID_MODEL_FROM_DATABASE=USB 3.0 Controller (VIA VL80x-based xHCI Controller) + pci:v00001459* ID_VENDOR_FROM_DATABASE=DOOIN Electronics @@ -54380,6 +55010,9 @@ pci:v00001461d0000F436* pci:v00001462* ID_VENDOR_FROM_DATABASE=Micro-Star International Co., Ltd. [MSI] +pci:v00001462d00003483* + ID_MODEL_FROM_DATABASE=MSI USB 3.0 (VIA VL80x-based xHCI USB Controller) + pci:v00001462d0000AAF0* ID_MODEL_FROM_DATABASE=Radeon RX 580 Gaming X 8G @@ -55620,34 +56253,34 @@ pci:v000014E4d0000165Esv000010CFsd00001279* ID_MODEL_FROM_DATABASE=NetXtreme BCM5705M_2 Gigabit Ethernet (LifeBook E8010D) pci:v000014E4d0000165F* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe pci:v000014E4d0000165Fsv00001028sd000004F7* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (PowerEdge R320 server) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (PowerEdge R320 server) pci:v000014E4d0000165Fsv00001028sd000008FD* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (PowerEdge R6515/R7515 LOM) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (PowerEdge R6515/R7515 LOM) pci:v000014E4d0000165Fsv00001028sd000008FF* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (PowerEdge Rx5xx LOM Board) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (PowerEdge Rx5xx LOM Board) pci:v000014E4d0000165Fsv00001028sd00000900* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (PowerEdge C6525 LOM) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (PowerEdge C6525 LOM) pci:v000014E4d0000165Fsv0000103Csd00001786* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (NC332T Adapter) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (NC332T Adapter) pci:v000014E4d0000165Fsv0000103Csd0000193D* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (NC332i Adapter) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (NC332i Adapter) pci:v000014E4d0000165Fsv0000103Csd00002133* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (NC332i Adapter) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (NC332i Adapter) pci:v000014E4d0000165Fsv0000103Csd000022E8* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (NC332i Adapter) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (NC332i Adapter) pci:v000014E4d0000165Fsv0000103Csd000022EB* - ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 2-port Gigabit Ethernet PCIe (NC332i Adapter) + ID_MODEL_FROM_DATABASE=NetXtreme BCM5720 Gigabit Ethernet PCIe (NC332i Adapter) pci:v000014E4d00001662* ID_MODEL_FROM_DATABASE=NetXtreme II BCM57712 10 Gigabit Ethernet @@ -55886,6 +56519,9 @@ pci:v000014E4d0000168Esv0000193Dsd00001003* pci:v000014E4d0000168Esv0000193Dsd00001006* ID_MODEL_FROM_DATABASE=NetXtreme II BCM57810 10 Gigabit Ethernet (530F-L) +pci:v000014E4d0000168Esv0000193Dsd0000100F* + ID_MODEL_FROM_DATABASE=NetXtreme II BCM57810 10 Gigabit Ethernet (NIC-ETH522i-Mb-2x10G) + pci:v000014E4d00001690* ID_MODEL_FROM_DATABASE=NetXtreme BCM57760 Gigabit Ethernet PCIe @@ -55964,6 +56600,9 @@ pci:v000014E4d000016A1* pci:v000014E4d000016A1sv00001043sd0000866E* ID_MODEL_FROM_DATABASE=BCM57840 NetXtreme II 10 Gigabit Ethernet (PEB-10G/57840-2T 10GBase-T Network Adapter) +pci:v000014E4d000016A1sv0000193Dsd0000100B* + ID_MODEL_FROM_DATABASE=BCM57840 NetXtreme II 10 Gigabit Ethernet (NIC-ETH521i-Mb-4x10G) + pci:v000014E4d000016A2* ID_MODEL_FROM_DATABASE=BCM57840 NetXtreme II 10/20-Gigabit Ethernet @@ -56315,6 +56954,9 @@ pci:v000014E4d000016D5* pci:v000014E4d000016D6* ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller +pci:v000014E4d000016D6sv000014E4sd00001202* + ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller (BCM957412M4122C OCP 1x25G Type1 wRoCE) + pci:v000014E4d000016D6sv000014E4sd00004120* ID_MODEL_FROM_DATABASE=BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller (NetXtreme E-Series Advanced Dual-port 10Gb SFP+ Ethernet Network Daughter Card) @@ -56330,9 +56972,6 @@ pci:v000014E4d000016D6sv0000152Dsd00008B22* pci:v000014E4d000016D7* ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller -pci:v000014E4d000016D7sv000014E4sd00001202* - ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller (BCM957412M4122C OCP 1x25G Type1 wRoCE) - pci:v000014E4d000016D7sv000014E4sd00001402* ID_MODEL_FROM_DATABASE=BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller (BCM957414A4142CC 10Gb/25Gb Ethernet PCIe) @@ -56516,6 +57155,9 @@ pci:v000014E4d00001750sv000014E4sd00002100* pci:v000014E4d00001750sv000014E4sd00005208* ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (NetXtreme-E Dual-port 100G QSFP56 Ethernet OCP 3.0 Adapter (BCM957508-N2100G)) +pci:v000014E4d00001750sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet (BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet) + pci:v000014E4d00001751* ID_MODEL_FROM_DATABASE=BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet @@ -56531,6 +57173,9 @@ pci:v000014E4d00001801* pci:v000014E4d00001802* ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E Ethernet Partition +pci:v000014E4d00001802sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E Ethernet Partition (BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet Partition) + pci:v000014E4d00001803* ID_MODEL_FROM_DATABASE=BCM57502 NetXtreme-E RDMA Partition @@ -56538,14 +57183,38 @@ pci:v000014E4d00001804* ID_MODEL_FROM_DATABASE=BCM57504 NetXtreme-E RDMA Partition pci:v000014E4d00001805* - ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E RDMA Partition + ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Partition + +pci:v000014E4d00001805sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Partition (NetXtreme-E NGM2100D BCM57508 2x100G KR Mezz RDMA Partition) pci:v000014E4d00001806* ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E Ethernet Virtual Function +pci:v000014E4d00001806sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E Ethernet Virtual Function (BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet Virtual Function) + pci:v000014E4d00001807* ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E RDMA Virtual Function +pci:v000014E4d00001807sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E RDMA Virtual Function (BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Virtual Function) + +pci:v000014E4d00001808* + ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E Ethernet Virtual Function + +pci:v000014E4d00001808sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E Ethernet Virtual Function (BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet Virtual Function) + +pci:v000014E4d00001809* + ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E RDMA Virtual Function + +pci:v000014E4d00001809sv000014E4sd0000DF24* + ID_MODEL_FROM_DATABASE=BCM5750X NetXtreme-E RDMA Virtual Function (BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Virtual Function) + +pci:v000014E4d00002711* + ID_MODEL_FROM_DATABASE=BCM2711 PCIe Bridge + pci:v000014E4d00003352* ID_MODEL_FROM_DATABASE=BCM3352 @@ -58796,6 +59465,9 @@ pci:v00001542d00009271* pci:v00001542d00009272* ID_MODEL_FROM_DATABASE=Pulse Width Modulator Card +pci:v00001542d00009273* + ID_MODEL_FROM_DATABASE=RCIM-IV Real-Time Clock & Interrupt Module (PCIe) + pci:v00001542d00009277* ID_MODEL_FROM_DATABASE=5 Volt Delta Sigma Converter Card @@ -59660,6 +60332,18 @@ pci:v000015B3d00001015sv000015B3sd00000025* pci:v000015B3d00001015sv0000193Dsd0000100A* ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx] (620F-B) +pci:v000015B3d00001015sv0000193Dsd00001023* + ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx] (NIC-ETH540F-LP-2P) + +pci:v000015B3d00001015sv0000193Dsd00001031* + ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx] (NIC-ETH640i-Mb-2x25G) + +pci:v000015B3d00001015sv0000193Dsd00001083* + ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx] (NIC-ETH640F-3S-2P) + +pci:v000015B3d00001015sv0000193Dsd00001084* + ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx] (NIC-ETH540F-3S-2P) + pci:v000015B3d00001016* ID_MODEL_FROM_DATABASE=MT27710 Family [ConnectX-4 Lx Virtual Function] @@ -59678,6 +60362,9 @@ pci:v000015B3d00001017sv000015B3sd00000020* pci:v000015B3d00001017sv000015B3sd00000068* ID_MODEL_FROM_DATABASE=MT27800 Family [ConnectX-5] (ConnectX®-5 EN network interface card for OCP2.0, Type 1, with host management, 25GbE dual-port SFP28, PCIe3.0 x8, no bracket Halogen free ; MCX542B-ACAN) +pci:v000015B3d00001017sv0000193Dsd00001051* + ID_MODEL_FROM_DATABASE=MT27800 Family [ConnectX-5] (NIC-IB1040i-Mb-2P) + pci:v000015B3d00001018* ID_MODEL_FROM_DATABASE=MT27800 Family [ConnectX-5 Virtual Function] @@ -60030,10 +60717,10 @@ pci:v000015B7d00005001* ID_MODEL_FROM_DATABASE=WD Black NVMe SSD pci:v000015B7d00005002* - ID_MODEL_FROM_DATABASE=WD Black 2018 / PC SN720 NVMe SSD + ID_MODEL_FROM_DATABASE=WD Black 2018/SN750 / PC SN720 NVMe SSD pci:v000015B7d00005003* - ID_MODEL_FROM_DATABASE=WD Black 2018 / PC SN520 NVMe SSD + ID_MODEL_FROM_DATABASE=WD Blue SN500 / PC SN520 NVMe SSD pci:v000015B7d00005004* ID_MODEL_FROM_DATABASE=PC SN520 NVMe SSD @@ -60042,7 +60729,7 @@ pci:v000015B7d00005005* ID_MODEL_FROM_DATABASE=PC SN520 NVMe SSD pci:v000015B7d00005006* - ID_MODEL_FROM_DATABASE=WD Black 2019/PC SN750 NVMe SSD + ID_MODEL_FROM_DATABASE=WD Black SN750 / PC SN730 NVMe SSD pci:v000015B7d00005009* ID_MODEL_FROM_DATABASE=WD Blue SN550 NVMe SSD @@ -60050,9 +60737,18 @@ pci:v000015B7d00005009* pci:v000015B7d00005009sv000015B7sd00005009* ID_MODEL_FROM_DATABASE=WD Blue SN550 NVMe SSD +pci:v000015B7d0000500B* + ID_MODEL_FROM_DATABASE=PC SN530 NVMe SSD + +pci:v000015B7d0000500Bsv00001414sd0000500B* + ID_MODEL_FROM_DATABASE=PC SN530 NVMe SSD (Xbox Series X) + pci:v000015B7d0000500D* ID_MODEL_FROM_DATABASE=WD Ultrastar DC SN340 NVMe SSD +pci:v000015B7d00005011* + ID_MODEL_FROM_DATABASE=WD Black SN850 + pci:v000015B8* ID_VENDOR_FROM_DATABASE=ADDI-DATA GmbH @@ -60953,6 +61649,15 @@ pci:v0000168Ad0000C040* pci:v0000168Ad0000C051* ID_MODEL_FROM_DATABASE=CryptoServer Se-Series Gen2 Hardware Security Module +pci:v0000168Ad0000C070* + ID_MODEL_FROM_DATABASE=u.trust Anchor Hardware Security Module cs7.2 Series + +pci:v0000168Ad0000C071* + ID_MODEL_FROM_DATABASE=u.trust Anchor Hardware Security Module cs7.3 Series + +pci:v0000168Ad0000C072* + ID_MODEL_FROM_DATABASE=u.trust Anchor Hardware Security Module cs7.3 Series Virtual Function + pci:v0000168C* ID_VENDOR_FROM_DATABASE=Qualcomm Atheros @@ -62255,6 +62960,9 @@ pci:v00001737d0000AB09* pci:v0000173B* ID_VENDOR_FROM_DATABASE=Altima (nee Broadcom) +pci:v0000173Bd00000001* + ID_MODEL_FROM_DATABASE=AC1002 PCI Gigabit Ethernet controller + pci:v0000173Bd000003E8* ID_MODEL_FROM_DATABASE=AC1000 Gigabit Ethernet @@ -62396,6 +63104,18 @@ pci:v00001760d00000303* pci:v00001760d00000800* ID_MODEL_FROM_DATABASE=PCD8006 - PCIe digital Inputs/Outputs +pci:v00001760d00000840* + ID_MODEL_FROM_DATABASE=PCA-8428 General-purpose multifunctional PCIe card with 8 analog inputs and 2 analog outputs + +pci:v00001760d00000841* + ID_MODEL_FROM_DATABASE=PCA-8429 General-purpose multifunctional PCIe card with 8 analog inputs + +pci:v00001760d00000842* + ID_MODEL_FROM_DATABASE=PCA-8438 General-purpose multifunctional PCIe card with 16 analog inputs and 2 analog outputs + +pci:v00001760d00000843* + ID_MODEL_FROM_DATABASE=PCA-8439 General-purpose multifunctional PCIe card with 16 analog inputs + pci:v00001760d0000FF00* ID_MODEL_FROM_DATABASE=CTU CAN FD PCIe Card @@ -62906,6 +63626,9 @@ pci:v000017A0d0000E763* pci:v000017AA* ID_VENDOR_FROM_DATABASE=Lenovo +pci:v000017AAd00003181* + ID_MODEL_FROM_DATABASE=ThinkCentre M75n IoT + pci:v000017AAd0000402B* ID_MODEL_FROM_DATABASE=Intel 82599ES 10Gb 2-port Server Adapter X520-2 @@ -62990,6 +63713,9 @@ pci:v000017CBd00000401* pci:v000017CBd00001000* ID_MODEL_FROM_DATABASE=QCS405 PCIe Root Complex +pci:v000017CBd00001101* + ID_MODEL_FROM_DATABASE=QCA6390 Wireless Network Adapter [AX500-DBS (2x2)] + pci:v000017CC* ID_VENDOR_FROM_DATABASE=NetChip Technology, Inc @@ -65936,9 +66662,45 @@ pci:v000019E5d00001822sv000019E5sd0000D141* pci:v000019E5d00001822sv000019E5sd0000D146* ID_MODEL_FROM_DATABASE=Hi1822 Family (4*25GE) (Hi1822 SP585 (4*25GE)) +pci:v000019E5d00003714* + ID_MODEL_FROM_DATABASE=ES3000 V5 NVMe PCIe SSD + +pci:v000019E5d00003714sv000019E5sd00005312* + ID_MODEL_FROM_DATABASE=ES3000 V5 NVMe PCIe SSD (NVMe SSD ES3500P V5 2000GB 2.5" U.2) + pci:v000019E5d0000371E* ID_MODEL_FROM_DATABASE=Hi1822 Family Virtual Bridge +pci:v000019E5d00003754* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD + +pci:v000019E5d00003754sv000019E5sd00006122* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3600P V6 1600GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006123* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3600P V6 3200GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006124* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3600P V6 6400GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006141* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3800P V6 800GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006142* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3800P V6 1600GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006212* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3500P V6 1920GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006213* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3500P V6 3840GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006214* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3500P V6 7680GB 2.5" U.2) + +pci:v000019E5d00003754sv000019E5sd00006215* + ID_MODEL_FROM_DATABASE=ES3000 V6 NVMe PCIe SSD (NVMe SSD ES3500P V6 15360GB 2.5" U.2) + pci:v000019E5d0000375E* ID_MODEL_FROM_DATABASE=Hi1822 Family Virtual Function @@ -66218,6 +66980,9 @@ pci:v00001A4Ad00001000* pci:v00001A4Ad00001010* ID_MODEL_FROM_DATABASE=AMC EVR - Stockholm Timing Board +pci:v00001A4Ad00001020* + ID_MODEL_FROM_DATABASE=PGPCard - Gen3 Cameralink Interface + pci:v00001A4Ad00001030* ID_MODEL_FROM_DATABASE=PGPCard - Gen3 GIGe Interface @@ -66800,6 +67565,9 @@ pci:v00001B21d00001343* pci:v00001B21d00002142* ID_MODEL_FROM_DATABASE=ASM2142 USB 3.1 Host Controller +pci:v00001B21d00002142sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=ASM2142 USB 3.1 Host Controller (H270 PC MATE) + pci:v00001B21d00003242* ID_MODEL_FROM_DATABASE=ASM3242 USB 3.2 Host Controller @@ -66893,6 +67661,9 @@ pci:v00001B36d0000000C* pci:v00001B36d0000000D* ID_MODEL_FROM_DATABASE=QEMU XHCI Host Controller +pci:v00001B36d00000010* + ID_MODEL_FROM_DATABASE=QEMU NVM Express Controller + pci:v00001B36d00000100* ID_MODEL_FROM_DATABASE=QXL paravirtual graphic card @@ -66989,6 +67760,9 @@ pci:v00001B47d00000602* pci:v00001B4B* ID_VENDOR_FROM_DATABASE=Marvell Technology Group Ltd. +pci:v00001B4Bd00000100* + ID_MODEL_FROM_DATABASE=88F3700 [Armada 3700 Family] ARM SoC + pci:v00001B4Bd00000640* ID_MODEL_FROM_DATABASE=88SE9128 SATA III 6Gb/s RAID Controller @@ -67037,6 +67811,9 @@ pci:v00001B4Bd00009178* pci:v00001B4Bd0000917A* ID_MODEL_FROM_DATABASE=88SE9172 SATA III 6Gb/s RAID Controller +pci:v00001B4Bd00009182* + ID_MODEL_FROM_DATABASE=88SE9182 PCIe 2.0 x2 2-port SATA 6 Gb/s Controller + pci:v00001B4Bd00009183* ID_MODEL_FROM_DATABASE=88SS9183 PCIe SSD Controller @@ -67049,41 +67826,44 @@ pci:v00001B4Bd000091A0* pci:v00001B4Bd000091A4* ID_MODEL_FROM_DATABASE=88SE912x IDE Controller +pci:v00001B4Bd00009215* + ID_MODEL_FROM_DATABASE=88SE9215 PCIe 2.0 x1 4-port SATA 6 Gb/s Controller + pci:v00001B4Bd00009220* ID_MODEL_FROM_DATABASE=88SE9220 PCIe 2.0 x2 2-port SATA 6 Gb/s RAID Controller pci:v00001B4Bd00009230* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller pci:v00001B4Bd00009230sv00001028sd00001FD6* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (BOSS-S1 Adapter) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (BOSS-S1 Adapter) pci:v00001B4Bd00009230sv00001028sd00001FDF* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (BOSS-S1 Modular) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (BOSS-S1 Modular) pci:v00001B4Bd00009230sv00001028sd00001FE2* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (BOSS-S1 Adapter) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (BOSS-S1 Adapter) pci:v00001B4Bd00009230sv00001028sd00002010* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (BOSS-S2 Adapter) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (BOSS-S2 Adapter) pci:v00001B4Bd00009230sv00001D49sd00000300* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem M.2 with Mirroring Enablement Kit) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (ThinkSystem M.2 with Mirroring Enablement Kit) pci:v00001B4Bd00009230sv00001D49sd00000301* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem SR630 x16 PCIE with 4 SATA ports Riser) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (ThinkSystem SR630 x16 PCIE with 4 SATA ports Riser) pci:v00001B4Bd00009230sv00001D49sd00000302* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit) pci:v00001B4Bd00009230sv00001D49sd00000303* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (ThinkSystem SE350 M.2 SATA 4-Bay Data RAID Mirroring Enablement Kit) pci:v00001B4Bd00009230sv00001D49sd00000304* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem M.2 SATA 2-Bay RAID Enablement Kit) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (ThinkSystem M.2 SATA 2-Bay RAID Enablement Kit) pci:v00001B4Bd00009230sv00001D49sd00000305* - ID_MODEL_FROM_DATABASE=88SE9230 PCIe SATA 6Gb/s Controller (ThinkSystem 7mm SATA 2-Bay Rear RAID Enablement Kit) + ID_MODEL_FROM_DATABASE=88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller (ThinkSystem 7mm SATA 2-Bay Rear RAID Enablement Kit) pci:v00001B4Bd00009235* ID_MODEL_FROM_DATABASE=88SE9235 PCIe 2.0 x2 4-port SATA 6 Gb/s Controller @@ -67229,6 +68009,9 @@ pci:v00001B96d00002404* pci:v00001B96d00002500* ID_MODEL_FROM_DATABASE=Ultrastar DC SN840 NVMe SSD +pci:v00001B96d00002600* + ID_MODEL_FROM_DATABASE=Ultrastar DC ZN540 ZNS NVMe SSD + pci:v00001B96d00003714* ID_MODEL_FROM_DATABASE=PC SN730 NVMe SSD @@ -67412,6 +68195,18 @@ pci:v00001BD0d00001004* pci:v00001BD0d00001005* ID_MODEL_FROM_DATABASE=PE1000 (Multi-Protocol PCIe/104 Interface Card) +pci:v00001BD0d00001006* + ID_MODEL_FROM_DATABASE=webCS Wireless Aircraft Communications Server + +pci:v00001BD0d00001007* + ID_MODEL_FROM_DATABASE=AB3000 Series Rugged Computer (Series N) + +pci:v00001BD0d00001008* + ID_MODEL_FROM_DATABASE=ME1000 mPCIe Avionics Interface Card + +pci:v00001BD0d0000100A* + ID_MODEL_FROM_DATABASE=NG1 Series Avionics Converter + pci:v00001BD0d00001101* ID_MODEL_FROM_DATABASE=OmniBus II PCIe Multi-Protocol Interface Card @@ -67421,6 +68216,18 @@ pci:v00001BD0d00001102* pci:v00001BD0d00001103* ID_MODEL_FROM_DATABASE=OmniBus II cPCIe/PXIe Multi-Protocol Interface Card +pci:v00001BD0d00001200* + ID_MODEL_FROM_DATABASE=NG3 Series Mil-Std-1553 Interface + +pci:v00001BD0d00001201* + ID_MODEL_FROM_DATABASE=NG3 Series ARINC 429 Interface + +pci:v00001BD0d00001202* + ID_MODEL_FROM_DATABASE=NG3 Series Avionics Discrete & Serial Interface + +pci:v00001BD0d00001203* + ID_MODEL_FROM_DATABASE=NG3 Series Avionics Discrete Interface + pci:v00001BD4* ID_VENDOR_FROM_DATABASE=Inspur Electronic Information Industry Co., Ltd. @@ -67517,6 +68324,9 @@ pci:v00001C1Fd0000001C* pci:v00001C1Fd0000001D* ID_MODEL_FROM_DATABASE=Vega +pci:v00001C1Fd0000001F* + ID_MODEL_FROM_DATABASE=FD940 + pci:v00001C28* ID_VENDOR_FROM_DATABASE=Lite-On IT Corp. / Plextor @@ -67685,9 +68495,15 @@ pci:v00001C5Cd00001285* pci:v00001C5Cd00001327* ID_MODEL_FROM_DATABASE=BC501 NVMe Solid State Drive 512GB +pci:v00001C5Cd00001339* + ID_MODEL_FROM_DATABASE=BC511 + pci:v00001C5Cd00001504* ID_MODEL_FROM_DATABASE=SC300 512GB M.2 2280 SATA Solid State Drive +pci:v00001C5Cd00001527* + ID_MODEL_FROM_DATABASE=PC401 NVMe Solid State Drive 256GB + pci:v00001C5Cd0000243B* ID_MODEL_FROM_DATABASE=PE6110 NVMe Solid State Drive @@ -67704,16 +68520,25 @@ pci:v00001C5F* ID_VENDOR_FROM_DATABASE=Beijing Memblaze Technology Co. Ltd. pci:v00001C5Fd0000000D* - ID_MODEL_FROM_DATABASE=PBlaze5 520/526 AIC + ID_MODEL_FROM_DATABASE=PBlaze5 520/526 pci:v00001C5Fd0000003D* - ID_MODEL_FROM_DATABASE=PBlaze5 920/926 AIC + ID_MODEL_FROM_DATABASE=PBlaze5 920/926 -pci:v00001C5Fd0000010D* - ID_MODEL_FROM_DATABASE=PBlaze5 520/526 U.2 +pci:v00001C5Fd0000003E* + ID_MODEL_FROM_DATABASE=PBlaze6 6920 -pci:v00001C5Fd0000013D* - ID_MODEL_FROM_DATABASE=PBlaze5 920/926 U.2 +pci:v00001C5Fd0000003Esv00001C5Fsd00000A31* + ID_MODEL_FROM_DATABASE=PBlaze6 6920 (NVMe SSD PBlaze6 6920 3840GB 2.5" U.2) + +pci:v00001C5Fd0000003Esv00001C5Fsd00000A41* + ID_MODEL_FROM_DATABASE=PBlaze6 6920 (NVMe SSD PBlaze6 6920 7680GB 2.5" U.2) + +pci:v00001C5Fd0000003Esv00001C5Fsd00004A31* + ID_MODEL_FROM_DATABASE=PBlaze6 6920 (NVMe SSD PBlaze6 6920 3200GB 2.5" U.2) + +pci:v00001C5Fd0000003Esv00001C5Fsd00004A41* + ID_MODEL_FROM_DATABASE=PBlaze6 6920 (NVMe SSD PBlaze6 6920 6400GB 2.5" U.2) pci:v00001C5Fd00000540* ID_MODEL_FROM_DATABASE=PBlaze4 NVMe SSD @@ -67922,6 +68747,9 @@ pci:v00001CE4d0000000A* pci:v00001CE4d0000000B* ID_MODEL_FROM_DATABASE=ExaNIC V9P +pci:v00001CE4d0000000C* + ID_MODEL_FROM_DATABASE=ExaNIC V9P-3 + pci:v00001CE4d00000100* ID_MODEL_FROM_DATABASE=ExaDISK FX1 @@ -67940,6 +68768,9 @@ pci:v00001D05* pci:v00001D0F* ID_VENDOR_FROM_DATABASE=Amazon.com, Inc. +pci:v00001D0Fd00008061* + ID_MODEL_FROM_DATABASE=NVMe EBS Controller + pci:v00001D0Fd0000CD01* ID_MODEL_FROM_DATABASE=NVMe SSD Controller @@ -68327,6 +69158,15 @@ pci:v00001D6Cd00001015* pci:v00001D6Cd00001016* ID_MODEL_FROM_DATABASE=AR-ARK-BBDEV-FX1 [Arkville 64B DPDK Baseband Device] +pci:v00001D6Cd00001017* + ID_MODEL_FROM_DATABASE=AR-ARK-FX1 [Arkville 64B Multi-Homed Primary Endpoint] + +pci:v00001D6Cd00001018* + ID_MODEL_FROM_DATABASE=AR-ARK-FX1 [Arkville 64B Multi-Homed Secondary Endpoint] + +pci:v00001D6Cd00001019* + ID_MODEL_FROM_DATABASE=AR-ARK-FX1 [Arkville 64B Multi-Homed Tertiary Endpoint] + pci:v00001D6Cd00004200* ID_MODEL_FROM_DATABASE=A5PL-E1-10GETI [10 GbE Ethernet Traffic Instrument] @@ -68394,7 +69234,7 @@ pci:v00001D82d00000202* ID_MODEL_FROM_DATABASE=Codensity T408 Video Encoding-Decoding Accelerator pci:v00001D87* - ID_VENDOR_FROM_DATABASE=Fuzhou Rockchip Electronics Co., Ltd + ID_VENDOR_FROM_DATABASE=Rockchip Electronics Co., Ltd pci:v00001D87d00000100* ID_MODEL_FROM_DATABASE=RK3399 PCI Express Root Port @@ -68402,11 +69242,14 @@ pci:v00001D87d00000100* pci:v00001D87d00001808* ID_MODEL_FROM_DATABASE=RK1808 Neural Network Processor Card +pci:v00001D87d00003566* + ID_MODEL_FROM_DATABASE=RK3568 Remote Signal Processor + pci:v00001D8F* ID_VENDOR_FROM_DATABASE=Enyx pci:v00001D93* - ID_VENDOR_FROM_DATABASE=YADRO (KNS Group) + ID_VENDOR_FROM_DATABASE=YADRO pci:v00001D94* ID_VENDOR_FROM_DATABASE=Chengdu Haiguang IC Design Co., Ltd. @@ -68571,10 +69414,10 @@ pci:v00001DD8d00001000sv00001DD8sd00004002* ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (Naples 25Gb 2-port SFP28 x8 4GB) pci:v00001DD8d00001000sv00001DD8sd00004007* - ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-25 10/25G 2p OCP Card) + ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-25 Ent 10/25G OCP3 Card) pci:v00001DD8d00001000sv00001DD8sd00004008* - ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC) + ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-25 10/25G 2p SFP28 Card) pci:v00001DD8d00001000sv00001DD8sd0000400A* ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card) @@ -68583,7 +69426,10 @@ pci:v00001DD8d00001000sv00001DD8sd0000400C* ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001000sv00001DD8sd0000400D* - ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-100 100G 2p QSFP28 Card) + ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSP DSC-100 Ent 100Gb Card) + +pci:v00001DD8d00001000sv00001DD8sd0000400E* + ID_MODEL_FROM_DATABASE=DSC Capri Upstream Port (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001001* ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port @@ -68598,10 +69444,10 @@ pci:v00001DD8d00001001sv00001DD8sd00004002* ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (Naples 25Gb 2-port SFP28 x8 4GB) pci:v00001DD8d00001001sv00001DD8sd00004007* - ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-25 10/25G 2p OCP Card) + ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-25 Ent 10/25G OCP3 Card) pci:v00001DD8d00001001sv00001DD8sd00004008* - ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC) + ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-25 10/25G 2p SFP28 Card) pci:v00001DD8d00001001sv00001DD8sd0000400A* ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card) @@ -68610,7 +69456,10 @@ pci:v00001DD8d00001001sv00001DD8sd0000400C* ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001001sv00001DD8sd0000400D* - ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-100 100G 2p QSFP28 Card) + ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSP DSC-100 Ent 100Gb Card) + +pci:v00001DD8d00001001sv00001DD8sd0000400E* + ID_MODEL_FROM_DATABASE=DSC Virtual Downstream Port (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001002* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller @@ -68625,10 +69474,10 @@ pci:v00001DD8d00001002sv00001DD8sd00004002* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (Naples 25Gb 2-port SFP28 x8 4GB) pci:v00001DD8d00001002sv00001DD8sd00004007* - ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-25 10/25G 2p OCP Card) + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-25 Ent 10/25G OCP3 Card) pci:v00001DD8d00001002sv00001DD8sd00004008* - ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC) + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-25 10/25G 2p SFP28 Card) pci:v00001DD8d00001002sv00001DD8sd0000400A* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card) @@ -68637,7 +69486,10 @@ pci:v00001DD8d00001002sv00001DD8sd0000400C* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001002sv00001DD8sd0000400D* - ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-100 100G 2p QSFP28 Card) + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSP DSC-100 Ent 100Gb Card) + +pci:v00001DD8d00001002sv00001DD8sd0000400E* + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001003* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF @@ -68652,10 +69504,10 @@ pci:v00001DD8d00001003sv00001DD8sd00004002* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (Naples 25Gb 2-port SFP28 x8 4GB) pci:v00001DD8d00001003sv00001DD8sd00004007* - ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-25 10/25G 2p OCP Card) + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-25 Ent 10/25G OCP3 Card) pci:v00001DD8d00001003sv00001DD8sd00004008* - ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC) + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-25 10/25G 2p SFP28 Card) pci:v00001DD8d00001003sv00001DD8sd0000400A* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card) @@ -68664,7 +69516,10 @@ pci:v00001DD8d00001003sv00001DD8sd0000400C* ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001003sv00001DD8sd0000400D* - ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-100 100G 2p QSFP28 Card) + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSP DSC-100 Ent 100Gb Card) + +pci:v00001DD8d00001003sv00001DD8sd0000400E* + ID_MODEL_FROM_DATABASE=DSC Ethernet Controller VF (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001004* ID_MODEL_FROM_DATABASE=DSC Management Controller @@ -68679,10 +69534,10 @@ pci:v00001DD8d00001004sv00001DD8sd00004002* ID_MODEL_FROM_DATABASE=DSC Management Controller (Naples 25Gb 2-port SFP28 x8 4GB) pci:v00001DD8d00001004sv00001DD8sd00004007* - ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-25 10/25G 2p OCP Card) + ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-25 Ent 10/25G OCP3 Card) pci:v00001DD8d00001004sv00001DD8sd00004008* - ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC) + ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-25 10/25G 2p SFP28 Card) pci:v00001DD8d00001004sv00001DD8sd0000400A* ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card) @@ -68691,7 +69546,10 @@ pci:v00001DD8d00001004sv00001DD8sd0000400C* ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001004sv00001DD8sd0000400D* - ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-100 100G 2p QSFP28 Card) + ID_MODEL_FROM_DATABASE=DSC Management Controller (DSP DSC-100 Ent 100Gb Card) + +pci:v00001DD8d00001004sv00001DD8sd0000400E* + ID_MODEL_FROM_DATABASE=DSC Management Controller (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001007* ID_MODEL_FROM_DATABASE=DSC Storage Accelerator @@ -68706,10 +69564,10 @@ pci:v00001DD8d00001007sv00001DD8sd00004002* ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (Naples 25Gb 2-port SFP28 x8 4GB) pci:v00001DD8d00001007sv00001DD8sd00004007* - ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-25 10/25G 2p OCP Card) + ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-25 Ent 10/25G OCP3 Card) pci:v00001DD8d00001007sv00001DD8sd00004008* - ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC) + ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-25 10/25G 2p SFP28 Card) pci:v00001DD8d00001007sv00001DD8sd0000400A* ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card) @@ -68718,13 +69576,16 @@ pci:v00001DD8d00001007sv00001DD8sd0000400C* ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DD8d00001007sv00001DD8sd0000400D* - ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-100 100G 2p QSFP28 Card) + ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSP DSC-100 Ent 100Gb Card) + +pci:v00001DD8d00001007sv00001DD8sd0000400E* + ID_MODEL_FROM_DATABASE=DSC Storage Accelerator (DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card) pci:v00001DE0* ID_VENDOR_FROM_DATABASE=Groq pci:v00001DE0d00000000* - ID_MODEL_FROM_DATABASE=Q100 Tensor Streaming Processor + ID_MODEL_FROM_DATABASE=TSP100 Tensor Streaming Processor pci:v00001DE1* ID_VENDOR_FROM_DATABASE=Tekram Technology Co.,Ltd. @@ -68733,7 +69594,7 @@ pci:v00001DE1d00000391* ID_MODEL_FROM_DATABASE=TRM-S1040 [DC-315 / DC-395 series] pci:v00001DE1d00002020* - ID_MODEL_FROM_DATABASE=DC-390 + ID_MODEL_FROM_DATABASE=DC-390 Series SCSI Adapter [AMD Am53C974] pci:v00001DE1d0000690C* ID_MODEL_FROM_DATABASE=690c @@ -68783,6 +69644,60 @@ pci:v00001DEFd0000E00B* pci:v00001DEFd0000E00C* ID_MODEL_FROM_DATABASE=eMAG PCI Express Root Port 7 +pci:v00001DEFd0000E100* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Complex A + +pci:v00001DEFd0000E101* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a0 + +pci:v00001DEFd0000E102* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a1 + +pci:v00001DEFd0000E103* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a2 + +pci:v00001DEFd0000E104* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a3 + +pci:v00001DEFd0000E105* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a4 + +pci:v00001DEFd0000E106* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a5 + +pci:v00001DEFd0000E107* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a6 + +pci:v00001DEFd0000E108* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port a7 + +pci:v00001DEFd0000E110* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Complex B + +pci:v00001DEFd0000E111* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b0 + +pci:v00001DEFd0000E112* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b1 + +pci:v00001DEFd0000E113* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b2 + +pci:v00001DEFd0000E114* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b3 + +pci:v00001DEFd0000E115* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b4 + +pci:v00001DEFd0000E116* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b5 + +pci:v00001DEFd0000E117* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b6 + +pci:v00001DEFd0000E118* + ID_MODEL_FROM_DATABASE=Altra PCI Express Root Port b7 + pci:v00001DF3* ID_VENDOR_FROM_DATABASE=Ethernity Networks @@ -68852,6 +69767,12 @@ pci:v00001DF3d00000206sv00001DF3sd00000000* pci:v00001DF3d00000206sv00001DF3sd00000001* ID_MODEL_FROM_DATABASE=ACE-NIC200 Programmable Network Accelerator (ENA2200F) +pci:v00001DF3d00000207* + ID_MODEL_FROM_DATABASE=ACE-NIC50RN Programmable Network Accelerator + +pci:v00001DF3d00000208* + ID_MODEL_FROM_DATABASE=ACE-NIC100RN Programmable Network Accelerator + pci:v00001DF7* ID_VENDOR_FROM_DATABASE=opencpi.org @@ -68987,6 +69908,9 @@ pci:v00001E36d00000003* pci:v00001E36d00008011* ID_MODEL_FROM_DATABASE=I10 [CloudBlazer] +pci:v00001E36d00008012* + ID_MODEL_FROM_DATABASE=I10L [CloudBlazer] + pci:v00001E38* ID_VENDOR_FROM_DATABASE=Blaize, Inc @@ -69102,10 +70026,10 @@ pci:v00001E4C* ID_VENDOR_FROM_DATABASE=GSI Technology pci:v00001E4Cd00000010* - ID_MODEL_FROM_DATABASE=APU [Leda-G] + ID_MODEL_FROM_DATABASE=APU [Leda] pci:v00001E4Cd00000010sv00001E4Csd00000120* - ID_MODEL_FROM_DATABASE=APU [Leda-G] (SE120) + ID_MODEL_FROM_DATABASE=APU [Leda] (SE120) pci:v00001E57* ID_VENDOR_FROM_DATABASE=Beijing Panyi Technology Co., Ltd @@ -69116,6 +70040,12 @@ pci:v00001E57d00000100* pci:v00001E57d00000100sv00000000sd00000100* ID_MODEL_FROM_DATABASE=The device has already been deleted. (PY8800 64GB Accelerator) +pci:v00001E60* + ID_VENDOR_FROM_DATABASE=Hailo Technologies Ltd. + +pci:v00001E60d00002864* + ID_MODEL_FROM_DATABASE=Hailo-8 AI Processor + pci:v00001E6B* ID_VENDOR_FROM_DATABASE=Axiado Corp. @@ -69146,9 +70076,21 @@ pci:v00001E94* pci:v00001E95* ID_VENDOR_FROM_DATABASE=Solid State Storage Technology Corporation +pci:v00001EA0* + ID_VENDOR_FROM_DATABASE=Tencent Technology (Shenzhen) Company Limited + +pci:v00001EA0d00002A16* + ID_MODEL_FROM_DATABASE=Cloud Intelligent Inference Controller + pci:v00001EAB* ID_VENDOR_FROM_DATABASE=Hefei DATANG Storage Technology Co.,LTD. +pci:v00001EABd0000300A* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller 300A + +pci:v00001EABd0000300B* + ID_MODEL_FROM_DATABASE=NVMe SSD Controller 300B + pci:v00001EAE* ID_VENDOR_FROM_DATABASE=XFX Limited @@ -69158,6 +70100,21 @@ pci:v00001EB1* pci:v00001EB1d00001001* ID_MODEL_FROM_DATABASE=Video Accelerator +pci:v00001ED3* + ID_VENDOR_FROM_DATABASE=Yeston + +pci:v00001ED8* + ID_VENDOR_FROM_DATABASE=Digiteq Automotive + +pci:v00001ED8d00000101* + ID_MODEL_FROM_DATABASE=FG4 PCIe Frame Grabber + +pci:v00001ED9* + ID_VENDOR_FROM_DATABASE=Myrtle.ai + +pci:v00001EE9* + ID_VENDOR_FROM_DATABASE=SUSE LLC + pci:v00001FC0* ID_VENDOR_FROM_DATABASE=Ascom (Finland) Oy @@ -69395,9 +70352,21 @@ pci:v00002348d00002010* pci:v00002646* ID_VENDOR_FROM_DATABASE=Kingston Technology Company, Inc. +pci:v00002646d00000010* + ID_MODEL_FROM_DATABASE=HyperX Predator PCIe AHCI SSD + +pci:v00002646d00002262* + ID_MODEL_FROM_DATABASE=KC2000 NVMe SSD + pci:v00002646d00002263* ID_MODEL_FROM_DATABASE=A2000 NVMe SSD +pci:v00002646d00005008* + ID_MODEL_FROM_DATABASE=U-SNS8154P3 NVMe SSD + +pci:v00002646d0000500D* + ID_MODEL_FROM_DATABASE=OM3PDP3 NVMe SSD + pci:v0000270B* ID_VENDOR_FROM_DATABASE=Xantel Corporation @@ -69885,7 +70854,10 @@ pci:v00004348d00007173* ID_MODEL_FROM_DATABASE=CH355 PCI Quad Serial Port Controller pci:v0000434E* - ID_VENDOR_FROM_DATABASE=CAST Navigation LLC + ID_VENDOR_FROM_DATABASE=Cornelis Networks + +pci:v000043BC* + ID_VENDOR_FROM_DATABASE=Tiger Lake-H PCIe Root Port #5 pci:v00004444* ID_VENDOR_FROM_DATABASE=Internext Compression Inc @@ -71624,6 +72596,9 @@ pci:v00008086d00000100sv00001028sd000004AA* pci:v00008086d00000100sv00001043sd0000844D* ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family DRAM Controller (P8P67/P8H67 Series Motherboard) +pci:v00008086d00000100sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=2nd Generation Core Processor Family DRAM Controller (DH61CR motherboard) + pci:v00008086d00000101* ID_MODEL_FROM_DATABASE=Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port @@ -71861,6 +72836,9 @@ pci:v00008086d00000172* pci:v00008086d00000176* ID_MODEL_FROM_DATABASE=3rd Gen Core processor Graphics Controller +pci:v00008086d00000201* + ID_MODEL_FROM_DATABASE=Arctic Sound + pci:v00008086d00000284* ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP LPC Premium Controller/eSPI Controller @@ -71873,6 +72851,27 @@ pci:v00008086d000002A4* pci:v00008086d000002A6* ID_MODEL_FROM_DATABASE=Comet Lake North Peak +pci:v00008086d000002B0* + ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #9 + +pci:v00008086d000002B1* + ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #10 + +pci:v00008086d000002B3* + ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #12 + +pci:v00008086d000002B4* + ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #13 + +pci:v00008086d000002B8* + ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #1 + +pci:v00008086d000002BC* + ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #5 + +pci:v00008086d000002C5* + ID_MODEL_FROM_DATABASE=Comet Lake Serial IO I2C Host Controller + pci:v00008086d000002C8* ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP cAVS @@ -71888,6 +72887,9 @@ pci:v00008086d000002E8* pci:v00008086d000002E9* ID_MODEL_FROM_DATABASE=Comet Lake Serial IO I2C Host Controller +pci:v00008086d000002EA* + ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP LPSS: I2C Controller #2 + pci:v00008086d000002ED* ID_MODEL_FROM_DATABASE=Comet Lake PCH-LP USB 3.1 xHCI Host Controller @@ -72002,9 +73004,15 @@ pci:v00008086d0000040A* pci:v00008086d00000412* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller +pci:v00008086d00000412sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (Alienware X51 R2) + pci:v00008086d00000412sv0000103Csd00001998* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (EliteDesk 800 G1) +pci:v00008086d00000412sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (ThinkCentre E73) + pci:v00008086d00000412sv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller (ThinkCentre M83) @@ -72167,15 +73175,24 @@ pci:v00008086d000006AC* pci:v00008086d000006B0* ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #9 +pci:v00008086d000006BD* + ID_MODEL_FROM_DATABASE=Comet Lake PCIe Port #6 + pci:v00008086d000006C0* ID_MODEL_FROM_DATABASE=Comet Lake PCI Express Root Port #17 pci:v00008086d000006C8* ID_MODEL_FROM_DATABASE=Comet Lake PCH cAVS +pci:v00008086d000006D2* + ID_MODEL_FROM_DATABASE=Comet Lake SATA AHCI Controller + pci:v00008086d000006E0* ID_MODEL_FROM_DATABASE=Comet Lake HECI Controller +pci:v00008086d000006E3* + ID_MODEL_FROM_DATABASE=Comet Lake Keyboard and Text (KT) Redirection + pci:v00008086d000006E8* ID_MODEL_FROM_DATABASE=Comet Lake PCH Serial IO I2C Controller #0 @@ -73224,43 +74241,52 @@ pci:v00008086d00000B27* ID_MODEL_FROM_DATABASE=Thunderbolt 4 USB Controller [Goshen Ridge 2020] pci:v00008086d00000B60* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] pci:v00008086d00000B60sv00001028sd00002060* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe SED MU U.2 1.6TB (P5600)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe SED MU U.2 1.6TB (P5600)) pci:v00008086d00000B60sv00001028sd00002061* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe SED MU U.2 3.2TB (P5600)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe SED MU U.2 3.2TB (P5600)) pci:v00008086d00000B60sv00001028sd00002062* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe SED MU U.2 6.4TB (P5600)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe SED MU U.2 6.4TB (P5600)) pci:v00008086d00000B60sv00001028sd00002064* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe SED RI U.2 1.92TB (P5500)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe SED RI U.2 1.92TB (P5500)) pci:v00008086d00000B60sv00001028sd00002065* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe SED RI U.2 3.84TB (P5500)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe SED RI U.2 3.84TB (P5500)) pci:v00008086d00000B60sv00001028sd00002066* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe SED RI U.2 7.68TB (P5500)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe SED RI U.2 7.68TB (P5500)) pci:v00008086d00000B60sv00001028sd0000209E* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe MU U.2 1.6TB (P5600)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe MU U.2 1.6TB (P5600)) pci:v00008086d00000B60sv00001028sd0000209F* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe MU U.2 3.2TB (P5600)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe MU U.2 3.2TB (P5600)) pci:v00008086d00000B60sv00001028sd00002100* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe MU U.2 6.4TB (P5600)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe MU U.2 6.4TB (P5600)) pci:v00008086d00000B60sv00001028sd00002102* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe RI U.2 1.92TB (P5500)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe RI U.2 1.92TB (P5500)) pci:v00008086d00000B60sv00001028sd00002103* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe RI U.2 3.84TB (P5500)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe RI U.2 3.84TB (P5500)) pci:v00008086d00000B60sv00001028sd00002104* - ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Beta Rock Controller] (NVMe RI U.2 7.68TB (P5500)) + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe RI U.2 7.68TB (P5500)) + +pci:v00008086d00000B60sv00008086sd00008008* + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe Datacenter SSD [3DNAND] SE 2.5" U.2 (P5510)) + +pci:v00008086d00000B60sv00008086sd00008D08* + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe Datacenter SSD [3DNAND] VE 2.5" U.2 (P5316)) + +pci:v00008086d00000B60sv00008086sd00008D1D* + ID_MODEL_FROM_DATABASE=NVMe DC SSD [3DNAND, Sentinel Rock Controller] (NVMe Datacenter SSD [3DNAND] VE E1.L 9.5/18mm (P5316)) pci:v00008086d00000BE0* ID_MODEL_FROM_DATABASE=Atom Processor D2xxx/N2xxx Integrated Graphics Controller @@ -73343,9 +74369,15 @@ pci:v00008086d00000BF7* pci:v00008086d00000C00* ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller +pci:v00008086d00000C00sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller (Alienware X51 R2) + pci:v00008086d00000C00sv0000103Csd00001998* ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller (EliteDesk 800 G1) +pci:v00008086d00000C00sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller (ThinkCentre E73) + pci:v00008086d00000C00sv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=4th Gen Core Processor DRAM Controller (ThinkCentre M83) @@ -75704,6 +76736,15 @@ pci:v00008086d00001132sv00008086sd00004541* pci:v00008086d00001132sv00008086sd00004557* ID_MODEL_FROM_DATABASE=82815 Chipset Graphics Controller (CGC) (D815EGEW Mainboard) +pci:v00008086d00001136* + ID_MODEL_FROM_DATABASE=Thunderbolt 4 Bridge [Maple Ridge 4C 2020] + +pci:v00008086d00001137* + ID_MODEL_FROM_DATABASE=Thunderbolt 4 NHI [Maple Ridge 4C 2020] + +pci:v00008086d00001138* + ID_MODEL_FROM_DATABASE=Thunderbolt 4 USB Controller [Maple Ridge 4C 2020] + pci:v00008086d00001161* ID_MODEL_FROM_DATABASE=82806AA PCI64 Hub Advanced Programmable Interrupt Controller @@ -76403,6 +77444,9 @@ pci:v00008086d00001503sv00001043sd0000849C* pci:v00008086d00001503sv000010CFsd0000161C* ID_MODEL_FROM_DATABASE=82579V Gigabit Network Connection (LIFEBOOK E752) +pci:v00008086d00001503sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=82579V Gigabit Network Connection (DH61CR motherboard) + pci:v00008086d00001507* ID_MODEL_FROM_DATABASE=Ethernet Express Module X520-P2 @@ -76604,6 +77648,9 @@ pci:v00008086d00001521sv0000193Dsd00001005* pci:v00008086d00001521sv0000193Dsd00001007* ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (360T-L) +pci:v00008086d00001521sv0000193Dsd00001080* + ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (NIC-ETH360T-3S-4P) + pci:v00008086d00001521sv00001BD4sd0000001D* ID_MODEL_FROM_DATABASE=I350 Gigabit Network Connection (1G base-T QP EP014Ti1 Adapter) @@ -77060,6 +78107,9 @@ pci:v00008086d0000156Fsv00001028sd000006DC* pci:v00008086d0000156Fsv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Ethernet Connection I219-LM (EliteBook 840 G3) +pci:v00008086d0000156Fsv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Ethernet Connection I219-LM (ThinkPad T570) + pci:v00008086d00001570* ID_MODEL_FROM_DATABASE=Ethernet Connection I219-V @@ -77114,9 +78164,21 @@ pci:v00008086d00001572sv000017AAsd00004001* pci:v00008086d00001572sv000017AAsd00004002* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (ThinkServer X710-2 AnyFabric for 10GbE SFP+) +pci:v00008086d00001572sv0000193Dsd00001020* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (NIC-ETH561F-sL-4x10G) + +pci:v00008086d00001572sv0000193Dsd00001021* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (NIC-ETH561F-sL-2x10G) + +pci:v00008086d00001572sv0000193Dsd00001081* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (NIC-ETH561F-3S-2P) + pci:v00008086d00001572sv000019E5sd0000D11C* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet 2-port X710 10Gb SFP+ Adapter SP330) +pci:v00008086d00001572sv00001BD4sd00000042* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (10G SFP+ DP EP102Fi4 Adapter) + pci:v00008086d00001572sv00001BD4sd00000056* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE SFP+ (Ethernet Network Adapter X710-BM2 for OCP NIC 3.0) @@ -77213,6 +78275,9 @@ pci:v00008086d00001578* pci:v00008086d0000157B* ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection +pci:v00008086d0000157Bsv0000EA50sd0000CC10* + ID_MODEL_FROM_DATABASE=I210 Gigabit Network Connection (RXi2-BP) + pci:v00008086d0000157C* ID_MODEL_FROM_DATABASE=I210 Gigabit Backplane Connection @@ -77249,6 +78314,9 @@ pci:v00008086d00001581sv00001590sd00000000* pci:v00008086d00001581sv00001590sd000000F8* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE backplane (Ethernet 2-port 563i Adapter) +pci:v00008086d00001581sv0000193Dsd0000100E* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE backplane (NIC-ETH561i-Mb-4x10G) + pci:v00008086d00001581sv00008086sd00000000* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GbE backplane (Ethernet Converged Network Adapter XL710-Q2) @@ -77477,6 +78545,9 @@ pci:v00008086d00001592* pci:v00008086d00001592sv00001137sd000002BF* ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (E810CQDA2 2x100 GbE QSFP28 PCIe NIC) +pci:v00008086d00001592sv00008086sd00000001* + ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet Network Adapter E810-C-Q1) + pci:v00008086d00001592sv00008086sd00000002* ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet Network Adapter E810-C-Q2) @@ -77501,6 +78572,12 @@ pci:v00008086d00001592sv00008086sd0000000B* pci:v00008086d00001592sv00008086sd0000000C* ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet 100G 2P E810-C OCP) +pci:v00008086d00001592sv00008086sd0000000D* + ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet Network Adapter E810-L-Q2 for OCP 3.0) + +pci:v00008086d00001592sv00008086sd0000000E* + ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for QSFP (Ethernet Network Adapter E810-2C-Q2) + pci:v00008086d00001593* ID_MODEL_FROM_DATABASE=Ethernet Controller E810-C for SFP @@ -77633,6 +78710,9 @@ pci:v00008086d000015B7* pci:v00008086d000015B8* ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-V +pci:v00008086d000015B8sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=Ethernet Connection (2) I219-V (H270 PC MATE) + pci:v00008086d000015B9* ID_MODEL_FROM_DATABASE=Ethernet Connection (3) I219-LM @@ -77840,6 +78920,15 @@ pci:v00008086d000015FFsv00001137sd000002C1* pci:v00008086d000015FFsv00001137sd000002C2* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (X710T4LG 4x10 GbE RJ45 PCIe NIC) +pci:v00008086d000015FFsv00001137sd000002D9* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-T2L OCP 3.0) + +pci:v00008086d000015FFsv00001137sd000002DA* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-T4L OCP 3.0) + +pci:v00008086d000015FFsv0000193Dsd00001082* + ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (NIC-ETH565T-3S-2P) + pci:v00008086d000015FFsv00008086sd00000000* ID_MODEL_FROM_DATABASE=Ethernet Controller X710 for 10GBASE-T (Ethernet Network Adapter X710-TL) @@ -78036,7 +79125,7 @@ pci:v00008086d00001900* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers pci:v00008086d00001901* - ID_MODEL_FROM_DATABASE=6th-9th Gen Core Processor PCIe Controller (x16) + ID_MODEL_FROM_DATABASE=6th-10th Gen Core Processor PCIe Controller (x16) pci:v00008086d00001902* ID_MODEL_FROM_DATABASE=HD Graphics 510 @@ -78053,6 +79142,9 @@ pci:v00008086d00001903sv00001028sd000006DC* pci:v00008086d00001903sv00001028sd000006E4* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem (XPS 15 9550) +pci:v00008086d00001903sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem (Latitude 11 5175 2-in-1) + pci:v00008086d00001903sv0000103Csd0000825B* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem (OMEN-17-w001nv) @@ -78071,6 +79163,9 @@ pci:v00008086d00001904sv00001028sd000006F3* pci:v00008086d00001904sv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (EliteBook 840 G3) +pci:v00008086d00001904sv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (ThinkPad T570) + pci:v00008086d00001904sv000017AAsd0000382A* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (B51-80 Laptop) @@ -78095,6 +79190,9 @@ pci:v00008086d0000190C* pci:v00008086d0000190Csv00001028sd000006D6* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (Latitude 7275 tablet) +pci:v00008086d0000190Csv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers (Latitude 11 5175 2-in-1) + pci:v00008086d0000190F* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers @@ -78113,6 +79211,9 @@ pci:v00008086d00001911* pci:v00008086d00001911sv00001028sd00000869* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model (Vostro 3470) +pci:v00008086d00001911sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model (H270 PC MATE) + pci:v00008086d00001911sv000017AAsd00002247* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model (ThinkPad T570) @@ -78137,6 +79238,9 @@ pci:v00008086d00001916sv00001028sd000006F3* pci:v00008086d00001916sv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Skylake GT2 [HD Graphics 520] (EliteBook 840 G3) +pci:v00008086d00001916sv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Skylake GT2 [HD Graphics 520] (ThinkPad T570) + pci:v00008086d00001918* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers @@ -78146,6 +79250,9 @@ pci:v00008086d00001919* pci:v00008086d00001919sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Imaging Unit (Latitude 7275 tablet) +pci:v00008086d00001919sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Imaging Unit (Latitude 11 5175 2-in-1) + pci:v00008086d0000191B* ID_MODEL_FROM_DATABASE=HD Graphics 530 @@ -78164,6 +79271,9 @@ pci:v00008086d0000191E* pci:v00008086d0000191Esv00001028sd000006D6* ID_MODEL_FROM_DATABASE=HD Graphics 515 (Latitude 7275 tablet) +pci:v00008086d0000191Esv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=HD Graphics 515 (Latitude 11 5175 2-in-1) + pci:v00008086d0000191F* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers @@ -78497,6 +79607,9 @@ pci:v00008086d00001C02sv00001028sd000004AA* pci:v00008086d00001C02sv00001043sd0000844D* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller (P8 series motherboard) +pci:v00008086d00001C02sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller (DH61CR motherboard) + pci:v00008086d00001C02sv00008086sd00007270* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller (Server Board S1200BT Family) @@ -78644,6 +79757,9 @@ pci:v00008086d00001C20sv000017AAsd000021CF* pci:v00008086d00001C20sv00008086sd00002008* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family High Definition Audio Controller (DQ67SW board) +pci:v00008086d00001C20sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family High Definition Audio Controller (DH61CR motherboard) + pci:v00008086d00001C20sv00008086sd00007270* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family High Definition Audio Controller (Apple MacBookPro8,2 [Core i7, 15", 2011]) @@ -78668,6 +79784,9 @@ pci:v00008086d00001C22sv00001043sd0000844D* pci:v00008086d00001C22sv000017AAsd000021CF* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SMBus Controller (ThinkPad T520) +pci:v00008086d00001C22sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SMBus Controller (DH61CR motherboard) + pci:v00008086d00001C22sv00008086sd00007270* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family SMBus Controller (Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2) @@ -78698,6 +79817,9 @@ pci:v00008086d00001C26sv00001043sd0000844D* pci:v00008086d00001C26sv000017AAsd000021CF* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 (ThinkPad T520) +pci:v00008086d00001C26sv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 (DH61CR motherboard) + pci:v00008086d00001C26sv00008086sd00007270* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #1 (Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2) @@ -78734,6 +79856,9 @@ pci:v00008086d00001C2Dsv00001043sd0000844D* pci:v00008086d00001C2Dsv000017AAsd000021CF* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 (ThinkPad T520) +pci:v00008086d00001C2Dsv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 (DH61CR motherboard) + pci:v00008086d00001C2Dsv00008086sd00007270* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family USB Enhanced Host Controller #2 (Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2) @@ -78764,6 +79889,9 @@ pci:v00008086d00001C3Asv00001043sd0000844D* pci:v00008086d00001C3Asv000017AAsd000021CF* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family MEI Controller #1 (ThinkPad T520) +pci:v00008086d00001C3Asv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family MEI Controller #1 (DH61CR motherboard) + pci:v00008086d00001C3Asv00008086sd00007270* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family MEI Controller #1 (Apple MacBookPro8,2 [Core i7, 15", 2011]) @@ -78893,6 +80021,9 @@ pci:v00008086d00001C5B* pci:v00008086d00001C5C* ID_MODEL_FROM_DATABASE=H61 Express Chipset LPC Controller +pci:v00008086d00001C5Csv00008086sd0000200D* + ID_MODEL_FROM_DATABASE=H61 Express Chipset LPC Controller (DH61CR motherboard) + pci:v00008086d00001C5D* ID_MODEL_FROM_DATABASE=6 Series/C200 Series Chipset Family LPC Controller @@ -80282,6 +81413,9 @@ pci:v00008086d00002442sv00008086sd00004532* pci:v00008086d00002442sv00008086sd00004557* ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (D815EGEW Mainboard) +pci:v00008086d00002442sv00008086sd00004D44* + ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (D850EMV2 motherboard) + pci:v00008086d00002442sv00008086sd00005744* ID_MODEL_FROM_DATABASE=82801BA/BAM UHCI USB 1.1 Controller #1 (S845WD1-E mainboard) @@ -80405,6 +81539,9 @@ pci:v00008086d00002445sv00008086sd00004557* pci:v00008086d00002445sv00008086sd00004656* ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (Desktop Board D815EFV) +pci:v00008086d00002445sv00008086sd00004D44* + ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Audio Controller (D850EMV2 motherboard) + pci:v00008086d00002446* ID_MODEL_FROM_DATABASE=82801BA/BAM AC'97 Modem Controller @@ -80627,6 +81764,9 @@ pci:v00008086d0000244Bsv00008086sd00004532* pci:v00008086d0000244Bsv00008086sd00004557* ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (D815EGEW Mainboard) +pci:v00008086d0000244Bsv00008086sd00004D44* + ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (D850EMV2 motherboard) + pci:v00008086d0000244Bsv00008086sd00005744* ID_MODEL_FROM_DATABASE=82801BA IDE U100 Controller (S845WD1-E mainboard) @@ -82127,6 +83267,9 @@ pci:v00008086d000024F0sv00001CB8sd00000003* pci:v00008086d000024F0sv00001CB8sd00000004* ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, TC4600E QSFP28) +pci:v00008086d000024F0sv0000434Esd00000001* + ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI 100 Series, 1 Port, OCP 3.0 Adapter) + pci:v00008086d000024F0sv00008086sd00002628* ID_MODEL_FROM_DATABASE=Omni-Path HFI Silicon 100 Series [discrete] (Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16) @@ -82481,6 +83624,9 @@ pci:v00008086d00002590sv0000103Csd00000944* pci:v00008086d00002590sv0000103Csd0000099C* ID_MODEL_FROM_DATABASE=Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller (NX6110/NC6120) +pci:v00008086d00002590sv00001043sd000082D9* + ID_MODEL_FROM_DATABASE=Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller (Asus Eee PC 900) + pci:v00008086d00002590sv0000104Dsd000081B7* ID_MODEL_FROM_DATABASE=Mobile 915GM/PM/GMS/910GML Express Processor to DRAM Controller (Vaio VGN-S3XP) @@ -83804,6 +84950,9 @@ pci:v00008086d0000277Csv00001043sd00008178* pci:v00008086d0000277D* ID_MODEL_FROM_DATABASE=82975X PCI Express Root Port +pci:v00008086d00002780* + ID_MODEL_FROM_DATABASE=82915G/GV/GL/910GL [Grantsdale] Graphics Device + pci:v00008086d00002782* ID_MODEL_FROM_DATABASE=82915G Integrated Graphics Controller @@ -86687,6 +87836,9 @@ pci:v00008086d00002A00sv0000103Csd000030C0* pci:v00008086d00002A00sv0000103Csd000030C1* ID_MODEL_FROM_DATABASE=Mobile PM965/GM965/GL960 Memory Controller Hub (Compaq 6910p) +pci:v00008086d00002A00sv0000103Csd000030C5* + ID_MODEL_FROM_DATABASE=Mobile PM965/GM965/GL960 Memory Controller Hub (Compaq 8510p) + pci:v00008086d00002A00sv0000103Csd000030CC* ID_MODEL_FROM_DATABASE=Mobile PM965/GM965/GL960 Memory Controller Hub (Pavilion dv6700) @@ -86852,6 +88004,9 @@ pci:v00008086d00002A41sv0000E4BFsd0000CC4D* pci:v00008086d00002A42* ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset Integrated Graphics Controller +pci:v00008086d00002A42sv00001028sd000002AA* + ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset Integrated Graphics Controller (Dell Inspiron 1545) + pci:v00008086d00002A42sv000017AAsd00002112* ID_MODEL_FROM_DATABASE=Mobile 4 Series Chipset Integrated Graphics Controller (ThinkPad T400) @@ -88092,10 +89247,10 @@ pci:v00008086d00003166sv00008086sd00004210* ID_MODEL_FROM_DATABASE=Dual Band Wireless-AC 3165 Plus Bluetooth (Dual Band Wireless-AC 3165) pci:v00008086d00003184* - ID_MODEL_FROM_DATABASE=UHD Graphics 605 + ID_MODEL_FROM_DATABASE=GeminiLake [UHD Graphics 605] pci:v00008086d00003185* - ID_MODEL_FROM_DATABASE=UHD Graphics 605 + ID_MODEL_FROM_DATABASE=GeminiLake [UHD Graphics 600] pci:v00008086d0000318C* ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor Dynamic Platform and Thermal Framework Processor Participant @@ -88124,6 +89279,12 @@ pci:v00008086d0000319A* pci:v00008086d000031A2* ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor Integrated Sensor Solution +pci:v00008086d000031A8* + ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor USB 3.0 xHCI Controller + +pci:v00008086d000031A8sv00001849sd000031A8* + ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor USB 3.0 xHCI Controller + pci:v00008086d000031AC* ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor Serial IO I2C Host Controller @@ -88175,6 +89336,12 @@ pci:v00008086d000031DB* pci:v00008086d000031DC* ID_MODEL_FROM_DATABASE=AC 1550i Wireless +pci:v00008086d000031E3* + ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor SATA Controller + +pci:v00008086d000031E8* + ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor LPC Controller + pci:v00008086d000031EE* ID_MODEL_FROM_DATABASE=Celeron/Pentium Silver Processor Serial IO UART Host Controller @@ -88430,6 +89597,9 @@ pci:v00008086d000034AB* pci:v00008086d000034B0* ID_MODEL_FROM_DATABASE=Ice Lake-LP PCI Express Root Port #9 +pci:v00008086d000034B7* + ID_MODEL_FROM_DATABASE=Ice Lake-LP PCI Express Root Port #16 + pci:v00008086d000034BC* ID_MODEL_FROM_DATABASE=Ice Lake-LP PCI Express Root Port #5 @@ -88440,13 +89610,13 @@ pci:v00008086d000034C6* ID_MODEL_FROM_DATABASE=Ice Lake-LP Serial IO I2c Controller #5 pci:v00008086d000034C8* - ID_MODEL_FROM_DATABASE=Smart Sound Technology Audio Controller + ID_MODEL_FROM_DATABASE=Ice Lake-LP Smart Sound Technology Audio Controller pci:v00008086d000034D3* ID_MODEL_FROM_DATABASE=Ice Lake-LP SATA Controller [AHCI mode] pci:v00008086d000034E0* - ID_MODEL_FROM_DATABASE=Management Engine Interface + ID_MODEL_FROM_DATABASE=Ice Lake-LP Management Engine pci:v00008086d000034E8* ID_MODEL_FROM_DATABASE=Ice Lake-LP Serial IO I2C Controller #0 @@ -88463,12 +89633,18 @@ pci:v00008086d000034EB* pci:v00008086d000034ED* ID_MODEL_FROM_DATABASE=Ice Lake-LP USB 3.1 xHCI Host Controller +pci:v00008086d000034EF* + ID_MODEL_FROM_DATABASE=Ice Lake-LP DRAM Controller + pci:v00008086d000034F0* ID_MODEL_FROM_DATABASE=Killer Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW) pci:v00008086d000034F8* ID_MODEL_FROM_DATABASE=Ice Lake-LP SD Controller +pci:v00008086d000034FC* + ID_MODEL_FROM_DATABASE=Ice Lake-LP Integrated Sensor Solution + pci:v00008086d00003500* ID_MODEL_FROM_DATABASE=6311ESB/6321ESB PCI Express Upstream Port @@ -90308,35 +91484,38 @@ pci:v00008086d00003E85* pci:v00008086d00003E89* ID_MODEL_FROM_DATABASE=8th Gen Core Processor PCIe Controller (x4) +pci:v00008086d00003E90* + ID_MODEL_FROM_DATABASE=CoffeeLake-S GT1 [UHD Graphics 610] + pci:v00008086d00003E91* - ID_MODEL_FROM_DATABASE=8th Gen Core Processor Gaussian Mixture Model + ID_MODEL_FROM_DATABASE=CoffeeLake-S GT2 [UHD Graphics 630] pci:v00008086d00003E92* - ID_MODEL_FROM_DATABASE=UHD Graphics 630 (Desktop) + ID_MODEL_FROM_DATABASE=CometLake-S GT2 [UHD Graphics 630] pci:v00008086d00003E92sv00001028sd00000869* - ID_MODEL_FROM_DATABASE=UHD Graphics 630 (Desktop) (Vostro 3470) + ID_MODEL_FROM_DATABASE=CometLake-S GT2 [UHD Graphics 630] (Vostro 3470) pci:v00008086d00003E93* - ID_MODEL_FROM_DATABASE=UHD Graphics 610 + ID_MODEL_FROM_DATABASE=CoffeeLake-S GT1 [UHD Graphics 610] pci:v00008086d00003E96* - ID_MODEL_FROM_DATABASE=HD Graphics P630 + ID_MODEL_FROM_DATABASE=CoffeeLake-S GT2 [UHD Graphics P630] pci:v00008086d00003E98* - ID_MODEL_FROM_DATABASE=UHD Graphics 630 (Desktop 9 Series) + ID_MODEL_FROM_DATABASE=CoffeeLake-S GT2 [UHD Graphics 630] pci:v00008086d00003E9B* - ID_MODEL_FROM_DATABASE=UHD Graphics 630 (Mobile) + ID_MODEL_FROM_DATABASE=CoffeeLake-H GT2 [UHD Graphics 630] pci:v00008086d00003EA0* - ID_MODEL_FROM_DATABASE=UHD Graphics 620 (Whiskey Lake) + ID_MODEL_FROM_DATABASE=WhiskeyLake-U GT2 [UHD Graphics 620] pci:v00008086d00003EA0sv00001028sd0000089E* - ID_MODEL_FROM_DATABASE=UHD Graphics 620 (Whiskey Lake) (Inspiron 5482) + ID_MODEL_FROM_DATABASE=WhiskeyLake-U GT2 [UHD Graphics 620] (Inspiron 5482) pci:v00008086d00003EA5* - ID_MODEL_FROM_DATABASE=Iris Plus Graphics 655 + ID_MODEL_FROM_DATABASE=CoffeeLake-U GT3e [Iris Plus Graphics 655] pci:v00008086d00003EC2* ID_MODEL_FROM_DATABASE=8th Gen Core Processor Host Bridge/DRAM Registers @@ -90419,6 +91598,9 @@ pci:v00008086d00004035* pci:v00008086d00004036* ID_MODEL_FROM_DATABASE=5400 Chipset FBD Registers +pci:v00008086d00004041* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] + pci:v00008086d00004100* ID_MODEL_FROM_DATABASE=Moorestown Graphics and Video @@ -90458,6 +91640,27 @@ pci:v00008086d00004116* pci:v00008086d00004117* ID_MODEL_FROM_DATABASE=Atom Processor E6xx PCI Host Bridge #4 +pci:v00008086d00004140* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] + +pci:v00008086d00004140sv00001028sd00002134* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (SED 400GB 2.5" U.2 (P5800X)) + +pci:v00008086d00004140sv00001028sd00002135* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (SED 800GB 2.5" U.2 (P5800X)) + +pci:v00008086d00004140sv00001028sd00002136* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (SED 1.6GB 2.5" U.2 (P5800X)) + +pci:v00008086d00004140sv00001028sd00002137* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (400GB 2.5" U.2 (P5800X)) + +pci:v00008086d00004140sv00001028sd00002138* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (800GB 2.5" U.2 (P5800X)) + +pci:v00008086d00004140sv00001028sd00002139* + ID_MODEL_FROM_DATABASE=NVMe Datacenter SSD [Optane] (1.6TB 2.5" U.2 (P5800X)) + pci:v00008086d00004220* ID_MODEL_FROM_DATABASE=PRO/Wireless 2200BG [Calexico2] Network Connection @@ -90725,15 +91928,75 @@ pci:v00008086d0000423Dsv00008086sd00001311* pci:v00008086d0000423Dsv00008086sd00001316* ID_MODEL_FROM_DATABASE=WiMAX/WiFi Link 5150 (ABG) +pci:v00008086d0000438B* + ID_MODEL_FROM_DATABASE=Tiger Lake-H LPC/eSPI Controller + +pci:v00008086d000043A3* + ID_MODEL_FROM_DATABASE=Tiger Lake-H SMBus Controller + +pci:v00008086d000043A4* + ID_MODEL_FROM_DATABASE=Tiger Lake-H SPI Controller + +pci:v00008086d000043B0* + ID_MODEL_FROM_DATABASE=Tiger Lake-H PCI Express Root Port #9 + +pci:v00008086d000043BC* + ID_MODEL_FROM_DATABASE=Tiger Lake-H PCI Express Root Port #5 + +pci:v00008086d000043C8* + ID_MODEL_FROM_DATABASE=Tiger Lake-H HD Audio Controller + +pci:v00008086d000043E0* + ID_MODEL_FROM_DATABASE=Tiger Lake-H Management Engine Interface + +pci:v00008086d000043E8* + ID_MODEL_FROM_DATABASE=Tiger Lake-H Serial IO I2C Controller #0 + +pci:v00008086d000043ED* + ID_MODEL_FROM_DATABASE=Tiger Lake-H USB 3.2 Gen 2x1 xHCI Host Controller + +pci:v00008086d000043EF* + ID_MODEL_FROM_DATABASE=Tiger Lake-H Shared SRAM + +pci:v00008086d000043F0* + ID_MODEL_FROM_DATABASE=Wi-Fi 6 AX201 + pci:v00008086d0000444E* ID_MODEL_FROM_DATABASE=Turbo Memory Controller pci:v00008086d0000467F* ID_MODEL_FROM_DATABASE=Volume Management Device NVMe RAID Controller +pci:v00008086d00004680* + ID_MODEL_FROM_DATABASE=AlderLake-S GT1 + +pci:v00008086d000046A0* + ID_MODEL_FROM_DATABASE=AlderLake-P GT2 + +pci:v00008086d00004905* + ID_MODEL_FROM_DATABASE=DG1 [Iris Xe MAX Graphics] + +pci:v00008086d00004906* + ID_MODEL_FROM_DATABASE=DG1 [Iris Xe Pod] + +pci:v00008086d00004907* + ID_MODEL_FROM_DATABASE=SG1 [Server GPU SG-18M] + +pci:v00008086d00004908* + ID_MODEL_FROM_DATABASE=DG1 [Iris Xe Graphics] + pci:v00008086d00004C3D* ID_MODEL_FROM_DATABASE=Volume Management Device NVMe RAID Controller +pci:v00008086d00004F80* + ID_MODEL_FROM_DATABASE=DG2 + +pci:v00008086d00004F81* + ID_MODEL_FROM_DATABASE=DG2 + +pci:v00008086d00004F82* + ID_MODEL_FROM_DATABASE=DG2 + pci:v00008086d00005001* ID_MODEL_FROM_DATABASE=LE80578 @@ -90890,6 +92153,9 @@ pci:v00008086d0000530D* pci:v00008086d00005502* ID_MODEL_FROM_DATABASE=Ethernet Controller (2) I225-LMvP +pci:v00008086d00005504* + ID_MODEL_FROM_DATABASE=Ethernet Controller I226-K + pci:v00008086d00005845* ID_MODEL_FROM_DATABASE=QEMU NVM Express Controller @@ -90932,6 +92198,9 @@ pci:v00008086d0000590F* pci:v00008086d0000590Fsv00001462sd00007A68* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers (B250 KRAIT GAMING (MS-7A68)) +pci:v00008086d0000590Fsv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers (H270 PC MATE) + pci:v00008086d00005910* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers @@ -90941,6 +92210,9 @@ pci:v00008086d00005911* pci:v00008086d00005912* ID_MODEL_FROM_DATABASE=HD Graphics 630 +pci:v00008086d00005912sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=HD Graphics 630 (H270 PC MATE) + pci:v00008086d00005914* ID_MODEL_FROM_DATABASE=Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers @@ -92081,6 +93353,9 @@ pci:v00008086d00008500sv00001993sd00000DEE* pci:v00008086d00008500sv00001993sd00000DEF* ID_MODEL_FROM_DATABASE=IXP4XX Network Processor (IXP420/421/422/425/IXC1100) (mGuard-PCI AV#0) +pci:v00008086d00008603* + ID_MODEL_FROM_DATABASE=Ice Lake-LP Dynamic Tuning Processor Participant + pci:v00008086d000087C0* ID_MODEL_FROM_DATABASE=UHD Graphics 617 @@ -92165,12 +93440,18 @@ pci:v00008086d00008819* pci:v00008086d00008A0D* ID_MODEL_FROM_DATABASE=Ice Lake Thunderbolt 3 NHI #1 +pci:v00008086d00008A12* + ID_MODEL_FROM_DATABASE=Ice Lake-LP Processor Host Bridge/DRAM Registers + pci:v00008086d00008A13* ID_MODEL_FROM_DATABASE=Ice Lake Thunderbolt 3 USB Controller pci:v00008086d00008A17* ID_MODEL_FROM_DATABASE=Ice Lake Thunderbolt 3 NHI #0 +pci:v00008086d00008A19* + ID_MODEL_FROM_DATABASE=Image Signal Processor + pci:v00008086d00008A1D* ID_MODEL_FROM_DATABASE=Ice Lake Thunderbolt 3 PCI Express Root Port #0 @@ -92207,9 +93488,15 @@ pci:v00008086d00008C01* pci:v00008086d00008C02* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] +pci:v00008086d00008C02sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (Alienware X51 R2) + pci:v00008086d00008C02sv0000103Csd00001998* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (EliteDesk 800 G1) +pci:v00008086d00008C02sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (ThinkCentre E73) + pci:v00008086d00008C02sv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] (ThinkCentre M83) @@ -92258,6 +93545,9 @@ pci:v00008086d00008C10sv00001043sd00008534* pci:v00008086d00008C10sv000017AAsd0000220E* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 (ThinkPad T440p) +pci:v00008086d00008C10sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 (ThinkCentre E73) + pci:v00008086d00008C11* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #1 @@ -92294,6 +93584,9 @@ pci:v00008086d00008C19* pci:v00008086d00008C1A* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #6 +pci:v00008086d00008C1Asv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #6 (ThinkCentre E73) + pci:v00008086d00008C1B* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family PCI Express Root Port #6 @@ -92312,6 +93605,9 @@ pci:v00008086d00008C1F* pci:v00008086d00008C20* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller +pci:v00008086d00008C20sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller (Alienware X51 R2) + pci:v00008086d00008C20sv0000103Csd00001909* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset High Definition Audio Controller (ZBook 15) @@ -92330,6 +93626,9 @@ pci:v00008086d00008C21* pci:v00008086d00008C22* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller +pci:v00008086d00008C22sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (Alienware X51 R2) + pci:v00008086d00008C22sv0000103Csd00001909* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (ZBook 15) @@ -92339,6 +93638,9 @@ pci:v00008086d00008C22sv0000103Csd00001998* pci:v00008086d00008C22sv000017AAsd0000220E* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (ThinkPad T440p) +pci:v00008086d00008C22sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (ThinkCentre E73) + pci:v00008086d00008C22sv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family SMBus Controller (ThinkCentre M83) @@ -92351,6 +93653,9 @@ pci:v00008086d00008C24* pci:v00008086d00008C26* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 +pci:v00008086d00008C26sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (Alienware X51 R2) + pci:v00008086d00008C26sv0000103Csd00001909* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (ZBook 15) @@ -92363,6 +93668,9 @@ pci:v00008086d00008C26sv000017AAsd0000220E* pci:v00008086d00008C26sv000017AAsd00002210* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (ThinkPad T540p) +pci:v00008086d00008C26sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (ThinkCentre E73) + pci:v00008086d00008C26sv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #1 (ThinkCentre M83) @@ -92372,6 +93680,9 @@ pci:v00008086d00008C26sv00002210sd000017AA* pci:v00008086d00008C2D* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 +pci:v00008086d00008C2Dsv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (Alienware X51 R2) + pci:v00008086d00008C2Dsv0000103Csd00001909* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (ZBook 15) @@ -92381,12 +93692,18 @@ pci:v00008086d00008C2Dsv0000103Csd00001998* pci:v00008086d00008C2Dsv000017AAsd0000220E* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (ThinkPad T440p) +pci:v00008086d00008C2Dsv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (ThinkCentre E73) + pci:v00008086d00008C2Dsv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB EHCI #2 (ThinkCentre M83) pci:v00008086d00008C31* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI +pci:v00008086d00008C31sv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (Alienware X51 R2) + pci:v00008086d00008C31sv0000103Csd00001909* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (ZBook 15) @@ -92396,6 +93713,9 @@ pci:v00008086d00008C31sv0000103Csd00001998* pci:v00008086d00008C31sv000017AAsd0000220E* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (ThinkPad T440p) +pci:v00008086d00008C31sv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (ThinkCentre E73) + pci:v00008086d00008C31sv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family USB xHCI (ThinkCentre M83) @@ -92408,6 +93728,9 @@ pci:v00008086d00008C34* pci:v00008086d00008C3A* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 +pci:v00008086d00008C3Asv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (Alienware X51 R2) + pci:v00008086d00008C3Asv0000103Csd00001909* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (ZBook 15) @@ -92417,6 +93740,9 @@ pci:v00008086d00008C3Asv0000103Csd00001998* pci:v00008086d00008C3Asv000017AAsd0000220E* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (ThinkPad T440p) +pci:v00008086d00008C3Asv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (ThinkCentre E73) + pci:v00008086d00008C3Asv000017AAsd0000309F* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family MEI Controller #1 (ThinkCentre M83) @@ -92465,6 +93791,9 @@ pci:v00008086d00008C49* pci:v00008086d00008C4A* ID_MODEL_FROM_DATABASE=H87 Express LPC Controller +pci:v00008086d00008C4Asv00001028sd000005D7* + ID_MODEL_FROM_DATABASE=H87 Express LPC Controller (Alienware X51 R2) + pci:v00008086d00008C4B* ID_MODEL_FROM_DATABASE=HM87 Express LPC Controller @@ -92531,6 +93860,9 @@ pci:v00008086d00008C5B* pci:v00008086d00008C5C* ID_MODEL_FROM_DATABASE=H81 Express LPC Controller +pci:v00008086d00008C5Csv000017AAsd00003098* + ID_MODEL_FROM_DATABASE=H81 Express LPC Controller (ThinkCentre E73) + pci:v00008086d00008C5D* ID_MODEL_FROM_DATABASE=8 Series/C220 Series Chipset Family LPC Controller @@ -92885,83 +94217,119 @@ pci:v00008086d00009641* pci:v00008086d000096A1* ID_MODEL_FROM_DATABASE=Integrated RAID +pci:v00008086d00009A01* + ID_MODEL_FROM_DATABASE=11th Gen Core Processor PCIe Controller #1 + +pci:v00008086d00009A03* + ID_MODEL_FROM_DATABASE=TigerLake-LP Dynamic Tuning Processor Participant + pci:v00008086d00009A09* ID_MODEL_FROM_DATABASE=11th Gen Core Processor PCIe Controller pci:v00008086d00009A0B* ID_MODEL_FROM_DATABASE=Volume Management Device NVMe RAID Controller +pci:v00008086d00009A0D* + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Telemetry Aggregator + +pci:v00008086d00009A0F* + ID_MODEL_FROM_DATABASE=11th Gen Core Processor PCIe Controller #0 + +pci:v00008086d00009A11* + ID_MODEL_FROM_DATABASE=GNA Scoring Accelerator module + pci:v00008086d00009A13* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt USB Controller + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 USB Controller pci:v00008086d00009A14* ID_MODEL_FROM_DATABASE=11th Gen Core Processor Host Bridge/DRAM Registers pci:v00008086d00009A17* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt USB Controller + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 USB Controller pci:v00008086d00009A1B* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt NHI #0 + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 NHI #0 pci:v00008086d00009A1D* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt NHI #1 + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 NHI #1 pci:v00008086d00009A1F* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt NHI #0 + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 NHI #0 pci:v00008086d00009A21* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt NHI #1 + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 NHI #1 pci:v00008086d00009A23* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt PCI Express Root Port #0 + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #0 pci:v00008086d00009A25* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt PCI Express Root Port #1 + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #1 + +pci:v00008086d00009A26* + ID_MODEL_FROM_DATABASE=11th Gen Core Processor Host Bridge/DRAM Registers pci:v00008086d00009A27* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt PCI Express Root Port #2 + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #2 pci:v00008086d00009A29* - ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt PCI Express Root Port #3 + ID_MODEL_FROM_DATABASE=Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #3 pci:v00008086d00009A2B* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt PCI Express Root Port #0 + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 PCI Express Root Port #0 pci:v00008086d00009A2D* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt PCI Express Root Port #1 + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 PCI Express Root Port #1 pci:v00008086d00009A2F* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt PCI Express Root Port #2 + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 PCI Express Root Port #2 pci:v00008086d00009A31* - ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt PCI Express Root Port #3 + ID_MODEL_FROM_DATABASE=Tiger Lake-H Thunderbolt 4 PCI Express Root Port #3 pci:v00008086d00009A33* ID_MODEL_FROM_DATABASE=Tiger Lake Trace Hub +pci:v00008086d00009A36* + ID_MODEL_FROM_DATABASE=11th Gen Core Processor Host Bridge/DRAM Registers + pci:v00008086d00009A49* - ID_MODEL_FROM_DATABASE=Iris Xe Graphics + ID_MODEL_FROM_DATABASE=TigerLake GT2 [Iris Xe Graphics] + +pci:v00008086d00009A60* + ID_MODEL_FROM_DATABASE=TigerLake GT2 [Iris Xe Graphics] + +pci:v00008086d00009A68* + ID_MODEL_FROM_DATABASE=Tiger Lake-H UHD Graphics pci:v00008086d00009B41* - ID_MODEL_FROM_DATABASE=UHD Graphics + ID_MODEL_FROM_DATABASE=CometLake-U GT2 [UHD Graphics] pci:v00008086d00009B44* ID_MODEL_FROM_DATABASE=10th Gen Core Processor Host Bridge/DRAM Registers +pci:v00008086d00009B53* + ID_MODEL_FROM_DATABASE=Comet Lake-S 6c Host Bridge/DRAM Controller + pci:v00008086d00009B54* ID_MODEL_FROM_DATABASE=10th Gen Core Processor Host Bridge/DRAM Registers pci:v00008086d00009B61* ID_MODEL_FROM_DATABASE=Comet Lake-U v1 4c Host Bridge/DRAM Controller +pci:v00008086d00009B63* + ID_MODEL_FROM_DATABASE=10th Gen Core Processor Host Bridge/DRAM Registers + pci:v00008086d00009B64* ID_MODEL_FROM_DATABASE=10th Gen Core Processor Host Bridge/DRAM Registers pci:v00008086d00009BC4* - ID_MODEL_FROM_DATABASE=UHD Graphics + ID_MODEL_FROM_DATABASE=CometLake-H GT2 [UHD Graphics] + +pci:v00008086d00009BC5* + ID_MODEL_FROM_DATABASE=CometLake-S GT2 [UHD Graphics 630] pci:v00008086d00009BC8* - ID_MODEL_FROM_DATABASE=UHD Graphics 630 + ID_MODEL_FROM_DATABASE=CometLake-S GT2 [UHD Graphics 630] pci:v00008086d00009C00* ID_MODEL_FROM_DATABASE=8 Series SATA Controller 1 [IDE mode] @@ -93287,6 +94655,9 @@ pci:v00008086d00009D03sv00001025sd0000115F* pci:v00008086d00009D03sv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] (Latitude E7470) +pci:v00008086d00009D03sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] (Latitude 11 5175 2-in-1) + pci:v00008086d00009D03sv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP SATA Controller [AHCI mode] (Latitude 3570) @@ -93332,6 +94703,9 @@ pci:v00008086d00009D17* pci:v00008086d00009D18* ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #9 +pci:v00008086d00009D18sv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #9 (ThinkPad T570) + pci:v00008086d00009D18sv000017AAsd0000382A* ID_MODEL_FROM_DATABASE=Sunrise Point-LP PCI Express Root Port #9 (B51-80 Laptop) @@ -93353,12 +94727,18 @@ pci:v00008086d00009D21sv00001028sd000006D6* pci:v00008086d00009D21sv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (Latitude E7470) +pci:v00008086d00009D21sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (Latitude 11 5175 2-in-1) + pci:v00008086d00009D21sv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (Latitude 3570) pci:v00008086d00009D21sv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (EliteBook 840 G3) +pci:v00008086d00009D21sv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (ThinkPad T570) + pci:v00008086d00009D21sv000017AAsd0000224F* ID_MODEL_FROM_DATABASE=Sunrise Point-LP PMC (ThinkPad X1 Carbon 5th Gen) @@ -93380,6 +94760,9 @@ pci:v00008086d00009D23sv00001028sd000006D6* pci:v00008086d00009D23sv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus (Latitude E7470) +pci:v00008086d00009D23sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus (Latitude 11 5175 2-in-1) + pci:v00008086d00009D23sv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP SMBus (Latitude 3570) @@ -93425,6 +94808,9 @@ pci:v00008086d00009D2Fsv00001028sd000006D6* pci:v00008086d00009D2Fsv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (Latitude E7470) +pci:v00008086d00009D2Fsv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (Latitude 11 5175 2-in-1) + pci:v00008086d00009D2Fsv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP USB 3.0 xHCI Controller (Latitude 3570) @@ -93452,6 +94838,9 @@ pci:v00008086d00009D31sv00001028sd000006D6* pci:v00008086d00009D31sv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem (Latitude E7470) +pci:v00008086d00009D31sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem (Latitude 11 5175 2-in-1) + pci:v00008086d00009D31sv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Thermal subsystem (Latitude 3570) @@ -93476,12 +94865,18 @@ pci:v00008086d00009D32* pci:v00008086d00009D32sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=CSI-2 Host Controller (Latitude 7275 tablet) +pci:v00008086d00009D32sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=CSI-2 Host Controller (Latitude 11 5175 2-in-1) + pci:v00008086d00009D35* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Integrated Sensor Hub pci:v00008086d00009D35sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Integrated Sensor Hub (Latitude 7275 tablet) +pci:v00008086d00009D35sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Integrated Sensor Hub (Latitude 11 5175 2-in-1) + pci:v00008086d00009D3A* ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 @@ -93494,6 +94889,9 @@ pci:v00008086d00009D3Asv00001028sd000006D6* pci:v00008086d00009D3Asv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 (Latitude E7470) +pci:v00008086d00009D3Asv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 (Latitude 11 5175 2-in-1) + pci:v00008086d00009D3Asv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP CSME HECI #1 (Latitude 3570) @@ -93518,6 +94916,9 @@ pci:v00008086d00009D3D* pci:v00008086d00009D3Dsv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Active Management Technology - SOL (EliteBook 840 G3) +pci:v00008086d00009D3Dsv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Active Management Technology - SOL (ThinkPad T570) + pci:v00008086d00009D43* ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller @@ -93530,6 +94931,9 @@ pci:v00008086d00009D46* pci:v00008086d00009D46sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=LPC/eSPI Controller (Latitude 7275 tablet) +pci:v00008086d00009D46sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=LPC/eSPI Controller (Latitude 11 5175 2-in-1) + pci:v00008086d00009D48* ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller @@ -93542,6 +94946,9 @@ pci:v00008086d00009D48sv00001028sd000006F3* pci:v00008086d00009D48sv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller (EliteBook 840 G3) +pci:v00008086d00009D48sv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP LPC Controller (ThinkPad T570) + pci:v00008086d00009D4E* ID_MODEL_FROM_DATABASE=Sunrise Point LPC Controller/eSPI Controller @@ -93575,6 +94982,9 @@ pci:v00008086d00009D60sv00001025sd0000115F* pci:v00008086d00009D60sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (Latitude 7275 tablet) +pci:v00008086d00009D60sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (Latitude 11 5175 2-in-1) + pci:v00008086d00009D60sv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #0 (Latitude 3570) @@ -93593,12 +95003,18 @@ pci:v00008086d00009D61* pci:v00008086d00009D61sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #1 (Latitude 7275 tablet) +pci:v00008086d00009D61sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #1 (Latitude 11 5175 2-in-1) + pci:v00008086d00009D62* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #2 pci:v00008086d00009D62sv00001028sd000006D6* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #2 (Latitude 7275 tablet) +pci:v00008086d00009D62sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #2 (Latitude 11 5175 2-in-1) + pci:v00008086d00009D63* ID_MODEL_FROM_DATABASE=Sunrise Point-LP Serial IO I2C Controller #3 @@ -93620,12 +95036,18 @@ pci:v00008086d00009D70sv00001028sd000006D6* pci:v00008086d00009D70sv00001028sd000006DC* ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (Latitude E7470) +pci:v00008086d00009D70sv00001028sd000006E6* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (Latitude 11 5175 2-in-1) + pci:v00008086d00009D70sv00001028sd000006F3* ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (Latitude 3570) pci:v00008086d00009D70sv0000103Csd00008079* ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (EliteBook 840 G3) +pci:v00008086d00009D70sv000017AAsd00002247* + ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (ThinkPad T570) + pci:v00008086d00009D70sv000017AAsd0000382A* ID_MODEL_FROM_DATABASE=Sunrise Point-LP HD Audio (B51-80 Laptop) @@ -93821,6 +95243,9 @@ pci:v00008086d0000A0AB* pci:v00008086d0000A0B0* ID_MODEL_FROM_DATABASE=Tiger Lake-LP PCI Express Root Port #9 +pci:v00008086d0000A0BD* + ID_MODEL_FROM_DATABASE=Tigerlake PCH-LP PCI Express Root Port #6 + pci:v00008086d0000A0BF* ID_MODEL_FROM_DATABASE=Tiger Lake-LP PCI Express Root Port #8 @@ -94382,6 +95807,9 @@ pci:v00008086d0000A256* pci:v00008086d0000A282* ID_MODEL_FROM_DATABASE=200 Series PCH SATA controller [AHCI mode] +pci:v00008086d0000A282sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH SATA controller [AHCI mode] (H270 PC MATE) + pci:v00008086d0000A286* ID_MODEL_FROM_DATABASE=200 Series PCH SATA controller [RAID mode] @@ -94400,18 +95828,27 @@ pci:v00008086d0000A293* pci:v00008086d0000A294* ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #5 +pci:v00008086d0000A294sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #5 (H270 PC MATE) + pci:v00008086d0000A295* ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #6 pci:v00008086d0000A296* ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #7 +pci:v00008086d0000A296sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #7 (H270 PC MATE) + pci:v00008086d0000A297* ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #8 pci:v00008086d0000A298* ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #9 +pci:v00008086d0000A298sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #9 (H270 PC MATE) + pci:v00008086d0000A299* ID_MODEL_FROM_DATABASE=200 Series PCH PCI Express Root Port #10 @@ -94439,9 +95876,15 @@ pci:v00008086d0000A2A0* pci:v00008086d0000A2A1* ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family Power Management Controller +pci:v00008086d0000A2A1sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family Power Management Controller (H270 PC MATE) + pci:v00008086d0000A2A3* ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family SMBus Controller +pci:v00008086d0000A2A3sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family SMBus Controller (H270 PC MATE) + pci:v00008086d0000A2A4* ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family SPI Controller @@ -94466,18 +95909,30 @@ pci:v00008086d0000A2AA* pci:v00008086d0000A2AF* ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family USB 3.0 xHCI Controller +pci:v00008086d0000A2AFsv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series/Z370 Chipset Family USB 3.0 xHCI Controller (H270 PC MATE) + pci:v00008086d0000A2B1* ID_MODEL_FROM_DATABASE=200 Series PCH Thermal Subsystem +pci:v00008086d0000A2B1sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH Thermal Subsystem (H270 PC MATE) + pci:v00008086d0000A2BA* ID_MODEL_FROM_DATABASE=200 Series PCH CSME HECI #1 +pci:v00008086d0000A2BAsv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH CSME HECI #1 (H270 PC MATE) + pci:v00008086d0000A2BB* ID_MODEL_FROM_DATABASE=200 Series PCH CSME HECI #2 pci:v00008086d0000A2C4* ID_MODEL_FROM_DATABASE=200 Series PCH LPC Controller (H270) +pci:v00008086d0000A2C4sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH LPC Controller (H270) (H270 PC MATE) + pci:v00008086d0000A2C5* ID_MODEL_FROM_DATABASE=200 Series PCH LPC Controller (Z270) @@ -94541,6 +95996,12 @@ pci:v00008086d0000A2EE* pci:v00008086d0000A2F0* ID_MODEL_FROM_DATABASE=200 Series PCH HD Audio +pci:v00008086d0000A2F0sv00001462sd00007A72* + ID_MODEL_FROM_DATABASE=200 Series PCH HD Audio (H270 PC MATE) + +pci:v00008086d0000A2F0sv00001462sd0000FA72* + ID_MODEL_FROM_DATABASE=200 Series PCH HD Audio (H270 PC MATE) + pci:v00008086d0000A304* ID_MODEL_FROM_DATABASE=H370 Chipset LPC/eSPI Controller @@ -94580,6 +96041,9 @@ pci:v00008086d0000A324sv00001028sd00000869* pci:v00008086d0000A328* ID_MODEL_FROM_DATABASE=Cannon Lake PCH Serial IO UART Host Controller +pci:v00008086d0000A32B* + ID_MODEL_FROM_DATABASE=Cannon Lake PCH SPI Host Controller + pci:v00008086d0000A32C* ID_MODEL_FROM_DATABASE=Cannon Lake PCH PCI Express Root Port #21 @@ -94715,9 +96179,15 @@ pci:v00008086d0000A379sv00001028sd00000869* pci:v00008086d0000A382* ID_MODEL_FROM_DATABASE=400 Series Chipset Family SATA AHCI Controller +pci:v00008086d0000A3A1* + ID_MODEL_FROM_DATABASE=Memory controller + pci:v00008086d0000A3A3* ID_MODEL_FROM_DATABASE=Comet Lake PCH-V SMBus Host Controller +pci:v00008086d0000A3AF* + ID_MODEL_FROM_DATABASE=Comet Lake PCH-V USB Controller + pci:v00008086d0000A3B1* ID_MODEL_FROM_DATABASE=Comet Lake PCH-V Thermal Subsystem @@ -94835,6 +96305,9 @@ pci:v00008086d0000D158* pci:v00008086d0000F1A5* ID_MODEL_FROM_DATABASE=SSD 600P Series +pci:v00008086d0000F1A5sv00008086sd0000390A* + ID_MODEL_FROM_DATABASE=SSD 600P Series (SSDPEKKW256G7 256GB) + pci:v00008086d0000F1A6* ID_MODEL_FROM_DATABASE=SSD Pro 7600p/760p/E 6100p Series @@ -94853,6 +96326,15 @@ pci:v00008088d00000101* pci:v00008088d00000101sv00008088sd00000201* ID_MODEL_FROM_DATABASE=WX1860A2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200T) +pci:v00008088d00000101sv00008088sd00004201* + ID_MODEL_FROM_DATABASE=WX1860A2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200T (WOL)) + +pci:v00008088d00000101sv00008088sd00008201* + ID_MODEL_FROM_DATABASE=WX1860A2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200T (NCSI)) + +pci:v00008088d00000101sv00008088sd0000C201* + ID_MODEL_FROM_DATABASE=WX1860A2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200T (WOL, NCSI)) + pci:v00008088d00000102* ID_MODEL_FROM_DATABASE=WX1860A2S Gigabit Ethernet Controller @@ -94868,6 +96350,15 @@ pci:v00008088d00000103sv00008088sd00000401* pci:v00008088d00000103sv00008088sd00000440* ID_MODEL_FROM_DATABASE=WX1860A4 Gigabit Ethernet Controller (Qual-Port Ethernet Network Adaptor SF400-OCP) +pci:v00008088d00000103sv00008088sd00004103* + ID_MODEL_FROM_DATABASE=WX1860A4 Gigabit Ethernet Controller (Quad-Port Ethernet Network Adaptor SF400T (WOL)) + +pci:v00008088d00000103sv00008088sd00008103* + ID_MODEL_FROM_DATABASE=WX1860A4 Gigabit Ethernet Controller (Quad-Port Ethernet Network Adaptor SF400T (NCSI)) + +pci:v00008088d00000103sv00008088sd0000C103* + ID_MODEL_FROM_DATABASE=WX1860A4 Gigabit Ethernet Controller (Quad-Port Ethernet Network Adaptor SF400T (WOL, NCSI)) + pci:v00008088d00000104* ID_MODEL_FROM_DATABASE=WX1860A4S Gigabit Ethernet Controller @@ -94880,6 +96371,15 @@ pci:v00008088d00000105* pci:v00008088d00000105sv00008088sd00000202* ID_MODEL_FROM_DATABASE=WX1860AL2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200HT) +pci:v00008088d00000105sv00008088sd00004202* + ID_MODEL_FROM_DATABASE=WX1860AL2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200HT (WOL)) + +pci:v00008088d00000105sv00008088sd00008202* + ID_MODEL_FROM_DATABASE=WX1860AL2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200HT (NCSI)) + +pci:v00008088d00000105sv00008088sd0000C202* + ID_MODEL_FROM_DATABASE=WX1860AL2 Gigabit Ethernet Controller (Dual-Port Ethernet Network Adaptor SF200HT (WOL, NCSI)) + pci:v00008088d00000106* ID_MODEL_FROM_DATABASE=WX1860AL2S Gigabit Ethernet Controller @@ -94892,18 +96392,75 @@ pci:v00008088d00000107* pci:v00008088d00000107sv00008088sd00000402* ID_MODEL_FROM_DATABASE=WX1860AL4 Gigabit Ethernet Controller (Qual-Port Ethernet Network Adaptor SF400HT) +pci:v00008088d00000107sv00008088sd00004402* + ID_MODEL_FROM_DATABASE=WX1860AL4 Gigabit Ethernet Controller (Quad-Port Ethernet Network Adaptor SF400HT (WOL)) + +pci:v00008088d00000107sv00008088sd00008402* + ID_MODEL_FROM_DATABASE=WX1860AL4 Gigabit Ethernet Controller (Quad-Port Ethernet Network Adaptor SF400HT (NCSI)) + +pci:v00008088d00000107sv00008088sd0000C402* + ID_MODEL_FROM_DATABASE=WX1860AL4 Gigabit Ethernet Controller (Quad-Port Ethernet Network Adaptor SF400HT (WOL, NCSI)) + pci:v00008088d00000108* ID_MODEL_FROM_DATABASE=WX1860AL4S Gigabit Ethernet Controller pci:v00008088d00000108sv00008088sd00000420* ID_MODEL_FROM_DATABASE=WX1860AL4S Gigabit Ethernet Controller (Qual-Port Ethernet Network Adaptor SF400HT-S) +pci:v00008088d00000109* + ID_MODEL_FROM_DATABASE=WX1860-LC Gigabit Ethernet Controller + +pci:v00008088d0000010A* + ID_MODEL_FROM_DATABASE=WX1860A1 Gigabit Ethernet Controller + +pci:v00008088d0000010B* + ID_MODEL_FROM_DATABASE=WX1860AL1 Gigabit Ethernet Controller + +pci:v00008088d0000010Bsv00008088sd00000102* + ID_MODEL_FROM_DATABASE=WX1860AL1 Gigabit Ethernet Controller (Single-Port Ethernet Network Adaptor SF100HT) + +pci:v00008088d0000010Bsv00008088sd00004102* + ID_MODEL_FROM_DATABASE=WX1860AL1 Gigabit Ethernet Controller (Single-Port Ethernet Network Adaptor SF100HT (WOL)) + +pci:v00008088d0000010Bsv00008088sd00008102* + ID_MODEL_FROM_DATABASE=WX1860AL1 Gigabit Ethernet Controller (Single-Port Ethernet Network Adaptor SF100HT (NCSI)) + +pci:v00008088d0000010Bsv00008088sd0000C102* + ID_MODEL_FROM_DATABASE=WX1860AL1 Gigabit Ethernet Controller (Single-Port Ethernet Network Adaptor SF100HT (WOL, NCSI)) + +pci:v00008088d00000111* + ID_MODEL_FROM_DATABASE=WX1860A2 Ethernet Controller Virtual Function + +pci:v00008088d00000113* + ID_MODEL_FROM_DATABASE=WX1860A4 Ethernet Controller Virtual Function + +pci:v00008088d00000115* + ID_MODEL_FROM_DATABASE=WX1860AL2 Ethernet Controller Virtual Function + +pci:v00008088d00000117* + ID_MODEL_FROM_DATABASE=WX1860AL4 Ethernet Controller Virtual Function + +pci:v00008088d00000119* + ID_MODEL_FROM_DATABASE=WX1860-LC Gigabit Ethernet Controller Virtual Function + +pci:v00008088d0000011A* + ID_MODEL_FROM_DATABASE=WX1860A1 Gigabit Ethernet Controller Virtual Function + +pci:v00008088d0000011B* + ID_MODEL_FROM_DATABASE=WX1860AL1 Gigabit Ethernet Controller Virtual Function + +pci:v00008088d00001000* + ID_MODEL_FROM_DATABASE=Ethernet Controller RP1000 Virtual Function for 10GbE SFP+ + pci:v00008088d00001001* ID_MODEL_FROM_DATABASE=Ethernet Controller RP1000 for 10GbE SFP+ pci:v00008088d00001001sv00008088sd00000000* ID_MODEL_FROM_DATABASE=Ethernet Controller RP1000 for 10GbE SFP+ (Ethernet Network Adaptor RP1000 for 10GbE SFP+) +pci:v00008088d00002000* + ID_MODEL_FROM_DATABASE=Ethernet Controller RP2000 Virtual Function for 10GbE SFP+ + pci:v00008088d00002001* ID_MODEL_FROM_DATABASE=Ethernet Controller RP2000 for 10GbE SFP+ @@ -96437,6 +97994,9 @@ pci:v00009902d00000002* pci:v00009902d00000003* ID_MODEL_FROM_DATABASE=SG1010 Starfabric Switch and PCI Bridge +pci:v00009A11* + ID_VENDOR_FROM_DATABASE=Tiger Lake-H Gaussian & Neural Accelerator + pci:v00009D32* ID_VENDOR_FROM_DATABASE=Beijing Starblaze Technology Co. Ltd. @@ -97077,7 +98637,7 @@ pci:v0000E000d0000E000* ID_MODEL_FROM_DATABASE=W89C940 pci:v0000E159* - ID_VENDOR_FROM_DATABASE=Tiger Jet Network Inc. + ID_VENDOR_FROM_DATABASE=Tiger Jet Network Inc. / ICP DAS pci:v0000E159d00000001* ID_MODEL_FROM_DATABASE=Tiger3XX Modem/ISDN interface @@ -97169,6 +98729,9 @@ pci:v0000EA01d00000052* pci:v0000EA01d00000800* ID_MODEL_FROM_DATABASE=PCI-800 Digital I/O Card +pci:v0000EA50* + ID_VENDOR_FROM_DATABASE=Emerson Automation Solutions + pci:v0000EA60* ID_VENDOR_FROM_DATABASE=RME @@ -97502,6 +99065,9 @@ pci:v0000F1D0d0000EB24* pci:v0000F1D0d0000EB25* ID_MODEL_FROM_DATABASE=Corvid 44 12g +pci:v0000F1D0d0000EB26* + ID_MODEL_FROM_DATABASE=T-Tap Pro + pci:v0000F1D0d0000EFAC* ID_MODEL_FROM_DATABASE=Xena SD-MM/SD-22-MM diff --git a/hwdb.d/20-usb-vendor-model.hwdb b/hwdb.d/20-usb-vendor-model.hwdb index 4d3fcb63e..6cb0d4685 100644 --- a/hwdb.d/20-usb-vendor-model.hwdb +++ b/hwdb.d/20-usb-vendor-model.hwdb @@ -4511,6 +4511,9 @@ usb:v0421p0156* usb:v0421p0157* ID_MODEL_FROM_DATABASE=5800 XpressMusic (Imaging mode) +usb:v0421p0189* + ID_MODEL_FROM_DATABASE=N810 Internet Tablet WiMAX + usb:v0421p0199* ID_MODEL_FROM_DATABASE=6700 Classic (msc) @@ -4533,7 +4536,7 @@ usb:v0421p01C7* ID_MODEL_FROM_DATABASE=N900 (Storage Mode) usb:v0421p01C8* - ID_MODEL_FROM_DATABASE=N900 (PC-Suite Mode) + ID_MODEL_FROM_DATABASE=N900/N950 (PC-Suite Mode) usb:v0421p0228* ID_MODEL_FROM_DATABASE=5530 XpressMusic @@ -4593,7 +4596,10 @@ usb:v0421p03CD* ID_MODEL_FROM_DATABASE=C7-00 (Nokia Suite mode) usb:v0421p03D1* - ID_MODEL_FROM_DATABASE=N950 + ID_MODEL_FROM_DATABASE=N950 (Storage Mode) + +usb:v0421p03D2* + ID_MODEL_FROM_DATABASE=N950 (PC Suite mode) usb:v0421p0400* ID_MODEL_FROM_DATABASE=7600 Phone Parent @@ -4686,7 +4692,7 @@ usb:v0421p0429* ID_MODEL_FROM_DATABASE=6230i MultiMedia Card usb:v0421p0431* - ID_MODEL_FROM_DATABASE=770 Internet Tablet + ID_MODEL_FROM_DATABASE=770/N800 Internet Tablet usb:v0421p0432* ID_MODEL_FROM_DATABASE=N90 Phone Parent @@ -4788,7 +4794,13 @@ usb:v0421p0509* ID_MODEL_FROM_DATABASE=E65 (Storage mode) usb:v0421p0518* - ID_MODEL_FROM_DATABASE=N9 Phone + ID_MODEL_FROM_DATABASE=N9 (Storage mode) + +usb:v0421p0519* + ID_MODEL_FROM_DATABASE=N9 (RNDIS/Ethernet mode) + +usb:v0421p051A* + ID_MODEL_FROM_DATABASE=N9 (PC Suite mode) usb:v0421p054D* ID_MODEL_FROM_DATABASE=C2-01 @@ -26198,6 +26210,9 @@ usb:v05FCp0001* usb:v05FCp0010* ID_MODEL_FROM_DATABASE=Soundcraft Si MADI combo card +usb:v05FCp0021* + ID_MODEL_FROM_DATABASE=Soundcraft Signature 12 MTK + usb:v05FCp7849* ID_MODEL_FROM_DATABASE=Harman/Kardon SoundSticks @@ -67280,6 +67295,15 @@ usb:v32B3pD1A6* usb:v32B3pD1A7* ID_MODEL_FROM_DATABASE=TXT Multihub +usb:v3310* + ID_VENDOR_FROM_DATABASE=MUDITA Sp. z o.o. + +usb:v3310p0100* + ID_MODEL_FROM_DATABASE=Pure + +usb:v3310p0101* + ID_MODEL_FROM_DATABASE=Pure tethering + usb:v3333* ID_VENDOR_FROM_DATABASE=InLine @@ -67313,6 +67337,15 @@ usb:v3344* usb:v3344p3744* ID_MODEL_FROM_DATABASE=OEM PC Remote +usb:v3384* + ID_VENDOR_FROM_DATABASE=System76 + +usb:v3384p0000* + ID_MODEL_FROM_DATABASE=Thelio Io (thelio-io) + +usb:v3384p0001* + ID_MODEL_FROM_DATABASE=Launch Configurable Keyboard (launch_1) + usb:v348F* ID_VENDOR_FROM_DATABASE=ISY diff --git a/hwdb.d/60-autosuspend-fingerprint-reader.hwdb b/hwdb.d/60-autosuspend-fingerprint-reader.hwdb new file mode 100644 index 000000000..8923e12ea --- /dev/null +++ b/hwdb.d/60-autosuspend-fingerprint-reader.hwdb @@ -0,0 +1,277 @@ +# This file is part of systemd. +# +# Rules to autosuspend known fingerprint readers (pulled from libfprint). +# +# SPDX-License-Identifier: LGPL-2.1-or-later +# This file has been generated using fprint-list-udev-hwdb with all drivers enabled + +# Supported by libfprint driver aes1610 +usb:v08FFp1600* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes1660 +usb:v08FFp1660* +usb:v08FFp1680* +usb:v08FFp1681* +usb:v08FFp1682* +usb:v08FFp1683* +usb:v08FFp1684* +usb:v08FFp1685* +usb:v08FFp1686* +usb:v08FFp1687* +usb:v08FFp1688* +usb:v08FFp1689* +usb:v08FFp168A* +usb:v08FFp168B* +usb:v08FFp168C* +usb:v08FFp168D* +usb:v08FFp168E* +usb:v08FFp168F* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes2501 +usb:v08FFp2500* +usb:v08FFp2580* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes2550 +usb:v08FFp2550* +usb:v08FFp2810* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes2660 +usb:v08FFp2660* +usb:v08FFp2680* +usb:v08FFp2681* +usb:v08FFp2682* +usb:v08FFp2683* +usb:v08FFp2684* +usb:v08FFp2685* +usb:v08FFp2686* +usb:v08FFp2687* +usb:v08FFp2688* +usb:v08FFp2689* +usb:v08FFp268A* +usb:v08FFp268B* +usb:v08FFp268C* +usb:v08FFp268D* +usb:v08FFp268E* +usb:v08FFp268F* +usb:v08FFp2691* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes3500 +usb:v08FFp5731* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver aes4000 +usb:v5501p08FF* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver elan +usb:v04F3p0903* +usb:v04F3p0907* +usb:v04F3p0C01* +usb:v04F3p0C02* +usb:v04F3p0C03* +usb:v04F3p0C04* +usb:v04F3p0C05* +usb:v04F3p0C06* +usb:v04F3p0C07* +usb:v04F3p0C08* +usb:v04F3p0C09* +usb:v04F3p0C0A* +usb:v04F3p0C0B* +usb:v04F3p0C0C* +usb:v04F3p0C0D* +usb:v04F3p0C0E* +usb:v04F3p0C0F* +usb:v04F3p0C10* +usb:v04F3p0C11* +usb:v04F3p0C12* +usb:v04F3p0C13* +usb:v04F3p0C14* +usb:v04F3p0C15* +usb:v04F3p0C16* +usb:v04F3p0C17* +usb:v04F3p0C18* +usb:v04F3p0C19* +usb:v04F3p0C1A* +usb:v04F3p0C1B* +usb:v04F3p0C1C* +usb:v04F3p0C1D* +usb:v04F3p0C1E* +usb:v04F3p0C1F* +usb:v04F3p0C20* +usb:v04F3p0C21* +usb:v04F3p0C22* +usb:v04F3p0C23* +usb:v04F3p0C24* +usb:v04F3p0C25* +usb:v04F3p0C26* +usb:v04F3p0C27* +usb:v04F3p0C28* +usb:v04F3p0C29* +usb:v04F3p0C2A* +usb:v04F3p0C2B* +usb:v04F3p0C2C* +usb:v04F3p0C2D* +usb:v04F3p0C2E* +usb:v04F3p0C2F* +usb:v04F3p0C30* +usb:v04F3p0C31* +usb:v04F3p0C32* +usb:v04F3p0C33* +usb:v04F3p0C42* +usb:v04F3p0C4D* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver etes603 +usb:v1C7Ap0603* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver goodixmoc +usb:v27C6p5840* +usb:v27C6p6496* +usb:v27C6p60A2* +usb:v27C6p63AC* +usb:v27C6p639C* +usb:v27C6p6594* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver synaptics +usb:v06CBp00BD* +usb:v06CBp00E9* +usb:v06CBp00DF* +usb:v06CBp00F9* +usb:v06CBp00FC* +usb:v06CBp00C2* +usb:v06CBp00C9* +usb:v06CBp0100* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver upeksonly +usb:v147Ep2016* +usb:v147Ep1000* +usb:v147Ep1001* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver upektc +usb:v0483p2015* +usb:v147Ep3001* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver upektc_img +usb:v147Ep2020* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver uru4000 +usb:v045Ep00BC* +usb:v045Ep00BD* +usb:v045Ep00CA* +usb:v05BAp0007* +usb:v05BAp0008* +usb:v05BAp000A* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vcom5s +usb:v061Ap0110* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs0050 +usb:v138Ap0050* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs101 +usb:v138Ap0001* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs301 +usb:v138Ap0005* +usb:v138Ap0008* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs5011 +usb:v138Ap0010* +usb:v138Ap0011* +usb:v138Ap0015* +usb:v138Ap0017* +usb:v138Ap0018* + ID_AUTOSUSPEND=1 + +# Supported by libfprint driver vfs7552 +usb:v138Ap0091* + ID_AUTOSUSPEND=1 + +# Known unsupported devices +usb:v04F3p036B* +usb:v04F3p0C00* +usb:v04F3p0C4B* +usb:v04F3p0C4C* +usb:v04F3p0C4F* +usb:v04F3p0C57* +usb:v04F3p0C5E* +usb:v04F3p2706* +usb:v06CBp0081* +usb:v06CBp0088* +usb:v06CBp008A* +usb:v06CBp009A* +usb:v06CBp009B* +usb:v06CBp00A2* +usb:v06CBp00B7* +usb:v06CBp00BB* +usb:v06CBp00BE* +usb:v06CBp00C4* +usb:v06CBp00CB* +usb:v06CBp00D8* +usb:v06CBp00DA* +usb:v0A5Cp5801* +usb:v0A5Cp5805* +usb:v0A5Cp5834* +usb:v0A5Cp5840* +usb:v0A5Cp5841* +usb:v0A5Cp5842* +usb:v0A5Cp5843* +usb:v0A5Cp5845* +usb:v10A5p0007* +usb:v1188p9545* +usb:v138Ap0007* +usb:v138Ap003A* +usb:v138Ap003C* +usb:v138Ap003D* +usb:v138Ap003F* +usb:v138Ap0090* +usb:v138Ap0092* +usb:v138Ap0094* +usb:v138Ap0097* +usb:v138Ap009D* +usb:v138Ap00AB* +usb:v147Ep1002* +usb:v1491p0088* +usb:v16D1p1027* +usb:v1C7Ap0300* +usb:v1C7Ap0570* +usb:v1C7Ap0575* +usb:v27C6p5042* +usb:v27C6p5110* +usb:v27C6p5117* +usb:v27C6p5201* +usb:v27C6p521D* +usb:v27C6p5301* +usb:v27C6p530C* +usb:v27C6p532D* +usb:v27C6p533C* +usb:v27C6p5381* +usb:v27C6p5385* +usb:v27C6p538C* +usb:v27C6p538D* +usb:v27C6p5395* +usb:v27C6p5584* +usb:v27C6p55A2* +usb:v27C6p55A4* +usb:v27C6p55B4* +usb:v27C6p5740* +usb:v2808p9338* +usb:v298Dp2033* +usb:v3538p0930* + ID_AUTOSUSPEND=1 diff --git a/hwdb.d/60-evdev.hwdb b/hwdb.d/60-evdev.hwdb index ce068280c..82a92cf54 100644 --- a/hwdb.d/60-evdev.hwdb +++ b/hwdb.d/60-evdev.hwdb @@ -38,6 +38,15 @@ # Sort by brand, model +######################################### +# ACECAD +######################################### + +# Acecad Flair / Pentagram Quadpen +evdev:input:b0003v0460p0004* + EVDEV_ABS_00=::40 + EVDEV_ABS_01=::40 + ######################################### # AIPTEK ######################################### @@ -226,6 +235,13 @@ evdev:name:SynPS/2 Synaptics TouchPad:dmi:*bvn*:bvr*:bd*:svnDellInc.:pnMM061:* EVDEV_ABS_00=1008:5793:66 EVDEV_ABS_01=687:5176:107 +# Dell Latitude E5510 +evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnDellInc.:pnLatitudeE5510:* + EVDEV_ABS_00=73:1828:26 + EVDEV_ABS_01=101:1319:27 + EVDEV_ABS_35=73:1828:26 + EVDEV_ABS_36=101:1319:27 + # Dell Latitude E6220 evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6220:* EVDEV_ABS_00=76:1815:22 @@ -249,10 +265,10 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE725 # Dell Latitude E7470 evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470:* - EVDEV_ABS_00=29:2930:30 - EVDEV_ABS_01=26:1533:29 - EVDEV_ABS_35=29:2930:30 - EVDEV_ABS_36=26:1533:29 + EVDEV_ABS_00=29:2930:30:16 + EVDEV_ABS_01=26:1533:29:16 + EVDEV_ABS_35=29:2930:30:16 + EVDEV_ABS_36=26:1533:29:16 # Dell Precision 5510 evdev:name:SynPS/2 Synaptics TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnPrecision5510:* @@ -544,8 +560,9 @@ evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:*svnLENOVO:*pvrLenovoYoga500-14IBD:* EVDEV_ABS_35=117:3952:36 EVDEV_ABS_36=105:1960:26 -# Lenovo Thinkpad T490 +# Lenovo Thinkpad T490 and T14 Gen1 evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT490:* +evdev:name:SynPS/2 Synaptics TouchPad:dmi:*:svnLENOVO:*pvrThinkPadT14Gen1:* EVDEV_ABS_00=::44 EVDEV_ABS_01=::52 EVDEV_ABS_35=::44 @@ -558,6 +575,15 @@ evdev:name:MSFT0001:02 04F3:304B Touchpad:dmi:*svnLENOVO:*pvrLenovoLegionY9000X2 EVDEV_ABS_35=::31 EVDEV_ABS_36=::30 +######################################### +# NEWYES +######################################### + +# NEWYES 10" LCD writing tablet +evdev:input:b0003v6161p4D15* + EVDEV_ABS_00=::152 + EVDEV_ABS_01=::244 + ######################################### # Razer ######################################### @@ -657,7 +683,12 @@ evdev:input:b0003v172Fp0031* EVDEV_ABS_00=0:10000:400 EVDEV_ABS_01=0:6250:400 -#WALTOP International Corp. Graphics Tablet +# WALTOP International Corp. Graphics Tablet evdev:input:b0003v172Fp0047* EVDEV_ABS_00=0:20000:80 EVDEV_ABS_01=0:12500:80 + +# WALTOP International Corp. Batteryless Tablet +evdev:input:b0003v172Fp0505* + EVDEV_ABS_00=::160 + EVDEV_ABS_01=::160 diff --git a/hwdb.d/60-input-id.hwdb b/hwdb.d/60-input-id.hwdb index 1eec77688..2b1aa4579 100644 --- a/hwdb.d/60-input-id.hwdb +++ b/hwdb.d/60-input-id.hwdb @@ -72,3 +72,7 @@ id-input:modalias:input:b0003v04B3p301Ee0100-e0,1,2,4* # Logitech Ultrathin Touch Mouse id-input:modalias:input:b0005v046DpB00De0700* ID_INPUT_MOUSE=1 + +# Logitech MX Keys +id-input:modalias:input:b0003v046Dp408Ae0111* + ID_INPUT_MOUSE=0 diff --git a/hwdb.d/60-keyboard.hwdb b/hwdb.d/60-keyboard.hwdb index 52115faf6..5485f892b 100644 --- a/hwdb.d/60-keyboard.hwdb +++ b/hwdb.d/60-keyboard.hwdb @@ -323,6 +323,13 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1110:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1210:* KEYBOARD_KEY_84=wlan +# Dell Inspiron 11 3168 +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron11-3168:pvr* + KEYBOARD_KEY_c7=!home # Fn-LeftArrow + KEYBOARD_KEY_cf=!end # Fn-RightArrow + KEYBOARD_KEY_c9=!pageup # Fn-UpArrow + KEYBOARD_KEY_d1=!pagedown # Fn-DownArrow + # Dell Inspiron 1520 and Latitude 2110 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnInspiron*1520:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*2110:* @@ -376,7 +383,7 @@ evdev:name:Dell WMI hotkeys:dmi:bvn*:bvr*:bd*:svnDell*:pnPrecision*:* KEYBOARD_KEY_100150=f20 # Mic mute toggle, should be micmute # Dell Latitude privacy microphone mute -evdev:name:Dell Privacy Driver:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:sku0A3E:* +evdev:name:Dell Privacy Driver:dmi:bvn*:bvr*:bd*:svnDell*:pnLatitude*:* KEYBOARD_KEY_12001=f20 # Mic mute toggle, should be micmute ########################################################### @@ -540,19 +547,21 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pn*[sS][pP][eE][cC][tT][rR][eE]*x360Convert # Spectre x360 13 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPSpectrex360Convertible13*:* - KEYBOARD_KEY_82=f20 # Fn+F12; Microphone mute button, should be micmute +# ENVY x360 13 +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP*:pnHPENVYx360Convertible13*:* + KEYBOARD_KEY_82=f20 # Microphone mute button, should be micmute # HP Elite x2 1013 G3 evdev:atkbd:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:* - KEYBOARD_KEY_f8=unknown # rfkill is also reported by HP Wireless hotkeys - KEYBOARD_KEY_64=calendar - KEYBOARD_KEY_81=f20 # Microphone mute button - KEYBOARD_KEY_ee=switchvideomode # Switch display outputs - KEYBOARD_KEY_92=brightnessdown - KEYBOARD_KEY_97=brightnessup + KEYBOARD_KEY_f8=unknown # rfkill is also reported by HP Wireless hotkeys + KEYBOARD_KEY_64=calendar + KEYBOARD_KEY_81=f20 # Microphone mute button + KEYBOARD_KEY_ee=switchvideomode # Switch display outputs + KEYBOARD_KEY_92=brightnessdown + KEYBOARD_KEY_97=brightnessup evdev:name:Intel HID events:dmi:bvn*:bvr*:svnHP*:pnHPElitex21013G3:* - KEYBOARD_KEY_08=unknown # rfkill is also reported by HP Wireless hotkeys + KEYBOARD_KEY_08=unknown # rfkill is also reported by HP Wireless hotkeys # Elitebook evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pn*Compaq*:* @@ -653,7 +662,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPEliteBookFolio1040G2:* # HP EliteBook Folio G1 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHP:pnHPEliteBookFolioG1:* KEYBOARD_KEY_64=calendar - KEYBOARD_KEY_81=micmute + KEYBOARD_KEY_81=f20 # HP ProBook 650 evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHP*ProBook*650*:* @@ -691,12 +700,14 @@ evdev:name:gpio-keys:phys:gpio-keys/input0:ev:23:dmi:*:svnHewlett-Packard:pnHPSt evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI:* KEYBOARD_KEY_287=f20 # Microphone mute button, should be micmute -# Huawei MACH-WX9 +# Huawei MACH-WX9 and EUL-WX9 evdev:atkbd:dmi:bvn*:bvr*:svnHUAWEI*:pnMACH-WX9:* +evdev:atkbd:dmi:bvn*:bvr*:svnHUAWEI*:pnEUL-WX9:* KEYBOARD_KEY_f7=unknown KEYBOARD_KEY_f8=fn evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI*:pnMACH-WX9:* +evdev:name:Huawei WMI hotkeys:dmi:bvn*:bvr*:bd*:svnHUAWEI*:pnEUL-WX9:* KEYBOARD_KEY_281=unknown # Brightness Down, also emitted by acpi-video, ignore KEYBOARD_KEY_282=unknown # Brightness Up, also emitted by acpi-video, ignore @@ -1269,6 +1280,16 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-Star*:pn*A10SC*:* KEYBOARD_KEY_f1=f20 KEYBOARD_KEY_f2=f21 +# MSI Modern series +evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-StarInternational*:pnModern*:* + KEYBOARD_KEY_f1=f20 # Fn+F5 micmute + KEYBOARD_KEY_76=f21 # Fn+F4 touchpad, becomes meta+ctrl+toggle + KEYBOARD_KEY_91=prog1 # Fn+F7 Creation Center, sometime F7 + KEYBOARD_KEY_f2=prog2 # Fn+F12 screen rotation + KEYBOARD_KEY_97=unknown # lid close + KEYBOARD_KEY_98=unknown # lid open + #Fn+PrntScr sends meta+shif+s + ########################################################### # MSI ########################################################### @@ -1442,17 +1463,29 @@ evdev:input:b0003v047FpC006* # Purism ########################################################### -# Purism Librem 13 V2 -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v2*:* - KEYBOARD_KEY_56=backslash - -# Purism Librem 13 V3 -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v3*:* - KEYBOARD_KEY_56=backslash - -# Purism Librem 13 V4 -evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v4*:* - KEYBOARD_KEY_56=backslash +# If you're using an us layout keyboard in one of the below models of +# Purism Librem 13 consider copying this file to /etc/systemd/hwdb.d/ +# to enable the following rule acording to your model. +# +# There's a bug in the keyboards firmware and the additional rule +# will make your keyboard behave as expected. +# +# More info: +# - https://github.com/systemd/systemd/issues/15360 +# - https://github.com/systemd/systemd/pull/11516 +# - https://tracker.pureos.net/T888 +# +# # Purism Librem 13 V2 +# evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v2*:* +# KEYBOARD_KEY_56=backslash +# +# # Purism Librem 13 V3 +# evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v3*:* +# KEYBOARD_KEY_56=backslash +# +# # Purism Librem 13 V4 +# evdev:atkbd:dmi:bvn*:bvr*:bd*:svnPurism*:pn*Librem13v4*:* +# KEYBOARD_KEY_56=backslash ########################################################### # Quanta @@ -1488,6 +1521,20 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*300E[457]*:* evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*200E[45]*:* KEYBOARD_KEY_ce=! # Fn+F1 launch control setting +evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*356V[45]*:pvr* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*355V[45]*:pvr* + KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch control setting + KEYBOARD_KEY_89=!brightnessdown # Fn+F2 brightness down + KEYBOARD_KEY_88=!brightnessup # Fn+F3 brightness up + KEYBOARD_KEY_82=!switchvideomode # Fn+F4 display toggle + KEYBOARD_KEY_f7=!f22 # Fn+F5 touchpad on + KEYBOARD_KEY_f9=!f23 # Fn+F5 touchpad off + KEYBOARD_KEY_a0=!mute # Fn+F6 mute + KEYBOARD_KEY_ae=!volumedown # Fn+F7 volume down + KEYBOARD_KEY_b0=!volumeup # Fn+F8 volume up + KEYBOARD_KEY_b3=!prog2 # Fn+F11 toggle fan/cool mode + KEYBOARD_KEY_d5=!wlan # Fn+F12 toggle wifi + # Series 5 evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*530U*:* KEYBOARD_KEY_ce=!prog1 # Fn+F1 launch settings @@ -1514,7 +1561,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*940X3G*:* KEYBOARD_KEY_96=!kbdillumup # Fn+F10 keyboard backlight up KEYBOARD_KEY_b3=!prog3 # Fn+F11 fan/cooling mode changer -evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X[34][AB]*:* +evdev:atkbd:dmi:bvn*:bvr*:bd*:svn[sS][aA][mM][sS][uU][nN][gG]*:pn*900X3A*:* KEYBOARD_KEY_ce=! # Fn+F8 keyboard backlight up KEYBOARD_KEY_8d=! # Fn+F7 keyboard backlight down KEYBOARD_KEY_96=! # Fn+F1 performance mode (?) diff --git a/hwdb.d/60-sensor.hwdb b/hwdb.d/60-sensor.hwdb index 0f75fd11a..54f6f34b7 100644 --- a/hwdb.d/60-sensor.hwdb +++ b/hwdb.d/60-sensor.hwdb @@ -251,16 +251,11 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svncube:pni1-TF:* sensor:modalias:acpi:SMO8500*:dmi:*:svncube:pni7:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 -# Cube i7 Stylus +# Cube i7 Stylus, i7 Stylus I8L Model, i7 Book (i16) and Mix Plus (i18B) sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni7Stylus:* - ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 - -# Cube i7 Book (i16) -sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni16:* - ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 - -# Cube i7 Stylus I8L Model sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni8-L:* +sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni16:* +sensor:modalias:acpi:KIOX000A*:dmi:*:svnCube:pni18B:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 # Cube iWork 10 Flagship @@ -307,6 +302,14 @@ sensor:modalias:acpi:INVN6500*:dmi:*svnDell*:pnVenue10Pro5055:* sensor:modalias:acpi:SMO8500*:dmi:*svn*DEXP*:*pn*DEXPOEM:* ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 +######################################### +# Digibras +######################################### + +# Digibras F10-30 +sensor:modalias:acpi:SMO8500*:dmi:*:svnDigibras:pnF10-30:* + ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 + ######################################### # DIGMA ######################################### @@ -321,6 +324,12 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:svnDigma:pnCITIE203ES2010EW:* sensor:modalias:acpi:ACCE0001*:dmi:*svnEndless*:*pnELT-NL3:* ACCEL_MOUNT_MATRIX=0, 1, 0; 0, 0, -1; -1, 0, 0 +######################################### +# Estar +######################################### +sensor:modalias:acpi:SMO8500*:dmi:*:svnEstar:pneSTARBEAUTYHDIntelQuadcore:* + ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 + ######################################### # Eve Technology ######################################### @@ -445,6 +454,10 @@ sensor:modalias:acpi:BOSC0200*:dmi:bvnINSYDECorp.:bvrjumperx.T87.KFBNEE:* sensor:modalias:acpi:BOSC0200*:dmi:*:svnJumper:pnEZpad:*:rvr.A006:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, 1 +# EZpad 7 +sensor:modalias:acpi:KIOX0009*:dmi:*:bvrJumper12x.WJ2012.bsBKRCP*:svnJumper:pnEZpad:* + ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 + # EZpad Go sensor:modalias:acpi:KIOX000A*:dmi:bvnAmericanMegatrendsInc.:*:svnjumper:pnEZpad:*:ct31:* ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 @@ -484,8 +497,9 @@ sensor:modalias:acpi:BMA250E*:dmi:bvnLENOVO:*:pvrLenovoMIIX3-1030:* sensor:modalias:acpi:SMO8500*:dmi:bvnLENOVO:*:pvrLenovoMIIX3-830:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 -# IdeaPad D330 +# IdeaPad D330 and D330-10IGM sensor:modalias:acpi:BOSC0200*:dmi:*:svnLENOVO:pn81H3:* +sensor:modalias:acpi:BOSC0200*:dmi:*:svnLENOVO:*:cvrLenovoideapadD330-10IGM:* ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1 # IdeaPad Miix 300 @@ -517,13 +531,18 @@ sensor:modalias:acpi:*BOSC0200*:dmi:*:svnLENOVO*:pn80U1:* sensor:modalias:acpi:BOSC0200*:dmi:*:svnLINX*:pnLINX1010B:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, -1 -# Linx 12X64 and 12V64 +# Linx 12X64, 12V64 and Vision 8 sensor:modalias:acpi:KIOX000A*:dmi:*:svnLINX*:pnLINX12*64:* +sensor:modalias:acpi:KIOX000A*:dmi:*:svnLINX:pnVISION004:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 ######################################### # Medion ######################################### +# Medion Akoya E2228T MD61900 +sensor:modalias:acpi:KIOX020A*:dmi:*:svnMEDION:pnE2228TMD61900:* + ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1 + ACCEL_LOCATION=base # Medion Akoya E1239T MD60568 sensor:modalias:acpi:KIOX0009*:dmi:*:svnMEDION:pnE1239TMD60568:* @@ -580,6 +599,10 @@ sensor:modalias:acpi:SMO8500*:dmi:*:svnMicro-StarInternationalCo.,Ltd.:pnS100:* sensor:modalias:acpi:BOSC0200*:dmi:*:svnCompletElectroServ:pnMY8307:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 +# MY8312 +sensor:modalias:acpi:KIOX010A*:dmi:*:svnCompletElectroServSA:pnMY8312:* + ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, 1 + ######################################### # Nuvision (TMax) ######################################### @@ -680,6 +703,14 @@ sensor:modalias:acpi:BOSC0200*:dmi:bvnINSYDECorp.:bvrMx.WT107.KUBNGEA*svnInsyde: sensor:modalias:acpi:SMO8500*:dmi:*:svnProwise:pnPT301:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 +######################################### +# Reeder +######################################### + +# A8iW-Rev.A +sensor:modalias:acpi:SMO8500*:dmi:*:rvnReeder:rnA8iW-Rev.A:* + ACCEL_MOUNT_MATRIX=1, 0, 0; 0, -1, 0; 0, 0, 1 + ######################################### # Schneider ######################################### @@ -747,6 +778,10 @@ sensor:modalias:acpi:BMA250*:dmi:*:bvrTREK.G.WI71C.JGBMRBA*:*:svnInsyde:pnST7041 sensor:modalias:acpi:BMA250*:dmi:*:bvrTREK.G.WI71C.JGBMRBA*:*:svnTrekStor:pnSurfTabwintron7.0ST70416-6:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 +# SurfTab Wintron 10.1 ST10432-3, generic DMI string, use partial BIOS version match +sensor:modalias:acpi:SMO8500*:dmi:*:bvrWintron.R25M.02.0*:*:svnInsyde:pnBayTrail:* + ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1 + sensor:modalias:acpi:KIOX000A*:dmi:*:svnTrekStor:pnSurfTabtwin10.1:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1 @@ -761,11 +796,15 @@ sensor:modalias:acpi:BOSC0200*:dmi:*:bvrTP15-VT5.2.1.3:*:svnTrekStor*:pnSurfTabt sensor:modalias:acpi:KIOX010A*:dmi:*:svnTREKSTOR:pnPrimebookC11B:* sensor:modalias:acpi:KIOX010A*:dmi:*:svnTREKSTOR:pnPRIMEBOOKC11B:* +sensor:modalias:acpi:KIOX010A*:dmi:*:svnTREKSTOR:pnYourbookC11B:* +sensor:modalias:acpi:KIOX010A*:dmi:*:svnTREKSTOR:pnYOURBOOKC11B:* ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, -1, 0; 0, 0, -1 ACCEL_LOCATION=display sensor:modalias:acpi:KIOX020A*:dmi:*:svnTREKSTOR:pnPrimebookC11B:* sensor:modalias:acpi:KIOX020A*:dmi:*:svnTREKSTOR:pnPRIMEBOOKC11B:* +sensor:modalias:acpi:KIOX020A*:dmi:*:svnTREKSTOR:pnYourbookC11B:* +sensor:modalias:acpi:KIOX020A*:dmi:*:svnTREKSTOR:pnYOURBOOKC11B:* ACCEL_MOUNT_MATRIX=0, 1, 0; 1, 0, 0; 0, 0, 1 ACCEL_LOCATION=base diff --git a/hwdb.d/70-mouse.hwdb b/hwdb.d/70-mouse.hwdb index 98b79dc0d..a609b30d6 100644 --- a/hwdb.d/70-mouse.hwdb +++ b/hwdb.d/70-mouse.hwdb @@ -190,6 +190,14 @@ mouse:usb:v413cp301a:name:PixArt Dell MS116 USB Optical Mouse:* mouse:usb:v0461p4d46:name:USB Optical Mouse:* MOUSE_DPI=1000@125 +########################################## +# Elecom +######################################### + +# Elecom HUGE TrackBall (M-HT1DR) +mouse:usb:v056ep010d:name:ELECOM TrackBall Mouse HUGE TrackBall:* + MOUSE_DPI=500@125 *1000@125 1500@125 + ########################################## # Fujitsu Siemens ########################################## @@ -267,6 +275,7 @@ mouse:usb:v04b3p3107:name:* # Kensington Expert Mouse trackball mouse:usb:v047dp1020:*Kensington Expert Mouse*:* ID_INPUT_TRACKBALL=1 + MOUSE_DPI=400@125 ########################################## # Lenovo @@ -424,6 +433,10 @@ mouse:usb:v046dpc51a:name:Logitech USB Receiver:* mouse:usb:v046dpc01e:name:Logitech USB-PS/2 Optical Mouse:* MOUSE_DPI=400@125 *800@125 1600@125 +# Logitech MX 518 Legendary (HERO sensor) +mouse:usb:v046dpc08e:name:Logitech MX518 Gaming Mouse:* + MOUSE_DPI=400@1000 *800@1000 1600@1000 3200@1000 6400@1000 + # Logitech MX1000 Laser Cordless Mouse mouse:bluetooth:v046dpb003:name:Logitech MX1000 mouse:* MOUSE_DPI=800@80 @@ -478,7 +491,9 @@ mouse:bluetooth:v046dpb019:name:MX Master 2S Mouse:* MOUSE_WHEEL_CLICK_COUNT=24 MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL=14 -# Logitech MX Ergo (via Bluetooth) +# Logitech MX Ergo +mouse:usb:v046dp406f:name:Logitech MX Ergo:* +mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:406f:* mouse:bluetooth:v046dpb01d:name:MX Ergo Mouse:* ID_INPUT_TRACKBALL=1 diff --git a/hwdb.d/README b/hwdb.d/README new file mode 100644 index 000000000..594f5bfe0 --- /dev/null +++ b/hwdb.d/README @@ -0,0 +1,11 @@ +Files in this directory specify a description of hardware devices, in the form +of mappings from modalias-like keys (which identify specific hardware devices) +to udev properties. + +Files in this directory are not read by udev directly. Instead, +man:systemd-hwdb(8) compiles them into a binary database. + +See man:hwdb(7) for an overview of the configuration file format, and +man:systemd-udevd.service(8) for a description of the udev daemon. + +Use 'systemd-analyze cat-config udev/hwdb.d' to display the effective config. diff --git a/hwdb.d/acpi_id_registry.html b/hwdb.d/acpi_id_registry.html index e7c830541..d22bb22b9 100644 --- a/hwdb.d/acpi_id_registry.html +++ b/hwdb.d/acpi_id_registry.html @@ -100,6 +100,11 @@ CHENGDU HAIGUANG IC DESIGN CO., LTDHYGO07/15/2020 PixArt imaging inc.PIXA07/15/2020 Loongson Technology Corporation LimitedLOON09/10/2020 + Seiko Epson CorporationSECC02/16/2021 + Alibaba Co., Ltd.BABA02/02/2021 + Juniper Systems, Inc.JSYS03/18/2021 + Framework Computer LLCFRMW03/22/2021 + Pensando Systems, Inc.PNSO03/24/2021 diff --git a/hwdb.d/ma-large.txt b/hwdb.d/ma-large.txt index 7c6f32338..5de04e929 100644 --- a/hwdb.d/ma-large.txt +++ b/hwdb.d/ma-large.txt @@ -917,12 +917,6 @@ C4B36A (base 16) Cisco Systems, Inc Hsinchu 30077 TW -C8-C6-4A (hex) Flextronics Tech.(Ind) Pvt Ltd -C8C64A (base 16) Flextronics Tech.(Ind) Pvt Ltd - SURVEYNO.381, PADUR ROAD, KUTHAMBAKKAM VILLAGE, 602107 POONAMALLEE TALUK, THIRUVALLUR DISTRIC - Chennai 602107 - IN - 30-EA-26 (hex) Sycada BV 30EA26 (base 16) Sycada BV Burgemeester Stramanweg 105B @@ -1007,9 +1001,6 @@ EC5623 (base 16) HUAWEI TECHNOLOGIES CO.,LTD Hangzhou Zhejiang 310052 CN -8C-E7-48 (hex) Private -8CE748 (base 16) Private - 10-82-86 (hex) Luxshare Precision Industry Co.,Ltd 108286 (base 16) Luxshare Precision Industry Co.,Ltd 2nd floor, A building, Sanyo New Industrial Area, West of Maoyi, Shajing Baoan District @@ -1208,9 +1199,6 @@ ACF6F7 (base 16) LG Electronics (Mobile Communications) Seoul 153-801 KR -E8-9E-0C (hex) Private -E89E0C (base 16) Private - 48-E6-C0 (hex) SIMCom Wireless Solutions Co.,Ltd. 48E6C0 (base 16) SIMCom Wireless Solutions Co.,Ltd. Building B,SIM Technology Building,No.633,Jinzhong Road @@ -3521,12 +3509,6 @@ A4933F (base 16) HUAWEI TECHNOLOGIES CO.,LTD San Jose CA 94568 US -2C-B8-ED (hex) SonicWall -2CB8ED (base 16) SonicWall - 5455 Great America Parkway - Santa Clara CA 95054 - US - 68-D4-82 (hex) SHENZHEN GONGJIN ELECTRONICS CO.,LT 68D482 (base 16) SHENZHEN GONGJIN ELECTRONICS CO.,LT SONGGANG @@ -5483,12 +5465,6 @@ B4417A (base 16) SHENZHEN GONGJIN ELECTRONICS CO.,LT ShenZhen GuangDong 518067 CN -18-52-07 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -185207 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 00-00-62 (hex) BULL HN INFORMATION SYSTEMS 000062 (base 16) BULL HN INFORMATION SYSTEMS 300 CONCORD ROAD M/S 864A @@ -5693,12 +5669,6 @@ F8FF0B (base 16) Electronic Technology Inc. Cupertino CA 95014 US -E0-C6-3C (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -E0C63C (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 00-0C-46 (hex) Allied Telesyn Inc. 000C46 (base 16) Allied Telesyn Inc. 960 Stewart Drive, Suite B @@ -7958,12 +7928,6 @@ FC55DC (base 16) Baltic Latvian Universal Electronics LLC Westlake Village CA 91362 US -08-01-0F (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -08010F (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 94-18-82 (hex) Hewlett Packard Enterprise 941882 (base 16) Hewlett Packard Enterprise 8000 Foothills Blvd. @@ -17777,12 +17741,6 @@ F8D756 (base 16) Simm Tronic Limited Dublin 12 IE -64-D0-2D (hex) Next Generation Integration (NGI) -64D02D (base 16) Next Generation Integration (NGI) - 137 rue de Versailles - Le Chesnay 78150 - FR - 90-51-3F (hex) Elettronica Santerno SpA 90513F (base 16) Elettronica Santerno SpA Via della Concia 7 @@ -25814,12 +25772,6 @@ D4C766 (base 16) Acentic GmbH Tokyo 196-8666 JP -00-04-7D (hex) Pelco -00047D (base 16) Pelco - 3500 Pelco Way - Clovis CA 93612 - US - 00-07-BF (hex) Armillaire Technologies, Inc. 0007BF (base 16) Armillaire Technologies, Inc. 10411 Motor City Drive @@ -33692,12 +33644,6 @@ C08F20 (base 16) Shenzhen Skyworth Digital Technology CO., Ltd Shanghai Yang Pu District 200433 CN -C0-CC-42 (hex) Sichuan Tianyi Comheart Telecom Co., Ltd. -C0CC42 (base 16) Sichuan Tianyi Comheart Telecom Co., Ltd. - No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County - Chengdu Sichuan 611330 - CN - 24-1A-E6 (hex) Huawei Device Co., Ltd. 241AE6 (base 16) Huawei Device Co., Ltd. No.2 of Xincheng Road, Songshan Lake Zone @@ -34961,12 +34907,6 @@ AC8247 (base 16) Intel Corporate Huntingdon TN 38344 US -0C-51-D0 (hex) Altice Labs S.A. -0C51D0 (base 16) Altice Labs S.A. - NIF 504705610, Rua Eng. José Ferreira Pinto Basto - Aveiro 3810-106 - PT - A4-5E-5A (hex) ACTIVIO Inc. A45E5A (base 16) ACTIVIO Inc. Takeuchi Lorie Bldg. Room 503, 1-34-12, Takadanobaba @@ -35045,6 +34985,852 @@ CC03D9 (base 16) Cisco Meraki Vancouver WA 98682 US +4C-F2-02 (hex) Xiaomi Communications Co Ltd +4CF202 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +A8-77-E5 (hex) SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD +A877E5 (base 16) SHENZHEN CHUANGWEI-RGB ELECTRONICS CO.,LTD + Unit East Block22-24/F,Skyworth semiconductor design Bldg., Gaoxin Ave.4.S.,Nanshan District,Shenzhen,China + SHENZHEN GUANGDONG 518057 + CN + +10-A4-DA (hex) HUAWEI TECHNOLOGIES CO.,LTD +10A4DA (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +38-20-28 (hex) HUAWEI TECHNOLOGIES CO.,LTD +382028 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +E4-77-27 (hex) HUAWEI TECHNOLOGIES CO.,LTD +E47727 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +10-51-07 (hex) Intel Corporate +105107 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +AC-74-C4 (hex) Maytronics Ltd. +AC74C4 (base 16) Maytronics Ltd. + Kibbutz Yizrael + Kibbutz Yizrael 1935000 + IL + +84-D6-08 (hex) Wingtech Mobile Communications Co., Ltd. +84D608 (base 16) Wingtech Mobile Communications Co., Ltd. + No.777,Yazhong Road,Nanhu District, + Jiaxing Zhejiang 314006 + CN + +34-68-93 (hex) Tecnovideo Srl +346893 (base 16) Tecnovideo Srl + Via A. De Gasperi, 3 + Villaverla Vicenza 36030 + IT + +3C-7A-AA (hex) China Dragon Technology Limited +3C7AAA (base 16) China Dragon Technology Limited + B4 Bldg.Haoshan 1st Industry Park, + Shenzhen Guangdong 518104 + CN + +6C-47-60 (hex) Sunitec Enterprise Co.,Ltd +6C4760 (base 16) Sunitec Enterprise Co.,Ltd + 3F.,No.98-1,Mincyuan Rd.Sindian City + Taipei County 231 231141 + CN + +18-32-19 (hex) EM Microelectronic +183219 (base 16) EM Microelectronic + Rue des Sors 3 + Marin-Epagnier Neuchatel 2074 + CH + +28-D3-EA (hex) Huawei Device Co., Ltd. +28D3EA (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +A8-F2-66 (hex) Huawei Device Co., Ltd. +A8F266 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +84-26-7A (hex) GUANGDONG TAIDE ZHILIAN TECHNOLOGY CO.,LTD +84267A (base 16) GUANGDONG TAIDE ZHILIAN TECHNOLOGY CO.,LTD + Taide Technology Park,Jinfenghuang Industrial District, Fenggang Town, + Dongguan GUANGDONG 523000 + CN + +D8-EC-5E (hex) Belkin International Inc. +D8EC5E (base 16) Belkin International Inc. + 12045 East Waterfront Drive + Playa Vista 90094 + US + +84-FD-27 (hex) Silicon Laboratories +84FD27 (base 16) Silicon Laboratories + 400 West Cesar Chavez Street + Austin 78701 + US + +CC-9C-3E (hex) Cisco Meraki +CC9C3E (base 16) Cisco Meraki + 500 Terry A. Francois Blvd + San Francisco 94158 + US + +48-29-E4 (hex) ZAO NPK Rotek +4829E4 (base 16) ZAO NPK Rotek + Prospekt Mira + Moscow 129223 + RU + +FC-A9-DC (hex) Renesas Electronics (Penang) Sdn. Bhd. +FCA9DC (base 16) Renesas Electronics (Penang) Sdn. Bhd. + Phase 3, Bayan Lepas FIZ + Bayan Lepas Penang 11900 + MY + +FC-58-4A (hex) xiamenshi c-chip technology co., ltd +FC584A (base 16) xiamenshi c-chip technology co., ltd + Baoyuan Road + Shenzhen City Guangdong Province 518101 + CN + +78-65-3B (hex) Shaoxing Ourten Electronics Co., Ltd. +78653B (base 16) Shaoxing Ourten Electronics Co., Ltd. + 3rd Floor # 7, No. 1732 Yanhua industrial park West Renmin Road,Shangyu + Shaoxing Zhejiang 312000 + CN + +E0-E6-56 (hex) Nethesis srl +E0E656 (base 16) Nethesis srl + strada degli olmi 12 + Pesaro Pesaro e Urbino 61122 + IT + +90-23-B4 (hex) New H3C Technologies Co., Ltd +9023B4 (base 16) New H3C Technologies Co., Ltd + 466 Changhe Road, Binjiang District + Hangzhou Zhejiang 310052 + CN + +88-2A-5E (hex) New H3C Technologies Co., Ltd +882A5E (base 16) New H3C Technologies Co., Ltd + 466 Changhe Road, Binjiang District + Hangzhou Zhejiang 310052 + CN + +84-1E-A3 (hex) Sagemcom Broadband SAS +841EA3 (base 16) Sagemcom Broadband SAS + 250, route de l'Empereur + Rueil Malmaison Cedex hauts de seine 92848 + FR + +F4-02-23 (hex) PAX Computer Technology(Shenzhen) Ltd. +F40223 (base 16) PAX Computer Technology(Shenzhen) Ltd. + 4/F, No.3 Building, Software Park, Second Central Science-Tech Road, High-Tech + Shenzhen GuangDong 518057 + CN + +88-46-04 (hex) Xiaomi Communications Co Ltd +884604 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +64-6E-E0 (hex) Intel Corporate +646EE0 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +04-56-E5 (hex) Intel Corporate +0456E5 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +08-10-86 (hex) NEC Platforms, Ltd. +081086 (base 16) NEC Platforms, Ltd. + 2-3 Kandatsukasamachi + Chiyodaku Tokyo 101-8532 + JP + +64-79-F0 (hex) Intel Corporate +6479F0 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +1C-D1-E0 (hex) Cisco Systems, Inc +1CD1E0 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +24-45-6B (hex) Huawei Device Co., Ltd. +24456B (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +48-38-71 (hex) Huawei Device Co., Ltd. +483871 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +44-BD-DE (hex) BHTC GmbH +44BDDE (base 16) BHTC GmbH + Hansastrasse 40 + Lippstadt 59557 + DE + +8C-2A-8E (hex) DongGuan Ramaxel Memory Technology +8C2A8E (base 16) DongGuan Ramaxel Memory Technology + No.32, Industrial East Road,Innovation Park, High-tech Industrial Development Zone, Songshan Lake, Dongguan City, Guangdong Province,China + DongGuan Guangdong 523808 + CN + +40-44-FD (hex) Realme Chongqing Mobile Telecommunications Corp.,Ltd. +4044FD (base 16) Realme Chongqing Mobile Telecommunications Corp.,Ltd. + No.178 Yulong Avenue, Yufengshan, Yubei District, Chongqing. + Chongqing China 401120 + CN + +E8-FD-35 (hex) Huawei Device Co., Ltd. +E8FD35 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +EC-C5-D2 (hex) Huawei Device Co., Ltd. +ECC5D2 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +B4-60-8C (hex) Fiberhome Telecommunication Technologies Co.,LTD +B4608C (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +B8-14-DB (hex) OHSUNG +B814DB (base 16) OHSUNG + 335-4,SANHODAERO,GUMI,GYEONG BUK,KOREA + GUMI GYEONG BUK 730-030 + KR + +80-07-1B (hex) VSOLUTION TELECOMMUNICATION TECHNOLOGY CO.,LTD. +80071B (base 16) VSOLUTION TELECOMMUNICATION TECHNOLOGY CO.,LTD. + Room 601,Originality Building B2, NO.162 Science Avenue,Science Town + Guangzhou Guangdong 510663 + CN + +FC-13-F0 (hex) Bouffalo Lab (Nanjing) Co., Ltd. +FC13F0 (base 16) Bouffalo Lab (Nanjing) Co., Ltd. + 5F, Gongxiang Space, No.100 Tuanjie Road, Nanjing, China + Nanjing Jiangsu 211800 + CN + +1C-6E-E6 (hex) NHNETWORKS +1C6EE6 (base 16) NHNETWORKS + 54,Chemdanyeonsin-ro 30beon-gil,Buk-gu + Gwangju 61080 + KR + +08-F6-06 (hex) zte corporation +08F606 (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +E8-9E-0C (hex) MAX8USA DISTRIBUTORS INC. +E89E0C (base 16) MAX8USA DISTRIBUTORS INC. + 4757 NW 72ND AVENUE + MIAMI FL 33166 + US + +FC-9C-98 (hex) Arlo Technology +FC9C98 (base 16) Arlo Technology + 3030 Orchard Parkway + San Jose CA 95134 + US + +A0-70-B7 (hex) HUAWEI TECHNOLOGIES CO.,LTD +A070B7 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +78-B5-54 (hex) Huawei Device Co., Ltd. +78B554 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +68-9E-6A (hex) Huawei Device Co., Ltd. +689E6A (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +28-2B-96 (hex) Huawei Device Co., Ltd. +282B96 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +CC-68-B6 (hex) TP-Link Corporation Limited +CC68B6 (base 16) TP-Link Corporation Limited + Room 901,9/F.New East Ocean Centre, 9 Science Museum Road + Tsim Sha Tsui Kowloon 999077 + HK + +14-DD-9C (hex) vivo Mobile Communication Co., Ltd. +14DD9C (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +64-64-4A (hex) Beijing Xiaomi Mobile Software Co., Ltd +64644A (base 16) Beijing Xiaomi Mobile Software Co., Ltd + The Rainbow City Office Building, 68 Qinghe Middle Street Haidian District + Beijing Beijing 100085 + CN + +A4-39-B6 (hex) SHENZHEN PEIZHE MICROELECTRONICS CO .LTD +A439B6 (base 16) SHENZHEN PEIZHE MICROELECTRONICS CO .LTD + 1110 Nanshan Street, Nanshan District, Shenzhen, China Petroleum Building 2012 + Shenzhen 518000 + CN + +F4-FB-B8 (hex) HUAWEI TECHNOLOGIES CO.,LTD +F4FBB8 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +CC-33-31 (hex) Texas Instruments +CC3331 (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +2C-B8-ED (hex) SonicWall +2CB8ED (base 16) SonicWall + 1033 McCarthy Blvd + Milpitas CA 95035 + US + +C8-9B-AD (hex) Honor Device Co., Ltd. +C89BAD (base 16) Honor Device Co., Ltd. + Suite 3401, Unit A, Building 6, Shum Yip Sky Park, No. 8089, Hongli West Road, Xiangmihu Street, Futian District,Shenzhen, Guangdong 518040, People's Republic of China + Shenzhen 518040 + CN + +C4-5B-BE (hex) Espressif Inc. +C45BBE (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +88-90-09 (hex) Juniper Networks +889009 (base 16) Juniper Networks + 1133 Innovation Way + Sunnyvale CA 94089 + US + +90-B6-7A (hex) Shenzhen Skyworth Digital Technology CO., Ltd +90B67A (base 16) Shenzhen Skyworth Digital Technology CO., Ltd + 4F,Block A, Skyworth?Building, + Shenzhen Guangdong 518057 + CN + +7C-D9-F4 (hex) UAB Teltonika Telematics +7CD9F4 (base 16) UAB Teltonika Telematics + Saltoniskiu str. 9B-1 + Vilnius LT-08105 + LT + +C8-C6-4A (hex) Flextronics Tech.(Ind) Pvt Ltd +C8C64A (base 16) Flextronics Tech.(Ind) Pvt Ltd + 365, Benjamin Road + Sricity Vardahiah Palem(M),Chilamathur Village, Chittoor Distict 517646 + IN + +FC-4E-A4 (hex) Apple, Inc. +FC4EA4 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +F4-BE-EC (hex) Apple, Inc. +F4BEEC (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +BC-FF-4D (hex) Espressif Inc. +BCFF4D (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +54-E6-1B (hex) Apple, Inc. +54E61B (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +D8-9A-C1 (hex) Nokia +D89AC1 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +F0-B1-1D (hex) Nokia +F0B11D (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +00-04-7D (hex) Motorola Solutions Inc. +00047D (base 16) Motorola Solutions Inc. + 500 W Monroe Street, Ste 4400 + Chicago IL 60661-3781 + US + +A4-D7-95 (hex) Wingtech Mobile Communications Co.,Ltd +A4D795 (base 16) Wingtech Mobile Communications Co.,Ltd + No.777,Yazhong Road,Nanhu District + Jiaxing Zhejiang 314001 + CN + +84-AB-26 (hex) Tiinlab Corporation +84AB26 (base 16) Tiinlab Corporation + 35F,Tower A,Tanglang City,3333 Liuxian Avenue,Nanshan District + Shenzhen Guangdong 518000 + CN + +F8-97-53 (hex) Huawei Device Co., Ltd. +F89753 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +58-94-AE (hex) Huawei Device Co., Ltd. +5894AE (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +B0-3A-CE (hex) Huawei Device Co., Ltd. +B03ACE (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +34-AB-95 (hex) Espressif Inc. +34AB95 (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +C4-91-CF (hex) Luxul +C491CF (base 16) Luxul + 12884 Frontrunner Blvd, Suite 201 + Draper UT 84020 + US + +58-35-6B (hex) TECNO MOBILE LIMITED +58356B (base 16) TECNO MOBILE LIMITED + ROOMS 05-15, 13A/F., SOUTH TOWER, WORLD FINANCE CENTRE, HARBOUR CITY, 17 CANTON ROAD, TSIM SHA TSUI, KOWLOON, HONG KONG + Hong Kong Hong Kong 999077 + HK + +F8-4C-DA (hex) HUAWEI TECHNOLOGIES CO.,LTD +F84CDA (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +A8-93-4A (hex) CHONGQING FUGUI ELECTRONICS CO.,LTD. +A8934A (base 16) CHONGQING FUGUI ELECTRONICS CO.,LTD. + Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District + Chongqing Chongqing 401332 + CN + +A4-05-6E (hex) Tiinlab Corporation +A4056E (base 16) Tiinlab Corporation + 35F,Tower A,Tanglang City,3333 Liuxian Avenue,Nanshan District + Shenzhen Guangdong 518000 + CN + +8C-19-B5 (hex) Arcadyan Corporation +8C19B5 (base 16) Arcadyan Corporation + No.8, Sec.2, Guangfu Rd. + Hsinchu City Hsinchu 30071 + TW + +C8-7B-23 (hex) Bose Corporation +C87B23 (base 16) Bose Corporation + The Mountain + Framingham MA 01701-9168 + US + +78-D9-E9 (hex) MOMENTUM IOT +78D9E9 (base 16) MOMENTUM IOT + 100 W. BROADWAY, STE. 500 + LONG BEACH CA 90802 + US + +2C-08-23 (hex) Sercomm France Sarl +2C0823 (base 16) Sercomm France Sarl + 2/4 Rue Maurice Hartmann 92370 Issy Les Moulineaux France + Moulineaux 92370 + FR + +30-8E-7A (hex) Shenzhen iComm Semiconductor CO.,LTD +308E7A (base 16) Shenzhen iComm Semiconductor CO.,LTD + Room 504A,Block B,Digital Building,Gargen City,No.1079,Nanhai Road,Nanshan District,Shenzhen. + Shenzhen 518067 + CN + +9C-1C-37 (hex) AltoBeam (China) Inc. +9C1C37 (base 16) AltoBeam (China) Inc. + B808, Tsinghua Tongfang Hi-Tech Plaza, Haidian + Beijing Beijing 100083 + CN + +8C-E7-48 (hex) Hangzhou Hikvision Digital Technology Co.,Ltd. +8CE748 (base 16) Hangzhou Hikvision Digital Technology Co.,Ltd. + No.469,Jianghui Road + Hangzhou Zhejiang 310052 + CN + +98-42-65 (hex) Sagemcom Broadband SAS +984265 (base 16) Sagemcom Broadband SAS + 250, route de l'Empereur + Rueil Malmaison Cedex hauts de seine 92848 + FR + +B8-A3-77 (hex) Cisco Systems, Inc +B8A377 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +E4-4E-2D (hex) Cisco Systems, Inc +E44E2D (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +00-CC-34 (hex) Juniper Networks +00CC34 (base 16) Juniper Networks + 1133 Innovation Way + Sunnyvale CA 94089 + US + +1C-D1-07 (hex) Realme Chongqing Mobile Telecommunications Corp.,Ltd. +1CD107 (base 16) Realme Chongqing Mobile Telecommunications Corp.,Ltd. + No.178 Yulong Avenue, Yufengshan, Yubei District, Chongqing. + Chongqing China 401120 + CN + +10-3D-1C (hex) Intel Corporate +103D1C (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +38-87-D5 (hex) Intel Corporate +3887D5 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +80-65-59 (hex) EM Microelectronic +806559 (base 16) EM Microelectronic + Rue des Sors 3 + Marin-Epagnier Neuchatel 2074 + CH + +D0-47-C1 (hex) Elma Electronic AG +D047C1 (base 16) Elma Electronic AG + Hofstrasse 93 + Wetzikon Zuerich 8620 + CH + +C0-CC-42 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +C0CC42 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County + Chengdu Sichuan 611330 + CN + +C4-23-60 (hex) Intel Corporate +C42360 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +08-01-0F (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +08010F (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +18-52-07 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +185207 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +E0-C6-3C (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +E0C63C (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +DC-21-5C (hex) Intel Corporate +DC215C (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +BC-EC-A0 (hex) COMPAL INFORMATION (KUNSHAN) CO., LTD. +BCECA0 (base 16) COMPAL INFORMATION (KUNSHAN) CO., LTD. + NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE + KUNSHAN SUZHOU 215300 + CN + +F8-BA-E6 (hex) Nokia +F8BAE6 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +58-FD-5D (hex) Hangzhou Xinyun technology Co., Ltd. +58FD5D (base 16) Hangzhou Xinyun technology Co., Ltd. + Room 803, Block 8, Singapore Science & Technology Park + Hangzhou Zhejiang 310018 + CN + +24-A7-99 (hex) Huawei Device Co., Ltd. +24A799 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +7C-3E-74 (hex) Huawei Device Co., Ltd. +7C3E74 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +A4-55-90 (hex) Xiaomi Communications Co Ltd +A45590 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +14-89-19 (hex) 2bps +148919 (base 16) 2bps + #1502 , T-dong, Pungrim I-want, 170, Seohyeon-ro + Seongnam-si Gyeonggi-do 13590 + KR + +4C-71-67 (hex) PoLabs d.o.o. +4C7167 (base 16) PoLabs d.o.o. + Volavlje 30 + Ljubljana 1000 + SI + +04-71-53 (hex) SERNET (SUZHOU) TECHNOLOGIES CORPORATION +047153 (base 16) SERNET (SUZHOU) TECHNOLOGIES CORPORATION + NO.8 Tangzhuang Road,Suzhou Industrial Park,Su ZhouCity,JiangSu Province,China + Suzhou 215021 + CN + +48-E7-DA (hex) AzureWave Technology Inc. +48E7DA (base 16) AzureWave Technology Inc. + 8F., No. 94, Baozhong Rd. + New Taipei City Taiwan 231 + TW + +40-C4-8C (hex) N-iTUS CO.,LTD. +40C48C (base 16) N-iTUS CO.,LTD. + NiTUS 85, Deokcheon-ro + Anyang-si Gyeonggi-do, Korea 14086 + KR + +48-22-18 (hex) Shenzhen Yipingfang Network Technology Co., Ltd. +482218 (base 16) Shenzhen Yipingfang Network Technology Co., Ltd. + 21 / F, Kangjia R & D building, No.28, Keji South 12th Road, Nanshan District, Shenzhen City, Guangdong Province, China + Shenzhen Nanshan District 518000 + CN + +E4-0C-FD (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +E40CFD (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + NO.18 HAIBIN ROAD, + DONG GUAN GUANG DONG 523860 + CN + +58-D6-97 (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +58D697 (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + NO.18 HAIBIN ROAD, + DONG GUAN GUANG DONG 523860 + CN + +54-37-BB (hex) Taicang T&W Electronics +5437BB (base 16) Taicang T&W Electronics + 89# Jiang Nan RD + Suzhou Jiangsu 215412 + CN + +60-F8-F2 (hex) Synaptec +60F8F2 (base 16) Synaptec + 204 George Street + Glasgow G1 1XW + GB + +AC-74-B1 (hex) Intel Corporate +AC74B1 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +30-A1-76 (hex) Fiberhome Telecommunication Technologies Co.,LTD +30A176 (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +F4-E4-51 (hex) HUAWEI TECHNOLOGIES CO.,LTD +F4E451 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +1C-3C-D4 (hex) HUAWEI TECHNOLOGIES CO.,LTD +1C3CD4 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +F4-60-77 (hex) Texas Instruments +F46077 (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +24-9A-C8 (hex) Shenzhen Skyworth Digital Technology CO., Ltd +249AC8 (base 16) Shenzhen Skyworth Digital Technology CO., Ltd + 4F,Block A, Skyworth?Building, + Shenzhen Guangdong 518057 + CN + +C0-3C-04 (hex) Sagemcom Broadband SAS +C03C04 (base 16) Sagemcom Broadband SAS + 250, route de l'Empereur + Rueil Malmaison Cedex hauts de seine 92848 + FR + +A4-D7-3C (hex) Seiko Epson Corporation +A4D73C (base 16) Seiko Epson Corporation + 2070 Kotobuki Koaka + Matsumoto-shi Nagano-ken 399-8702 + JP + +2C-48-81 (hex) vivo Mobile Communication Co., Ltd. +2C4881 (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +60-26-EF (hex) Aruba, a Hewlett Packard Enterprise Company +6026EF (base 16) Aruba, a Hewlett Packard Enterprise Company + 3333 Scott Blvd + Santa Clara CA 95054 + US + +F8-8E-A1 (hex) Edgecore Networks Corporation +F88EA1 (base 16) Edgecore Networks Corporation + 1 Creation RD 3. + Hsinchu 30077 + TW + +7C-85-30 (hex) Nokia +7C8530 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +64-D0-2D (hex) NEXT GENERATION INTEGRATION LIMITED (NGI) +64D02D (base 16) NEXT GENERATION INTEGRATION LIMITED (NGI) + Unit 1102, 11 / F, 29 Austin Road, TSIM SHA TSUI + KOWLOON Hong Kong 999077 + HK + +24-28-FD (hex) Hangzhou Hikvision Digital Technology Co.,Ltd. +2428FD (base 16) Hangzhou Hikvision Digital Technology Co.,Ltd. + No.555 Qianmo Road + Hangzhou Zhejiang 310052 + CN + +88-AE-DD (hex) EliteGroup Computer Systems Co., LTD +88AEDD (base 16) EliteGroup Computer Systems Co., LTD + No. 239, Sec. 2, Ti ding Blvd. + Taipei City 11493 + TW + +A0-E7-0B (hex) Intel Corporate +A0E70B (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +B0-D8-88 (hex) Panasonic Corporation Automotive +B0D888 (base 16) Panasonic Corporation Automotive + 5652 + Matsumoto City Nagano 399-8730 + JP + +F4-63-E7 (hex) Nanjing Maxon O.E. Tech. Co., LTD +F463E7 (base 16) Nanjing Maxon O.E. Tech. Co., LTD + 6/F, Building A3, Zidong International Creative Park, Zidong Road, Qixia District, Nanjing + NAN JING JIANG SU 210000 + CN + +04-EE-EE (hex) Laplace System Co., Ltd. +04EEEE (base 16) Laplace System Co., Ltd. + 1-245 Kyo-machi + Fushimi, Kyoto Kyoto 6128083 + JP + +6C-10-8B (hex) WeLink Communications +6C108B (base 16) WeLink Communications + 4186 N Red Maple Court + Lehi UT 84043 + US + 9C-FF-C2 (hex) AVI Systems GmbH 9CFFC2 (base 16) AVI Systems GmbH Dr. Franz Wilhelmstraße 2A @@ -35843,12 +36629,6 @@ D0196A (base 16) Ciena Corporation Beijing Beijing 100012 CN -84-C7-8F (hex) STORDIS GmbH -84C78F (base 16) STORDIS GmbH - Rosenwiesstr. 17 - Stuttgart 70567 - DE - 50-41-B9 (hex) I-O DATA DEVICE,INC. 5041B9 (base 16) I-O DATA DEVICE,INC. 3-10,Sakurada-machi @@ -38849,12 +39629,6 @@ D88F76 (base 16) Apple, Inc. Cupertino CA 95014 US -5C-A1-76 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -5CA176 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 58-38-79 (hex) RICOH COMPANY, LTD. 583879 (base 16) RICOH COMPANY, LTD. 1005, Shimo-ogino @@ -39383,12 +40157,6 @@ FC8B97 (base 16) SHENZHEN GONGJIN ELECTRONICS CO.,LT Shenzhen Guangdong 518109 CN -00-1F-92 (hex) Avigilon Corporation -001F92 (base 16) Avigilon Corporation - Box 378, 101 - 1001 West Broadway - Vancouver BC V6H 4E4 - CA - 00-0C-03 (hex) HDMI Licensing, LLC 000C03 (base 16) HDMI Licensing, LLC 1060 East Arques Ave. @@ -40325,12 +41093,6 @@ BCA8A6 (base 16) Intel Corporate shenzhen guangdong 518057 CN -E0-4F-BD (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -E04FBD (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 7C-EB-AE (hex) Ridgeline Instruments 7CEBAE (base 16) Ridgeline Instruments 4803 Innovation Drive, Suite 3B @@ -41225,18 +41987,6 @@ E0E7BB (base 16) Nureva, Inc. Calgary AB T2R 0L4 CA -00-80-8C (hex) NetAlly -00808C (base 16) NetAlly - 310 Littleton Road - Westford MA 01886 - US - -04-9F-81 (hex) NetAlly -049F81 (base 16) NetAlly - 310 Littleton Road - Westford MA 01886 - US - 00-10-87 (hex) XSTREAMIS PLC 001087 (base 16) XSTREAMIS PLC OXFORD SCIENCE PARK @@ -41705,12 +42455,6 @@ E8886C (base 16) Shenzhen SC Technologies Co.,LTD 000 0000 IL -9C-61-21 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -9C6121 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 00-A0-C6 (hex) Qualcomm Inc. 00A0C6 (base 16) Qualcomm Inc. 6455 LUSK BLVD @@ -41897,12 +42641,6 @@ C4F1D1 (base 16) BEIJING SOGOU TECHNOLOGY DEVELOPMENT CO., LTD. Beijing 100000 CN -AC-E7-7B (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -ACE77B (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 2C-36-A0 (hex) Capisco Limited 2C36A0 (base 16) Capisco Limited PO Box 938 @@ -41939,12 +42677,6 @@ C86C87 (base 16) Zyxel Communications Corporation Chandler AZ 85224 US -64-5D-92 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -645D92 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, Chengdu, Sichuan - Chengdu Sichuan 610000 - CN - 38-BC-1A (hex) MEIZU Technology Co., Ltd. 38BC1A (base 16) MEIZU Technology Co., Ltd. MEIZU Tech Bldg., Technology & Innovation Coast @@ -42029,12 +42761,6 @@ C8AFE3 (base 16) Hefei Radio Communication Technology Co., Ltd Hefei Anhui 230088 CN -CC-A2-60 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -CCA260 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 7C-57-4E (hex) COBI GmbH 7C574E (base 16) COBI GmbH Solmsstrasse 4 @@ -42095,12 +42821,6 @@ E47B3F (base 16) BEIJING CO-CLOUD TECHNOLOGY LTD. San Francisco CA 94103 US -40-F4-20 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -40F420 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 34-A2-A2 (hex) HUAWEI TECHNOLOGIES CO.,LTD 34A2A2 (base 16) HUAWEI TECHNOLOGIES CO.,LTD No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park @@ -48446,12 +49166,6 @@ F48139 (base 16) CANON INC. Olathe KS 66061 US -A4-D0-94 (hex) Erwin Peters Systemtechnik GmbH -A4D094 (base 16) Erwin Peters Systemtechnik GmbH - Josef Baumann Strasse 37 - Bochum D44805 - DE - 88-23-64 (hex) Watchnet DVR Inc 882364 (base 16) Watchnet DVR Inc Unit 5 - 351 Ferrier St. @@ -53510,12 +54224,6 @@ D4AAFF (base 16) MICRO WORLD San Luis Obispo CA 93401 US -00-23-BB (hex) Schmitt Industries -0023BB (base 16) Schmitt Industries - 2765 NW Nicolai St - Portland Oregon 97210 - US - 00-23-8D (hex) Techno Design Co., Ltd. 00238D (base 16) Techno Design Co., Ltd. 312-2 @@ -55439,12 +56147,6 @@ D4AAFF (base 16) MICRO WORLD St. Ingbert Saarland 66386 DE -00-1A-86 (hex) AdvancedIO Systems Inc -001A86 (base 16) AdvancedIO Systems Inc - 595 Howe Street, Suite 502 - Vancouver BC V6C 2T5 - CA - 00-1A-C7 (hex) UNIPOINT 001AC7 (base 16) UNIPOINT 7F Gwangsung Bld 831-47 YeokSam-Dong @@ -61709,12 +62411,6 @@ D4AAFF (base 16) MICRO WORLD KR -00-03-24 (hex) SANYO Consumer Electronics Co., Ltd. -000324 (base 16) SANYO Consumer Electronics Co., Ltd. - 7-101 Tachikawa-cho - Tottori City 680-8634 - JP - 00-02-BF (hex) dotRocket, Inc. 0002BF (base 16) dotRocket, Inc. 1901 S. Bascom, Suite 300 @@ -66416,12 +67112,6 @@ A4B239 (base 16) Cisco Systems, Inc San Jose CA 94568 US -D8-D5-B9 (hex) Rainforest Automation, Inc. -D8D5B9 (base 16) Rainforest Automation, Inc. - 827 Cambie St. - Vancouver British Columbia V6B 2P4 - CA - 00-1B-B0 (hex) Bharat Electronics Limited 001BB0 (base 16) Bharat Electronics Limited JALAHALLI POST @@ -67619,12 +68309,6 @@ D8F2CA (base 16) Intel Corporate Kulim Kedah 09000 MY -44-56-E2 (hex) Sichuan Tianyi Comheart Telecom Co., Ltd. -4456E2 (base 16) Sichuan Tianyi Comheart Telecom Co., Ltd. - No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County - Chengdu Sichuan 611330 - CN - 68-EC-C5 (hex) Intel Corporate 68ECC5 (base 16) Intel Corporate Lot 8, Jalan Hi-Tech 2/3 @@ -69383,6 +70067,66 @@ D4A651 (base 16) Tuya Smart Inc. Grand Rapids MI 49505 US +88-C3-E5 (hex) Betop Techonologies +88C3E5 (base 16) Betop Techonologies + 6F., No. 669, Bannan Road, Zhonghe District + New Taipei City 235 + TW + +E4-28-A4 (hex) Prama India Private Limited +E428A4 (base 16) Prama India Private Limited + Off 103, 765 Fly Edge, TPS III Jn of S V Rd, Nr Kora Kendra + Borivali West, Mumbai Maharashtra 400092 + IN + +94-3A-91 (hex) Amazon Technologies Inc. +943A91 (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +00-0F-A0 (hex) CANON KOREA BUSINESS SOLUTIONS INC. +000FA0 (base 16) CANON KOREA BUSINESS SOLUTIONS INC. + Canon BS Tower, 607 Teheran-ro + Seoul Gangnam-gu 06173 + KR + +40-8C-1F (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +408C1F (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + NO.18 HAIBIN ROAD, + DONG GUAN GUANG DONG 523860 + CN + +2C-3F-0B (hex) Cisco Meraki +2C3F0B (base 16) Cisco Meraki + 500 Terry A. Francois Blvd + San Francisco 94158 + US + +80-C5-01 (hex) OctoGate IT Security Systems GmbH +80C501 (base 16) OctoGate IT Security Systems GmbH + Friedrich List Strasse 42 + Paderborn NRW 33100 + DE + +04-F0-3E (hex) Huawei Device Co., Ltd. +04F03E (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +78-E2-2C (hex) Huawei Device Co., Ltd. +78E22C (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C0-D0-26 (hex) Huawei Device Co., Ltd. +C0D026 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + 14-D1-9E (hex) Apple, Inc. 14D19E (base 16) Apple, Inc. 1 Infinite Loop @@ -69407,48 +70151,1038 @@ D4A651 (base 16) Tuya Smart Inc. Cupertino CA 95014 US -00-0F-A0 (hex) CANON KOREA BUSINESS SOLUTIONS INC. -000FA0 (base 16) CANON KOREA BUSINESS SOLUTIONS INC. - Canon BS Tower, 607 Teheran-ro - Seoul Gangnam-gu 06173 +00-2D-B3 (hex) AMPAK Technology,Inc. +002DB3 (base 16) AMPAK Technology,Inc. + 3F, No.15-1 Zhonghua Road, Hsinchu Industrail Park, Hukou, + Hsinchu Hsinchu,Taiwan R.O.C. 30352 + TW + +3C-C7-86 (hex) DONGGUAN HUARONG COMMUNICATION TECHNOLOGIES CO.,LTD. +3CC786 (base 16) DONGGUAN HUARONG COMMUNICATION TECHNOLOGIES CO.,LTD. + No.130 Dongxing East Road, Dongkeng Town + DONGGUAN 523450 + CN + +28-C8-7C (hex) zte corporation +28C87C (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +14-50-51 (hex) SHARP Corporation +145051 (base 16) SHARP Corporation + 1 Takumi-cho, Sakai-ku + Sakai City Osaka 590-8522 + JP + +C4-D0-E3 (hex) Intel Corporate +C4D0E3 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +E4-FD-45 (hex) Intel Corporate +E4FD45 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +18-4C-AE (hex) CONTINENTAL +184CAE (base 16) CONTINENTAL + 1 AVENUE PAUL OURLIAC + TOULOUSE 31100 + FR + +98-38-7D (hex) ITRONIC TECHNOLOGY CO . , LTD . +98387D (base 16) ITRONIC TECHNOLOGY CO . , LTD . + 2F C Building Fu Xin Lin lndustrial Park Hangcheng + lndustrial Zone Xixiang Street Baoan District Shenzhen 518100 + CN + +C8-D8-84 (hex) Universal Electronics, Inc. +C8D884 (base 16) Universal Electronics, Inc. + 201 E. Sandpointe Ave + Santa Ana CA 92707 + US + +B4-A2-5C (hex) Cambium Networks Limited +B4A25C (base 16) Cambium Networks Limited + Unit B2, Linhay Business Park, + Ashburton Devon TQ13 7UP + GB + +2C-71-FF (hex) Amazon Technologies Inc. +2C71FF (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +AC-D6-18 (hex) OnePlus Technology (Shenzhen) Co., Ltd +ACD618 (base 16) OnePlus Technology (Shenzhen) Co., Ltd + 18C02, 18C03, 18C04 ,18C05,TAIRAN BUILDING, + Shenzhen Guangdong 518000 + CN + +6C-56-40 (hex) BLU Products Inc +6C5640 (base 16) BLU Products Inc + 10814 NW 33rd Street + Miami FL 33172 + US + +48-78-5E (hex) Amazon Technologies Inc. +48785E (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +20-C7-4F (hex) SensorPush +20C74F (base 16) SensorPush + PO Box 211 + Garrison NY 10524 + US + +48-29-52 (hex) Sagemcom Broadband SAS +482952 (base 16) Sagemcom Broadband SAS + 250, route de l'Empereur + Rueil Malmaison Cedex hauts de seine 92848 + FR + +A4-7E-36 (hex) EM Microelectronic +A47E36 (base 16) EM Microelectronic + Rue des Sors 3 + Marin-Epagnier Neuchatel 2074 + CH + +B0-5D-D4 (hex) ARRIS Group, Inc. +B05DD4 (base 16) ARRIS Group, Inc. + 6450 Sequence Drive + San Diego CA 92121 + US + +24-E8-53 (hex) LG Innotek +24E853 (base 16) LG Innotek + 26, Hanamsandan 5beon-ro + Gwangju Gwangsan-gu 506-731 KR -40-8C-1F (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD -408C1F (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +30-7C-4A (hex) Huawei Device Co., Ltd. +307C4A (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +2C-CE-1E (hex) Cloudtronics Pty Ltd +2CCE1E (base 16) Cloudtronics Pty Ltd + Unit 1 6 Powells Road Brookvale + Sydney NSW 2100 + AU + +F0-21-E0 (hex) eero inc. +F021E0 (base 16) eero inc. + 660 3rd Street + San Francisco 94107 + US + +9C-DB-CB (hex) Wuhan Funshion Online Technologies Co.,Ltd +9CDBCB (base 16) Wuhan Funshion Online Technologies Co.,Ltd + 5th Floor,Financial Port Building A9,No.77 Optical Valley Avenue, East Lake High-Tech Development Zone, Wuhan + Wuhan CN/Hubei 430000 + CN + +64-17-59 (hex) Intellivision Holdings, LLC +641759 (base 16) Intellivision Holdings, LLC + 1844 E Carnegie + Santa Ana CA 92705 + US + +50-43-48 (hex) ThingsMatrix Inc. +504348 (base 16) ThingsMatrix Inc. + 9442 North Capital of Texas Hwy Plaza One Suite 500 Austin + Austin TX 78759 + US + +D8-59-82 (hex) HUAWEI TECHNOLOGIES CO.,LTD +D85982 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +48-B2-5D (hex) HUAWEI TECHNOLOGIES CO.,LTD +48B25D (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +2C-FD-B3 (hex) TCL Technoly Electronics(Huizhou).,Ltd +2CFDB3 (base 16) TCL Technoly Electronics(Huizhou).,Ltd + Section 37, Zhongkai Hi-Tech Development Zone + Huizhou Guangdong 516006 + CN + +A4-1B-34 (hex) China Mobile Group Device Co.,Ltd. +A41B34 (base 16) China Mobile Group Device Co.,Ltd. + 32 Xuanwumen West Street,Xicheng District + Beijing 100053 + CN + +80-45-DD (hex) Intel Corporate +8045DD (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +C0-D4-6B (hex) Huawei Device Co., Ltd. +C0D46B (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +9C-95-67 (hex) Huawei Device Co., Ltd. +9C9567 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +58-AE-F1 (hex) Fiberhome Telecommunication Technologies Co.,LTD +58AEF1 (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +A4-7B-1A (hex) Huawei Device Co., Ltd. +A47B1A (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +14-7D-05 (hex) SERCOMM PHILIPPINES INC +147D05 (base 16) SERCOMM PHILIPPINES INC + Lot 1 & 5, Phase 1, Filinvest Technology Park 1, Brgy. Punta, Calamba City + Calamba Lot 1 + PH + +78-7A-6F (hex) Juice Technology AG +787A6F (base 16) Juice Technology AG + Gewerbestrasse 7 + Cham Select State CH-6330 + CH + +E8-6C-C7 (hex) IEEE Registration Authority +E86CC7 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +40-24-B2 (hex) Sichuan AI-Link Technology Co., Ltd. +4024B2 (base 16) Sichuan AI-Link Technology Co., Ltd. + Anzhou, Industrial Park + Mianyang Sichuan 622650 + CN + +64-0D-22 (hex) LG Electronics (Mobile Communications) +640D22 (base 16) LG Electronics (Mobile Communications) + 60-39, Gasan-dong, Geumcheon-gu + Seoul 153-801 + KR + +20-A7-F9 (hex) SHENZHEN OLANBOA TECHNOLOGY CO., LTD +20A7F9 (base 16) SHENZHEN OLANBOA TECHNOLOGY CO., LTD + 4/F, Building B, Block A, Longquan Science Park, Tongfuyu Phase II, Tongsheng Community, Dalang Street, Longhua District, Shenzhen + shenzhen Guangdong 518000 + CN + +C0-06-C3 (hex) TP-Link Corporation Limited +C006C3 (base 16) TP-Link Corporation Limited + Room 901,9/F.New East Ocean Centre, 9 Science Museum Road + Tsim Sha Tsui Kowloon 999077 + HK + +3C-15-12 (hex) Shenzhen Huanhu Technology Co.,Ltd +3C1512 (base 16) Shenzhen Huanhu Technology Co.,Ltd + 7 / F, building C4, Hengfeng Industrial City, 739 Zhoushi Road, Hezhou community, Hangcheng street, Bao'an District, Shenzhen + Shenzhen 518000 + CN + +8C-31-E2 (hex) DAYOUPLUS +8C31E2 (base 16) DAYOUPLUS + 3F 509, Dunchon-daero, Jungwon-gu, Seongnam-si, Gyeonggi-do, Republic of Korea + Seongnam-si Gyeonggi-do 13217 + KR + +10-39-4E (hex) Hisense broadband multimedia technology Co.,Ltd +10394E (base 16) Hisense broadband multimedia technology Co.,Ltd + Song ling Road 399 + Qingdao 266000 + CN + +D8-D5-B9 (hex) Rainforest Automation, Inc. +D8D5B9 (base 16) Rainforest Automation, Inc. + 200 – 311 Pender St. W + Vancouver British Columbia V6B 1T3 + CA + +04-BA-1C (hex) Huawei Device Co., Ltd. +04BA1C (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +7C-3D-2B (hex) Huawei Device Co., Ltd. +7C3D2B (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +18-C2-41 (hex) SonicWall +18C241 (base 16) SonicWall + 1033 McCarthy Blvd + Milpitas CA 95035 + US + +58-45-4C (hex) Ericsson AB +58454C (base 16) Ericsson AB + Torshamnsgatan 36 + Stockholm SE-164 80 + SE + +FC-4D-A6 (hex) HUAWEI TECHNOLOGIES CO.,LTD +FC4DA6 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +B4-14-E6 (hex) HUAWEI TECHNOLOGIES CO.,LTD +B414E6 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +AC-99-29 (hex) HUAWEI TECHNOLOGIES CO.,LTD +AC9929 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +18-48-59 (hex) Castlenet Technology Inc. +184859 (base 16) Castlenet Technology Inc. + 5th Fl., No.159-1, Sec.3, Beishen Rd., Shenkeng Dist., + New Taipei City 222004 + TW + +14-51-7E (hex) New H3C Technologies Co., Ltd +14517E (base 16) New H3C Technologies Co., Ltd + 466 Changhe Road, Binjiang District + Hangzhou Zhejiang 310052 + CN + +08-3A-38 (hex) New H3C Technologies Co., Ltd +083A38 (base 16) New H3C Technologies Co., Ltd + 466 Changhe Road, Binjiang District + Hangzhou Zhejiang 310052 + CN + +70-F0-88 (hex) Nintendo Co.,Ltd +70F088 (base 16) Nintendo Co.,Ltd + 11-1 HOKOTATE-CHO KAMITOBA,MINAMI-KU + KYOTO KYOTO 601-8501 + JP + +84-23-88 (hex) Ruckus Wireless +842388 (base 16) Ruckus Wireless + 350 West Java Drive + Sunnyvale CA 94089 + US + +F4-C7-AA (hex) Marvell Semiconductors +F4C7AA (base 16) Marvell Semiconductors + 15485 Sand Canyon Ave + IRVINE CA 92618 + US + +F8-AB-E5 (hex) shenzhen worldelite electronics co., LTD +F8ABE5 (base 16) shenzhen worldelite electronics co., LTD + Office 5 F, Xiang Yu Industrial Park, Longsheng Road, Longgang Dist + Shenzhen Guangdong 51800 + CN + +E0-DB-D1 (hex) Technicolor CH USA Inc. +E0DBD1 (base 16) Technicolor CH USA Inc. + 5030 Sugarloaf Parkway Bldg 6 + Lawrenceville GA 30044 + US + +CC-ED-21 (hex) Nokia Shanghai Bell Co., Ltd. +CCED21 (base 16) Nokia Shanghai Bell Co., Ltd. + No.388 Ning Qiao Road,Jin Qiao Pudong Shanghai + Shanghai 201206 + CN + +10-D5-61 (hex) Tuya Smart Inc. +10D561 (base 16) Tuya Smart Inc. + 160 Greentree Drive, Suite 101 + Dover DE 19904 + US + +00-1A-86 (hex) New Wave Design & Verification +001A86 (base 16) New Wave Design & Verification + 4950 W 78th St. + Minneapolis MN 55435 + US + +50-9A-46 (hex) Safetrust Inc +509A46 (base 16) Safetrust Inc + 8112 Mill Creek Rd + Fremont CA 94539 + US + +D0-CF-D8 (hex) Huizhou Boshijie Technology Co.,Ltd +D0CFD8 (base 16) Huizhou Boshijie Technology Co.,Ltd + No.1 Xisan road, Huifeng west road, Zhongkai high-tech zone + Huizhou Guangdong 516006 + CN + +84-C7-8F (hex) APS Networks GmbH +84C78F (base 16) APS Networks GmbH + Rosenwiesstr. 17 + Stuttgart 70567 + DE + +F0-A3-B2 (hex) Hui Zhou Gaoshengda Technology Co.,LTD +F0A3B2 (base 16) Hui Zhou Gaoshengda Technology Co.,LTD + No.75,Zhongkai High-Tech Development District,Huizhou + Hui Zhou Guangdong 516006 + CN + +08-BB-3C (hex) Flextronics Tech.(Ind) Pvt Ltd +08BB3C (base 16) Flextronics Tech.(Ind) Pvt Ltd + 365, Benjamin Road + Sricity Vardahiah Palem(M),Chilamathur Village, Chittoor Distict 517646 + IN + +2C-BE-EB (hex) Nothing Technology Limited +2CBEEB (base 16) Nothing Technology Limited + 11 Staple Inn + London London WC1V 7QH + GB + +F0-4A-02 (hex) Cisco Systems, Inc +F04A02 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +74-09-AC (hex) Quext, LLC +7409AC (base 16) Quext, LLC + 5214 68th St., Suite 201 + Lubbock TX 79424 + US + +F0-01-6E (hex) Tianyi Telecom Terminals Company Limited +F0016E (base 16) Tianyi Telecom Terminals Company Limited + 6/F Changshang Building, No.29 North Xinhua Street, Xicheng District + Beijing 100031 + CN + +EC-0B-AE (hex) Hangzhou BroadLink Technology Co.,Ltd +EC0BAE (base 16) Hangzhou BroadLink Technology Co.,Ltd + Room 101,1/F,Unit C,Building 1,No.57 Jiang'er Road,Changhe Street,Binjiang District,Hangzhou,Zhejiang,P.R.China + Hangzhou Zhejiang 310052 + CN + +80-25-11 (hex) ITEL MOBILE LIMITED +802511 (base 16) ITEL MOBILE LIMITED + RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING NO.7 KO FAI ROAD, YAU TONG, KLN, H.K + Hong Kong KOWLOON 999077 + HK + +E8-A6-60 (hex) HUAWEI TECHNOLOGIES CO.,LTD +E8A660 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +CC-24-2E (hex) Shenzhen SuperElectron Technology Co.,Ltd. +CC242E (base 16) Shenzhen SuperElectron Technology Co.,Ltd. + 1213-1214, haosheng business center, dongbin road, nanshan street, nanshan district, shenzhen city + Shenzhen Guangdong 518000 + CN + +08-2F-E9 (hex) HUAWEI TECHNOLOGIES CO.,LTD +082FE9 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +98-48-74 (hex) HUAWEI TECHNOLOGIES CO.,LTD +984874 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +1C-A6-81 (hex) HUAWEI TECHNOLOGIES CO.,LTD +1CA681 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +B8-81-FA (hex) Apple, Inc. +B881FA (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +9C-76-0E (hex) Apple, Inc. +9C760E (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +94-EA-32 (hex) Apple, Inc. +94EA32 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +C8-BF-FE (hex) Huawei Device Co., Ltd. +C8BFFE (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +08-2E-36 (hex) Huawei Device Co., Ltd. +082E36 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +50-F4-EB (hex) Apple, Inc. +50F4EB (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +28-C7-09 (hex) Apple, Inc. +28C709 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +38-02-DE (hex) Sercomm Corporation. +3802DE (base 16) Sercomm Corporation. + 3F,No.81,Yu-Yih Rd.,Chu-Nan Chen + Miao-Lih Hsuan 115 + TW + +5C-62-5A (hex) CANON INC. +5C625A (base 16) CANON INC. + 30-2 Shimomaruko 3-chome, + Ohta-ku Tokyo 146-8501 + JP + +7C-0A-3F (hex) Samsung Electronics Co.,Ltd +7C0A3F (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + +08-AA-89 (hex) zte corporation +08AA89 (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +A4-35-2D (hex) TRIZ Networks corp. +A4352D (base 16) TRIZ Networks corp. + 815 Daewangpangyo-ro + Sujeong-gu, Seongnam-si Gyeonggi-do 13449 + KR + +04-D6-0E (hex) FUNAI ELECTRIC CO., LTD. +04D60E (base 16) FUNAI ELECTRIC CO., LTD. + 7-7-1, Nakagaito + Daito Osaka 574-0013 + JP + +04-9F-81 (hex) NETSCOUT SYSTEMS INC +049F81 (base 16) NETSCOUT SYSTEMS INC + 310 Littleton Road + Westford MA 01886 + US + +00-80-8C (hex) NETSCOUT SYSTEMS INC +00808C (base 16) NETSCOUT SYSTEMS INC + 310 Littleton Road + Westford MA 01886 + US + +00-1F-92 (hex) Motorola Solutions Inc. +001F92 (base 16) Motorola Solutions Inc. + 500 W Monroe Street, Ste 4400 + Chicago IL 60661-3781 + US + +00-23-BB (hex) Accretech SBS, Inc. +0023BB (base 16) Accretech SBS, Inc. + 2451 NW 28th Ave. + Portland OR 97210 + US + +B0-C9-52 (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +B0C952 (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD NO.18 HAIBIN ROAD, DONG GUAN GUANG DONG 523860 CN -04-F0-3E (hex) Huawei Device Co., Ltd. -04F03E (base 16) Huawei Device Co., Ltd. +F4-41-9E (hex) Huawei Device Co., Ltd. +F4419E (base 16) Huawei Device Co., Ltd. No.2 of Xincheng Road, Songshan Lake Zone Dongguan Guangdong 523808 CN -78-E2-2C (hex) Huawei Device Co., Ltd. -78E22C (base 16) Huawei Device Co., Ltd. +90-F9-B7 (hex) HUAWEI TECHNOLOGIES CO.,LTD +90F9B7 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +F4-45-88 (hex) HUAWEI TECHNOLOGIES CO.,LTD +F44588 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +C8-BB-81 (hex) Huawei Device Co., Ltd. +C8BB81 (base 16) Huawei Device Co., Ltd. No.2 of Xincheng Road, Songshan Lake Zone Dongguan Guangdong 523808 CN -C0-D0-26 (hex) Huawei Device Co., Ltd. -C0D026 (base 16) Huawei Device Co., Ltd. +1C-47-2F (hex) Huawei Device Co., Ltd. +1C472F (base 16) Huawei Device Co., Ltd. No.2 of Xincheng Road, Songshan Lake Zone Dongguan Guangdong 523808 CN -2C-3F-0B (hex) Cisco Meraki -2C3F0B (base 16) Cisco Meraki - 500 Terry A. Francois Blvd - San Francisco 94158 +20-5E-64 (hex) Huawei Device Co., Ltd. +205E64 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +60-57-7D (hex) eero inc. +60577D (base 16) eero inc. + 660 3rd Street + San Francisco CA 94107 US -80-C5-01 (hex) OctoGate IT Security Systems GmbH -80C501 (base 16) OctoGate IT Security Systems GmbH - Friedrich List Strasse 42 - Paderborn NRW 33100 +C8-13-8B (hex) Shenzhen Skyworth Digital Technology CO., Ltd +C8138B (base 16) Shenzhen Skyworth Digital Technology CO., Ltd + 4F,Block A, Skyworth?Building, + Shenzhen Guangdong 518057 + CN + +78-F2-35 (hex) Sichuan AI-Link Technology Co., Ltd. +78F235 (base 16) Sichuan AI-Link Technology Co., Ltd. + Anzhou, Industrial Park + Mianyang Sichuan 622650 + CN + +F4-4E-E3 (hex) Intel Corporate +F44EE3 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +D0-E0-42 (hex) Cisco Systems, Inc +D0E042 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +3C-37-12 (hex) AVM Audiovisuelles Marketing und Computersysteme GmbH +3C3712 (base 16) AVM Audiovisuelles Marketing und Computersysteme GmbH + Alt-Moabit 95 + Berlin Berlin 10559 DE +80-B6-55 (hex) Intel Corporate +80B655 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +0C-CB-0C (hex) iSYS RTS GmbH +0CCB0C (base 16) iSYS RTS GmbH + Moosacher Str. 88 + Munich Bavaria 80809 + DE + +44-56-E2 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +4456E2 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County + Chengdu Sichuan 611330 + CN + +54-AE-D2 (hex) CSL Dualcom Ltd +54AED2 (base 16) CSL Dualcom Ltd + Salamander Quay West, Park Lane + Harefield Middlesex UB9 6NZ + GB + +F4-6F-A4 (hex) Physik Instrumente GmbH & Co. KG +F46FA4 (base 16) Physik Instrumente GmbH & Co. KG + Auf der Roemerstr. 1 + Karlsruhe 76228 + DE + +C4-74-69 (hex) BT9 +C47469 (base 16) BT9 + Dolev 33 + Tefen 2495900 + IL + +64-5D-92 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +645D92 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, Chengdu, Sichuan + Chengdu Sichuan 610000 + CN + +9C-61-21 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +9C6121 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +E0-4F-BD (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +E04FBD (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +40-F4-20 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +40F420 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +CC-A2-60 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +CCA260 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +AC-E7-7B (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +ACE77B (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +4C-D3-AF (hex) HMD Global Oy +4CD3AF (base 16) HMD Global Oy + Bertel Jungin aukio 9 + Espoo 02600 + FI + +C8-51-42 (hex) Samsung Electronics Co.,Ltd +C85142 (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +CC-0D-E7 (hex) B METERS S.R.L. +CC0DE7 (base 16) B METERS S.R.L. + VIA FRIULI 3 + GONARS UDINE 33050 + IT + +5C-A1-76 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +5CA176 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +10-E4-C2 (hex) Samsung Electronics Co.,Ltd +10E4C2 (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +0C-8D-CA (hex) Samsung Electronics Co.,Ltd +0C8DCA (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +58-2F-F7 (hex) Sagemcom Broadband SAS +582FF7 (base 16) Sagemcom Broadband SAS + 250, route de l'Empereur + Rueil Malmaison Cedex hauts de seine 92848 + FR + +8C-FD-15 (hex) Imagine Marketing Private Limited +8CFD15 (base 16) Imagine Marketing Private Limited + 501B, Shri Guru Har Krishan Bhavan Charat Singh Colony Road, Chakala, Andheri East, + Mumbai Maharashtra 400093 + IN + +AC-D8-29 (hex) Bouffalo Lab (Nanjing) Co., Ltd. +ACD829 (base 16) Bouffalo Lab (Nanjing) Co., Ltd. + 5F, Gongxiang Space, No.100 Tuanjie Road, Nanjing, China + Nanjing Jiangsu 211800 + CN + +68-3A-48 (hex) SAMJIN Co., Ltd. +683A48 (base 16) SAMJIN Co., Ltd. + 199-6, Anyang 7-dong, Manan-gu + Anyang-si Gyeonggi-do 430-817 + KR + +B0-27-CF (hex) Extreme Networks, Inc. +B027CF (base 16) Extreme Networks, Inc. + 6480 Via Del Oro + San Jose CA 95119 + US + +14-22-3B (hex) Google, Inc. +14223B (base 16) Google, Inc. + 1600 Amphitheatre Parkway + Mountain View CA 94043 + US + +48-F8-FF (hex) CHENGDU KT ELECTRONIC HI-TECH CO.,LTD +48F8FF (base 16) CHENGDU KT ELECTRONIC HI-TECH CO.,LTD + No.9, 3rd Wuke Road, Wuhou District + Chengdu Sichuan Province 610045 + CN + +E8-C1-E8 (hex) Shenzhen Xiao Bi En Culture Education Technology Co.,Ltd. +E8C1E8 (base 16) Shenzhen Xiao Bi En Culture Education Technology Co.,Ltd. + 4GH Unit,Block D,Central Avenue,Intersection of Xixiang Avenue and Baoyuan Road,Labor Community,Xixiang Street,Baoan District + Shenzhen China 518102 + CN + +2C-DD-E9 (hex) Arista Networks +2CDDE9 (base 16) Arista Networks + 5453 Great America Parkway + Santa Clara CA 95054 + US + +70-97-41 (hex) Arcadyan Corporation +709741 (base 16) Arcadyan Corporation + No.8, Sec.2, Guangfu Rd. + Hsinchu City Hsinchu 30071 + TW + +C4-FF-22 (hex) Huawei Device Co., Ltd. +C4FF22 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +A0-A0-DC (hex) Huawei Device Co., Ltd. +A0A0DC (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C4-80-8A (hex) Cloud Diagnostics Canada ULC +C4808A (base 16) Cloud Diagnostics Canada ULC + 72 Victoria St. S., Unit 100 + Kitchener Ontario N2G 4Y9 + CA + +E4-08-E7 (hex) Quectel Wireless Solutions Co.,Ltd. +E408E7 (base 16) Quectel Wireless Solutions Co.,Ltd. + 7th Floor, Hongye Building, No.1801 Hongmei Road, Xuhui District + Shanghai 200233 + CN + +7C-70-DB (hex) Intel Corporate +7C70DB (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +8C-94-CC (hex) SFR +8C94CC (base 16) SFR + 12 rue jean-philippe Rameau CS 80001 + La plaine saint denis FRANCE 93634 + FR + +60-DB-15 (hex) New H3C Technologies Co., Ltd +60DB15 (base 16) New H3C Technologies Co., Ltd + 466 Changhe Road, Binjiang District + Hangzhou Zhejiang 310052 + CN + +5C-A7-21 (hex) New H3C Technologies Co., Ltd +5CA721 (base 16) New H3C Technologies Co., Ltd + 466 Changhe Road, Binjiang District + Hangzhou Zhejiang 310052 + CN + +98-F2-17 (hex) Castlenet Technology Inc. +98F217 (base 16) Castlenet Technology Inc. + 5F., No. 10, Daye Rd., Beitou Dist. + Taipei City 112030 + TW + +6C-43-3C (hex) TECNO MOBILE LIMITED +6C433C (base 16) TECNO MOBILE LIMITED + ROOMS 05-15, 13A/F., SOUTH TOWER, WORLD FINANCE CENTRE, HARBOUR CITY, 17 CANTON ROAD, TSIM SHA TSUI, KOWLOON, HONG KONG + Hong Kong Hong Kong 999077 + HK + +44-5B-ED (hex) Aruba, a Hewlett Packard Enterprise Company +445BED (base 16) Aruba, a Hewlett Packard Enterprise Company + 3333 Scott Blvd + Santa Clara CA 95054 + US + +70-A6-CC (hex) Intel Corporate +70A6CC (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +84-EB-EF (hex) Cisco Systems, Inc +84EBEF (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +90-80-60 (hex) Nilfisk A/S +908060 (base 16) Nilfisk A/S + Kornmarksvej 1 + Broendby 2605 + DK + +10-09-F9 (hex) Amazon Technologies Inc. +1009F9 (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +D0-3E-7D (hex) CHIPSEA TECHNOLOGIES (SHENZHEN) CORP. +D03E7D (base 16) CHIPSEA TECHNOLOGIES (SHENZHEN) CORP. + 9F,BLOCK A,GARDEN CITY DIGITAL BUILDING,NO.1079 NANHAI ROAD,NANSHAN DISTRICT + SHEN ZHEN GUANG DONG 518000 + CN + +6C-79-B8 (hex) Texas Instruments +6C79B8 (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +A4-D0-94 (hex) VIVAVIS AG +A4D094 (base 16) VIVAVIS AG + Nobelstr. 18 + Ettlingen D-76375 + DE + +8C-A3-99 (hex) SERVERCOM (INDIA) PRIVATE LIMITED +8CA399 (base 16) SERVERCOM (INDIA) PRIVATE LIMITED + E-43/1 OKHLA INDUSTRIAL AREA PHASE-II NEW DELHI SOUTH DELHI + NEW DELHI NA + IN + +D4-54-8B (hex) Intel Corporate +D4548B (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +60-A5-E2 (hex) Intel Corporate +60A5E2 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +FC-92-57 (hex) Renesas Electronics (Penang) Sdn. Bhd. +FC9257 (base 16) Renesas Electronics (Penang) Sdn. Bhd. + Phase 3, Bayan Lepas FIZ + Bayan Lepas Penang 11900 + MY + +90-69-76 (hex) Withrobot Inc. +906976 (base 16) Withrobot Inc. + #1001, Seoul Forest M-tower, 31, Ttukseom-ro 1-gil, Seongdong-gu + Seoul Seoul 04778 + KR + +60-B6-E1 (hex) Texas Instruments +60B6E1 (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +D0-1E-1D (hex) SaiNXT Technologies LLP +D01E1D (base 16) SaiNXT Technologies LLP + Shop No. 7, Sonawala Building, 1st Floor, Proctor Road, Grant Road (E) + Mumbai Maharashtra 400007 + IN + +A8-23-16 (hex) Nokia +A82316 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +38-E3-9F (hex) Motorola Mobility LLC, a Lenovo Company +38E39F (base 16) Motorola Mobility LLC, a Lenovo Company + 222 West Merchandise Mart Plaza + Chicago IL 60654 + US + +A4-2A-71 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +A42A71 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County + Chengdu Sichuan 611330 + CN + +44-67-52 (hex) Wistron INFOCOMM (Zhongshan) CORPORATION +446752 (base 16) Wistron INFOCOMM (Zhongshan) CORPORATION + 15 Cuiwei Road, Cuiheng New District + zhongshan Guangdong 528400 + CN + +78-BB-88 (hex) Maxio Technology (Hangzhou) Ltd. +78BB88 (base 16) Maxio Technology (Hangzhou) Ltd. + 6F, Building C, No.459 Qianmo Road, Juguang Center + Hangzhou Zhejiang 310051 + CN + +A8-64-F1 (hex) Intel Corporate +A864F1 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +58-4D-42 (hex) Dragos, Inc. +584D42 (base 16) Dragos, Inc. + 1745 Dorsey Rd, Suite R + Hanover MD 21076 + US + +60-8A-10 (hex) Microchip Technology Inc. +608A10 (base 16) Microchip Technology Inc. + 2355 W. Chandler Blvd. + Chandler AZ 85224 + US + +10-6F-D9 (hex) CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. +106FD9 (base 16) CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. + B22 Building,NO.51 Tongle Road, Shajing Town, Jiangnan District, Nanning, Guangxi Province, China + Nanning Guangxi 530007 + CN + +00-03-24 (hex) SANYO Techno Solutions Tottori Co., Ltd. +000324 (base 16) SANYO Techno Solutions Tottori Co., Ltd. + 7-101 Tachikawa-cho + Tottori City 680-8634 + JP + 84-80-94 (hex) Meter, Inc. 848094 (base 16) Meter, Inc. 148 Townsend St @@ -69896,9 +71630,6 @@ FCBCD1 (base 16) HUAWEI TECHNOLOGIES CO.,LTD Dongguan 523808 CN -CC-3A-DF (hex) Private -CC3ADF (base 16) Private - 38-EF-E3 (hex) INGENICO TERMINALS SAS 38EFE3 (base 16) INGENICO TERMINALS SAS 28-32 BOULEVARD DE GRENELLE @@ -70562,9 +72293,6 @@ DCED84 (base 16) Haverford Systems Inc San Jose CA 94568 US -28-EF-01 (hex) Private -28EF01 (base 16) Private - C0-53-36 (hex) Beijing National Railway Research & Design Institute of Signal & Communication Group Co..Ltd. C05336 (base 16) Beijing National Railway Research & Design Institute of Signal & Communication Group Co..Ltd. 7 floor, No.1 Automobile Museum South Road, Fengtai Science and Technology Park, @@ -71363,12 +73091,6 @@ A83FA1 (base 16) IEEE Registration Authority Piscataway NJ 08554 US -78-47-E3 (hex) SICHUAN TIANYI COMHEART TELECOM CO.,LTD -7847E3 (base 16) SICHUAN TIANYI COMHEART TELECOM CO.,LTD - NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, - CHENGDU SICHUAN 611330 - CN - 6C-9B-C0 (hex) Chemoptics Inc. 6C9BC0 (base 16) Chemoptics Inc. 261, Techno 2-ro, Yuseong-gu @@ -73517,12 +75239,6 @@ D0D2B0 (base 16) Apple, Inc. Nishi-ku, Fukuoka-shi Fukuoka 819-0373 JP -F0-92-B4 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -F092B4 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - E8-DF-70 (hex) AVM Audiovisuelles Marketing und Computersysteme GmbH E8DF70 (base 16) AVM Audiovisuelles Marketing und Computersysteme GmbH Alt-Moabit 95 @@ -73553,12 +75269,6 @@ F06D78 (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD Shenzhen Guangdong 518057 CN -EC-F8-EB (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -ECF8EB (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 70-7D-95 (hex) Shenzhen City LinwlanTechnology Co. Ltd. 707D95 (base 16) Shenzhen City LinwlanTechnology Co. Ltd. 106 village road , manhole street Baoan district . @@ -75179,12 +76889,6 @@ C8AA55 (base 16) Hunan Comtom Electronic Incorporated Co.,Ltd Sunnyvale CA 94089 US -2C-63-73 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -2C6373 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 24-A7-DC (hex) BSkyB Ltd 24A7DC (base 16) BSkyB Ltd 130 Kings Road @@ -86579,12 +88283,6 @@ C89383 (base 16) Embedded Automation, Inc. Shenzhen Guangdong 518107 CN -8C-4D-EA (hex) Cerio Corporation -8C4DEA (base 16) Cerio Corporation - 5F., No.88, Mincyuan Rd., Sindian City - Taipei County 23141 - TW - 24-BA-30 (hex) Technical Consumer Products, Inc. 24BA30 (base 16) Technical Consumer Products, Inc. 325 Campus Drive @@ -86819,12 +88517,6 @@ C8A1B6 (base 16) Shenzhen Longway Technologies Co., Ltd Shenzhen Guangdong 518057 CN -A8-55-6A (hex) Pocketnet Technology Inc. -A8556A (base 16) Pocketnet Technology Inc. - Suite B, 7F., No. 550, Ruie Kwang Rd., Neihu District, - Taipei 11429 - TW - B4-C8-10 (hex) UMPI Elettronica B4C810 (base 16) UMPI Elettronica Via Respighi, 15 @@ -87005,12 +88697,6 @@ F0BDF1 (base 16) Sipod Inc. Beijing 100190 CN -58-FD-20 (hex) Bravida Sakerhet AB -58FD20 (base 16) Bravida Sakerhet AB - Mikrofonvagen 28 - STOCKHOLM 126 81 - SE - AC-A0-16 (hex) Cisco Systems, Inc ACA016 (base 16) Cisco Systems, Inc 80 West Tasman Drive @@ -87221,12 +88907,6 @@ DC1D9F (base 16) U & B tech Anyang-Si Gyeonggi-Do 431-061 KR -D8-E7-2B (hex) NetAlly -D8E72B (base 16) NetAlly - 310 Littleton Road - Westford MA 01886 - US - 78-5C-72 (hex) Hioso Technology Co., Ltd. 785C72 (base 16) Hioso Technology Co., Ltd. 6th Floor, 12th Building, Wangtang Industrial Zone, @@ -90848,12 +92528,6 @@ D8D67E (base 16) GSK CNC EQUIPMENT CO.,LTD Paris 75001 FR -00-18-85 (hex) Avigilon Corporation -001885 (base 16) Avigilon Corporation - Box 378, 101 - 1001 West Broadway - Vancouver BC V6H 4E4 - CA - 00-18-88 (hex) GOTIVE a.s. 001888 (base 16) GOTIVE a.s. Zámocká 34 @@ -94247,12 +95921,6 @@ D8D67E (base 16) GSK CNC EQUIPMENT CO.,LTD Yokohama Kanagawa 224-0037 JP -00-0B-3A (hex) QuStream Corporation -000B3A (base 16) QuStream Corporation - 3305 Breckinridge Blvd. - Duluth Georgia 30096 - US - 00-0B-33 (hex) Vivato Technologies 000B33 (base 16) Vivato Technologies 444 Cedros Ave @@ -95123,12 +96791,6 @@ D8D67E (base 16) GSK CNC EQUIPMENT CO.,LTD Kyunggi-Do 435-040 KR -00-08-0C (hex) VDA Elettronica spa -00080C (base 16) VDA Elettronica spa - Viale Lino Zanussi, 3 - 33170 Pordenone - IT - 00-08-04 (hex) ICA Inc. 000804 (base 16) ICA Inc. 542-1 Noguki @@ -100766,12 +102428,6 @@ AA0002 (base 16) DIGITAL EQUIPMENT CORPORATION Chatsworth CA 91311 US -E4-05-F8 (hex) Delta Innovation Technology Co., Ltd. -E405F8 (base 16) Delta Innovation Technology Co., Ltd. - China Digital Kingdom Building, Chaoyang District - Beijing Beijing 100102 - CN - 00-00-09 (hex) XEROX CORPORATION 000009 (base 16) XEROX CORPORATION M/S 105-50C @@ -102770,12 +104426,6 @@ D8C678 (base 16) MitraStar Technology Corp. Shenzhen Guangdong 518000 CN -C4-A1-51 (hex) Sichuan Tianyi Comheart Telecom Co., Ltd. -C4A151 (base 16) Sichuan Tianyi Comheart Telecom Co., Ltd. - No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County - Chengdu Sichuan 611330 - CN - 10-E7-7A (hex) STMicrolectronics International NV 10E77A (base 16) STMicrolectronics International NV 39, Chemin du Champ-des-Filles @@ -104327,11 +105977,29 @@ CCC95D (base 16) Apple, Inc. Piscataway NJ 08554 US -34-56-FE (hex) Cisco Meraki -3456FE (base 16) Cisco Meraki - 500 Terry A. Francois Blvd - San Francisco 94158 - US +C8-94-02 (hex) CHONGQING FUGUI ELECTRONICS CO.,LTD. +C89402 (base 16) CHONGQING FUGUI ELECTRONICS CO.,LTD. + Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District + Chongqing Chongqing 401332 + CN + +7C-B9-4C (hex) Bouffalo Lab (Nanjing) Co., Ltd. +7CB94C (base 16) Bouffalo Lab (Nanjing) Co., Ltd. + 5F, Gongxiang Space, No.100 Tuanjie Road, Nanjing, China + Nanjing Jiangsu 211800 + CN + +DC-15-C8 (hex) AVM Audiovisuelles Marketing und Computersysteme GmbH +DC15C8 (base 16) AVM Audiovisuelles Marketing und Computersysteme GmbH + Alt-Moabit 95 + Berlin Berlin 10559 + DE + +6C-D6-30 (hex) Rootous System Co.,Ltd +6CD630 (base 16) Rootous System Co.,Ltd + KT B/D 4Floor, 100, Ahopgeori-gil + Yeonseo-myeon Sejong-si 30049 + KR B8-07-56 (hex) Cisco Meraki B80756 (base 16) Cisco Meraki @@ -104339,6 +106007,906 @@ B80756 (base 16) Cisco Meraki San Francisco 94158 US +C8-33-E5 (hex) HUAWEI TECHNOLOGIES CO.,LTD +C833E5 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +34-56-FE (hex) Cisco Meraki +3456FE (base 16) Cisco Meraki + 500 Terry A. Francois Blvd + San Francisco 94158 + US + +B8-44-AE (hex) TCT mobile ltd +B844AE (base 16) TCT mobile ltd + No.86 hechang 7th road, zhongkai, Hi-Tech District + Hui Zhou Guang Dong 516006 + CN + +E4-F7-5B (hex) ARRIS Group, Inc. +E4F75B (base 16) ARRIS Group, Inc. + 6450 Sequence Drive + San Diego CA 92121 + US + +F8-79-0A (hex) ARRIS Group, Inc. +F8790A (base 16) ARRIS Group, Inc. + 6450 Sequence Drive + San Diego CA 92121 + US + +0C-CF-89 (hex) SHENZHEN BILIAN ELECTRONIC CO.,LTD +0CCF89 (base 16) SHENZHEN BILIAN ELECTRONIC CO.,LTD + NO.268? Fuqian Rd, Jutang community, Guanlan Town, Longhua New district + shenzhen guangdong 518000 + CN + +0C-8C-69 (hex) Shenzhen elink smart Co., ltd +0C8C69 (base 16) Shenzhen elink smart Co., ltd + Floor 2,Building A , Hongtian Xinfengze Industrial Park Huang Pu Community , Xin Qiao District ,Baoan Area + shenzhen Guangdong Province 518101 + CN + +D8-BB-C1 (hex) Micro-Star INTL CO., LTD. +D8BBC1 (base 16) Micro-Star INTL CO., LTD. + No.69, Lide St., + New Taipei City Taiwan 235 + TW + +AC-5A-FC (hex) Intel Corporate +AC5AFC (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +1C-93-7C (hex) ARRIS Group, Inc. +1C937C (base 16) ARRIS Group, Inc. + 6450 Sequence Drive + San Diego CA 92121 + US + +58-FC-20 (hex) Altice Labs S.A. +58FC20 (base 16) Altice Labs S.A. + NIF 504705610, Rua Eng. José Ferreira Pinto Basto + Aveiro 3810-106 + PT + +58-FD-20 (hex) Systemhouse Solutions AB +58FD20 (base 16) Systemhouse Solutions AB + Mikrofonvagen 28 + STOCKHOLM 126 81 + SE + +04-D6-F4 (hex) GD Midea Air-Conditioning Equipment Co.,Ltd. +04D6F4 (base 16) GD Midea Air-Conditioning Equipment Co.,Ltd. + Midea Global Innovation Center,Beijiao Town,Shunde + Foshan Guangdong 528311 + CN + +04-90-81 (hex) Pensando Systems, Inc. +049081 (base 16) Pensando Systems, Inc. + 570 Alder Drive + Milpitas CA 95035 + US + +4C-79-6E (hex) Intel Corporate +4C796E (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +98-AD-1D (hex) Huawei Device Co., Ltd. +98AD1D (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +F8-AA-3F (hex) DWnet Technologies(Suzhou) Corporation +F8AA3F (base 16) DWnet Technologies(Suzhou) Corporation + No.8,Tangzhuang Road, Suzhou Industrial Park, Jiangsu, China + Suzhou 21500 + CN + +00-68-2B (hex) Huawei Device Co., Ltd. +00682B (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +F0-9E-4A (hex) Intel Corporate +F09E4A (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +F0-77-C3 (hex) Intel Corporate +F077C3 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +24-9A-D8 (hex) YEALINK(XIAMEN) NETWORK TECHNOLOGY CO.,LTD. +249AD8 (base 16) YEALINK(XIAMEN) NETWORK TECHNOLOGY CO.,LTD. + 309, 3th Floor, No.16, Yun Ding North Road, Huli District + xiamen Fujian 361015 + CN + +D8-5E-D3 (hex) GIGA-BYTE TECHNOLOGY CO.,LTD. +D85ED3 (base 16) GIGA-BYTE TECHNOLOGY CO.,LTD. + Pin-Jen City, Taoyuan, Taiwan, R.O.C. + Pin-Jen Taoyuan 324 + TW + +00-E4-21 (hex) Sony Interactive Entertainment Inc. +00E421 (base 16) Sony Interactive Entertainment Inc. + 1-7-1 Konan + Minato-ku Tokyo 108-0075 + JP + +CC-DB-04 (hex) DataRemote Inc. +CCDB04 (base 16) DataRemote Inc. + 18001 Old Cutler Rd. Suite 600 + Palmetto Bay FL 33157 + US + +E8-9F-39 (hex) Nokia +E89F39 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +34-73-5A (hex) Dell Inc. +34735A (base 16) Dell Inc. + One Dell Way + Round Rock TX 78682 + US + +8C-AA-CE (hex) Xiaomi Communications Co Ltd +8CAACE (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +98-1A-35 (hex) HUAWEI TECHNOLOGIES CO.,LTD +981A35 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +80-34-28 (hex) Microchip Technology Inc. +803428 (base 16) Microchip Technology Inc. + 2355 W. Chandler Blvd. + Chandler AZ 85224 + US + +28-EF-01 (hex) Amazon Technologies Inc. +28EF01 (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +B0-22-7A (hex) HP Inc. +B0227A (base 16) HP Inc. + 10300 Energy Dr + Spring TX 77389 + US + +60-A7-51 (hex) Huawei Device Co., Ltd. +60A751 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +10-2B-41 (hex) Samsung Electronics Co.,Ltd +102B41 (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + +34-4A-C3 (hex) HuNan ZiKun Information Technology CO., Ltd +344AC3 (base 16) HuNan ZiKun Information Technology CO., Ltd + 101-8, 1st Floor, Juxing Venture Base, No. 8 Lujing Road, GaoXin Development District + Changsha City Hunan Province 410000 + CN + +68-2D-83 (hex) SHENZHEN DINGHE COMMUNICATION COMPANY +682D83 (base 16) SHENZHEN DINGHE COMMUNICATION COMPANY + ROOM 1802, BAOYUNDA WULIU INFORMATION BUILDING + SHENZHEN GUANGDONG 518101 + CN + +A8-43-97 (hex) Innogrit Corporation +A84397 (base 16) Innogrit Corporation + 1735 Technology Dr, Suite 620 + San Jose CA 95110 + US + +D8-CD-2C (hex) WUXI NEIHUA NETWORK TECHNOLOGY CO., LTD +D8CD2C (base 16) WUXI NEIHUA NETWORK TECHNOLOGY CO., LTD + 16 Lexing Road, Xinwu District + Wuxi Jiangsu 214000 + CN + +58-D3-91 (hex) Quectel Wireless Solutions Co., Ltd. +58D391 (base 16) Quectel Wireless Solutions Co., Ltd. + 7th Floor, Hongye Building, No.1801 Hongmei Road, Xuhui District + Shanghai 200233 + CN + +08-47-4C (hex) Nokia +08474C (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +90-C1-19 (hex) Nokia +90C119 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +7C-F8-80 (hex) Cisco Systems, Inc +7CF880 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +E4-05-F8 (hex) Bytedance +E405F8 (base 16) Bytedance + E World Center,11 Zhongguancun Street Haidian Dist + Beijing City Beijing 100102 + CN + +F8-45-C4 (hex) Shenzhen Netforward Micro-Electronic Co., Ltd. +F845C4 (base 16) Shenzhen Netforward Micro-Electronic Co., Ltd. + Room 611-2?6st Floor,Building 1, The Sunmax Technology Park, No 8 Keyuan Road, Nanshan District + Shenzhen Guangdong 518000 + CN + +78-10-53 (hex) China Mobile Group Device Co.,Ltd. +781053 (base 16) China Mobile Group Device Co.,Ltd. + 32 Xuanwumen West Street,Xicheng District + Beijing 100053 + CN + +9C-4F-5F (hex) TAP Sound System +9C4F5F (base 16) TAP Sound System + 15 rue Castel + Fontenay-sous-Bois 94120 + FR + +00-08-0C (hex) VDA Group S.p.a. +00080C (base 16) VDA Group S.p.a. + Viale Lino Zanussi 3 + Pordenone Pordenone 33170 + IT + +D0-97-FE (hex) Realme Chongqing Mobile Telecommunications Corp.,Ltd. +D097FE (base 16) Realme Chongqing Mobile Telecommunications Corp.,Ltd. + No.178 Yulong Avenue, Yufengshan, Yubei District, Chongqing. + Chongqing China 401120 + CN + +84-3A-5B (hex) Inventec(Chongqing) Corporation +843A5B (base 16) Inventec(Chongqing) Corporation + No.66 West District 2nd Rd, Shapingba District + Chongqing Chongqing 401331 + CN + +54-49-DF (hex) Peloton Interactive, Inc +5449DF (base 16) Peloton Interactive, Inc + 158 W 27th St, 4th Fl + New York NY 10001 + US + +18-2A-57 (hex) HUAWEI TECHNOLOGIES CO.,LTD +182A57 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +F8-3E-95 (hex) HUAWEI TECHNOLOGIES CO.,LTD +F83E95 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +48-12-58 (hex) HUAWEI TECHNOLOGIES CO.,LTD +481258 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +D8-EB-46 (hex) Google, Inc. +D8EB46 (base 16) Google, Inc. + 1600 Amphitheatre Parkway + Mountain View CA 94043 + US + +2C-17-E0 (hex) SYSTEMES ET TECHNOLOGIES IDENTIFICATION (STid) +2C17E0 (base 16) SYSTEMES ET TECHNOLOGIES IDENTIFICATION (STid) + 20 Parc d’activités des Pradeaux + GREASQUE Select State F-13850 + FR + +CC-32-96 (hex) Huawei Device Co., Ltd. +CC3296 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +98-CD-AC (hex) Espressif Inc. +98CDAC (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +80-8A-F7 (hex) Nanoleaf +808AF7 (base 16) Nanoleaf + 100 Front Street East, 4th Floor + Toronto Ontario M5A 1E1 + CA + +B0-3D-C2 (hex) Wasp artificial intelligence(Shenzhen) Co.,ltd +B03DC2 (base 16) Wasp artificial intelligence(Shenzhen) Co.,ltd + A402,Block ABCD,Building 3,Phase 1,Tianan Yungu Industrial Park,Gangtou Comunity,Bantian Street,Longhua District,Shenzhen + Shenzhen Select State 518000 + CN + +C8-4D-34 (hex) LIONS Taiwan Technology Inc. +C84D34 (base 16) LIONS Taiwan Technology Inc. + 3F-2, 120, Sec. 2, Gongdao 5th Rd. + Hsinchu Taiwan 30072 + TW + +44-6F-F8 (hex) Dyson Limited +446FF8 (base 16) Dyson Limited + Tetbury Hill + Malmesbury Wiltshire SN16 0RP + GB + +6C-1B-3F (hex) MiraeSignal Co., Ltd +6C1B3F (base 16) MiraeSignal Co., Ltd + #701,C-dong Bundang Techno Park Pangyoro 744 + Bundang-gu Sungnam-si Kyungkido 13510 + KR + +28-AF-FD (hex) Cisco Systems, Inc +28AFFD (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +9C-76-13 (hex) Ring LLC +9C7613 (base 16) Ring LLC + 1523 26th St + Santa Monica CA 90404 + US + +44-9B-C1 (hex) HUAWEI TECHNOLOGIES CO.,LTD +449BC1 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +20-25-D2 (hex) Fiberhome Telecommunication Technologies Co.,LTD +2025D2 (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +28-F4-9B (hex) LEETEK +28F49B (base 16) LEETEK + Ojeong-ro, 47 + Bucheon-si Gyeonggi-do 14445 + KR + +18-42-D4 (hex) Wuhan Hosan Telecommunication Technology Co.,Ltd +1842D4 (base 16) Wuhan Hosan Telecommunication Technology Co.,Ltd + Fourth Floor,Building N,Quannengtong Shuangchuang Yuan,Gold-silver Lake Street,East West Lake District, + Wuhan Hubei 430043 + CN + +A8-63-7D (hex) D-Link International +A8637D (base 16) D-Link International + 1 Internal Business Park, #03-12,The Synergy + Singapore Singapore 609917 + SG + +2C-43-BE (hex) Sunnovo International Limited +2C43BE (base 16) Sunnovo International Limited + 1717 Haitai Building + Beijing Beijing 100083 + CN + +58-10-B7 (hex) Infinix mobility limited +5810B7 (base 16) Infinix mobility limited + RMS 05-15, 13A/F SOUTH TOWER WORLD FINANCE CTR HARBOUR CITY 17 CANTON RD TST KLN HONG KONG + HongKong HongKong 999077 + HK + +B0-24-91 (hex) Huawei Device Co., Ltd. +B02491 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +98-75-1A (hex) Huawei Device Co., Ltd. +98751A (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +1C-91-80 (hex) Apple, Inc. +1C9180 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +4C-B9-10 (hex) Apple, Inc. +4CB910 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +B4-89-01 (hex) HUAWEI TECHNOLOGIES CO.,LTD +B48901 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +E0-92-5C (hex) Apple, Inc. +E0925C (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +EC-15-3D (hex) Beijing Yaxunhongda Technology Co., Ltd. +EC153D (base 16) Beijing Yaxunhongda Technology Co., Ltd. + East area,4th floor,No.5,Shangdi 5th Street Haidian District,Beijing + Beijing Beijing 100000 + CN + +D8-A3-5C (hex) Samsung Electronics Co.,Ltd +D8A35C (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + +C0-92-96 (hex) zte corporation +C09296 (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +50-E2-4E (hex) zte corporation +50E24E (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +4C-77-66 (hex) SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. +4C7766 (base 16) SHENZHEN MERCURY COMMUNICATION TECHNOLOGIES CO.,LTD. + 3/F, Building R1-B, High-Tech Industrial Park, Nanshan District + Shenzhen Guangdong 518057 + CN + +78-E3-6D (hex) Espressif Inc. +78E36D (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +14-5A-FC (hex) Liteon Technology Corporation +145AFC (base 16) Liteon Technology Corporation + 4F, 90, Chien 1 Road + New Taipei City Taiwan 23585 + TW + +1C-A0-EF (hex) IEEE Registration Authority +1CA0EF (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +00-18-85 (hex) Motorola Solutions Inc. +001885 (base 16) Motorola Solutions Inc. + 500 W Monroe Street, Ste 4400 + Chicago IL 60661-3781 + US + +D8-E7-2B (hex) NETSCOUT SYSTEMS INC +D8E72B (base 16) NETSCOUT SYSTEMS INC + 310 Littleton Road + Westford MA 01886 + US + +18-BF-B3 (hex) Samsung Electronics Co., Ltd., Memory Division +18BFB3 (base 16) Samsung Electronics Co., Ltd., Memory Division + 1, Samsungjeonja-ro + Hwaseong-si Gyeonggi-do 18448 + KR + +2C-8D-B1 (hex) Intel Corporate +2C8DB1 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +58-6C-25 (hex) Intel Corporate +586C25 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +08-2C-ED (hex) Technity Solutions Inc. +082CED (base 16) Technity Solutions Inc. + 100 West Beaver Creek Rd, Unit 13 + Richmond Hill Ontario L4B 1H4 + CA + +34-86-5D (hex) Espressif Inc. +34865D (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +B4-E3-F9 (hex) Silicon Laboratories +B4E3F9 (base 16) Silicon Laboratories + 400 West Cesar Chavez Street + Austin TX 78701 + US + +A4-9B-CD (hex) Cisco Systems, Inc +A49BCD (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +04-27-28 (hex) Microsoft Corporation +042728 (base 16) Microsoft Corporation + One Microsoft Way + REDMOND WA 98052 + US + +20-66-CF (hex) FREEBOX SAS +2066CF (base 16) FREEBOX SAS + 16 rue de la Ville l'Eveque + PARIS IdF 75008 + FR + +2C-C8-1B (hex) Routerboard.com +2CC81B (base 16) Routerboard.com + Mikrotikls SIA + Riga Riga LV1009 + LV + +88-E0-56 (hex) HUAWEI TECHNOLOGIES CO.,LTD +88E056 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +D0-7D-33 (hex) Huawei Device Co., Ltd. +D07D33 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C0-E1-BE (hex) HUAWEI TECHNOLOGIES CO.,LTD +C0E1BE (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +D0-35-E5 (hex) EM Microelectronic +D035E5 (base 16) EM Microelectronic + Rue des Sors 3 + Marin-Epagnier Neuchatel 2074 + CH + +90-96-F3 (hex) BUFFALO.INC +9096F3 (base 16) BUFFALO.INC + AKAMONDORI Bld.,30-20,Ohsu 3-chome,Naka-ku + Nagoya Aichi Pref. 460-8315 + JP + +54-0E-58 (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD +540E58 (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD + NO.18 HAIBIN ROAD, + DONG GUAN GUANG DONG 523860 + CN + +5C-64-8E (hex) Zyxel Communications Corporation +5C648E (base 16) Zyxel Communications Corporation + No. 6 Innovation Road II, Science Park + Hsichu Taiwan 300 + TW + +30-E3-96 (hex) Huawei Device Co., Ltd. +30E396 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C4-A1-51 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +C4A151 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County + Chengdu Sichuan 611330 + CN + +78-47-E3 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +7847E3 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, + CHENGDU SICHUAN 611330 + CN + +EC-F8-EB (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +ECF8EB (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +F0-92-B4 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +F092B4 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +F4-4E-38 (hex) Olibra LLC +F44E38 (base 16) Olibra LLC + 45 legin dr + creskill NJ 07626 + US + +2C-63-73 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +2C6373 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +A0-D7-22 (hex) Samsung Electronics Co.,Ltd +A0D722 (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +50-49-B0 (hex) Samsung Electronics Co.,Ltd +5049B0 (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +E8-05-DC (hex) Verifone Inc. +E805DC (base 16) Verifone Inc. + 2560 North First Street, Suite 220 + San Jose CA 95131 + US + +10-7B-CE (hex) Nokia +107BCE (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +C8-05-9E (hex) Hefei Symboltek Co.,Ltd +C8059E (base 16) Hefei Symboltek Co.,Ltd + Standard factory building 2 layer,Tianmen Lake 1#,No.36 Fairview Avenue District Econmic Development Zone Hefei, Anhui + Hefei Anhui 230601 + CN + +34-FC-A1 (hex) Micronet union Technology(Chengdu)Co., Ltd. +34FCA1 (base 16) Micronet union Technology(Chengdu)Co., Ltd. + No.502, Building 5, No. 528, Yuefei Road, Shibantan Street, Xindu District + Chengdu Sichuan 610000 + CN + +28-97-B8 (hex) myenergi Ltd +2897B8 (base 16) myenergi Ltd + Church View Business Centre, Binbrook + Market Rasen Lincolnshire LN8 6BY + GB + +48-06-2B (hex) Private +48062B (base 16) Private + +B0-A7-B9 (hex) TP-Link Corporation Limited +B0A7B9 (base 16) TP-Link Corporation Limited + Room 901,9/F.New East Ocean Centre, 9 Science Museum Road + Tsim Sha Tsui Kowloon 999077 + HK + +6C-5A-B0 (hex) TP-Link Corporation Limited +6C5AB0 (base 16) TP-Link Corporation Limited + Room 901,9/F.New East Ocean Centre, 9 Science Museum Road + Tsim Sha Tsui Kowloon 999077 + HK + +4C-F5-DC (hex) Hangzhou Hikvision Digital Technology Co.,Ltd. +4CF5DC (base 16) Hangzhou Hikvision Digital Technology Co.,Ltd. + No.555 Qianmo Road + Hangzhou Zhejiang 310052 + CN + +60-E6-F0 (hex) Wistron Neweb Corporation +60E6F0 (base 16) Wistron Neweb Corporation + No.20,Park Avenue II,Hsinchu Science Park + Hsin-Chu R.O.C. 308 + TW + +20-1F-3B (hex) Google, Inc. +201F3B (base 16) Google, Inc. + 1600 Amphitheatre Parkway + Mountain View CA 94043 + US + +B8-25-B5 (hex) Trakm8 Ltd +B825B5 (base 16) Trakm8 Ltd + 4 Roman Park, Roman Way + Coleshill West Midlands B46 1HG + GB + +20-D2-76 (hex) ITEL MOBILE LIMITED +20D276 (base 16) ITEL MOBILE LIMITED + RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING NO.7 KO FAI ROAD, YAU TONG, KLN, H.K + Hong Kong KOWLOON 999077 + HK + +08-A8-42 (hex) Huawei Device Co., Ltd. +08A842 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C8-F5-D6 (hex) IEEE Registration Authority +C8F5D6 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +40-58-99 (hex) Logitech Far East +405899 (base 16) Logitech Far East + #2 Creation Rd. 4, + Hsinchu 300 + TW + +8C-4D-EA (hex) Cerio Corporation +8C4DEA (base 16) Cerio Corporation + 4F.-3., No.192, Sec. 2, Zhongxing Rd., Xindian Dist. + New Taipei City 231 + TW + +98-43-FA (hex) Intel Corporate +9843FA (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +94-AA-0A (hex) Fiberhome Telecommunication Technologies Co.,LTD +94AA0A (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +7C-F4-62 (hex) BEIJING HUAWOO TECHNOLOGIES CO.LTD +7CF462 (base 16) BEIJING HUAWOO TECHNOLOGIES CO.LTD + A411-3, floor 3, block A, 9 Shangdi 3rd Street, Haidian District, Beijing + beijing 100094 + CN + +04-B9-E3 (hex) Samsung Electronics Co.,Ltd +04B9E3 (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + +C4-5E-5C (hex) HUAWEI TECHNOLOGIES CO.,LTD +C45E5C (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +E8-5C-0A (hex) Cisco Systems, Inc +E85C0A (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +70-B9-50 (hex) Texas Instruments +70B950 (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +D0-9F-D9 (hex) IEEE Registration Authority +D09FD9 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +A0-B0-86 (hex) Hirschmann Automation and Control GmbH +A0B086 (base 16) Hirschmann Automation and Control GmbH + Stuttgarter Straße 45-51 + Neckartenzlingen D-72654 + DE + +30-B3-46 (hex) CJSC NORSI-TRANS +30B346 (base 16) CJSC NORSI-TRANS + B.Novodmitrovskaya, 12/15 floor 2 r. 36 + Moscow MOSCOW 127015 + RU + +20-C1-9B (hex) Intel Corporate +20C19B (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +2C-6D-C1 (hex) Intel Corporate +2C6DC1 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +00-FA-B6 (hex) Kontakt Micro-Location Sp z o.o. +00FAB6 (base 16) Kontakt Micro-Location Sp z o.o. + Stoczniowcow 3 + Krakow 30-709 + PL + +54-C2-50 (hex) Iskratel d.o.o. +54C250 (base 16) Iskratel d.o.o. + Ljubljanska cesta 24a + Kranj 4000 + SI + +00-0B-3A (hex) PESA +000B3A (base 16) PESA + 103 Quality Circle, Suite 210 + Huntsville AL 35806 + US + +5C-E4-2A (hex) Intel Corporate +5CE42A (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +18-74-E2 (hex) IEEE Registration Authority +1874E2 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +F0-C8-14 (hex) SHENZHEN BILIAN ELECTRONIC CO.,LTD +F0C814 (base 16) SHENZHEN BILIAN ELECTRONIC CO.,LTD + NO.268? Fuqian Rd, Jutang community, Guanlan Town, Longhua New district + shenzhen guangdong 518000 + CN + +D0-17-69 (hex) Murata Manufacturing Co., Ltd. +D01769 (base 16) Murata Manufacturing Co., Ltd. + 1-10-1, Higashikotari + Nagaokakyo-shi Kyoto 617-8555 + JP + +CC-3A-DF (hex) Neptune Technology Group Inc. +CC3ADF (base 16) Neptune Technology Group Inc. + 1600 AL Highway 229 S + Tallassee AL 36078 + US + +A8-55-6A (hex) 3S System Technology Inc. +A8556A (base 16) 3S System Technology Inc. + 6F, No. 5, Ln. 16, Sec. 2, Sichuan Rd., Banqiao Dist., + New Taipei City 220620 + TW + +68-EC-8A (hex) Private +68EC8A (base 16) Private + F8-D0-27 (hex) Seiko Epson Corporation F8D027 (base 16) Seiko Epson Corporation 2070 Kotobuki Koaka @@ -105545,12 +108113,6 @@ D058C0 (base 16) Qingdao Haier Multimedia Limited. Qingdao Shandong 266103 CN -F8-D4-78 (hex) Flextronics Tech.(Ind) Pvt Ltd -F8D478 (base 16) Flextronics Tech.(Ind) Pvt Ltd - SURVEYNO.381, PADUR ROAD, KUTHAMBAKKAM VILLAGE, 602107 POONAMALLEE TALUK, THIRUVALLUR DISTRIC - Chennai 602107 - IN - 48-C3-B0 (hex) Pharos Co.Ltd 48C3B0 (base 16) Pharos Co.Ltd 503 Ogong-ro 144 Deokjin-gu @@ -105611,12 +108173,6 @@ DC6723 (base 16) barox Kommunikation GmbH Lörrach DE-79539 DE -44-B4-62 (hex) Flextronics Tech.(Ind) Pvt Ltd -44B462 (base 16) Flextronics Tech.(Ind) Pvt Ltd - SURVEYNO.381, PADUR ROAD, KUTHAMBAKKAM VILLAGE, 602107 POONAMALLEE TALUK, THIRUVALLUR DISTRIC - Chennai 602107 - IN - 94-B4-0F (hex) Aruba, a Hewlett Packard Enterprise Company 94B40F (base 16) Aruba, a Hewlett Packard Enterprise Company 3333 Scott Blvd @@ -106007,12 +108563,6 @@ DC48B2 (base 16) Baraja Pty. Ltd. NO.68, Qinghe Middle Street Haidian District, Beijing 100085 CN -10-12-B4 (hex) SICHUAN TIANYI COMHEART TELECOM CO.,LTD -1012B4 (base 16) SICHUAN TIANYI COMHEART TELECOM CO.,LTD - NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, - CHENGDU SICHUAN 611330 - CN - B8-2C-A0 (hex) Resideo B82CA0 (base 16) Resideo 2 Corporate Center Dr. @@ -106133,12 +108683,6 @@ B8599F (base 16) Mellanox Technologies, Inc. Fürth Deutschlang 90766 DE -04-6B-25 (hex) SICHUAN TIANYI COMHEART TELECOM CO.,LTD -046B25 (base 16) SICHUAN TIANYI COMHEART TELECOM CO.,LTD - NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, - CHENGDU SICHUAN 611330 - CN - 98-D3-E7 (hex) Netafim L 98D3E7 (base 16) Netafim L Kibutz Magal @@ -106169,12 +108713,6 @@ F063F9 (base 16) HUAWEI TECHNOLOGIES CO.,LTD Xinzhuang Dist., New Taipei City 24255 TW -14-69-A2 (hex) SICHUAN TIANYI COMHEART TELECOM CO.,LTD -1469A2 (base 16) SICHUAN TIANYI COMHEART TELECOM CO.,LTD - NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, - CHENGDU SICHUAN 611330 - CN - 54-80-28 (hex) Hewlett Packard Enterprise 548028 (base 16) Hewlett Packard Enterprise 8000 Foothills Blvd. @@ -109025,12 +111563,6 @@ B02628 (base 16) Broadcom Limited Dallas TX 75243 US -68-26-2A (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -68262A (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - E8-DE-8E (hex) Integrated Device Technology (Malaysia) Sdn. Bhd. E8DE8E (base 16) Integrated Device Technology (Malaysia) Sdn. Bhd. Phase 3, Bayan Lepas FIZ @@ -109055,12 +111587,6 @@ AC202E (base 16) Hitron Technologies. Inc Hsin-chu Taiwan 300 TW -9C-32-A9 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -9C32A9 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 1C-5A-0B (hex) Tegile Systems 1C5A0B (base 16) Tegile Systems 7999 Gateway Blvd Suite 120 @@ -109259,12 +111785,6 @@ E8D11B (base 16) ASKEY COMPUTER CORP NEW TAIPEI TAIWAN 23585 TW -B8-22-4F (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -B8224F (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 98-00-C1 (hex) GuangZhou CREATOR Technology Co.,Ltd.(CHINA) 9800C1 (base 16) GuangZhou CREATOR Technology Co.,Ltd.(CHINA) Level 3,Blg 6,No 9 Keji Yuan,LanYusi St, @@ -109463,12 +111983,6 @@ C87324 (base 16) Sow Cheng Technology Co. Ltd. Hui Zhou Guang Dong 516006 CN -90-86-74 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -908674 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 90-17-11 (hex) Hagenuk Marinekommunikation GmbH 901711 (base 16) Hagenuk Marinekommunikation GmbH Hamburger Chaussee 25 @@ -109895,12 +112409,6 @@ FCECDA (base 16) Ubiquiti Networks Inc. Zhubei City Hsinchu County 30265 TW -44-BA-46 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -44BA46 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - E0-7C-13 (hex) zte corporation E07C13 (base 16) zte corporation 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China @@ -111107,12 +113615,6 @@ D8EB97 (base 16) TRENDnet, Inc. Zhongshan Guangdong 528437 CN -64-3A-B1 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -643AB1 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, Chengdu, Sichuan - Chengdu Sichuan 610000 - CN - 00-1B-FE (hex) Zavio Inc. 001BFE (base 16) Zavio Inc. No.1,Lising 1st Rd. Science Based Industrial Park, @@ -111155,12 +113657,6 @@ D8EB97 (base 16) TRENDnet, Inc. Lawrenceville GA 30044 US -80-48-A5 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -8048A5 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,TianYi International Hotel - Chengdu Sichuan 61000 - CN - 68-3E-34 (hex) MEIZU Technology Co., Ltd. 683E34 (base 16) MEIZU Technology Co., Ltd. MEIZU Tech Bldg., Technology & Innovation Coast @@ -121286,12 +123782,6 @@ E01CEE (base 16) Bravo Tech, Inc. San Jose CA 94568 US -F4-C7-95 (hex) WEY Elektronik AG -F4C795 (base 16) WEY Elektronik AG - Dorfstrasse 57 - Unterengstringen Zurich 8103 - CH - 78-11-85 (hex) NBS Payment Solutions Inc. 781185 (base 16) NBS Payment Solutions Inc. 703 Evans Ave @@ -121736,12 +124226,6 @@ F8472D (base 16) X2gen Digital Corp. Ltd Pin-Jhen City, 324 TW -84-90-00 (hex) Arnold & Richter Cine Technik -849000 (base 16) Arnold & Richter Cine Technik - Tuerkenstrasse 89 - Munich Bavaria 80799 - DE - 08-18-4C (hex) A. S. Thomas, Inc. 08184C (base 16) A. S. Thomas, Inc. 355 Providence Hwy @@ -128735,12 +131219,6 @@ A07332 (base 16) Cashmaster International Limited Palo Alto CA 94303 US -00-0C-04 (hex) Tecnova -000C04 (base 16) Tecnova - 1486 St. Paul Ave. - Gurnee Illinois 60031 - US - 00-0C-01 (hex) Abatron AG 000C01 (base 16) Abatron AG Lettenstrasse 9 @@ -133187,12 +135665,6 @@ A06A00 (base 16) Verilink Corporation 213 76 MALMOE SE -00-E0-DF (hex) KEYMILE GmbH -00E0DF (base 16) KEYMILE GmbH - Wohlenbergstraße 3 - 30179 Hannover - DE - 00-E0-F2 (hex) ARLOTTO COMNET, INC. 00E0F2 (base 16) ARLOTTO COMNET, INC. 7F-4,55,TUNG-KUANG ROAD @@ -134435,12 +136907,6 @@ A06A00 (base 16) Verilink Corporation BEDFORD TX 76021 US -00-C0-6A (hex) ZAHNER-ELEKTRIK GMBH & CO. KG -00C06A (base 16) ZAHNER-ELEKTRIK GMBH & CO. KG - P.O. BOX 1846 - - DE - 00-C0-E3 (hex) OSITECH COMMUNICATIONS, INC. 00C0E3 (base 16) OSITECH COMMUNICATIONS, INC. 679 SOUTHGATE DRIVE @@ -137501,12 +139967,6 @@ D01411 (base 16) IEEE Registration Authority Landquart 7302 CH -00-E5-E4 (hex) Sichuan Tianyi Comheart Telecom Co., Ltd. -00E5E4 (base 16) Sichuan Tianyi Comheart Telecom Co., Ltd. - No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County - Chengdu Sichuan 611330 - CN - E8-13-6E (hex) HUAWEI TECHNOLOGIES CO.,LTD E8136E (base 16) HUAWEI TECHNOLOGIES CO.,LTD No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park @@ -138983,6 +141443,42 @@ F06F46 (base 16) Ubiik Cupertino CA 95014 US +FC-40-09 (hex) zte corporation +FC4009 (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +24-A6-5E (hex) zte corporation +24A65E (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +50-98-39 (hex) Xiaomi Communications Co Ltd +509839 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +48-00-7D (hex) DTS ELEKTRONIK SAN. TIC. LTD. STI. +48007D (base 16) DTS ELEKTRONIK SAN. TIC. LTD. STI. + MAHMUTBEY MAH. 2650.SOK. NO:21 + ISTANBUL 34218 + TR + +30-B1-B5 (hex) Arcadyan Corporation +30B1B5 (base 16) Arcadyan Corporation + No.8, Sec.2, Guangfu Rd. + Hsinchu City Hsinchu 30071 + TW + +64-07-F6 (hex) Samsung Electronics Co.,Ltd +6407F6 (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + E0-CB-BC (hex) Cisco Meraki E0CBBC (base 16) Cisco Meraki 500 Terry A. Francois Blvd @@ -138995,6 +141491,966 @@ E0CBBC (base 16) Cisco Meraki San Francisco 94158 US +D8-EC-E5 (hex) Zyxel Communications Corporation +D8ECE5 (base 16) Zyxel Communications Corporation + No. 6 Innovation Road II, Science Park + Hsichu Taiwan 300 + TW + +C4-70-AB (hex) Ruijie Networks Co.,LTD +C470AB (base 16) Ruijie Networks Co.,LTD + No. 2, 7th floor, xingwangruijie, haixi hi-tech industrial park, high-tech zone, fuzhou city + Fuzhou Fujian 350002 + CN + +CC-6B-1E (hex) CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. +CC6B1E (base 16) CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. + B22 Building,NO.51 Tongle Road, Shajing Town, Jiangnan District, Nanning, Guangxi Province, China + Nanning Guangxi 530007 + CN + +F0-D0-8C (hex) TCT mobile ltd +F0D08C (base 16) TCT mobile ltd + No.86 hechang 7th road, zhongkai, Hi-Tech District + Hui Zhou Guang Dong 516006 + CN + +84-90-00 (hex) Arnold&Richter Cine Technik GmbH & Co. Betriebs KG +849000 (base 16) Arnold&Richter Cine Technik GmbH & Co. Betriebs KG + Herbert-Bayer-Str. 10 + Munchen Bavaria 80807 + DE + +30-F9-4B (hex) Universal Electronics, Inc. +30F94B (base 16) Universal Electronics, Inc. + 201 E. Sandpointe Ave + Santa Ana CA 92707 + US + +B4-8A-5F (hex) Juniper Networks +B48A5F (base 16) Juniper Networks + 1133 Innovation Way + Sunnyvale CA 94089 + US + +70-DF-F7 (hex) ARRIS Group, Inc. +70DFF7 (base 16) ARRIS Group, Inc. + 6450 Sequence Drive + San Diego CA 92121 + US + +00-E0-DF (hex) DZS GmbH +00E0DF (base 16) DZS GmbH + Wohlenbergstrasse. 3 + Hannover 30179 + DE + +E0-E8-BB (hex) Unicom Vsens Telecommunications Co., Ltd. +E0E8BB (base 16) Unicom Vsens Telecommunications Co., Ltd. + Room612,613,615,6Floors,Block3,Hengji center,N0.18 Jianguomen inner Street,Dondcheng Distict, Beijing,P.R.China + Beijing 100005 + CN + +E4-C9-0B (hex) Radwin +E4C90B (base 16) Radwin + Habarzel 27 + Tel Aviv -- select -- 6971039 + IL + +98-27-82 (hex) IEEE Registration Authority +982782 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +38-A0-67 (hex) Nokia Solutions and Networks GmbH & Co. KG +38A067 (base 16) Nokia Solutions and Networks GmbH & Co. KG + Werinherstrasse 91 + München Bavaria D-81541 + DE + +CC-81-2A (hex) vivo Mobile Communication Co., Ltd. +CC812A (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +7C-1B-93 (hex) Huawei Device Co., Ltd. +7C1B93 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +DC-2D-3C (hex) Huawei Device Co., Ltd. +DC2D3C (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +04-11-19 (hex) IEEE Registration Authority +041119 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +E4-55-A8 (hex) Cisco Meraki +E455A8 (base 16) Cisco Meraki + 500 Terry A. Francois Blvd + San Francisco 94158 + US + +08-81-B2 (hex) Logitech (China) Technology Co., Ltd +0881B2 (base 16) Logitech (China) Technology Co., Ltd + 1111 Changshou Road + Shanghai 200001 + CN + +C4-F1-74 (hex) eero inc. +C4F174 (base 16) eero inc. + 660 3rd Street + San Francisco CA 94107 + US + +28-D0-EA (hex) Intel Corporate +28D0EA (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +E0-0C-E5 (hex) HUAWEI TECHNOLOGIES CO.,LTD +E00CE5 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +28-41-EC (hex) HUAWEI TECHNOLOGIES CO.,LTD +2841EC (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +7C-00-4D (hex) HUAWEI TECHNOLOGIES CO.,LTD +7C004D (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +04-D3-20 (hex) ITEL MOBILE LIMITED +04D320 (base 16) ITEL MOBILE LIMITED + RM B3 & B4 BLOCK B, KO FAI INDUSTRIAL BUILDING NO.7 KO FAI ROAD, YAU TONG, KLN, H.K + Hong Kong KOWLOON 999077 + HK + +1C-99-57 (hex) Intel Corporate +1C9957 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +F4-6B-8C (hex) Hon Hai Precision Ind. Co., Ltd. +F46B8C (base 16) Hon Hai Precision Ind. Co., Ltd. + GuangDongShenZhen + ShenZhen GuangDong 518109 + CN + +FC-34-97 (hex) ASUSTek COMPUTER INC. +FC3497 (base 16) ASUSTek COMPUTER INC. + 15,Li-Te Rd., Peitou, Taipei 112, Taiwan + Taipei Taiwan 112 + TW + +84-7A-B6 (hex) AltoBeam (China) Inc. +847AB6 (base 16) AltoBeam (China) Inc. + B808, Tsinghua Tongfang Hi-Tech Plaza, Haidian + Beijing Beijing 100083 + CN + +78-A6-A0 (hex) Hangzhou Ezviz Software Co.,Ltd. +78A6A0 (base 16) Hangzhou Ezviz Software Co.,Ltd. + Room 302, Unit B, Building 2, 399 Danfeng Road,Binjiang District + Hangzhou Zhejiang 310051 + CN + +48-51-CF (hex) Intelbras +4851CF (base 16) Intelbras + BR 101, km 210, S/N° + São José Santa Catarina 88104800 + BR + +4C-5D-3C (hex) Cisco Systems, Inc +4C5D3C (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +34-73-2D (hex) Cisco Systems, Inc +34732D (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +04-7B-CB (hex) Universal Global Scientific Industrial Co., Ltd. +047BCB (base 16) Universal Global Scientific Industrial Co., Ltd. + 141, Lane 351, Taiping Road, Sec.1,Tsao Tuen + Nan-Tou Taiwan 54261 + TW + +8C-34-46 (hex) Huawei Device Co., Ltd. +8C3446 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +80-47-86 (hex) Samsung Electronics Co.,Ltd +804786 (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + +D4-47-5A (hex) ScreenBeam, Inc. +D4475A (base 16) ScreenBeam, Inc. + 3301 Olcott St + Santa Clara CA 95054 + US + +E4-41-64 (hex) Nokia +E44164 (base 16) Nokia + 600 March Road + Kanata Ontario K2K 2E6 + CA + +34-E9-FE (hex) Metis Co., Ltd. +34E9FE (base 16) Metis Co., Ltd. + 25, Saenari-ro, Bundang-gu + Seongnam-si Gyeonggi-do 13509 + KR + +AC-13-9C (hex) Adtran Inc +AC139C (base 16) Adtran Inc + 901 Explorer Blvd. + Huntsville AL 35806-2807 + US + +A4-CE-DA (hex) Arcadyan Corporation +A4CEDA (base 16) Arcadyan Corporation + No.8, Sec.2, Guangfu Rd. + Hsinchu City Hsinchu 30071 + TW + +8C-43-61 (hex) Hailo Digital Hub GmbH & Co. KG +8C4361 (base 16) Hailo Digital Hub GmbH & Co. KG + Lahnstrasse 3a + Giessen Hessen 35398 + DE + +54-72-5E (hex) UNIONMAN TECHNOLOGY CO.,LTD +54725E (base 16) UNIONMAN TECHNOLOGY CO.,LTD + No.5,Huitai Road,Huinan High-Tech Park,Huiao Highway + Huizhou Guangdong 516025 + CN + +98-C3-D2 (hex) Ningbo Sanxing Medical Electric Co.,Ltd +98C3D2 (base 16) Ningbo Sanxing Medical Electric Co.,Ltd + No.26 FengWan Road,Cicheng Town,Jiangbei District,Ningbo,China + Ningbo 315029 + CN + +24-5D-FC (hex) IEEE Registration Authority +245DFC (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +9C-82-81 (hex) vivo Mobile Communication Co., Ltd. +9C8281 (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +48-7E-48 (hex) Earda Technologies co Ltd +487E48 (base 16) Earda Technologies co Ltd + Block A,Lianfeng Creative Park, #2 Jisheng Rd., Nansha District + Guangzhou Guangdong 511455 + CN + +E0-E3-7C (hex) Huawei Device Co., Ltd. +E0E37C (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +24-18-C6 (hex) HUNAN FN-LINK TECHNOLOGY LIMITED +2418C6 (base 16) HUNAN FN-LINK TECHNOLOGY LIMITED + No.8, Litong Road, Liuyan Economic & Tec + Changsha HUNAN 410329 + CN + +30-78-D3 (hex) Virgilant Technologies Ltd. +3078D3 (base 16) Virgilant Technologies Ltd. + 2F., No.3, Aly. 19, Lane 8, Tianmu E. Rd.,Shilin Dist., + Taipei City Taiwan 11153 + TW + +60-18-95 (hex) Dell Inc. +601895 (base 16) Dell Inc. + One Dell Way + Round Rock TX 78682 + US + +E8-EA-4D (hex) HUAWEI TECHNOLOGIES CO.,LTD +E8EA4D (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +3C-FF-D8 (hex) HUAWEI TECHNOLOGIES CO.,LTD +3CFFD8 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +4C-61-7E (hex) Huawei Device Co., Ltd. +4C617E (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +B4-10-7B (hex) Texas Instruments +B4107B (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +64-97-14 (hex) eero inc. +649714 (base 16) eero inc. + 660 3rd Street + San Francisco CA 94107 + US + +CC-86-EC (hex) Silicon Laboratories +CC86EC (base 16) Silicon Laboratories + 400 West Cesar Chavez Street + Austin 78701 + US + +40-41-01 (hex) Rockwell Automation +404101 (base 16) Rockwell Automation + 1 Allen-Bradley Dr. + Mayfield Heights OH 44124-6118 + US + +7C-55-A7 (hex) Kastle Systems +7C55A7 (base 16) Kastle Systems + 6402 Arlington Blvd + Falls Church VA 22042 + US + +40-BE-EE (hex) Shenzhen Yunding Information Technology Co.,Ltd +40BEEE (base 16) Shenzhen Yunding Information Technology Co.,Ltd + 32G, Tower E, CR Land Building, Tong Gu Road 5#, Nanshan District,,Guangdong,CN + Shenzhen Guangdong 518000 + CN + +A4-4C-62 (hex) Hangzhou Microimage Software Co., Ltd +A44C62 (base 16) Hangzhou Microimage Software Co., Ltd + Room 313, Unit B, Building 2, 399 Danfeng Road, Binjiang District + Hangzhou Zhejiang 310051 + CN + +FC-E8-06 (hex) Edifier International +FCE806 (base 16) Edifier International + Suit 2207, 22nd floor, Tower II, Lippo centre, 89 Queensway + Hong Kong 070 + CN + +F4-C7-95 (hex) WEY Technology AG +F4C795 (base 16) WEY Technology AG + Dorfstrasse 57 + Unterengstringen Zurich 8103 + CH + +44-B4-62 (hex) Flextronics Tech.(Ind) Pvt Ltd +44B462 (base 16) Flextronics Tech.(Ind) Pvt Ltd + 365, Benjamin Road + Sricity Vardahiah Palem(M),Chilamathur Village, Chittoor Distict 517646 + IN + +F8-D4-78 (hex) Flextronics Tech.(Ind) Pvt Ltd +F8D478 (base 16) Flextronics Tech.(Ind) Pvt Ltd + 365, Benjamin Road + Sricity Vardahiah Palem(M),Chilamathur Village, Chittoor Distict 517646 + IN + +50-C2-ED (hex) GN Audio A/S +50C2ED (base 16) GN Audio A/S + Lautrupbjerg 7 + Ballerup DK-2750 + DK + +90-A8-22 (hex) Amazon Technologies Inc. +90A822 (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +74-AD-98 (hex) Cisco Systems, Inc +74AD98 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +84-8C-8D (hex) Apple, Inc. +848C8D (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +0C-5C-B5 (hex) IEEE Registration Authority +0C5CB5 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +E8-4F-25 (hex) Murata Manufacturing Co., Ltd. +E84F25 (base 16) Murata Manufacturing Co., Ltd. + 1-10-1, Higashikotari + Nagaokakyo-shi Kyoto 617-8555 + JP + +04-25-E0 (hex) Taicang T&W Electronics +0425E0 (base 16) Taicang T&W Electronics + 89# Jiang Nan RD + Suzhou Jiangsu 215412 + CN + +30-85-EB (hex) Fiberhome Telecommunication Technologies Co.,LTD +3085EB (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +84-06-FA (hex) Fiberhome Telecommunication Technologies Co.,LTD +8406FA (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +B8-D4-3E (hex) vivo Mobile Communication Co., Ltd. +B8D43E (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +C0-DC-D7 (hex) Huawei Device Co., Ltd. +C0DCD7 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +30-37-B3 (hex) HUAWEI TECHNOLOGIES CO.,LTD +3037B3 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +14-CB-19 (hex) HP Inc. +14CB19 (base 16) HP Inc. + 10300 Energy Dr + Spring TX 77389 + US + +0C-E4-41 (hex) Apple, Inc. +0CE441 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +B8-2A-A9 (hex) Apple, Inc. +B82AA9 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +78-64-C0 (hex) Apple, Inc. +7864C0 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +74-15-75 (hex) Xiaomi Communications Co Ltd +741575 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +38-52-47 (hex) Huawei Device Co., Ltd. +385247 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +E8-1C-D8 (hex) Apple, Inc. +E81CD8 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +3C-06-30 (hex) Apple, Inc. +3C0630 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +F4-02-28 (hex) SAMSUNG ELECTRO-MECHANICS(THAILAND) +F40228 (base 16) SAMSUNG ELECTRO-MECHANICS(THAILAND) + 93Moo5T. Bangsamak SEMTHAI, WELLGROW INDUSTRIAL ESTATE + Bangpakong Chachoengsao 24180 + TH + +0C-83-CC (hex) Alpha Networks Inc. +0C83CC (base 16) Alpha Networks Inc. + No.8 Li-shing 7th Rd., Science-based Industrial Park, Hsinchu, Taiwan, R.O.C + Hsinchu Taiwan 300 + TW + +EC-B9-70 (hex) Ruijie Networks Co.,LTD +ECB970 (base 16) Ruijie Networks Co.,LTD + No. 2, 7th floor, xingwangruijie, haixi hi-tech industrial park, high-tech zone, fuzhou city + Fuzhou Fujian 350002 + CN + +30-83-98 (hex) Espressif Inc. +308398 (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +F8-89-D2 (hex) CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. +F889D2 (base 16) CLOUD NETWORK TECHNOLOGY SINGAPORE PTE. LTD. + B22 Building,NO.51 Tongle Road, Shajing Town, Jiangnan District, Nanning, Guangxi Province, China + Nanning Guangxi 530007 + CN + +10-27-F5 (hex) TP-Link Corporation Limited +1027F5 (base 16) TP-Link Corporation Limited + Room 901,9/F.New East Ocean Centre, 9 Science Museum Road + Tsim Sha Tsui Kowloon 999077 + HK + +B0-4F-13 (hex) Dell Inc. +B04F13 (base 16) Dell Inc. + One Dell Way + Round Rock TX 78682 + US + +C0-4B-13 (hex) WonderSound Technology Co., Ltd +C04B13 (base 16) WonderSound Technology Co., Ltd + 10A, Center of Shenmao, News Road 59, Meiling community, Lianhua Street, Futian district + Shenzhen 518034 + CN + +9C-7F-81 (hex) SHENZHEN FAST TECHNOLOGIES CO.,LTD +9C7F81 (base 16) SHENZHEN FAST TECHNOLOGIES CO.,LTD + Room 202,Building No.5,Section 30,No.2 of Kefa Road,Nanshan District,Shenzhen,P.R.China + Shenzhen Guangdong 518057 + CN + +C4-BC-D7 (hex) New Ryatek +C4BCD7 (base 16) New Ryatek + Room 103, 1st floor, building 19, yard 1, Baosheng South Road, Haidian District, Beijing + Beijing Beijing 100192 + CN + +C0-AE-FD (hex) Shenzhen HC-WLAN Technology Co.,Ltd +C0AEFD (base 16) Shenzhen HC-WLAN Technology Co.,Ltd + Room 201E, Block D, Donghai Wang Industrial Zone, No. 369, Bulong Road, Bantian Street, Longgang District + Shenzhen Guangdong 518129 + CN + +20-6A-94 (hex) Hitron Technologies. Inc +206A94 (base 16) Hitron Technologies. Inc + No. 1-8, Lising 1st Rd. Hsinchu Science Park, Hsinchu, 300, Taiwan, R.O.C + Hsin-chu Taiwan 300 + TW + +30-95-87 (hex) HUNAN FN-LINK TECHNOLOGY LIMITED +309587 (base 16) HUNAN FN-LINK TECHNOLOGY LIMITED + No.8, Litong Road, Liuyan Economic & Tec + Changsha HUNAN 410329 + CN + +DC-87-CB (hex) Beijing Perfectek Technologies Co., Ltd. +DC87CB (base 16) Beijing Perfectek Technologies Co., Ltd. + A-17, No. 101, 6F, Building 24, No. 68, Beiqing Road, Haidian District + Beijing Beijing 100094 + CN + +10-2D-41 (hex) Sichuan AI-Link Technology Co., Ltd. +102D41 (base 16) Sichuan AI-Link Technology Co., Ltd. + Anzhou, Industrial Park + Mianyang Sichuan 622650 + CN + +64-27-53 (hex) Huawei Device Co., Ltd. +642753 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +7C-F6-66 (hex) Tuya Smart Inc. +7CF666 (base 16) Tuya Smart Inc. + 160 Greentree Drive, Suite 101 + Dover DE 19904 + US + +28-53-4E (hex) HUAWEI TECHNOLOGIES CO.,LTD +28534E (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +5C-B0-0A (hex) HUAWEI TECHNOLOGIES CO.,LTD +5CB00A (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +00-C0-6A (hex) Zahner-Elektrik Ingeborg Zahner-Schiller GmbH & Co. KG. +00C06A (base 16) Zahner-Elektrik Ingeborg Zahner-Schiller GmbH & Co. KG. + Thüringer Str. 12 + Kronach - Gundelsdorf Bavaria 96317 + DE + +20-1E-88 (hex) Intel Corporate +201E88 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +20-CE-2A (hex) IEEE Registration Authority +20CE2A (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +58-13-D3 (hex) Gemtek Technology Co., Ltd. +5813D3 (base 16) Gemtek Technology Co., Ltd. + No.15-1 Zhonghua Road + Hukou Hsinchu 30352 + TW + +00-E5-E4 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +00E5E4 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County + Chengdu Sichuan 611330 + CN + +14-69-A2 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +1469A2 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, + CHENGDU SICHUAN 611330 + CN + +04-6B-25 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +046B25 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, + CHENGDU SICHUAN 611330 + CN + +10-12-B4 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +1012B4 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, + CHENGDU SICHUAN 611330 + CN + +9C-32-A9 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +9C32A9 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +68-26-2A (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +68262A (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +B8-22-4F (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +B8224F (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +90-86-74 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +908674 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +88-C9-B3 (hex) IEEE Registration Authority +88C9B3 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +C8-BD-69 (hex) Samsung Electronics Co.,Ltd +C8BD69 (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +64-3A-B1 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +643AB1 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, Chengdu, Sichuan + Chengdu Sichuan 610000 + CN + +44-BA-46 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +44BA46 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +A8-76-50 (hex) Samsung Electronics Co.,Ltd +A87650 (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +54-D1-7D (hex) Samsung Electronics Co.,Ltd +54D17D (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +60-3A-AF (hex) Samsung Electronics Co.,Ltd +603AAF (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +80-48-A5 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +8048A5 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,TianYi International Hotel + Chengdu Sichuan 61000 + CN + +54-66-F9 (hex) ConMet +5466F9 (base 16) ConMet + 5701 SE Columbia Way + Vancouver WA 98661 + US + +58-91-53 (hex) China Mobile IOT Company Limited +589153 (base 16) China Mobile IOT Company Limited + NO.8 Yu Ma Road, NanAn Area + Chongqing Chongqing 401336 + CN + +9C-5A-81 (hex) Xiaomi Communications Co Ltd +9C5A81 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +B8-13-32 (hex) AMPAK Technology,Inc. +B81332 (base 16) AMPAK Technology,Inc. + 3F, No.15-1 Zhonghua Road, Hsinchu Industrail Park, Hukou, + Hsinchu Hsinchu,Taiwan R.O.C. 30352 + TW + +98-7D-DD (hex) China Mobile Group Device Co.,Ltd. +987DDD (base 16) China Mobile Group Device Co.,Ltd. + 32 Xuanwumen West Street,Xicheng District + Beijing 100053 + CN + +44-DB-60 (hex) Nanjing Baihezhengliu Technology Co., Ltd +44DB60 (base 16) Nanjing Baihezhengliu Technology Co., Ltd + Science and technology innovation center, Shiqiu street, Lishui District + Nanjing Jiangsu 211222 + CN + +B8-B7-7D (hex) Guangdong Transtek Medical Electronics CO.,Ltd +B8B77D (base 16) Guangdong Transtek Medical Electronics CO.,Ltd + Zone A, No.105 ,Dongli Road, Torch Development District Zhongshan , CN 528437 + Zhongshan Guangdong 528437 + CN + +C4-78-A2 (hex) Huawei Device Co., Ltd. +C478A2 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +9C-9E-71 (hex) Huawei Device Co., Ltd. +9C9E71 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +0C-9A-3C (hex) Intel Corporate +0C9A3C (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +DC-21-48 (hex) Intel Corporate +DC2148 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +74-CF-00 (hex) Shenzhen SuperElectron Technology Co.,Ltd. +74CF00 (base 16) Shenzhen SuperElectron Technology Co.,Ltd. + 1213-1214, haosheng business center, dongbin road, nanshan street, nanshan district, shenzhen city + Shenzhen Guangdong 518000 + CN + +2C-EA-DC (hex) ASKEY COMPUTER CORP +2CEADC (base 16) ASKEY COMPUTER CORP + 10F,No.119,JIANKANG RD,ZHONGHE DIST + NEW TAIPEI TAIWAN 23585 + TW + +AC-E1-4F (hex) Autonomic Controls, Inc. +ACE14F (base 16) Autonomic Controls, Inc. + 28 Kaysal Ct + ARMONK NY 10504 + US + +AC-97-6C (hex) Greenliant +AC976C (base 16) Greenliant + 3970 Freedom Circle, Suite 100 + Santa Clara CA 95054 + US + +38-14-28 (hex) Dell Inc. +381428 (base 16) Dell Inc. + One Dell Way + Round Rock TX 78682 + US + +98-49-9F (hex) Domo Tactical Communications +98499F (base 16) Domo Tactical Communications + DTC Fusion 2, 1100 Parkway + Whiteley Hampshire PO15 7AB + GB + +C0-23-8D (hex) Samsung Electronics Co.,Ltd +C0238D (base 16) Samsung Electronics Co.,Ltd + 129, Samsung-ro, Youngtongl-Gu + Suwon Gyeonggi-Do 16677 + KR + +28-11-A8 (hex) Intel Corporate +2811A8 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +20-CF-AE (hex) Cisco Systems, Inc +20CFAE (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +C0-FB-F9 (hex) IEEE Registration Authority +C0FBF9 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +60-9B-B4 (hex) HUAWEI TECHNOLOGIES CO.,LTD +609BB4 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +7C-27-BC (hex) Hui Zhou Gaoshengda Technology Co.,LTD +7C27BC (base 16) Hui Zhou Gaoshengda Technology Co.,LTD + No.75,Zhongkai High-Tech Development District,Huizhou + Hui Zhou Guangdong 516006 + CN + +74-5D-68 (hex) Fiberhome Telecommunication Technologies Co.,LTD +745D68 (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +EC-08-E5 (hex) Motorola Mobility LLC, a Lenovo Company +EC08E5 (base 16) Motorola Mobility LLC, a Lenovo Company + 222 West Merchandise Mart Plaza + Chicago IL 60654 + US + +80-CC-9C (hex) NETGEAR +80CC9C (base 16) NETGEAR + 350 East Plumeria Drive + San Jose CA 95134 + US + +0C-60-46 (hex) vivo Mobile Communication Co., Ltd. +0C6046 (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +C0-F9-B0 (hex) HUAWEI TECHNOLOGIES CO.,LTD +C0F9B0 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +14-8C-4A (hex) HUAWEI TECHNOLOGIES CO.,LTD +148C4A (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +50-70-97 (hex) China Mobile Group Device Co.,Ltd. +507097 (base 16) China Mobile Group Device Co.,Ltd. + 32 Xuanwumen West Street,Xicheng District + Beijing 100053 + CN + +CC-15-31 (hex) Intel Corporate +CC1531 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +28-0F-EB (hex) LG Innotek +280FEB (base 16) LG Innotek + 26, Hanamsandan 5beon-ro + Gwangju Gwangsan-gu 506-731 + KR + +4C-D5-77 (hex) CHONGQING FUGUI ELECTRONICS CO.,LTD. +4CD577 (base 16) CHONGQING FUGUI ELECTRONICS CO.,LTD. + Building D21,No.1, East Zone 1st Road,Xiyong Town,Shapingba District + Chongqing Chongqing 401332 + CN + +74-E2-0C (hex) Amazon Technologies Inc. +74E20C (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +00-0C-04 (hex) Tecnova +000C04 (base 16) Tecnova + 2383 N Delany Rd + Waukegan IL 60087-1836 + US + +10-54-03 (hex) INTARSO GmbH +105403 (base 16) INTARSO GmbH + Schuchardstr. 3 + Düsseldorf NRW 40595 + DE + 7C-8A-E1 (hex) COMPAL INFORMATION (KUNSHAN) CO., LTD. 7C8AE1 (base 16) COMPAL INFORMATION (KUNSHAN) CO., LTD. NO. 25, THE 3RD Street KUNSHAN EXPORT PROCESSING ZONE @@ -140333,9 +143789,6 @@ A41908 (base 16) Fiberhome Telecommunication Technologies Co.,LTD Wuhan Hubei 430074 CN -38-AF-D0 (hex) Private -38AFD0 (base 16) Private - 80-D3-36 (hex) CERN 80D336 (base 16) CERN CH-1211 @@ -140636,12 +144089,6 @@ C09AD0 (base 16) Apple, Inc. Shenzhen Guangdong 518000 CN -C0-1B-23 (hex) SICHUAN TIANYI COMHEART TELECOM CO.,LTD -C01B23 (base 16) SICHUAN TIANYI COMHEART TELECOM CO.,LTD - NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, - CHENGDU SICHUAN 611330 - CN - B8-C7-4A (hex) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD B8C74A (base 16) GUANGDONG OPPO MOBILE TELECOMMUNICATIONS CORP.,LTD NO.18 HAIBIN ROAD, @@ -142397,12 +145844,6 @@ E43022 (base 16) Hanwha Techwin Security Vietnam Seongnam-si Gyeonggi-do 463-875 KR -5C-4A-1F (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -5C4A1F (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - E4-8F-34 (hex) Vodafone Italia S.p.A. E48F34 (base 16) Vodafone Italia S.p.A. Via Lorenteggio nr. 240 @@ -142790,12 +146231,6 @@ B0ECE1 (base 16) Private Taipei City Neihu Dist 248 TW -24-8B-E0 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -248BE0 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 00-24-24 (hex) Ace Axis Limited 002424 (base 16) Ace Axis Limited 602 Delta Business Park, Welton Road @@ -142910,12 +146345,6 @@ B4A382 (base 16) Hangzhou Hikvision Digital Technology Co.,Ltd. Hangzhou Zhejiang 310052 CN -9C-9C-40 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -9C9C40 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - A4-07-B6 (hex) Samsung Electronics Co.,Ltd A407B6 (base 16) Samsung Electronics Co.,Ltd #94-1, Imsoo-Dong @@ -144062,12 +147491,6 @@ C0D3C0 (base 16) Samsung Electronics Co.,Ltd Cupertino CA 95014 US -54-E0-61 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -54E061 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 50-3A-7D (hex) AlphaTech PLC Int’l Co., Ltd. 503A7D (base 16) AlphaTech PLC Int’l Co., Ltd. 13F., No.618, Sec. 7, New Taipei Blvd., Xinzhuang Dist., @@ -144620,12 +148043,6 @@ A0E0AF (base 16) Cisco Systems, Inc San Jose CA 94568 US -18-75-32 (hex) SICHUAN TIANYI COMHEART TELECOMCO., LTD -187532 (base 16) SICHUAN TIANYI COMHEART TELECOMCO., LTD - FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 4C-B8-1C (hex) SAM Electronics GmbH 4CB81C (base 16) SAM Electronics GmbH Behringstr. 120 @@ -144851,12 +148268,6 @@ E49E12 (base 16) FREEBOX SAS HangZhou ZheJiang 310053 CN -FC-37-2B (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -FC372B (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - A4-D9-A4 (hex) neXus ID Solutions AB A4D9A4 (base 16) neXus ID Solutions AB Telefonvägen 26 @@ -144881,12 +148292,6 @@ CCB0DA (base 16) Liteon Technology Corporation New Taipei City Taiwan 23585 TW -7C-CC-1F (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -7CCC1F (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 18-F2-92 (hex) Shannon Systems 18F292 (base 16) Shannon Systems Suite 1801,Wentong Building,739 Kunming Road, Yangpu, Shanghai @@ -145727,12 +149132,6 @@ E4BEED (base 16) Netcore Technology Inc. Kulim Kedah 09000 MY -00-A0-0E (hex) NetAlly -00A00E (base 16) NetAlly - 310 Littleton Road - Westford MA 01886 - US - 00-C0-17 (hex) NetAlly 00C017 (base 16) NetAlly 2075 Research Parkway @@ -146447,12 +149846,6 @@ D8D43C (base 16) Sony Corporation Minato-ku Tokyo 108-0075 JP -D4-41-65 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -D44165 (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - E4-02-9B (hex) Intel Corporate E4029B (base 16) Intel Corporate Lot 8, Jalan Hi-Tech 2/3 @@ -146807,12 +150200,6 @@ A81559 (base 16) Breathometer, Inc. Heuchelheim Hessen 35452 DE -78-B8-4B (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -78B84B (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, - Chengdu Sichuan 610000 - CN - 7C-B0-C2 (hex) Intel Corporate 7CB0C2 (base 16) Intel Corporate Lot 8, Jalan Hi-Tech 2/3 @@ -151703,12 +155090,6 @@ ACC73F (base 16) VITSMO CO., LTD. SEOUL 135-918 KR -44-35-6F (hex) Neterix -44356F (base 16) Neterix - The Printworks - Chester Cheshire CH1 4RN - GB - 74-E2-77 (hex) Vizmonet Pte Ltd 74E277 (base 16) Vizmonet Pte Ltd 32,Canberra drive,#05-28 @@ -154328,12 +157709,6 @@ F40F9B (base 16) WAVELINK Middleton WI 53562 US -AC-7A-42 (hex) iConnectivity -AC7A42 (base 16) iConnectivity - #21, 1725 30th Ave NE - Calgary Alberta T2E 7P6 - CA - 70-0B-C0 (hex) Dewav Technology Company 700BC0 (base 16) Dewav Technology Company Room 1408, Real Estate Mansion @@ -158543,12 +161918,6 @@ EC6C9F (base 16) Chengdu Volans Technology CO.,LTD North Wales PA 19454 US -00-22-89 (hex) Vandelrande APC inc. -002289 (base 16) Vandelrande APC inc. - 1280 Lebourgneuf Blvd. - Quebec G2K 0H1 - CA - 00-22-7D (hex) YE DATA INC. 00227D (base 16) YE DATA INC. 182 Shinko @@ -161813,12 +165182,6 @@ EC6C9F (base 16) Chengdu Volans Technology CO.,LTD Bucheon-shi Kyunggi-do 421-809 KR -00-14-1D (hex) LTI-Motion GmbH -00141D (base 16) LTI-Motion GmbH - Gewerbestrasse 5-9 - Lahnau Hessen 35633 - DE - 00-14-12 (hex) S-TEC electronics AG 001412 (base 16) S-TEC electronics AG Industriestrasse 49 @@ -164837,12 +168200,6 @@ EC6C9F (base 16) Chengdu Volans Technology CO.,LTD 224-0034 JP -00-08-18 (hex) Pixelworks, Inc. -000818 (base 16) Pixelworks, Inc. - 7700 SW Mohawk Street - Tualatin OR 97062 - US - 00-08-2A (hex) Powerwallz Network Security 00082A (base 16) Powerwallz Network Security 120-13160 Vanier Place, @@ -171710,12 +175067,6 @@ CCAB2C (base 16) HUMAX Co., Ltd. Takarazuka Hyogo 665-0051 JP -24-E1-24 (hex) Xiamen Ursalink Technology Co., Ltd. -24E124 (base 16) Xiamen Ursalink Technology Co., Ltd. - 4/F, No. 63-2 Wanghai Road, 2nd Software Park - Xiamen Fujian 361008 - CN - 24-43-E2 (hex) DASAN Network Solutions 2443E2 (base 16) DASAN Network Solutions DASAN Tower 8F, 49 Daewangpangyo-ro644beon-gil Bundang-gu @@ -171944,12 +175295,6 @@ D0768F (base 16) Calix Inc. San Jose CA 95131 US -1C-FF-59 (hex) Sichuan Tianyi Comheart Telecom Co., Ltd. -1CFF59 (base 16) Sichuan Tianyi Comheart Telecom Co., Ltd. - No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County - Chengdu Sichuan 611330 - CN - 14-13-FB (hex) HUAWEI TECHNOLOGIES CO.,LTD 1413FB (base 16) HUAWEI TECHNOLOGIES CO.,LTD No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park @@ -173666,23 +177011,41 @@ F01628 (base 16) Technicolor (China) Technology Co., Ltd. Dover DE 19904 US -14-98-77 (hex) Apple, Inc. -149877 (base 16) Apple, Inc. - 1 Infinite Loop - Cupertino CA 95014 +08-A7-C0 (hex) Technicolor CH USA Inc. +08A7C0 (base 16) Technicolor CH USA Inc. + 5030 Sugarloaf Parkway Bldg 6 + Lawrenceville GA 30044 US -88-66-5A (hex) Apple, Inc. -88665A (base 16) Apple, Inc. - 1 Infinite Loop - Cupertino CA 95014 - US +28-5B-0C (hex) Sichuan Jiuzhou Electronic Technology Co., Ltd. +285B0C (base 16) Sichuan Jiuzhou Electronic Technology Co., Ltd. + No. 259, Jiuzhou Road + Mianyang City Sichuan Province 621000 + CN -B0-E5-F9 (hex) Apple, Inc. -B0E5F9 (base 16) Apple, Inc. - 1 Infinite Loop - Cupertino CA 95014 - US +14-89-CB (hex) HUAWEI TECHNOLOGIES CO.,LTD +1489CB (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +6C-26-36 (hex) HUAWEI TECHNOLOGIES CO.,LTD +6C2636 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +48-68-4A (hex) Intel Corporate +48684A (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +BC-F1-71 (hex) Intel Corporate +BCF171 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY 84-71-6A (hex) Huawei Device Co., Ltd. 84716A (base 16) Huawei Device Co., Ltd. @@ -173708,6 +177071,48 @@ B0E5F9 (base 16) Apple, Inc. Dongguan Guangdong 523808 CN +58-56-C2 (hex) HUAWEI TECHNOLOGIES CO.,LTD +5856C2 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +A0-36-79 (hex) HUAWEI TECHNOLOGIES CO.,LTD +A03679 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +B8-D6-F6 (hex) HUAWEI TECHNOLOGIES CO.,LTD +B8D6F6 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +2C-52-AF (hex) HUAWEI TECHNOLOGIES CO.,LTD +2C52AF (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +14-98-77 (hex) Apple, Inc. +149877 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +88-66-5A (hex) Apple, Inc. +88665A (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +B0-E5-F9 (hex) Apple, Inc. +B0E5F9 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + AC-17-C8 (hex) Cisco Meraki AC17C8 (base 16) Cisco Meraki 500 Terry A. Francois Blvd @@ -173725,3 +177130,870 @@ AC17C8 (base 16) Cisco Meraki 500 Terry A. Francois Blvd San Francisco 94158 US + +58-FB-96 (hex) Ruckus Wireless +58FB96 (base 16) Ruckus Wireless + 350 West Java Drive + Sunnyvale CA 94089 + US + +F0-62-5A (hex) Realme Chongqing Mobile Telecommunications Corp.,Ltd. +F0625A (base 16) Realme Chongqing Mobile Telecommunications Corp.,Ltd. + No.178 Yulong Avenue, Yufengshan, Yubei District, Chongqing. + Chongqing China 401120 + CN + +64-E0-AB (hex) UNIONMAN TECHNOLOGY CO.,LTD +64E0AB (base 16) UNIONMAN TECHNOLOGY CO.,LTD + No.5,Huitai Road,Huinan High-Tech Park,Huiao Highway + Huizhou Guangdong 516025 + CN + +AC-23-16 (hex) Mist Systems, Inc. +AC2316 (base 16) Mist Systems, Inc. + 1601 South De Anza Blvd, Suite 248 + Cupertino CA 95014 + US + +2C-00-AB (hex) ARRIS Group, Inc. +2C00AB (base 16) ARRIS Group, Inc. + 6450 Sequence Drive + San Diego CA 92121 + US + +3C-E3-6B (hex) Zhejiang Dahua Technology Co., Ltd. +3CE36B (base 16) Zhejiang Dahua Technology Co., Ltd. + No.1199,Waterfront Road + Hangzhou Zhejiang 310053 + CN + +20-3B-69 (hex) vivo Mobile Communication Co., Ltd. +203B69 (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +5C-17-20 (hex) Huawei Device Co., Ltd. +5C1720 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +98-3F-66 (hex) Wuhan Funshion Online Technologies Co.,Ltd +983F66 (base 16) Wuhan Funshion Online Technologies Co.,Ltd + 5th Floor,Financial Port Building A9,No.77 Optical Valley Avenue, East Lake High-Tech Development Zone, Wuhan + Wuhan CN/Hubei 430000 + CN + +60-5E-4F (hex) Huawei Device Co., Ltd. +605E4F (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +1C-E6-AD (hex) Huawei Device Co., Ltd. +1CE6AD (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +50-97-07 (hex) Xiamen Paperang Technology Co.,Ltd. +509707 (base 16) Xiamen Paperang Technology Co.,Ltd. + Unit 1702-1703, 17/F, No.55, North Chengyi Road,Xiamen Software Park Phase 3 + Xiamen Fujian 361021 + CN + +EC-63-D7 (hex) Intel Corporate +EC63D7 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +14-85-7F (hex) Intel Corporate +14857F (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +7C-9F-07 (hex) CIG SHANGHAI CO LTD +7C9F07 (base 16) CIG SHANGHAI CO LTD + 5th Floor, Building 8 No 2388 Chenhang Road + SHANGHAI 201114 + CN + +1C-87-E3 (hex) TECNO MOBILE LIMITED +1C87E3 (base 16) TECNO MOBILE LIMITED + ROOMS 05-15, 13A/F., SOUTH TOWER, WORLD FINANCE CENTRE, HARBOUR CITY, 17 CANTON ROAD, TSIM SHA TSUI, KOWLOON, HONG KONG + Hong Kong Hong Kong 999077 + HK + +94-E2-3C (hex) Intel Corporate +94E23C (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +20-B7-30 (hex) TeconGroup, Inc +20B730 (base 16) TeconGroup, Inc + 3rd Khoroshevskaya str., 20, floor 1, room 112 + Moscow 123423 + RU + +48-88-99 (hex) Shenzhen SuperElectron Technology Co.,Ltd. +488899 (base 16) Shenzhen SuperElectron Technology Co.,Ltd. + 1213-1214, haosheng business center, dongbin road, nanshan street, nanshan district, shenzhen city + Shenzhen Guangdong 518000 + CN + +DC-B1-31 (hex) SHENZHEN HUARUIAN TECHNOLOGY CO.,LTD +DCB131 (base 16) SHENZHEN HUARUIAN TECHNOLOGY CO.,LTD + Floo2nd and 3rd floor, building A, Huixin Industrial Park, No.31 Yonghe Road, Heping community, Fuhai street, Bao'an District, Shenzhen, China + Shenzhen Guangdong 518101 + CN + +84-3B-10 (hex) Lv switch Inc. +843B10 (base 16) Lv switch Inc. + F1 building,New light source base Luocun town,Nanhai district + Foshan Guangdong 528000 + CN + +94-A4-F9 (hex) HUAWEI TECHNOLOGIES CO.,LTD +94A4F9 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +6C-34-91 (hex) HUAWEI TECHNOLOGIES CO.,LTD +6C3491 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +E8-4D-74 (hex) HUAWEI TECHNOLOGIES CO.,LTD +E84D74 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +CC-89-5E (hex) HUAWEI TECHNOLOGIES CO.,LTD +CC895E (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +80-44-FD (hex) China Mobile (Hangzhou) Information Technology Co., Ltd. +8044FD (base 16) China Mobile (Hangzhou) Information Technology Co., Ltd. + No. 1600 Yuhangtang Road, Wuchang Street, Yuhang District, Hangzhou, Zhejiang + Hangzhou Zhejiang 310000 + CN + +F4-6A-D7 (hex) Microsoft Corporation +F46AD7 (base 16) Microsoft Corporation + One Microsoft Way + REDMOND WA 98052 + US + +48-1F-2D (hex) Shenzhen Jie Shi Lian Industrial Co.,LTD +481F2D (base 16) Shenzhen Jie Shi Lian Industrial Co.,LTD + 6F,C Building,Jinao Industrial Park,Juling Rd,Guanlan Town,Longhua + Shenzhen Guangdong 518000 + CN + +8C-73-A0 (hex) Fiberhome Telecommunication Technologies Co.,LTD +8C73A0 (base 16) Fiberhome Telecommunication Technologies Co.,LTD + No.5 DongXin Road + Wuhan Hubei 430074 + CN + +14-09-B4 (hex) zte corporation +1409B4 (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +10-10-81 (hex) zte corporation +101081 (base 16) zte corporation + 12/F.,zte R&D building ,kejinan Road,Shenzhen,P.R.China + shenzhen guangdong 518057 + CN + +78-CF-F9 (hex) Huawei Device Co., Ltd. +78CFF9 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +A8-E8-1E (hex) ATW TECHNOLOGY, INC. +A8E81E (base 16) ATW TECHNOLOGY, INC. + 1F, No.236 Ba’ai Street, Shulin District + New Taipei City 23845 + TW + +F8-85-F9 (hex) Calix Inc. +F885F9 (base 16) Calix Inc. + 2777 Orchard Pkwy + San Jose CA 95131 + US + +CC-88-C7 (hex) Aruba, a Hewlett Packard Enterprise Company +CC88C7 (base 16) Aruba, a Hewlett Packard Enterprise Company + 3333 Scott Blvd + Santa Clara CA 95054 + US + +F8-1A-2B (hex) Google, Inc. +F81A2B (base 16) Google, Inc. + 1600 Amphitheatre Parkway + Mountain View CA 94043 + US + +F4-A8-0D (hex) Wistron InfoComm(Kunshan)Co.,Ltd. +F4A80D (base 16) Wistron InfoComm(Kunshan)Co.,Ltd. + 168# First Avenue,Kunshan Integrated Free Trade Zone,Kunshan,Jiangsu,China + Kunshan Jiangsu 215300 + CN + +08-A1-89 (hex) Hangzhou Hikvision Digital Technology Co.,Ltd. +08A189 (base 16) Hangzhou Hikvision Digital Technology Co.,Ltd. + No.555 Qianmo Road + Hangzhou Zhejiang 310052 + CN + +80-F3-EF (hex) Facebook Technologies, LLC +80F3EF (base 16) Facebook Technologies, LLC + 1601 Willow Rd + Menlo Park CA 94025 + US + +3C-A8-ED (hex) smart light technology +3CA8ED (base 16) smart light technology + 172 LSro + Gunpo Gyeonggido 15807 + KR + +04-C2-9B (hex) Aura Home, Inc. +04C29B (base 16) Aura Home, Inc. + 50 Eldridge Street, Suite 5D + New York NY 10002 + US + +14-3B-42 (hex) Realfit(Shenzhen) Intelligent Technology Co., Ltd +143B42 (base 16) Realfit(Shenzhen) Intelligent Technology Co., Ltd + Room 201, building a, No.1 Qianwan 1st Road, Shenzhen Hong Kong cooperation zone, Qianhai + Shenzhen Guangdong 518000 + CN + +EC-2E-98 (hex) AzureWave Technology Inc. +EC2E98 (base 16) AzureWave Technology Inc. + 8F., No. 94, Baozhong Rd. + New Taipei City Taiwan 231 + TW + +38-F3-AB (hex) LCFC(HeFei) Electronics Technology co., ltd +38F3AB (base 16) LCFC(HeFei) Electronics Technology co., ltd + YunGu Road 3188-1 + Hefei Anhui 230000 + CN + +50-AE-86 (hex) Linkintec Co., Ltd +50AE86 (base 16) Linkintec Co., Ltd + 3rd floor, building A3, phase I, Zhihui Industrial Park, intersection of Chongqing Road and Yan'an Road, Baohe Economic Development Zone + Hefei City Anhui 230041 + CN + +38-B3-F7 (hex) Huawei Device Co., Ltd. +38B3F7 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +84-E9-86 (hex) Huawei Device Co., Ltd. +84E986 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +AC-1F-0F (hex) Texas Instruments +AC1F0F (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +74-D2-85 (hex) Texas Instruments +74D285 (base 16) Texas Instruments + 12500 TI Blvd + Dallas TX 75243 + US + +60-15-92 (hex) IEEE Registration Authority +601592 (base 16) IEEE Registration Authority + 445 Hoes Lane + Piscataway NJ 08554 + US + +10-C9-CA (hex) Ace Technology Corp. +10C9CA (base 16) Ace Technology Corp. + 237, Namdongseo-ro, Namdong-gu + Incheon 21634 + KR + +BC-FA-B8 (hex) Guangzhou Shiyuan Electronic Technology Company Limited +BCFAB8 (base 16) Guangzhou Shiyuan Electronic Technology Company Limited + No.6, 4th Yunpu Road, Yunpu industry District + Guangzhou Guangdong 510530 + CN + +D4-77-98 (hex) Cisco Systems, Inc +D47798 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +A0-4A-5E (hex) Microsoft Corporation +A04A5E (base 16) Microsoft Corporation + One Microsoft Way + REDMOND WA 98052 + US + +EC-02-73 (hex) Aruba, a Hewlett Packard Enterprise Company +EC0273 (base 16) Aruba, a Hewlett Packard Enterprise Company + 3333 Scott Blvd + Santa Clara CA 95054 + US + +F4-B1-C2 (hex) Zhejiang Dahua Technology Co., Ltd. +F4B1C2 (base 16) Zhejiang Dahua Technology Co., Ltd. + No.1199,Waterfront Road + Hangzhou Zhejiang 310053 + CN + +A4-DA-D4 (hex) Yamato Denki Co.,Ltd. +A4DAD4 (base 16) Yamato Denki Co.,Ltd. + 3-2-14,Koyama + Shinagawa-ku,Tokyo 142-0062 + JP + +10-94-97 (hex) Logitech Hong Kong +109497 (base 16) Logitech Hong Kong + Room 1002-1003, 10/F, Tower 1, Cheung Sha Wan Plaza, 833 Cheung Sha Wan Road, Kowloon, Hong Kong + Hong Kong NA + HK + +00-14-1D (hex) KEBA Industrial Automation Germany GmbH +00141D (base 16) KEBA Industrial Automation Germany GmbH + Gewerbestrasse 5-9 + Lahnau Hessen 35633 + DE + +E0-DA-90 (hex) HUAWEI TECHNOLOGIES CO.,LTD +E0DA90 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +A4-A4-6B (hex) HUAWEI TECHNOLOGIES CO.,LTD +A4A46B (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +C0-47-54 (hex) vivo Mobile Communication Co., Ltd. +C04754 (base 16) vivo Mobile Communication Co., Ltd. + #283,BBK Road + Wusha,Chang'An DongGuan City,Guangdong, 523860 + CN + +A0-D7-A0 (hex) Huawei Device Co., Ltd. +A0D7A0 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +40-E6-4B (hex) Apple, Inc. +40E64B (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +B4-FA-48 (hex) Apple, Inc. +B4FA48 (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +94-3C-C6 (hex) Espressif Inc. +943CC6 (base 16) Espressif Inc. + Room 204, Building 2, 690 Bibo Rd, Pudong New Area + Shanghai Shanghai 201203 + CN + +8C-83-FC (hex) Axioma Metering UAB +8C83FC (base 16) Axioma Metering UAB + Veterinaru str. 52 + Biruliskes Kaunas district LT-54469 + LT + +F0-2F-4B (hex) Apple, Inc. +F02F4B (base 16) Apple, Inc. + 1 Infinite Loop + Cupertino CA 95014 + US + +60-A4-B7 (hex) TP-Link Corporation Limited +60A4B7 (base 16) TP-Link Corporation Limited + Room 901,9/F.New East Ocean Centre, 9 Science Museum Road + Tsim Sha Tsui Kowloon 999077 + HK + +8C-D9-D6 (hex) Xiaomi Communications Co Ltd +8CD9D6 (base 16) Xiaomi Communications Co Ltd + The Rainbow City of China Resources + NO.68, Qinghe Middle Street Haidian District, Beijing 100085 + CN + +60-C5-E6 (hex) Skullcandy +60C5E6 (base 16) Skullcandy + 6301 N. Landmark Dr. + Park City 84098 + US + +38-F3-FB (hex) Asperiq +38F3FB (base 16) Asperiq + Finngatan 8 + Lund SE-22362 + SE + +A4-58-02 (hex) SHIN-IL TECH +A45802 (base 16) SHIN-IL TECH + 711 HO,DAEMYEONG BELLI ON,10, Gyeongin-ro 53ga-gil, Guro-gu + Seoul KS013 + KR + +38-AF-D0 (hex) Nevro +38AFD0 (base 16) Nevro + 1800 Bridge Pkwy + Redwood City CA 94065 + US + +00-A0-0E (hex) NETSCOUT SYSTEMS INC +00A00E (base 16) NETSCOUT SYSTEMS INC + 310 Littleton Road + Westford MA 01886 + US + +30-A6-12 (hex) ShenZhen Hugsun Technology Co.,Ltd. +30A612 (base 16) ShenZhen Hugsun Technology Co.,Ltd. + 413~415 Room, 4/F, No.6 Bldg., TongFuYu Industrial Park, Dalang Street, 518109, Longhua New District, + ShengZhen GuangDong 518109 + CN + +EC-B4-E8 (hex) Wistron Mexico SA de CV +ECB4E8 (base 16) Wistron Mexico SA de CV + Baudelio Perez Mucharras #420 Col Paseos de Zaragoza + ciudad Juarez Chihuahua 32550 + MX + +10-38-1F (hex) Sichuan AI-Link Technology Co., Ltd. +10381F (base 16) Sichuan AI-Link Technology Co., Ltd. + Anzhou, Industrial Park + Mianyang Sichuan 622650 + CN + +3C-7A-C4 (hex) Chemtronics +3C7AC4 (base 16) Chemtronics + junho.hong@chemtronics.co.kr + Bundang-gu Gyeonggi-do 13493 + KR + +54-14-F3 (hex) Intel Corporate +5414F3 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +5C-C8-E3 (hex) Shintec Hozumi co.ltd. +5CC8E3 (base 16) Shintec Hozumi co.ltd. + neura-machi 3-5-1 + Miyoshi Aichi 470-0217 + JP + +18-BB-41 (hex) Huawei Device Co., Ltd. +18BB41 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +78-18-A8 (hex) Huawei Device Co., Ltd. +7818A8 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +80-72-64 (hex) Huawei Device Co., Ltd. +807264 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +54-F6-E2 (hex) HUAWEI TECHNOLOGIES CO.,LTD +54F6E2 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +A8-50-81 (hex) HUAWEI TECHNOLOGIES CO.,LTD +A85081 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +E8-F6-54 (hex) HUAWEI TECHNOLOGIES CO.,LTD +E8F654 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +20-87-EC (hex) HUAWEI TECHNOLOGIES CO.,LTD +2087EC (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +6C-FE-54 (hex) Intel Corporate +6CFE54 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +08-6A-C5 (hex) Intel Corporate +086AC5 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +8C-36-7A (hex) Palo Alto Networks +8C367A (base 16) Palo Alto Networks + 3000 Tannery Way + Santa Clara CA 95054 + US + +1C-FF-59 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +1CFF59 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + No.198,First Section,Snow Mountain Avenue, Jinyuan Town, Dayi County + Chengdu Sichuan 611330 + CN + +C0-1B-23 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +C01B23 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + NO.198 FIRST SECTION,SNOW MOUNTAIN AVENUE, JINYUAN TOWN, DAYI COUNTY, + CHENGDU SICHUAN 611330 + CN + +10-1E-DA (hex) INGENICO TERMINALS SAS +101EDA (base 16) INGENICO TERMINALS SAS + 28-32 Boulevard de Grenelle + PARIS 75015 + FR + +8C-6A-8D (hex) Technicolor CH USA Inc. +8C6A8D (base 16) Technicolor CH USA Inc. + 5030 Sugarloaf Parkway Bldg 6 + Lawrenceville GA 30044 + US + +68-DD-D9 (hex) HMD Global Oy +68DDD9 (base 16) HMD Global Oy + Bertel Jungin aukio 9 + Espoo 02600 + FI + +3C-19-5E (hex) Samsung Electronics Co.,Ltd +3C195E (base 16) Samsung Electronics Co.,Ltd + #94-1, Imsoo-Dong + Gumi Gyeongbuk 730-350 + KR + +6C-94-66 (hex) Intel Corporate +6C9466 (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +4C-3B-6C (hex) GARO AB +4C3B6C (base 16) GARO AB + Södergatan 26 + Gnosjö Jönköping 33525 + SE + +FC-37-2B (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +FC372B (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +7C-CC-1F (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +7CCC1F (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +5C-4A-1F (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +5C4A1F (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +24-8B-E0 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +248BE0 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +9C-9C-40 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +9C9C40 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +54-E0-61 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +54E061 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +18-75-32 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +187532 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12, TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +78-B8-4B (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +78B84B (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +D4-41-65 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +D44165 (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, + Chengdu Sichuan 610000 + CN + +EC-8A-C4 (hex) Amazon Technologies Inc. +EC8AC4 (base 16) Amazon Technologies Inc. + P.O Box 8102 + Reno NV 89507 + US + +44-35-6F (hex) Neterix Ltd +44356F (base 16) Neterix Ltd + Viscount House, River Lane + Chester Cheshire CH4 8RH + GB + +00-22-89 (hex) Vanderlande APC inc. +002289 (base 16) Vanderlande APC inc. + 1280 Lebourgneuf Blvd. + Quebec G2K 0H1 + CA + +50-8A-06 (hex) Tuya Smart Inc. +508A06 (base 16) Tuya Smart Inc. + 160 Greentree Drive, Suite 101 + Dover DE 19904 + US + +D4-08-68 (hex) Beijing Lanxum Computer Technology CO.,LTD. +D40868 (base 16) Beijing Lanxum Computer Technology CO.,LTD. + 3A Floor,BlockB,Technology Fortune Center,No 8 Xueqing Road,Haidian District, + Beijing Beijing 100192 + CN + +B8-14-5C (hex) Huawei Device Co., Ltd. +B8145C (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C8-9D-18 (hex) Huawei Device Co., Ltd. +C89D18 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +C4-80-25 (hex) Huawei Device Co., Ltd. +C48025 (base 16) Huawei Device Co., Ltd. + No.2 of Xincheng Road, Songshan Lake Zone + Dongguan Guangdong 523808 + CN + +DC-03-98 (hex) LG Innotek +DC0398 (base 16) LG Innotek + 26, Hanamsandan 5beon-ro + Gwangju Gwangsan-gu 506-731 + KR + +E8-DA-00 (hex) Kivo Technology, Inc. +E8DA00 (base 16) Kivo Technology, Inc. + 218 Main Street, Suite #724 + Kirkland 98033 + US + +78-D6-DC (hex) Motorola (Wuhan) Mobility Technologies Communication Co., Ltd. +78D6DC (base 16) Motorola (Wuhan) Mobility Technologies Communication Co., Ltd. + No.19, Gaoxin 4th Road, Wuhan East Lake High-tech Zone, Wuhan + Wuhan Hubei 430000 + CN + +0C-43-14 (hex) Silicon Laboratories +0C4314 (base 16) Silicon Laboratories + 400 West Cesar Chavez Street + Austin TX 78701 + US + +F4-C0-2F (hex) BlueBite +F4C02F (base 16) BlueBite + 230, Simin-daero + Anyang-si Gyeonggi-do 14067 + KR + +78-86-B6 (hex) Shenzhen YOUHUA Technology Co., Ltd +7886B6 (base 16) Shenzhen YOUHUA Technology Co., Ltd + Room 407 Shenzhen University-town Business Park,Lishan Road,Taoyuan Street,Nanshan District + Shenzhen Guangdong 518055 + CN + +CC-B5-D1 (hex) Beijing Xiaomi Mobile Software Co., Ltd +CCB5D1 (base 16) Beijing Xiaomi Mobile Software Co., Ltd + The Rainbow City Office Building, 68 Qinghe Middle Street Haidian District + Beijing Beijing 100085 + CN + +24-E1-24 (hex) Xiamen Milesight IoT Co., Ltd. +24E124 (base 16) Xiamen Milesight IoT Co., Ltd. + 4/F, No. 63-2 Wanghai Road, 2nd Software Park + Xiamen Fujian 361008 + CN + +28-FB-AE (hex) HUAWEI TECHNOLOGIES CO.,LTD +28FBAE (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +88-A0-BE (hex) HUAWEI TECHNOLOGIES CO.,LTD +88A0BE (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +A4-78-06 (hex) Cisco Systems, Inc +A47806 (base 16) Cisco Systems, Inc + 80 West Tasman Drive + San Jose CA 94568 + US + +D0-54-75 (hex) SAVI Controls +D05475 (base 16) SAVI Controls + 2420 Tarpley Rd, Suite 205 + Carrollton TX 75006 + US + +08-05-E2 (hex) Juniper Networks +0805E2 (base 16) Juniper Networks + 1133 Innovation Way + Sunnyvale CA 94089 + US + +B8-D5-6B (hex) Mirka Ltd. +B8D56B (base 16) Mirka Ltd. + Pensalavägen 210 + Jeppo 66850 + FI + +B8-A1-4A (hex) Raisecom Technology CO.,LTD +B8A14A (base 16) Raisecom Technology CO.,LTD + No. 11, East Area, No. 10 Block, East Xibeiwang Road + Beijing 100094 + CN + +BC-A3-7F (hex) Rail-Mil Sp. z o.o. Sp. K. +BCA37F (base 16) Rail-Mil Sp. z o.o. Sp. K. + Kosmatki 82 + Warsaw 03-982 + PL + +00-08-18 (hex) Pixelworks, Inc. +000818 (base 16) Pixelworks, Inc. + 226 Airport Parkway, Suite 595 + San Jose CA 95110 + US + +94-90-10 (hex) HUAWEI TECHNOLOGIES CO.,LTD +949010 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +98-F0-83 (hex) HUAWEI TECHNOLOGIES CO.,LTD +98F083 (base 16) HUAWEI TECHNOLOGIES CO.,LTD + No.2 Xin Cheng Road, Room R6,Songshan Lake Technology Park + Dongguan 523808 + CN + +8C-64-A2 (hex) OnePlus Technology (Shenzhen) Co., Ltd +8C64A2 (base 16) OnePlus Technology (Shenzhen) Co., Ltd + 18C02, 18C03, 18C04 ,18C05,TAIRAN BUILDING, + Shenzhen Guangdong 518000 + CN + +28-FA-19 (hex) Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd +28FA19 (base 16) Shenzhen Jingxun Software Telecommunication Technology Co.,Ltd + 3/F,A5 Building Zhiyuan Community No.1001,Xueyuan Road Nanshan District + Shenzhen Guangdong 518055 + CN + +20-3C-C0 (hex) Beijing Tosee Technology Co., Ltd. +203CC0 (base 16) Beijing Tosee Technology Co., Ltd. + Room S125, 1st Floor, Building 1, No. 9, Keyuan Road, Economic Development Zone, Daxing District + beijing 102600 + CN + +D8-A0-11 (hex) WiZ +D8A011 (base 16) WiZ + Unit 1203-5, 12/F, Tower 1, Enterprise Square, 9 Sheung Yuet Road + Kowloon Bay Hong Kong 0000 + HK + +50-09-E5 (hex) Drimsys,Inc +5009E5 (base 16) Drimsys,Inc + 147, Baumoe-ro + Seocho-gu Seoul 06752 + KR + +64-B3-79 (hex) Private +64B379 (base 16) Private + +28-DF-EB (hex) Intel Corporate +28DFEB (base 16) Intel Corporate + Lot 8, Jalan Hi-Tech 2/3 + Kulim Kedah 09000 + MY + +88-FC-A6 (hex) devolo AG +88FCA6 (base 16) devolo AG + Charlottenburger Allee 67 + Aachen NRW 52068 + DE + +AC-7A-42 (hex) iConnectivity +AC7A42 (base 16) iConnectivity + 4620 Manilla Road SE, Unit 58 + Calgary Alberta T2G 4B7 + CA + +48-9E-BD (hex) HP Inc. +489EBD (base 16) HP Inc. + 10300 Energy Dr + Spring TX 77389 + US diff --git a/hwdb.d/ma-medium.txt b/hwdb.d/ma-medium.txt index 43a498c09..ffc4ae59b 100644 --- a/hwdb.d/ma-medium.txt +++ b/hwdb.d/ma-medium.txt @@ -2153,12 +2153,6 @@ B00000-BFFFFF (base 16) ExaScaler Inc. Shenzhen 518000 CN -8C-19-2D (hex) DataRemote Inc. -200000-2FFFFF (base 16) DataRemote Inc. - 19301 SW 106th Ave Suite 6 - Miami FL 33157 - US - D0-D9-4F (hex) Perfant Technology Co., Ltd 000000-0FFFFF (base 16) Perfant Technology Co., Ltd Guo Ren Tong Xin B317,Ke Ji Zhong San Lu,Nanshan,Shenzhen,Guangdong,China @@ -4289,6 +4283,180 @@ A0-02-4A (hex) Xiaojie Technology (Shenzhen) Co., Ltd NINGBO ZHEJIANG PROVINCE 315191 CN +44-6F-D8 (hex) Changzhou Haitu Electronic Technology Co.,Ltd +C00000-CFFFFF (base 16) Changzhou Haitu Electronic Technology Co.,Ltd + Building 47, Hang Seng Science park, Tianning District + Changzhou Jiangsu 213000 + CN + +98-27-82 (hex) KORTEK CORPORATION +700000-7FFFFF (base 16) KORTEK CORPORATION + 26, Venture-ro24beon-gil, Yeonsu-gu + Incheon 22011 + KR + +98-27-82 (hex) Dspread Technology (Beijing) Inc. +400000-4FFFFF (base 16) Dspread Technology (Beijing) Inc. + Jingxin Building, 2045 Suite , Chaoyang District + Beijing 100027 + CN + +8C-19-2D (hex) DataRemote Inc. +200000-2FFFFF (base 16) DataRemote Inc. + 18001 Old Cutler Rd. Suite 600 + Palmetto Bay FL 33157 + US + +E8-6C-C7 (hex) Limited Liability Company M.S.Korp +C00000-CFFFFF (base 16) Limited Liability Company M.S.Korp + Mironovskaya st., 33, bldg.26, floor 4, office 5 + Moscow Russian Federation 105318 + RU + +E8-6C-C7 (hex) Trapeze Switzerland GmbH +000000-0FFFFF (base 16) Trapeze Switzerland GmbH + Industrieplatz 3. + Neuhausen am Rheinfall Schaffhausen 8212 + CH + +04-11-19 (hex) Herrick Tech Labs +700000-7FFFFF (base 16) Herrick Tech Labs + 20201 Century Blvd. + Germantown MD 20874 + US + +E8-6C-C7 (hex) Lighthouse EIP +800000-8FFFFF (base 16) Lighthouse EIP + 21370 Heywood Avenue + Lakeville MN 55044 + US + +E8-6C-C7 (hex) Xirgo Technologies LLC +200000-2FFFFF (base 16) Xirgo Technologies LLC + 188 Camino Ruiz + Camarillo CA 93012 + US + +E8-6C-C7 (hex) Koal Software Co., Ltd +400000-4FFFFF (base 16) Koal Software Co., Ltd + Floor 6, Building 4, Lane 299, Jiangchang West Road, Jing 'an District + Shanghai Shanghai 200436 + CN + +24-5D-FC (hex) Cosmicnode +800000-8FFFFF (base 16) Cosmicnode + Zandstrand + Eindhoven North Brabant 5658BJ + NL + +24-5D-FC (hex) Suzhou Jiangzhi electronic technology co., Ltd +400000-4FFFFF (base 16) Suzhou Jiangzhi electronic technology co., Ltd + Room 303, Building 2, No.88 Baifu Road, Kunshan Development Zone + Kunshan Jiangsu 215300 + CN + +60-15-92 (hex) S Labs sp. z o.o. +000000-0FFFFF (base 16) S Labs sp. z o.o. + Dworska 1a/1u + Kraków Lesser Poland 30-314 + PL + +60-15-92 (hex) Annapurna labs +B00000-BFFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +60-15-92 (hex) Zaptec +400000-4FFFFF (base 16) Zaptec + Richard Johnsensgate 4 + Stavanger Rogaland N-4021 + NO + +0C-5C-B5 (hex) The Raymond Corporation +500000-5FFFFF (base 16) The Raymond Corporation + 22 South Canal St + Greene NY 13778 + US + +0C-5C-B5 (hex) ADI +B00000-BFFFFF (base 16) ADI + 2 Crest Hollow Lane + Manorville NY 11949 + US + +1C-A0-EF (hex) Shenzhen Liandian Communication Technology Co.LTD +D00000-DFFFFF (base 16) Shenzhen Liandian Communication Technology Co.LTD + 1307, building A4, workshop 2, LiLang International Jewelry Industrial Park, 31 Bulan Road, xialilang community, Nanwan street, Longgang District + Shenzhen Guangdong 518112 + CN + +1C-A0-EF (hex) Wisnu and Supak Co.,Ltd. +100000-1FFFFF (base 16) Wisnu and Supak Co.,Ltd. + 102/111-112 Mooban Sinpattanatanee,, Tessabansongkroh Road., Ladyao, Jatujak, + Jatujak Bangkok Metropolis 10900 + TH + +88-C9-B3 (hex) Shenzhen MMUI Co.,Ltd +B00000-BFFFFF (base 16) Shenzhen MMUI Co.,Ltd + Shenzhen MMUI Co.,Ltd + Shenzhen Guangdong 518000 + CN + +88-C9-B3 (hex) Robert Bosch JuP1 +700000-7FFFFF (base 16) Robert Bosch JuP1 + Robert Bosch 1150 + Juarez Chihuahua 32557 + MX + +C8-F5-D6 (hex) Yarward Electronics Co., Ltd. +800000-8FFFFF (base 16) Yarward Electronics Co., Ltd. + 9509 Qinglongshan Street + Zibo Shandong 255089 + CN + +C8-F5-D6 (hex) Valeo Interior Controls (Shenzhen) Co.,Ltd +100000-1FFFFF (base 16) Valeo Interior Controls (Shenzhen) Co.,Ltd + North Junyi Ind. Park, Huaide Vil., Fuyong Town, Baoan Dist. + Shenzhen Guangzhong 518103 + CN + +C0-FB-F9 (hex) Dongmengling +800000-8FFFFF (base 16) Dongmengling + Floor 1, pool-side building, Villa district, Jiuwei Xiange Musical Instrument Co. , Ltd. , Jiuwei community, Hangcheng Street, Bao 'an district + Shenzhen Guangdong 518000 + CN + +C8-F5-D6 (hex) Qbic Technology Co., Ltd +200000-2FFFFF (base 16) Qbic Technology Co., Ltd + 26F.-12, No.99, Sec. 1, Xintai 5th Rd., Xizhi Dist., + New Taipei 22175 + TW + +C8-F5-D6 (hex) EVOTOR LLC +400000-4FFFFF (base 16) EVOTOR LLC + Timura Frunze Str., 24 + Moscow 119021 + RU + +C0-FB-F9 (hex) Dongguan Chuan OptoElectronics Limited +200000-2FFFFF (base 16) Dongguan Chuan OptoElectronics Limited + No.43 Songshui Road,Songmushan Village, Dalang Town + Dongguan Guangdong 523795 + CN + +C0-FB-F9 (hex) IVT corporation +600000-6FFFFF (base 16) IVT corporation + 5/F, Zhongguancun Fazhan Building, No 12, Shangdi Xinxi Road, Haidian District, Beijing, 100085, P.R. CHINA + Beijing 100085 + CN + +18-74-E2 (hex) HANGZHOU ZHOUJU ELECTRONIC TECHNOLOGICAL CO.,LTD +500000-5FFFFF (base 16) HANGZHOU ZHOUJU ELECTRONIC TECHNOLOGICAL CO.,LTD + Floor 6,A Building, Xianxing Road NO.32,Xianlin Town,Yuhang District + Hangzhou Zhejiang 311122 + CN + 4C-4B-F9 (hex) Shenzhen dingsheng technology co., LTD 400000-4FFFFF (base 16) Shenzhen dingsheng technology co., LTD Floor 3, building 5, kaijeda industrial zone, no.97, huaxing road, langkou community, dalang street, longhua district @@ -4592,9 +4760,6 @@ A00000-AFFFFF (base 16) ESTec Corporation San Jose CA 95113 US -F0-23-B9 (hex) Private -D00000-DFFFFF (base 16) Private - B0-FD-0B (hex) IDspire Corporation Ltd. 100000-1FFFFF (base 16) IDspire Corporation Ltd. 9F, No. 266, Sec. 1, Wenhua Rd., Banqiao Dist. @@ -4769,9 +4934,6 @@ E0-5A-9F (hex) Link of Things Co., Ltd. SAN DIEGO CA 92123 US -38-B8-EB (hex) Private -700000-7FFFFF (base 16) Private - 4C-BC-98 (hex) Dongguan SmartAction Technology Co.,Ltd B00000-BFFFFF (base 16) Dongguan SmartAction Technology Co.,Ltd Room1109,Building D,First Place,Nancheng District, Dongguan @@ -5471,9 +5633,6 @@ B00000-BFFFFF (base 16) KAGA ELECTRONICS CO.,LTD. Berlin 13127 DE -2C-D1-41 (hex) Private -D00000-DFFFFF (base 16) Private - 28-2C-02 (hex) Shenzhen emb-star technology co. LTD 200000-2FFFFF (base 16) Shenzhen emb-star technology co. LTD 2/f,building C,qinghu science park,qingxiang road,qinghu,longhua new district @@ -8156,12 +8315,6 @@ A4-53-EE (hex) MAHLE ELECTRONICS, SLU Motilla del Palancar Cuenca 16200 ES -A4-53-EE (hex) Aura Home, Inc. -600000-6FFFFF (base 16) Aura Home, Inc. - 50 Eldridge Street, Suite 5D - New York NY 10002 - US - A4-53-EE (hex) SSK CORPORATION D00000-DFFFFF (base 16) SSK CORPORATION 3F, M-10, Centre of Hi-Tech Industrial Park, Nanshan @@ -8210,6 +8363,234 @@ D00000-DFFFFF (base 16) Quidel Corporation Beaverton OR 97008 US +44-6F-D8 (hex) ZHEJIANG HIKAILINK TECHNOLOGY Co., Ltd +A00000-AFFFFF (base 16) ZHEJIANG HIKAILINK TECHNOLOGY Co., Ltd + Room 116, 1 / F, building 2, No. 87, Hexi, Changfeng street, Wuzhen Town, Tongxiang City + Jiaxing City Zhejiang China + CN + +44-6F-D8 (hex) Shenzhen Mestechs Technology CO., LTD +300000-3FFFFF (base 16) Shenzhen Mestechs Technology CO., LTD + The 3rd Floor, E4A Bldg?TCL International E city, NO.1001 zhongshanyuan Rd, Nanshan District + shenzhen GuangDong 518052 + CN + +98-27-82 (hex) Guangzhou Wuzhou Technology Co, Ltd. +500000-5FFFFF (base 16) Guangzhou Wuzhou Technology Co, Ltd. + 4th Floor, Building C2, Hi-Tech Enterprise Accelerator, Kaiyuan Avenue #11, Huangpu District + Guangzhou Guangdong 510530 + CN + +98-27-82 (hex) Wuxi GuoYiHaiJu Technology Co.,Ltd. +900000-9FFFFF (base 16) Wuxi GuoYiHaiJu Technology Co.,Ltd. + Innovation Industrial Park E2-2F + hefei 230000 + CN + +98-27-82 (hex) Nanjing BianYu Future Home Technology Co.Ltd +A00000-AFFFFF (base 16) Nanjing BianYu Future Home Technology Co.Ltd + Longyu Middle Street + Beijing Beijing 100085 + CN + +98-27-82 (hex) CATS Power design +800000-8FFFFF (base 16) CATS Power design + 144 route des Vernes + PRINGY 74370 + FR + +04-11-19 (hex) Alethea Communications Technologies Pvt. Ltd. +200000-2FFFFF (base 16) Alethea Communications Technologies Pvt. Ltd. + 2346, 17th Cross, HSR Layout + Bangalore Karnataka 560102 + IN + +E8-6C-C7 (hex) Huaqin Technology Co.,Ltd +700000-7FFFFF (base 16) Huaqin Technology Co.,Ltd + No. 10 Keyuan Road, Songshan Lake + Dongguan Guangdong 523808 + CN + +04-11-19 (hex) Acentury +100000-1FFFFF (base 16) Acentury + 120 West Beaver Creek Road, Unit 13 + Richmond Hill ON L4B 1L2 + CA + +E8-6C-C7 (hex) CoxSpace +A00000-AFFFFF (base 16) CoxSpace + 858ho, Business Support Hub, 815, Daewangpangyo-ro Sujeong-gu + Seongnam Kyeonggi-do 13449 + KR + +38-B8-EB (hex) Sirin Mobile Technologies +700000-7FFFFF (base 16) Sirin Mobile Technologies + Muhlentalstrasse 2 + Schaffhausen 8200 + CH + +24-5D-FC (hex) TORGOVYY DOM TEHNOLOGIY LLC +900000-9FFFFF (base 16) TORGOVYY DOM TEHNOLOGIY LLC + Gospytalnaya 10, ap. 109, village Selyatino, city Naro-Fominsk, + Moscow Moscow Region 143345 + RU + +24-5D-FC (hex) ContactProximity Inc +500000-5FFFFF (base 16) ContactProximity Inc + 241 Arlington Street #966 + Acton MA 01720 + US + +24-5D-FC (hex) CompanyDeep +000000-0FFFFF (base 16) CompanyDeep + 122, Ross Street + Cambridge Cambridgeshire CB13BU + GB + +24-5D-FC (hex) Guangzhou Lango Electronics Technology Co.,Ltd. +600000-6FFFFF (base 16) Guangzhou Lango Electronics Technology Co.,Ltd. + Room 238, Room 406, No. 1, Yichuang Street, Huangpu District + Guangzhou Guangdong 510336 + CN + +F0-23-B9 (hex) Shenyang Ali Technology Company Limited +D00000-DFFFFF (base 16) Shenyang Ali Technology Company Limited + No.17-5, Wensu Street + Dongling District Shenyang Liaoning Province 110168 + CN + +0C-5C-B5 (hex) Hunan Newman Car NetworKing Technology Co.,Ltd +C00000-CFFFFF (base 16) Hunan Newman Car NetworKing Technology Co.,Ltd + 128 Lixiang East Road,ChangshaEconomic and Technological Development Zone + Changsha Hunan 410100 + CN + +0C-5C-B5 (hex) S2C limited +600000-6FFFFF (base 16) S2C limited + E1 No.2555 Xiupu Rd. Pudong New Area + Shanghai Shanghai 201135 + CN + +1C-A0-EF (hex) Tangshan Liulin Automation Equipment Co., Ltd. +000000-0FFFFF (base 16) Tangshan Liulin Automation Equipment Co., Ltd. + Building 110-3, No.410 Huoju Road, High-tech Zone + Tangshan City Hebei Province 063000 + CN + +1C-A0-EF (hex) LLC Gagar.In +C00000-CFFFFF (base 16) LLC Gagar.In + Rybnikov Pereulok 1 + Moscow 107045 + RU + +1C-A0-EF (hex) Zillnk +800000-8FFFFF (base 16) Zillnk + No. 505, 5 / F, Unit 2, building 1, No. 777, North Section of Yizhou Avenue, Chengdu High Tech Zone, China (Sichuan) Pilot Free Trade Zone + Chengdu 610000 + CN + +1C-A0-EF (hex) Leviathan Solutions Ltd. +400000-4FFFFF (base 16) Leviathan Solutions Ltd. + Abel Jeno utca 23 + Budapest 1113 + HU + +20-CE-2A (hex) Shanghai Digicube Info&Tech Co.,Ltd. +100000-1FFFFF (base 16) Shanghai Digicube Info&Tech Co.,Ltd. + Room B, 9th floor, building 1, Hongqiao headquarters, 100 Zixiu Road, + Shanghai Minhang District 201103 + CN + +20-CE-2A (hex) Intelligraphics +800000-8FFFFF (base 16) Intelligraphics + 11615 Angus Road, Suite #104L + Austin TX 78759 + US + +2C-D1-41 (hex) Square Inc. +D00000-DFFFFF (base 16) Square Inc. + 1455 Market St. + San Francisco CA 94103 + US + +88-C9-B3 (hex) shenzhen franklin ESS technology CO.,Ltd +200000-2FFFFF (base 16) shenzhen franklin ESS technology CO.,Ltd + 102, 61 Liuxian Rd 2, Baoan Dst., Shenzhen + shenzhen 518000 + CN + +88-C9-B3 (hex) Cervoz Technology Co; Ltd. +100000-1FFFFF (base 16) Cervoz Technology Co; Ltd. + 8F; No.10, Aly6, Ln.235, Baociao Rd; + Sindian Dist. New Taipei City 23145 + TW + +C8-F5-D6 (hex) Oscars Pro +700000-7FFFFF (base 16) Oscars Pro + A 45, 1st Floor, Sector 4 + Noida Uttar Pradesh 201301 + IN + +C8-F5-D6 (hex) Pinmicro K K +500000-5FFFFF (base 16) Pinmicro K K + Kanda Jimbocho, 2-20-13 + Chiyoda Ku Tokyo 1010051 + JP + +D0-9F-D9 (hex) Shenzhen eloT Technology Co.,Ltd +D00000-DFFFFF (base 16) Shenzhen eloT Technology Co.,Ltd + North Wing of 2/F, Block 2, Viseen Technology & Business Park, No.43 Gaoxin South Ring Road + Shenzhen Guangdong 518000 + CN + +C0-FB-F9 (hex) Tiandi(Changzhou) Automation Co., Ltd. +A00000-AFFFFF (base 16) Tiandi(Changzhou) Automation Co., Ltd. + Tiandi(Changzhou) Automation Co., Ltd. + Changzhou Jiangsu 213015 + CN + +C0-FB-F9 (hex) Navitas Digital Safety Ltd +E00000-EFFFFF (base 16) Navitas Digital Safety Ltd + 1ST FLOOR, 13 PHOENIX PARK + COALVILLE Leicestershire LE673HB + GB + +D0-9F-D9 (hex) Poten (Shanghai) Technology Co.,Ltd. +400000-4FFFFF (base 16) Poten (Shanghai) Technology Co.,Ltd. + Rm.B,6th Fl., No.5, Caoxi Rd.251 + Shanghai Shanghai 200235 + CN + +D0-9F-D9 (hex) Raymax Technology Ltd. +700000-7FFFFF (base 16) Raymax Technology Ltd. + 604, Building D, No.1001 Wen Yi Xi Road + Hangzhou China 310012 + CN + +D0-9F-D9 (hex) Queclink Wireless Solutions Co., Ltd. +800000-8FFFFF (base 16) Queclink Wireless Solutions Co., Ltd. + No.30, Lane 500, Xinlong Road, Minhang District + Shanghai 201101 + CN + +D0-9F-D9 (hex) Fujian Newland Auto-ID Tech. Co,.Ltd. +C00000-CFFFFF (base 16) Fujian Newland Auto-ID Tech. Co,.Ltd. + Newland Science & Technology Park, No.1 Rujiang West Rd,Mawei,Fuzhou, P.R.China + Fuzhou 350015 + CN + +D0-9F-D9 (hex) Lemei Intelligent IOT (Shenzhen) Co., Ltd +000000-0FFFFF (base 16) Lemei Intelligent IOT (Shenzhen) Co., Ltd + #1101, Building #1, Yishang Sanwei Inductry Park, Zhongwu, Hangcheng Street, Baoan District + Shenzhen Guangdong 518000 + CN + +18-74-E2 (hex) Kano Computing Limited +800000-8FFFFF (base 16) Kano Computing Limited + Unit 12.1 - 12.2, 11-29 Fashion Street + London E1 6PX + GB + 20-85-93 (hex) UNILUMIN GROUP CO.,LTD 300000-3FFFFF (base 16) UNILUMIN GROUP CO.,LTD No.112 Yongfu Rd.,BaoanDistrict, @@ -8228,9 +8609,6 @@ B00000-BFFFFF (base 16) Stored Energy Systems Longmont CO 80501 US -DC-E5-33 (hex) Private -A00000-AFFFFF (base 16) Private - 24-15-10 (hex) SHANDONG KEHUI POWER AUTOMATION CO. LTD. 600000-6FFFFF (base 16) SHANDONG KEHUI POWER AUTOMATION CO. LTD. No. 16,Sanying Road @@ -10088,12 +10466,6 @@ A4-58-0F (hex) Ksenia Security srl Salford M5 4TH GB -7C-CB-E2 (hex) Aplex Technology Inc. -E00000-EFFFFF (base 16) Aplex Technology Inc. - 2nd Floor,Tower3,District5,HongHuaLing industrial park, Nanshan District - Shenzhen Guangdong 518055 - CN - 24-4E-7B (hex) Nanjing Wanlida Technology Co., Ltd. 700000-7FFFFF (base 16) Nanjing Wanlida Technology Co., Ltd. Wanlida Industry Zone, Nanjing County @@ -11882,12 +12254,6 @@ D0-14-11 (hex) Video Security, Inc. Kaohsiung, Taiwan, R.O.C. Kaohsiung City 807 TW -30-49-50 (hex) Xio Research, Inc -D00000-DFFFFF (base 16) Xio Research, Inc - 405 Lexington Avenue, Suite 3504 - New York NY 10174 - US - D0-14-11 (hex) Realwave Inc. 700000-7FFFFF (base 16) Realwave Inc. 5857 Owens Avenue, Suite 300 @@ -12254,6 +12620,282 @@ D00000-DFFFFF (base 16) SCAIME JUVIGNY Select State 74100 FR +44-6F-D8 (hex) Anhui GuDao Tech +600000-6FFFFF (base 16) Anhui GuDao Tech + Dangtu Qingshanhe + MaAnShan AnHui 243000 + CN + +44-6F-D8 (hex) Annapurna labs +900000-9FFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +98-27-82 (hex) SHENZHEN HEROFUN BIO-TECH CO., LTD +000000-0FFFFF (base 16) SHENZHEN HEROFUN BIO-TECH CO., LTD + 7001B, 7th Floor, LaoBing Building, East Block 2, No. 3012 XingYe Road, BaoAn District + Shenzhen 518100 + CN + +98-27-82 (hex) RayTron, INC. +B00000-BFFFFF (base 16) RayTron, INC. + 11F.ESLEAD Bldg.HONMACHI 1-4-8 HONMACHI CHUO-KU + Osaka Osaka 541-0053 + JP + +98-27-82 (hex) Thorlabs GmbH +D00000-DFFFFF (base 16) Thorlabs GmbH + Münchner Weg 1 + Bergkirchen 85232 + DE + +98-27-82 (hex) WESTERN SECURITY SOLUTIONS +600000-6FFFFF (base 16) WESTERN SECURITY SOLUTIONS + WSS TOWER HARINAGAR + GURUGRAM HARYANA 122001 + IN + +98-27-82 (hex) Danfoss Power Solutions +300000-3FFFFF (base 16) Danfoss Power Solutions + 3500 Annapolis Lane N + Minneapolis MN 55447 + US + +04-11-19 (hex) AC Power Distribution / ACT Entmt. +900000-9FFFFF (base 16) AC Power Distribution / ACT Entmt. + 2313 N. Valley St. + Burbank CA 91505 + US + +04-11-19 (hex) CyOne Security AG +A00000-AFFFFF (base 16) CyOne Security AG + Hinterbergstrasse 18 + Steinhausen Zug 6312 + CH + +04-11-19 (hex) SUZHOU RIBAO TECHNOLOGY CO.,LTD. +300000-3FFFFF (base 16) SUZHOU RIBAO TECHNOLOGY CO.,LTD. + SUZHOU RIBAO TECHNOLOGY CO.,LTD. + SUZHOU JIANGSU 215133 + CN + +04-11-19 (hex) Nuance Hearing Ltd. +D00000-DFFFFF (base 16) Nuance Hearing Ltd. + Raoul Wallenberg 24, Building A1, Floor 3 + Tel Aviv 6971920 + IL + +E8-6C-C7 (hex) Annapurna labs +E00000-EFFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +E8-6C-C7 (hex) Shenzhen Yibaifen Industrial Co.,Ltd. +300000-3FFFFF (base 16) Shenzhen Yibaifen Industrial Co.,Ltd. + 501/501, Building 2, Hongxiang Industrial Park, 21 Huancheng South Road, Ma'antang Community, Bantian Street, Longgang District, Shenzhen + Shenzhen 518000 + CN + +E8-6C-C7 (hex) z-max mediasolution +D00000-DFFFFF (base 16) z-max mediasolution + Surugadai Bldg.8F kanda surugadai 1-7-10 + Chiyodaku Tokyo 101-0062 + JP + +DC-E5-33 (hex) Amazinglayer Network Co., Ltd. +A00000-AFFFFF (base 16) Amazinglayer Network Co., Ltd. + Room118, Building B, JinTaiHuaYun Building, WuGenLin HuTong 11 + Beijing Beijing 100035 + CN + +24-5D-FC (hex) ARTICONA - Bechtle Logistik & Service GmbH +100000-1FFFFF (base 16) ARTICONA - Bechtle Logistik & Service GmbH + Bechtle Platz 1 + Neckarsulm Baden-Württemberg 74172 + DE + +24-5D-FC (hex) Blue Iris Labs +200000-2FFFFF (base 16) Blue Iris Labs + 18 Acacia Rd + Fairfax CA 94930 + US + +24-5D-FC (hex) LTY LLC +700000-7FFFFF (base 16) LTY LLC + 1321 UPLAND DR + HOUSTON TX 77043 + US + +60-15-92 (hex) PSS Co., Ltd +C00000-CFFFFF (base 16) PSS Co., Ltd + 4F., No. 10, Ln. 327, Sec. 2, Zhongshan Rd., Zhonghe Dist. + New Taipei City ??? 235 + TW + +60-15-92 (hex) RTDS Technologies Inc. +100000-1FFFFF (base 16) RTDS Technologies Inc. + 100-150 Innovation Drive + Winnipeg Manitoba R3T 2E1 + CA + +60-15-92 (hex) JIANGSU SUNFY TECHNOLOGIES HOLDING CO.,LTD. +900000-9FFFFF (base 16) JIANGSU SUNFY TECHNOLOGIES HOLDING CO.,LTD. + Building 6, No. 1088, Jiangcheng Road, Sutong Technology Industrial Park + Nantong Jiangsu 226017 + CN + +60-15-92 (hex) OSI TECHNOLOGY CO.,LTD. +300000-3FFFFF (base 16) OSI TECHNOLOGY CO.,LTD. + No.74, Fenyang Rd., Sanmin Dist. + Kaohsiung City Taiwan 807 + TW + +60-15-92 (hex) Annapurna labs +E00000-EFFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +0C-5C-B5 (hex) Annapurna labs +400000-4FFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +0C-5C-B5 (hex) Shenzhen C & D Electronics Co., Ltd. +800000-8FFFFF (base 16) Shenzhen C & D Electronics Co., Ltd. + 9th FIoor, Building 9, No.1 Qingxiang road, BaoNeng Science and TechnoIogy Industrial Park, Longhua New District + ShenZhen GuangDong 518000 + CN + +0C-5C-B5 (hex) iH&S Technology Limited +300000-3FFFFF (base 16) iH&S Technology Limited + iH&S Technology Limited + 7/F, Unify Commercial & Ind. Bldg., 31 Tai Yip Street, Kwun Tong Hong Kong 999077 + HK + +0C-5C-B5 (hex) Energybox Limited +700000-7FFFFF (base 16) Energybox Limited + 8/F., Green 18, HK Science Park + Sha Tin Hong Kong 0000 + HK + +1C-A0-EF (hex) HANJEN.CHIN CO., LTD. +600000-6FFFFF (base 16) HANJEN.CHIN CO., LTD. + Fl.2 No. 101 Jian 1st Rd., Zhonghe Dist., + NEW TAIPEI CITY TAIWAN 235 + TW + +0C-5C-B5 (hex) Colordeve International +900000-9FFFFF (base 16) Colordeve International + 601, block B, Logistics Park, Yihong Road, Yantian village, Fenggang Town, DG, GD, China + Dongguan City 523702 + CN + +20-CE-2A (hex) Beijing Huadianzhongxin Tech.Co.,Ltd +700000-7FFFFF (base 16) Beijing Huadianzhongxin Tech.Co.,Ltd + Room 318,the 3rd Floorl,Xingtianhaiyuan Building,Xianghuangqi East Rd,Nongda South Rd, Haidian District,Beijing,P.R.C + Bei Jing 100193 + CN + +20-CE-2A (hex) Ariston Thermo s.p.a. +C00000-CFFFFF (base 16) Ariston Thermo s.p.a. + Via Aristide Merloni 45 + Fabriano Ancona 60044 + IT + +20-CE-2A (hex) Jabil +200000-2FFFFF (base 16) Jabil + 10560 Dr M.L.K. Jr St N, St. + St. Petersburg 33716 + US + +88-C9-B3 (hex) ADOPT NETTECH PVT LTD +000000-0FFFFF (base 16) ADOPT NETTECH PVT LTD + A - 11, OKHLA INDUSTRIAL AREA, PHASE - I, + NEW DELHI DELHI 110020 + IN + +7C-CB-E2 (hex) Aplex Technology Inc. +E00000-EFFFFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +88-C9-B3 (hex) Gefran Drive & Motion srl +A00000-AFFFFF (base 16) Gefran Drive & Motion srl + Via Carducci 24 + Gerenzano (VA) Varese 21040 + IT + +C8-F5-D6 (hex) Jabil +600000-6FFFFF (base 16) Jabil + 10560 Dr M.L.K. Jr St N, St. + St. Petersburg 33716 + US + +C8-F5-D6 (hex) Volansys technologies pvt ltd +D00000-DFFFFF (base 16) Volansys technologies pvt ltd + Block A-7th Floor, Safal Profitaire, Corporate Road, Prahaladnagar + Ahmedabad Gujarat 380015 + IN + +C0-FB-F9 (hex) HAGUENET +500000-5FFFFF (base 16) HAGUENET + Nieuwe Parklaan 17 + The Hague 2597 LA + NL + +C0-FB-F9 (hex) LIXIL Corporation +100000-1FFFFF (base 16) LIXIL Corporation + 2-1-1 Ojima, Koto-ku + Tokyo Select Stat 136-8535 + JP + +C0-FB-F9 (hex) SHENZHEN COMIX HST CLOUD COMPUTING CO., LTD. +B00000-BFFFFF (base 16) SHENZHEN COMIX HST CLOUD COMPUTING CO., LTD. + 1408? Qiancheng Commercial Center, No. 5 Haicheng Road, Mabu Community, Xixiang Sub-district, Bao'an District + Shenzhen Guangdong 518000 + CN + +C0-FB-F9 (hex) SHENZHEN HEQIANG ELECTRONICS LIMITED +300000-3FFFFF (base 16) SHENZHEN HEQIANG ELECTRONICS LIMITED + ROOM F7, 6TH FLOOR, A1 BUILDING, RED BOX LOFT, NO. 3 SOUTH HUANCHENG ROAD, LONGGANG DISTRICT, + SHENZHEN GUANGDONG 518129 + CN + +D0-9F-D9 (hex) Carbon Mobile GmbH +500000-5FFFFF (base 16) Carbon Mobile GmbH + Winterfeldtstr. 21 + Berlin 10781 + DE + +D0-9F-D9 (hex) ENTTEC Pty Ltd. +900000-9FFFFF (base 16) ENTTEC Pty Ltd. + po box 4051 + ringwood vic 3134 + AU + +D0-9F-D9 (hex) elecgator bvba +100000-1FFFFF (base 16) elecgator bvba + Heerbaan, 308 + Beringen Limburg 3582 + BE + +D0-9F-D9 (hex) Minibems Ltd +E00000-EFFFFF (base 16) Minibems Ltd + Oxford Point, 19 Oxford Road + Bournemouth BH88GS + GB + +30-49-50 (hex) Merlyn Mind, Inc. +D00000-DFFFFF (base 16) Merlyn Mind, Inc. + 405 Lexington Avenue, Suite 3504 + New York NY 10174 + US + 4C-4B-F9 (hex) Shandong Linkotech Electronic Co., Ltd. 600000-6FFFFF (base 16) Shandong Linkotech Electronic Co., Ltd. 22nd Floor, Building 2, Aosheng Building, No.1166 Xinyi Street, High-tech Zone @@ -12815,12 +13457,6 @@ D00000-DFFFFF (base 16) Elink Technology (Shenzhen) Co., Limited Shenzhen Guangdong 518101 CN -E0-5A-9F (hex) Fujian Newland Auto-ID Tech. Co.,Ltd. -800000-8FFFFF (base 16) Fujian Newland Auto-ID Tech. Co.,Ltd. - Newland Science & Technology Park, No.1 Rujiang West Rd,Mawei,Fuzhou, P.R.China - Fuzhou Fujian 350015 - CN - 4C-BC-98 (hex) Charge-Amps AB 000000-0FFFFF (base 16) Charge-Amps AB GUSTAV III:S BOULEVARD 42, 8TR @@ -14663,12 +15299,6 @@ CC-1B-E0 (hex) Laserworld (Switzerland) AG San Jose California 95128 US -00-55-DA (hex) Nanoleaf -500000-5FFFFF (base 16) Nanoleaf - 162 John Street - Toronto Ontario M5V2E5 - CA - 00-55-DA (hex) Speechlab A00000-AFFFFF (base 16) Speechlab Gaasterlandstraat 3 @@ -14825,12 +15455,6 @@ B00000-BFFFFF (base 16) Capwave Technologies Inc Asbury Park NJ 07712 US -74-F8-DB (hex) Avantree Corporation -900000-9FFFFF (base 16) Avantree Corporation - 41871 Via San Miguel - Fremont CA 94539 - US - 88-5D-90 (hex) Creative Sensor Inc. 800000-8FFFFF (base 16) Creative Sensor Inc. 9F., No.501, Sec. 6, Nanjing E. Rd., Neihu Dist., Taipei City 114, Taiwan (R.O.C.) @@ -15482,12 +16106,6 @@ B00000-BFFFFF (base 16) Chongqing IQIYI Intelligence Technology Co., Ltd. Mail box 15123 Haifa 3508409 IL -40-11-75 (hex) disguise Technologies Limited -C00000-CFFFFF (base 16) disguise Technologies Limited - Units C&D 127 Great Suffolk Street - London SE1 1PP - GB - 10-DC-B6 (hex) Shenzhen Sunwoda intelligent hardware Co.,Ltd E00000-EFFFFF (base 16) Shenzhen Sunwoda intelligent hardware Co.,Ltd No.6-6,Yan Shan Rd.,Baoan District,Shenzhen City,China @@ -16256,6 +16874,270 @@ B00000-BFFFFF (base 16) Beijing gpthink technology co.,LTD. Irvine CA 92614 US +40-11-75 (hex) disguise Technologies Limited +C00000-CFFFFF (base 16) disguise Technologies Limited + 88-89 Blackfriars Rd + London South Bank SE1 8HA, + GB + +74-F8-DB (hex) Avantree Corporation +900000-9FFFFF (base 16) Avantree Corporation + 175 Bernal road Ste 106 + SAN JOSE CA 95119-1343 + US + +04-11-19 (hex) Shenzhen YIZHENG Technology Co.,Ltd +800000-8FFFFF (base 16) Shenzhen YIZHENG Technology Co.,Ltd + 2305, block A7, Chuangzhi Yuncheng, Liuxian Avenue, Xili Town, Nanshan District + ShenZhen GuangDong 518000 + CN + +04-11-19 (hex) Hubei Baobao Intelligent Technology Co.,LTD +B00000-BFFFFF (base 16) Hubei Baobao Intelligent Technology Co.,LTD + Hubei Baobao Intelligent Technology Co.,LTD + Wuhan Hubei 430000 + CN + +04-11-19 (hex) JULIDA LIMITED +E00000-EFFFFF (base 16) JULIDA LIMITED + 1F., NO. 137, DATONG ST., BEITOU DIST. + TAIPEI CITY Taiwan 112 + TW + +04-11-19 (hex) FORT Robotics Inc. +000000-0FFFFF (base 16) FORT Robotics Inc. + 170 S. Independence Mall, Suite 275W + Philadelphia PA 19106 + US + +E8-6C-C7 (hex) Hangzhou Lanxum Security Technology Co., Ltd +900000-9FFFFF (base 16) Hangzhou Lanxum Security Technology Co., Ltd + Room 402, Block A, 4th Floor, Building 3, No. 351 changhe Road, Changhe Street, Binjiang District + Hangzhou Zhejiang 310000 + CN + +E8-6C-C7 (hex) KLAB +600000-6FFFFF (base 16) KLAB + 94-23,Techno 2-ro + Yuseong-gu Daejeon 34014 + KR + +24-5D-FC (hex) Senix Corporation +C00000-CFFFFF (base 16) Senix Corporation + 10516 Route 116, Suite 300 + Hinesburg VT 05461 + US + +24-5D-FC (hex) Hunan Honestone lntelligence Technology Co.,Ltd +D00000-DFFFFF (base 16) Hunan Honestone lntelligence Technology Co.,Ltd + 705, Building 1, Fortune Plaza, Wankuntu, Xiangzhang Road, Yuhua District, Changsha City, + Changsha 410007 + CN + +E8-6C-C7 (hex) Shenzhen Rongda Computer Co.,Ltd +500000-5FFFFF (base 16) Shenzhen Rongda Computer Co.,Ltd + 905, Block B, DuoCaiKeChuan Park, No.5 Guanle Road + Longhua District Shenzhen, Guangdong 518110 + CN + +00-55-DA (hex) Nanoleaf +500000-5FFFFF (base 16) Nanoleaf + 100 Front Street East, 4th Floor + Toronto Ontario M5A 1E1 + CA + +24-5D-FC (hex) Dodge +E00000-EFFFFF (base 16) Dodge + 6040 Ponders Court + Greenville SC 29615 + US + +60-15-92 (hex) EDA Technology Co.,LTD +200000-2FFFFF (base 16) EDA Technology Co.,LTD + Room 301, Building 24, Shengchuang Enterprise Park,No.1661 Jialuo Road, Jiading District + Shanghai Shanghai 201822 + CN + +60-15-92 (hex) insensiv GmbH +A00000-AFFFFF (base 16) insensiv GmbH + Auf dem Esch 28 + Bielefeld Nordrhein-Westfalen 33619 + DE + +60-15-92 (hex) REMOWIRELESS COMMUNICATION INTERNATIONAL CO.,LIMITED +D00000-DFFFFF (base 16) REMOWIRELESS COMMUNICATION INTERNATIONAL CO.,LIMITED + REMOWIRELESS RM1111,HONGYI BUILDING NO.2158 WANYUAN ROAD + SHANGHAI SHANGHAI 201103 + CN + +0C-5C-B5 (hex) avxav Electronic Trading LLC +100000-1FFFFF (base 16) avxav Electronic Trading LLC + Office 534 Building # 6WA Dubai Airport Free Zone + Dubai United Arab Emirates 33964 + AE + +0C-5C-B5 (hex) Munters Europe AB +E00000-EFFFFF (base 16) Munters Europe AB + Borgarfjordsgatan 16 + Kista 16440 + SE + +0C-5C-B5 (hex) HongKong Blossom Limited +200000-2FFFFF (base 16) HongKong Blossom Limited + B1715,Jiansheng Building,No. 1 Pingji Road, NanWan Street Longgang + Shenzhen 518112 + CN + +1C-A0-EF (hex) Sequent AG +300000-3FFFFF (base 16) Sequent AG + Eptingerstrasse 3 + Basel 4052 + CH + +0C-5C-B5 (hex) Yamasei +000000-0FFFFF (base 16) Yamasei + 2F., No. 37, Ln. 11, Sec. 6, Minquan E. Rd., Neihu Dist. + Taipei Taiwan (R.O.C.) 114 + TW + +1C-A0-EF (hex) tec5AG +700000-7FFFFF (base 16) tec5AG + Weisskirchener Strasse 2-6 + Steinbach Hessen 61449 + DE + +20-CE-2A (hex) MeshPlusPlus, Inc. +A00000-AFFFFF (base 16) MeshPlusPlus, Inc. + 935 W. Chestnut St., Suite #505 + Chicago IL 60642 + US + +20-CE-2A (hex) LAUDA DR R WOBSER GMBH & CO KG +D00000-DFFFFF (base 16) LAUDA DR R WOBSER GMBH & CO KG + Pfarrstrasse 41/43 + Lauda-Koenigshofen 97922 + DE + +20-CE-2A (hex) Rugged Monitoring +900000-9FFFFF (base 16) Rugged Monitoring + 1415 Frank-Carrel, Suite 230 + Quebec City Quebec G1N4N7 + CA + +20-CE-2A (hex) Zaber Technologies Inc. +500000-5FFFFF (base 16) Zaber Technologies Inc. + #2 - 605 West Kent Ave. N. + Vancouver B.C. V6P 6T7 + CA + +20-CE-2A (hex) Swarovski Optik KG +B00000-BFFFFF (base 16) Swarovski Optik KG + Daniel Swarovski Street 70 + Absam 6067 + AT + +88-C9-B3 (hex) Brabender Technologie GmbH & Co, KG +500000-5FFFFF (base 16) Brabender Technologie GmbH & Co, KG + Kulturstrasse 49 + Duisburg 47055 + DE + +20-CE-2A (hex) Funkwerk Systems GmbH +E00000-EFFFFF (base 16) Funkwerk Systems GmbH + Im Funkwerk 5 + Koelleda 99625 + DE + +88-C9-B3 (hex) Hasbro Inc +400000-4FFFFF (base 16) Hasbro Inc + 1027 Newport Ave + Pawtucket RI 02861 + US + +88-C9-B3 (hex) Sercomm Corporation. +E00000-EFFFFF (base 16) Sercomm Corporation. + 3F,No.81,Yu-Yih Rd.,Chu-Nan Chen + Miao-Lih Hsuan 115 + TW + +88-C9-B3 (hex) Divelbiss Corporation +800000-8FFFFF (base 16) Divelbiss Corporation + 9778 Mount Gilead Road + Fredericktown OH 43019 + US + +88-C9-B3 (hex) Origins Technology Limited +D00000-DFFFFF (base 16) Origins Technology Limited + 18 Xinzhong St Dushiyangguang4-1106, Dongcheng + Beijing 100027 + CN + +C8-F5-D6 (hex) Shanghai Mo xiang Network Technology CO.,Ltd +900000-9FFFFF (base 16) Shanghai Mo xiang Network Technology CO.,Ltd + Room#418-421, ShaHeXiLi, 2-2 XiLi North Road, LiCheng Community, Xili Street, NanShan District + Shenzhen Guangdong 518071 + CN + +C8-F5-D6 (hex) United Barcode Systems +B00000-BFFFFF (base 16) United Barcode Systems + Av. Progres 56, Pol. Ind. els Garrofers + Vilassar de Mar Barcelona 08340 + ES + +C8-F5-D6 (hex) Eltako GmbH +C00000-CFFFFF (base 16) Eltako GmbH + Hofener Straße 54 + Fellbach BW 70736 + DE + +C0-FB-F9 (hex) SHENZHEN ELSKY TECHNOLOGY CO., LTD +C00000-CFFFFF (base 16) SHENZHEN ELSKY TECHNOLOGY CO., LTD + 1F BUILDING 2# ASIA INDUSTIAL PARK BANTIAN STREET LONGGANG DISTRICT + SHENZHEN GUANGDONG 518000 + CN + +C0-FB-F9 (hex) Dropbeats Technology Co., Ltd. +D00000-DFFFFF (base 16) Dropbeats Technology Co., Ltd. + Room 304, Building 4?Juli Road ? Pudong New District + Shanghai Shanghai 201203 + CN + +D0-9F-D9 (hex) Elevoc Technology Co., Ltd. +600000-6FFFFF (base 16) Elevoc Technology Co., Ltd. + 5/F,Unit B,Block12,ShenZhenwan Science and Technology Ecological Garden,Nanshan Dist. + Shenzhen Guangdong 518000 + CN + +D0-9F-D9 (hex) Eurolan Ltd +A00000-AFFFFF (base 16) Eurolan Ltd + jk. Drujba 1, ul. 5028, do bl. 15 + Sofia Sofia (stolitsa) 1592 + BG + +E0-5A-9F (hex) Fujian Newland Auto-ID Tech. Co,.Ltd. +800000-8FFFFF (base 16) Fujian Newland Auto-ID Tech. Co,.Ltd. + Newland Science & Technology Park, No.1 Rujiang West Rd,Mawei,Fuzhou, P.R.China + Fuzhou Fujian 350015 + CN + +18-74-E2 (hex) NextGen RF Design, Inc. +C00000-CFFFFF (base 16) NextGen RF Design, Inc. + 2130 Howard Dr W + North Mankato MN 56003 + US + +18-74-E2 (hex) Sartorius Lab Instruments GmbH & Co. KG +100000-1FFFFF (base 16) Sartorius Lab Instruments GmbH & Co. KG + Otto-Brenner-Straße 20 + Goettingen 37079 + DE + +D0-9F-D9 (hex) Sanken-Densetsu Co.,LTD. +300000-3FFFFF (base 16) Sanken-Densetsu Co.,LTD. + 677 Shimoakasaka-Ohnohara + Kawagoe-Shi Saitama 350-1155 + JP + 20-85-93 (hex) Great Lite International 700000-7FFFFF (base 16) Great Lite International 11F., No.207-2, Sec. 3, Beixin Rd., Xindian Dist., @@ -18341,12 +19223,6 @@ D00000-DFFFFF (base 16) Hubei Boyuan Zhijia Network Media Co. Ltd. Wuhan Hubei 42000 CN -78-C2-C0 (hex) SICHUAN TIANYI COMHEART TELECOMCO.,LTD -600000-6FFFFF (base 16) SICHUAN TIANYI COMHEART TELECOMCO.,LTD - FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, Chengdu, Sichuan - Chengdu Sichuan 610000 - CN - 8C-19-2D (hex) Elcon AB E00000-EFFFFF (base 16) Elcon AB Hyttrisvagen 27 @@ -19787,12 +20663,6 @@ D00000-DFFFFF (base 16) Sunthink S&T Development Co.,Ltd Shenzhen 518100 CN -94-05-BB (hex) Neurik AG -300000-3FFFFF (base 16) Neurik AG - Im alten Riet 143 - Schaan SCHAAN 9494 - LI - DC-44-27 (hex) Tesla,Inc. 100000-1FFFFF (base 16) Tesla,Inc. 3500 Deer Creek Road @@ -20339,8 +21209,296 @@ B00000-BFFFFF (base 16) Jiangsu byzoro intelligent technology Co.,Ltd Nanjing Jiangsu 210012 CN +44-6F-D8 (hex) BAYKON Endüstriyel Kontrol Sistemleri San. ve Tic. A.Ş. +200000-2FFFFF (base 16) BAYKON Endüstriyel Kontrol Sistemleri San. ve Tic. A.Ş. + Kimya Sanayicileri Org. San. Bolgesi Organik Cad. No:31 + Istanbul Tuzla 34956 + TR + 44-6F-D8 (hex) ITC 700000-7FFFFF (base 16) ITC 3030 Corporate Grove Drive Hudsonville MI 49426 US + +44-6F-D8 (hex) CTE +E00000-EFFFFF (base 16) CTE + No. 1-7, Gongjian Rd., Cidu District, Keelung City 20647, Taiwan R.O.C + Keelung Taiwan 106 + TW + +98-27-82 (hex) INFODAS GmbH +100000-1FFFFF (base 16) INFODAS GmbH + Rhonestr. 2 + Cologne 50765 + DE + +98-27-82 (hex) Anhui Shengren Electronic Technology Co., Ltd +200000-2FFFFF (base 16) Anhui Shengren Electronic Technology Co., Ltd + 520 Jiahe Road, Yuhui District + Bengbu Anhui 233000 + CN + +98-27-82 (hex) SureFlap Ltd +E00000-EFFFFF (base 16) SureFlap Ltd + 7 The Irwin Centre, Scotland Road, Dry Drayton + Cambridge Cambridgeshire CB23 8AR + GB + +04-11-19 (hex) CEITA COMMUNICATION TECHNOLOGY CO.,LTD +500000-5FFFFF (base 16) CEITA COMMUNICATION TECHNOLOGY CO.,LTD + 611, Renbao Building, 32 Baolong Road, Changlong Community, Buji Street, Longgang District + Shenzhen Guangdong 518000 + CN + +98-27-82 (hex) KRISTECH Krzysztof Kajstura +C00000-CFFFFF (base 16) KRISTECH Krzysztof Kajstura + Porzeczkowa 12 + Ustro? Please select region, state or province 43-450 + PL + +04-11-19 (hex) ZPD technology Co., Ltd +600000-6FFFFF (base 16) ZPD technology Co., Ltd + 2# Floor, 1# Gate?12# Building?5# Jiangtai Road, Chaoyang District,Beijing + Beijing Beijing 100015 + CN + +E8-6C-C7 (hex) ASSA ABLOY(GuangZhou) Smart Technology Co., Ltd +100000-1FFFFF (base 16) ASSA ABLOY(GuangZhou) Smart Technology Co., Ltd + Plant Building 5, 106 Xieshi Highway, Shibi 1st Village + Guangzhou GuangDong 511495 + CN + +04-11-19 (hex) Haerbin Donglin Technology Co., Ltd. +C00000-CFFFFF (base 16) Haerbin Donglin Technology Co., Ltd. + Room 2, Floor 1, Unit 6, Building 2,Yuanshi Street 35, Nangang District + Haerbin Heilongjiang 150000 + CN + +04-11-19 (hex) Bolicom Innovation Technology (BeiJing) Co.,LTD. +400000-4FFFFF (base 16) Bolicom Innovation Technology (BeiJing) Co.,LTD. + Rm2327, Building23, No.18 Anningzhuang East Road, Haidian District + Bei Jing 100000 + CN + +24-5D-FC (hex) Shenzhen Hailuck Electronic Technology CO.,LTD +300000-3FFFFF (base 16) Shenzhen Hailuck Electronic Technology CO.,LTD + 2/F, building 19, Baotian industrial zone, the Third Baotian Road, Bao'an district + Shenzhen GuangDong 518101 + CN + +E8-6C-C7 (hex) MORNSUN Guangzhou Science & Technology Co., Ltd. +B00000-BFFFFF (base 16) MORNSUN Guangzhou Science & Technology Co., Ltd. + No.5,Kehui St. 1,kehui Development Center,Science Ave.,Guangzhou Science City, Huangpu District + GuangZhou GuangDong 510000 + CN + +24-5D-FC (hex) ONLY +B00000-BFFFFF (base 16) ONLY + 1F., No. 16, Ln. 76, Zhongyang N. Rd., Sanchong Dist + New Taipei City Taiwan (R.O.C.) 24146 + TW + +24-5D-FC (hex) Tata Sky Limited +A00000-AFFFFF (base 16) Tata Sky Limited + Unit 301 to 305, 3rd Floor, Windsor, Off C.S.T. Road, Kalina, Santacruz (East), Mumbai – 400 098 + Mumbai Maharashtra 400098 + IN + +94-05-BB (hex) Neutrik AG +300000-3FFFFF (base 16) Neutrik AG + Im alten Riet 143 + Schaan SCHAAN 9494 + LI + +60-15-92 (hex) Yangzhou Wanfang Electronic Technology,CO .,Ltd. +800000-8FFFFF (base 16) Yangzhou Wanfang Electronic Technology,CO .,Ltd. + No.96 Anlin Road,Guangling District + Yangzhou City Jiangsu Province 225000 + CN + +A4-53-EE (hex) Shenzhen Xunqi Interconnet Technology Co., Ltd +600000-6FFFFF (base 16) Shenzhen Xunqi Interconnet Technology Co., Ltd + 26G, block B, Haiwang building, Chuangye Road, Nanshan District, + Shenzhen Guangdong 518000 + CN + +60-15-92 (hex) Faster CZ spol. s r.o. +700000-7FFFFF (base 16) Faster CZ spol. s r.o. + Jarní 44g + Brno 61400 + CZ + +60-15-92 (hex) BEIJING KUANGSHI TECHNOLOGY CO., LTD +600000-6FFFFF (base 16) BEIJING KUANGSHI TECHNOLOGY CO., LTD + Room 1018,10th Floor, No.1 Zhongguancun Street, Haidian District, + Beijing Beijing 100086 + CN + +0C-5C-B5 (hex) BSU Inc +D00000-DFFFFF (base 16) BSU Inc + 1611 Headway Circle, Building 1, Suite 200 + Austin TX 78754 + US + +1C-A0-EF (hex) Atlas Aerospace +900000-9FFFFF (base 16) Atlas Aerospace + Ulbrokas 19a + Riga Riga LV-1021 + LV + +0C-5C-B5 (hex) Zhengzhou coal machinery hydraulic electric control Co.,Ltd +A00000-AFFFFF (base 16) Zhengzhou coal machinery hydraulic electric control Co.,Ltd + 167 Jingkai 9th Street, Zhengzhou Economic Development Zone + Zhengzhou 45000 + CN + +1C-A0-EF (hex) Henrich Electronics Corporation +A00000-AFFFFF (base 16) Henrich Electronics Corporation + 225 Deming Place + Westmont 60559 + US + +1C-A0-EF (hex) BMK professional electronics GmbH +B00000-BFFFFF (base 16) BMK professional electronics GmbH + Werner-von-Siemens-Straße 6 + Augsburg 86159 + DE + +1C-A0-EF (hex) Nanjing Bilin Intelligent Identification Technology Co.,Ltd +500000-5FFFFF (base 16) Nanjing Bilin Intelligent Identification Technology Co.,Ltd + No.9 Bancang Street + Nanjing Jiangsu 210000 + CN + +1C-A0-EF (hex) Schneider-Electric(China)Co.Ltd,Shenzhen Branch +200000-2FFFFF (base 16) Schneider-Electric(China)Co.Ltd,Shenzhen Branch + Unit A to C 7/F and 8/F,CES Building ,No.3099,Keyuan South road, Nanshan Dist, Shenzhen, GD, China + SHENZHEN 518000 + CN + +1C-A0-EF (hex) RDA Microelectronics Technologies (Shanghai) Co. , Ltd +E00000-EFFFFF (base 16) RDA Microelectronics Technologies (Shanghai) Co. , Ltd + Room 336, No.3, Lane 2288, Zuchongzhi Road, Pudong Area + Shanghai Shanghai 200120 + CN + +20-CE-2A (hex) Annapurna labs +000000-0FFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +20-CE-2A (hex) Cuculus GmbH +300000-3FFFFF (base 16) Cuculus GmbH + Lindenstr. 9 -11 + Ilmenau Thuringia 98693 + DE + +20-CE-2A (hex) Annapurna labs +400000-4FFFFF (base 16) Annapurna labs + Matam Scientific Industries Center, Building 8.2 + Mail box 15123 Haifa 3508409 + IL + +20-CE-2A (hex) Radarxense BV +600000-6FFFFF (base 16) Radarxense BV + Kwekerijweg, 2A + Zeist Nederland 3709 JA + NL + +78-C2-C0 (hex) Sichuan Tianyi Comheart Telecom Co.,LTD +600000-6FFFFF (base 16) Sichuan Tianyi Comheart Telecom Co.,LTD + FL12,TowerB,Tianyi international Hotel,No.2 West Section One, Second Ring Road, Chengdu, Sichuan + Chengdu Sichuan 610000 + CN + +88-C9-B3 (hex) Shenzhen Viewsmart Technology Co.,Ltd +C00000-CFFFFF (base 16) Shenzhen Viewsmart Technology Co.,Ltd + Room 10C?Floor 10,South China Navigation Building, No.7 North Langshan Road,Nanshan District, Shenzhen, China. + SHENZHEN 518000 + CN + +88-C9-B3 (hex) Hugo Techno +600000-6FFFFF (base 16) Hugo Techno + F92 Green Park + New Delhi Delhi 110016 + IN + +88-C9-B3 (hex) Richbeam (Beijing) Technology Co., Ltd. +900000-9FFFFF (base 16) Richbeam (Beijing) Technology Co., Ltd. + 2608, Tower A, Tianzuo International, No.12, Zhongguancun South Street, Haidian District + Beijing Beijing 100081 + CN + +C8-F5-D6 (hex) HENAN FOXSTAR DIGITAL DISPLAY Co.,Ltd. +A00000-AFFFFF (base 16) HENAN FOXSTAR DIGITAL DISPLAY Co.,Ltd. + No. 7 Bldg., Yulong Block, Longsheng Road, Optronic Industry Area, Nanyang,Henan,P.R.China + Nanyang 473000 + CN + +C8-F5-D6 (hex) MEIRYO TECHNICA CORPORATION +000000-0FFFFF (base 16) MEIRYO TECHNICA CORPORATION + 2039-1,Shimoi, Shimoi-cho + Owariasahi-city Aichi 488-0052 + JP + +C0-FB-F9 (hex) Minato Advanced Technologies inc +400000-4FFFFF (base 16) Minato Advanced Technologies inc + 4105, Minami Yamata-cho, Tsuzuki-ku, + YOKOHAMA Kanagawa 224-0026 + JP + +C0-FB-F9 (hex) LongSung Technology (Shanghai) Co.,Ltd. +700000-7FFFFF (base 16) LongSung Technology (Shanghai) Co.,Ltd. + Room 606, Block B, Bldg. 1, No. 3000 Longdong Avenue., Zhangjiang Hi-Tech Park, Pudong District + ShangHai 201203 + CN + +C8-F5-D6 (hex) HEITEC AG +E00000-EFFFFF (base 16) HEITEC AG + Güterbahnhofstrasse 5 + Erlangen Please select state 91052 + DE + +C8-F5-D6 (hex) BBPOS International Limited +300000-3FFFFF (base 16) BBPOS International Limited + Suite 1602, Tower 2, Nina Tower, 8 Yeung Uk Road, Tsuen Wan, NT + Hong Kong China 00000 + HK + +88-C9-B3 (hex) Fortive Setra-ICG(Tianjin)Co.,Ltd +300000-3FFFFF (base 16) Fortive Setra-ICG(Tianjin)Co.,Ltd + 28 weiwu Road,Micro-electronics Industrial Park,Xiqing District Tianjin,P,R,China + Tianjin 300380 + CN + +C0-FB-F9 (hex) Xerox Corporation +000000-0FFFFF (base 16) Xerox Corporation + 800 Phillips Rd, Mailstop 0207-2Z + Webster NY 14580 + US + +C0-FB-F9 (hex) zxsolution +900000-9FFFFF (base 16) zxsolution + nanshan shenzhen + shenzhen 518000 + CN + +D0-9F-D9 (hex) Westar Display Technologies +200000-2FFFFF (base 16) Westar Display Technologies + 4 Research Park Dr + St Charles MO 63304 + US + +18-74-E2 (hex) Sansec Technology Co.,Ltd +700000-7FFFFF (base 16) Sansec Technology Co.,Ltd + Bejing Chaoyang District Guangshun North Street Hostpital No.16 No.2 building 14 room 1406 + Bejing Bejing 100102 + CN + +D0-9F-D9 (hex) Cablewireless Laboratory Co., Ltd +B00000-BFFFFF (base 16) Cablewireless Laboratory Co., Ltd + Room 218, Block E1, Yuanchenxin Building, 12 Yumin Road, Chaoyang District + Beijing 100029 + CN diff --git a/hwdb.d/ma-small.txt b/hwdb.d/ma-small.txt index 18422c1ab..b987a916d 100644 --- a/hwdb.d/ma-small.txt +++ b/hwdb.d/ma-small.txt @@ -218,9 +218,6 @@ CF8000-CF8FFF (base 16) Idneo Technologies S.A.U. Barcelona Barcelona 08028 ES -70-B3-D5 (hex) Private -A9F000-A9FFFF (base 16) Private - 70-B3-D5 (hex) Arevita 5E1000-5E1FFF (base 16) Arevita Baltu ave 145 @@ -413,9 +410,6 @@ E33000-E33FFF (base 16) DEUTA-WERKE GmbH New Taipei City, Taiwan 22101 TW -70-B3-D5 (hex) Private -9EE000-9EEFFF (base 16) Private - 70-B3-D5 (hex) Wuhan Xingtuxinke ELectronic Co.,Ltd 70E000-70EFFF (base 16) Wuhan Xingtuxinke ELectronic Co.,Ltd NO.C3-8F,Software Park,Optics Valley,East Lake Development Zone,Wuhan,Hubei,China @@ -1115,12 +1109,6 @@ D6F000-D6FFFF (base 16) X-SPEX GmbH Poellau bei Hartberg Steiermark 8225 AT -70-B3-D5 (hex) TORGOVYY DOM TEHNOLOGIY LLC -7C0000-7C0FFF (base 16) TORGOVYY DOM TEHNOLOGIY LLC - The village of Rumyantsevo, Build.1 - Moscow Moscow 142784 - RU - 70-B3-D5 (hex) Raft Technologies 8D0000-8D0FFF (base 16) Raft Technologies Habarzel 25 @@ -1391,12 +1379,6 @@ EA7000-EA7FFF (base 16) S.I.C.E.S. srl Mississauga Ontario L4V 1W1 CA -70-B3-D5 (hex) TAIYO SEIKI CO.,LTD. -69B000-69BFFF (base 16) TAIYO SEIKI CO.,LTD. - 1600 Aza-Shironoshita Asahi - Shin Asahi-cho Takashima, Shiga 520-1501 - JP - 70-B3-D5 (hex) PLUTO Solution co.,ltd. 842000-842FFF (base 16) PLUTO Solution co.,ltd. B-1018, Kumkang Penterium IT Tower, 282, Hagui-ro, Dongan-gu @@ -1415,12 +1397,6 @@ EA7000-EA7FFF (base 16) S.I.C.E.S. srl Plzen 301 28 CZ -70-B3-D5 (hex) S Labs sp. z o.o. -C53000-C53FFF (base 16) S Labs sp. z o.o. - Jasnogórska, 44 - Kraków Lesser Poland 31-358 - PL - 70-B3-D5 (hex) Dameca a/s EEA000-EEAFFF (base 16) Dameca a/s Islevdalvej 211 @@ -1493,12 +1469,6 @@ A7E000-A7EFFF (base 16) QUICCO SOUND Corporation Saint-Petersburg Russia 197183 RU -70-B3-D5 (hex) Leviathan Solutions Ltd. -A69000-A69FFF (base 16) Leviathan Solutions Ltd. - Kazal utca 64-66 - Budapest 1031 - HU - 70-B3-D5 (hex) BEDEROV GmbH 371000-371FFF (base 16) BEDEROV GmbH Rankestr. 8 @@ -2111,12 +2081,6 @@ F8D000-F8DFFF (base 16) Flextronics Canafa Design Services Niemce lubelskie 21-025 PL -70-B3-D5 (hex) Aplex Technology Inc. -9B1000-9B1FFF (base 16) Aplex Technology Inc. - 2nd Floor,Tower3,District5,HongHuaLing industrial park, Nanshan District - Shenzhen Guangdong 518055 - CN - 70-B3-D5 (hex) Netemera Sp. z o.o. CA4000-CA4FFF (base 16) Netemera Sp. z o.o. Ostrobramska 83/1208A @@ -4427,12 +4391,6 @@ D99000-D99FFF (base 16) Nilar AB Gävle Gavleborg 80647 SE -70-B3-D5 (hex) Jabil, Inc. -736000-736FFF (base 16) Jabil, Inc. - 888 Executive Center Dr. W. - St.Petersubrg FL 33702 - US - 70-B3-D5 (hex) Power Electronics Espana, S.L. 632000-632FFF (base 16) Power Electronics Espana, S.L. C/ Leonardo Da Vinci, 24-26 @@ -4871,6 +4829,324 @@ A11000-A11FFF (base 16) TRIOPTICS Wedel Schleswig-Holstein 22880 DE +70-B3-D5 (hex) SIAME +66E000-66EFFF (base 16) SIAME + RUE DES MATHEMATIQUES + GROMBALIA 8030 + TN + +70-B3-D5 (hex) Lockheed Martin - THAAD +9EE000-9EEFFF (base 16) Lockheed Martin - THAAD + 4800 Bradford Drive + Huntsville AL 35805 + US + +70-B3-D5 (hex) Plenty Unlimited Inc +D04000-D04FFF (base 16) Plenty Unlimited Inc + 590 Eccles Ave + South San Francisco CA 94080 + US + +70-B3-D5 (hex) TT Group SRL +BD7000-BD7FFF (base 16) TT Group SRL + Via Pazzano 112 + Roma RM 00118 + IT + +70-B3-D5 (hex) Aliter Technologies +586000-586FFF (base 16) Aliter Technologies + Turcianska 16 + Bratislava 82109 + SK + +70-B3-D5 (hex) Stecomp +EE0000-EE0FFF (base 16) Stecomp + Bollaarsdijk 11 + Brielle 3231LA + NL + +70-B3-D5 (hex) TORGOVYY DOM TEHNOLOGIY LLC +7C0000-7C0FFF (base 16) TORGOVYY DOM TEHNOLOGIY LLC + Gospytalnaya 10, ap. 109, village Selyatino, city Naro-Fominsk, + Moscow Moscow Region 143345 + RU + +70-B3-D5 (hex) XJ ELECTRIC CO., LTD. +F26000-F26FFF (base 16) XJ ELECTRIC CO., LTD. + #1298 XUJI AVENUE + XUCHANG HENAN 461000 + CN + +70-B3-D5 (hex) Automata GmbH & Co. KG +19D000-19DFFF (base 16) Automata GmbH & Co. KG + Gewerbering 5 + Ried Bavaria 86510 + DE + +70-B3-D5 (hex) Topic Embedded Products B.V. +63D000-63DFFF (base 16) Topic Embedded Products B.V. + Materiaalweg 4 + Best Noord-Brabant 5681 RJ + NL + +70-B3-D5 (hex) EcoG +1AE000-1AEFFF (base 16) EcoG + Gaenslerweg 24 + Furth Bavaria 82041 + DE + +70-B3-D5 (hex) Hubbell Power Systems +DDA000-DDAFFF (base 16) Hubbell Power Systems + 353 Powerville Road + Boonton Township NJ 07005 + US + +70-B3-D5 (hex) Potter Electric Signal Co. LLC +6D5000-6D5FFF (base 16) Potter Electric Signal Co. LLC + 1609 Park 370 Place + Hazelwood MO 63042 + US + +70-B3-D5 (hex) Jiangsu Etern Compamy Limited +DA0000-DA0FFF (base 16) Jiangsu Etern Compamy Limited + No. 1788 fenhu Guo Dao Road, Foho New&High-tech Industrial Development Zone, Wujiang + Suzhou Jiangsu 215211 + CN + +70-B3-D5 (hex) JSC Ural Factories +0FD000-0FDFFF (base 16) JSC Ural Factories + Gorky street 92 + Izhevsk Udmurtia 426000 + RU + +70-B3-D5 (hex) Semiconsoft, inc +212000-212FFF (base 16) Semiconsoft, inc + 83 PINE HILL RD + SOUTHBOROUGH MA 01772 + US + +70-B3-D5 (hex) M.S. CONTROL +CE0000-CE0FFF (base 16) M.S. CONTROL + 139-141 Fitzgerald Street + WEST PERTH WA 6005 + AU + +70-B3-D5 (hex) Master Meter Inc. +A9F000-A9FFFF (base 16) Master Meter Inc. + 101 Regency Pkwy + Mansfield TX 76063 + US + +70-B3-D5 (hex) TIAMA +798000-798FFF (base 16) TIAMA + ZA des Plattes - 1 Chemin des Plattes + VOURLES 69390 + FR + +70-B3-D5 (hex) Rapiot +265000-265FFF (base 16) Rapiot + Eteläesplanadi 2 + Helsinki 00130 + FI + +70-B3-D5 (hex) S Labs sp. z o.o. +C53000-C53FFF (base 16) S Labs sp. z o.o. + Dworska 1a/1u + Kraków Lesser Poland 30-314 + PL + +70-B3-D5 (hex) Torion Plasma Corporation +B70000-B70FFF (base 16) Torion Plasma Corporation + 99 Hooper Rd, Unit #6 + Barrie Ontario L4N9S3 + CA + +70-B3-D5 (hex) OMNISENSING PHOTONICS LLC +70D000-70DFFF (base 16) OMNISENSING PHOTONICS LLC + 8015 Four Quarter Road + Ellicott City MD 21043 + US + +70-B3-D5 (hex) Smart Systems LLC +746000-746FFF (base 16) Smart Systems LLC + Flat 1, building 7, Izmalkova street + Mykolaiv 54028 + UA + +70-B3-D5 (hex) Megger Germany GmbH +59F000-59FFFF (base 16) Megger Germany GmbH + Röderaue 41 + Radeburg 01471 + DE + +70-B3-D5 (hex) Leviathan Solutions Ltd. +A69000-A69FFF (base 16) Leviathan Solutions Ltd. + Abel Jeno utca 23 + Budapest 1113 + HU + +70-B3-D5 (hex) BluB0X Security, Inc. +16D000-16DFFF (base 16) BluB0X Security, Inc. + 9 Bartlet Street Suite 334 + Andover MA 01810 + US + +70-B3-D5 (hex) biosilver .co.,ltd +D21000-D21FFF (base 16) biosilver .co.,ltd + 2-14-4, shinyokohama + yokohama kanagawa 2220033 + JP + +70-B3-D5 (hex) ACD Elekronik GmbH +D6D000-D6DFFF (base 16) ACD Elekronik GmbH + Engelberg 2 + Achstetten 88480 + DE + +70-B3-D5 (hex) Network Integrity Systems +9FF000-9FFFFF (base 16) Network Integrity Systems + 1937 Tate Blvd. SE + Hickory NC 28602 + US + +70-B3-D5 (hex) Vemco Sp. z o. o. +D45000-D45FFF (base 16) Vemco Sp. z o. o. + ul. Biala 1 + Gdansk 80-435 + PL + +70-B3-D5 (hex) Beijing Xiansheng Technology Co., Ltd +8D6000-8D6FFF (base 16) Beijing Xiansheng Technology Co., Ltd + Room 02, 102-1 / F, building 32, yard 69, Yanfu Road, Fangshan District + Beijing Beijing 102488 + CN + +70-B3-D5 (hex) Subject Link Inc +137000-137FFF (base 16) Subject Link Inc + 9F-1, No. 77, Sec 4. Nanjing E. Rd., SongShan Dist. + Taipei City Taiwan 105406 + TW + +70-B3-D5 (hex) Crane-elec. Co., LTD. +1FB000-1FBFFF (base 16) Crane-elec. Co., LTD. + Tamakushicho-higashi 3-3-97 + Higashi osaka OSAKA 5780932 + JP + +70-B3-D5 (hex) Jabil +736000-736FFF (base 16) Jabil + 888 Executive Center Dr. W. + St.Petersubrg FL 33702 + US + +70-B3-D5 (hex) AudioTEC LLC +33A000-33AFFF (base 16) AudioTEC LLC + 108 Scott Street + Ripon WI 54971 + US + +70-B3-D5 (hex) IRT Technologies +D13000-D13FFF (base 16) IRT Technologies + 5580 BOULEVARD THIMENS + Saint-Laurent Quebec H4R 2K9 + CA + +70-B3-D5 (hex) 11811347 CANADA Inc. +7E6000-7E6FFF (base 16) 11811347 CANADA Inc. + 1215 13th St SE, Suite 114 + Calgary AB T2G 3J4 + CA + +70-B3-D5 (hex) Season Electronics Ltd +BA0000-BA0FFF (base 16) Season Electronics Ltd + 600 Nest Business Park + Havant Hampshire PO9 5TL + GB + +70-B3-D5 (hex) KST technology +20B000-20BFFF (base 16) KST technology + KST B/D 4-5, Wiryeseong-daero 12-gil + Songpa-gu Seoul 05636 + KR + +70-B3-D5 (hex) Aplex Technology Inc. +9B1000-9B1FFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +70-B3-D5 (hex) Santa Barbara Imaging Systems +4E6000-4E6FFF (base 16) Santa Barbara Imaging Systems + 340 Storke Road, Suite 101 + Goleta CA 93117 + US + +70-B3-D5 (hex) AM General Contractor +2C6000-2C6FFF (base 16) AM General Contractor + Via Angelo Scarsellini 147 + Genova Italy 16149 + IT + +70-B3-D5 (hex) ProtoConvert Pty Ltd +EC0000-EC0FFF (base 16) ProtoConvert Pty Ltd + 2 Clyden Court + Burwood East Victoria 3151 + AU + +70-B3-D5 (hex) Reflexion Medical +298000-298FFF (base 16) Reflexion Medical + Reflexion Medical 25841 Industrial Blvd. + Hayward CA 94545 + US + +70-B3-D5 (hex) Zumbach Electronic AG +C19000-C19FFF (base 16) Zumbach Electronic AG + Hauptstrasse 93 + Orpund Bern 2552 + CH + +70-B3-D5 (hex) Lobaro GmbH +E05000-E05FFF (base 16) Lobaro GmbH + Stadtdeich 7 + Hamburg 20097 + DE + +70-B3-D5 (hex) LDA Audiotech +685000-685FFF (base 16) LDA Audiotech + C/Severo Ochoa, 31 + Malaga Malaga 29590 + ES + +70-B3-D5 (hex) HORIZON.INC +69B000-69BFFF (base 16) HORIZON.INC + 1600 Aza-Shironoshita Asahi + Shin Asahi-cho Takashima, Shiga 520-1501 + JP + +70-B3-D5 (hex) aelettronica group srl +A14000-A14FFF (base 16) aelettronica group srl + via matteotti,22 + gaggiano milano 20083 + IT + +70-B3-D5 (hex) MedRx, Inc +3B6000-3B6FFF (base 16) MedRx, Inc + 1200 Starkey Rd Ste.105 + Largo FL 33771 + US + +70-B3-D5 (hex) ZIEHL-ABEGG SE +698000-698FFF (base 16) ZIEHL-ABEGG SE + Heinz-Ziehl-Strasse 1 + Kuenzelsau 74653 + DE + +70-B3-D5 (hex) Vema Venturi AB +036000-036FFF (base 16) Vema Venturi AB + Johan på gårdas gata 5A + Gothenburg Västra Götaland 41250 + SE + 70-B3-D5 (hex) EVCO SPA A80000-A80FFF (base 16) EVCO SPA VIA FELTRE N. 81 @@ -6005,9 +6281,6 @@ A76000-A76FFF (base 16) Pietro Fiorentini Arcugnano 36057 IT -70-B3-D5 (hex) Private -720000-720FFF (base 16) Private - 70-B3-D5 (hex) OnYield Inc Ltd B74000-B74FFF (base 16) OnYield Inc Ltd 814 Houston Centre, 63 Mody Road @@ -7304,12 +7577,6 @@ ABA000-ABAFFF (base 16) CL International Seongnam Kyeonggi-do 462-806 KR -70-B3-D5 (hex) Aplex Technology Inc. -35F000-35FFFF (base 16) Aplex Technology Inc. - 2Q , NanYouTianAn industrial park Tower4 ,Nanshan District - Shenzhen Guangdong 518054 - CN - 70-B3-D5 (hex) Emka Technologies AF1000-AF1FFF (base 16) Emka Technologies 59 bd General Martial Valin @@ -7328,12 +7595,6 @@ C87000-C87FFF (base 16) Siemens AG Shenzhen Guangdong 518054 CN -70-B3-D5 (hex) MiraeSignal Co., Ltd -38C000-38CFFF (base 16) MiraeSignal Co., Ltd - #203 E-dong Bundang Techno Park Yatapdong - Sungnam Kyungkido 463760 - KR - 70-B3-D5 (hex) Stara S/A Indústria de Implementos Agrícolas 13E000-13EFFF (base 16) Stara S/A Indústria de Implementos Agrícolas Avenida Stara 519 @@ -9692,12 +9953,6 @@ AFC000-AFCFFF (base 16) BAE Systems Endicott NY 13760 US -70-B3-D5 (hex) DAYOUPLUS -474000-474FFF (base 16) DAYOUPLUS - 3F 509, Dunchon-daero, Jungwon-gu, Seongnam-si, Gyeonggi-do, Republic of Korea - Seongnam-si Gyeonggi-do 13217 - KR - 70-B3-D5 (hex) Guangzhou Xianhe Technology Engineering Co., Ltd C13000-C13FFF (base 16) Guangzhou Xianhe Technology Engineering Co., Ltd No. 30-6, Jiantai Road, Dongyong Town, Nansha District @@ -9770,18 +10025,228 @@ E66000-E66FFF (base 16) Eneon sp. z o.o. Warsaw 02-486 PL +70-B3-D5 (hex) WIZAPPLY CO.,LTD +8D2000-8D2FFF (base 16) WIZAPPLY CO.,LTD + 1-3-13-5107, Benten + Osaka-shi, Minato-ku Osaka-fu 552-0007 + JP + +70-B3-D5 (hex) AmericanPharma Technologies +B4C000-B4CFFF (base 16) AmericanPharma Technologies + 222 N 13th Street Suite 200 + Boise ID 83702 + US + 70-B3-D5 (hex) ALFI B0D000-B0DFFF (base 16) ALFI Via Castelletto 20 Borgo Ticino NO 28040 IT -70-B3-D5 (hex) WIZAPPLY CO.,LTD -8D2000-8D2FFF (base 16) WIZAPPLY CO.,LTD - 1-3-13-5107, Benten - Osaka-shi, Minato-ku Osaka-fu 552-0007 +70-B3-D5 (hex) Medipense Inc. +72B000-72BFFF (base 16) Medipense Inc. + 9145 rue Boivin + Montreal Quebec H8R 2E5 + CA + +70-B3-D5 (hex) MITSUBISHI HEAVY INDUSTRIES THERMAL SYSTEMS, LTD. +7CC000-7CCFFF (base 16) MITSUBISHI HEAVY INDUSTRIES THERMAL SYSTEMS, LTD. + 3-1, Asahi, Nishibiwajima-Cho + Kiyosu Aichi 452-8561 JP +70-B3-D5 (hex) The-Box Development +F31000-F31FFF (base 16) The-Box Development + D.D. Eisenhowerstraat 74 + Groningen Groningen 9728 RX + NL + +70-B3-D5 (hex) MAS Elettronica sas di Mascetti Sandro e C. +4FB000-4FBFFF (base 16) MAS Elettronica sas di Mascetti Sandro e C. + Via Risorgimento 16/C + Selvazzano Dentro Padova 35030 + IT + +70-B3-D5 (hex) DHK Storage, LLC +915000-915FFF (base 16) DHK Storage, LLC + 13873 Park Center Rd, Ste 510N + Herndon VA 20171 + US + +70-B3-D5 (hex) Shenzhen Zhiting Technology Co.,Ltd +FE1000-FE1FFF (base 16) Shenzhen Zhiting Technology Co.,Ltd + Room 516, Building 4, Qidi Xiexin science and Technology Park, Longcheng Street + Shenzhen Guangdong 518109 + CN + +70-B3-D5 (hex) on-systems limited +5B7000-5B7FFF (base 16) on-systems limited + 615A Jubilee Road + Letchworth Garden City Hertfordshire SG6 1NE + GB + +70-B3-D5 (hex) Blueprint Lab +FE0000-FE0FFF (base 16) Blueprint Lab + 3-5 Queen St + Glebe NSW 2037 + AU + +70-B3-D5 (hex) MiraeSignal Co., Ltd +38C000-38CFFF (base 16) MiraeSignal Co., Ltd + #701,C-dong Bundang Techno Park Pangyoro 744 + Bundang-gu Sungnam-si Kyungkido 13510 + KR + +70-B3-D5 (hex) LEIDOS +004000-004FFF (base 16) LEIDOS + 1121 W Reeves + Ridgecrest CA 93555 + US + +70-B3-D5 (hex) Swiss Timing LTD +725000-725FFF (base 16) Swiss Timing LTD + Rue de l'Envers 1 + Corgemont 2606 + CH + +70-B3-D5 (hex) Avionica +CC0000-CC0FFF (base 16) Avionica + 9941 West Jessamine St + Miami FL 33157 + US + +70-B3-D5 (hex) RoyalShield Technologies India Private Limited +F1B000-F1BFFF (base 16) RoyalShield Technologies India Private Limited + B-116, DDA Sheds, Okhla Industrial Area, Okhla Phase -I + New Delhi New Delhi 110020 + IN + +70-B3-D5 (hex) Nudron IoT Solutions LLP +6B4000-6B4FFF (base 16) Nudron IoT Solutions LLP + 10, Gitaneel Arcade, Hill Road, Bandra-W + Mumbai Maharashtra 400050 + IN + +70-B3-D5 (hex) DORLET SAU +DEB000-DEBFFF (base 16) DORLET SAU + Albert Eistein 34 + Alava SPAIN 01510 + ES + +70-B3-D5 (hex) Dadacon GmbH +B79000-B79FFF (base 16) Dadacon GmbH + Hammarskjoeldring 75F + Frankfurt am Main Hessen 60439 + DE + +70-B3-D5 (hex) XIA LLC +3DC000-3DCFFF (base 16) XIA LLC + 31057 Genstar Road + HAYWARD CA 94544 + US + +70-B3-D5 (hex) Nordson Corporation +50B000-50BFFF (base 16) Nordson Corporation + 11475 Lakefield Dr + Duluth GA 30097 + US + +70-B3-D5 (hex) Jeio Tech +720000-720FFF (base 16) Jeio Tech + 19 Alexander Road, Suite 7 + Billerica MA 01821 + US + +70-B3-D5 (hex) BAB TECHNOLOGIE GmbH +E19000-E19FFF (base 16) BAB TECHNOLOGIE GmbH + Hoerder Burgstr.18 + Dortmund NRW 44263 + DE + +70-B3-D5 (hex) Schneider Electric Motion USA +2E4000-2E4FFF (base 16) Schneider Electric Motion USA + 370 N. Main St. + Marlborough CT 06447 + US + +70-B3-D5 (hex) Done Design Inc +928000-928FFF (base 16) Done Design Inc + 930 Delray Drive + Forest Hill MD 21050 + US + +70-B3-D5 (hex) TESCAN Brno, s.r.o. +812000-812FFF (base 16) TESCAN Brno, s.r.o. + Libusina tr.1 + Brno 62300 + CZ + +70-B3-D5 (hex) LINEAGE POWER PVT LTD., +965000-965FFF (base 16) LINEAGE POWER PVT LTD., + 30-A1, KIADB, 1ST PHASE INDUSTRIAL ESTATE,KUMBALGODU, BANGALORE-MYSORE ROAD + BANGALORE KARNATAKA 560074 + IN + +70-B3-D5 (hex) China Telecom Fufu Information Technology CO.,LTD +38E000-38EFFF (base 16) China Telecom Fufu Information Technology CO.,LTD + 22 Shuitou Road, Doumen,Fuzhou + Fuzhou FuJian 350013 + CN + +70-B3-D5 (hex) Dynim Oy +CE6000-CE6FFF (base 16) Dynim Oy + Kirkkokatu 5b + Oulu 90100 + FI + +70-B3-D5 (hex) Beijing Muniulinghang Technology Co., Ltd +198000-198FFF (base 16) Beijing Muniulinghang Technology Co., Ltd + C9001 Kangjianbaosheng Square C, No.8 Heiquan Road, Haidian District, + Beijing 100192 + CN + +70-B3-D5 (hex) Aplex Technology Inc. +35F000-35FFFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +70-B3-D5 (hex) TESSA AGRITECH SRL +F74000-F74FFF (base 16) TESSA AGRITECH SRL + VIA ALLA CASCATA, 56 + Trento Trento 38123 + IT + +70-B3-D5 (hex) CAR-connect GmbH +81F000-81FFFF (base 16) CAR-connect GmbH + Am Egelingsberg 8 + Leiferde Niedersachsen 38542 + DE + +70-B3-D5 (hex) MBJ +E03000-E03FFF (base 16) MBJ + Jochim-Klindt-Straße 7 + Ahrensburg Schleswig Holstein 22926 + DE + +70-B3-D5 (hex) Code Blue Corporation +271000-271FFF (base 16) Code Blue Corporation + 259 Hedcor Street + Holland MI 49423 + US + +70-B3-D5 (hex) Fischer Connectors +BF7000-BF7FFF (base 16) Fischer Connectors + 11 Waterberry drive + Waterlooville Hampshire PO7 7YH + GB + +70-B3-D5 (hex) VK Integrated Systems +A8F000-A8FFFF (base 16) VK Integrated Systems + 810 Crossland Ave + Clarksville TN 37040 + US + 70-B3-D5 (hex) System West dba ICS Electronics E06000-E06FFF (base 16) System West dba ICS Electronics 7034 Commerce Circle Suite A @@ -12050,12 +12515,6 @@ FCA000-FCAFFF (base 16) M2M Cybernetics Pvt Ltd Aarhus N 8200 DK -70-B3-D5 (hex) Aplex Technology Inc. -906000-906FFF (base 16) Aplex Technology Inc. - 2nd Floor,Tower3,District5,HongHuaLing industrial park, Nanshan District - Shenzhen Guangdong 518055 - CN - 70-B3-D5 (hex) Zoe Medical 721000-721FFF (base 16) Zoe Medical 460 Boston Street @@ -14663,6 +15122,168 @@ D78000-D78FFF (base 16) Nxvi Microelectronics Technology (Jinan) Co., Ltd. Paderborn NRW 33100 DE +70-B3-D5 (hex) AKASAKATEC INC. +D83000-D83FFF (base 16) AKASAKATEC INC. + 3F Marina Plaza 4-2 + Shiraho kanazawa-ku Yokohamashi 2360007 + JP + +70-B3-D5 (hex) VTEQ +B12000-B12FFF (base 16) VTEQ + Conca de Barbera + Castellar del Vallés Barcelona / Spain 08122 + ES + +70-B3-D5 (hex) promedias AG +520000-520FFF (base 16) promedias AG + Grabenackerstrasse 27 + Oberhasli ZH CH-8156 + CH + +70-B3-D5 (hex) REO AG +AD0000-AD0FFF (base 16) REO AG + Brühlerstr. 100 + Solingen 42657 + DE + +70-B3-D5 (hex) Array Technologies Inc. +FB4000-FB4FFF (base 16) Array Technologies Inc. + 21 Sequin Drive + Glastonbury 06033 + US + +70-B3-D5 (hex) ejoin, s.r.o. +44C000-44CFFF (base 16) ejoin, s.r.o. + Sturova 1 + Dubnica nad Vahom 01841 + SK + +70-B3-D5 (hex) TEX COMPUTER SRL +390000-390FFF (base 16) TEX COMPUTER SRL + VIA MERCADANTE 35 + CATTOLICA RIMINI 47841 + IT + +70-B3-D5 (hex) Grau Elektronik GmbH +314000-314FFF (base 16) Grau Elektronik GmbH + Badhausweg 14 + Karlsbad Ittersbach Baden-Württemberg 76307 + DE + +70-B3-D5 (hex) microWerk GmbH +D2C000-D2CFFF (base 16) microWerk GmbH + Kaffeegasse, 7 + Halsenbach 56283 + DE + +70-B3-D5 (hex) Foxtrot Research Corp +604000-604FFF (base 16) Foxtrot Research Corp + 6201 Johns Road, Suite 3 + Tampa FL 33634 + US + +70-B3-D5 (hex) Guan Show Technologe Co., Ltd. +46D000-46DFFF (base 16) Guan Show Technologe Co., Ltd. + No.127, Jianguo 1st Rd., Lingya Dist. + Kaohsiung City 802 + TW + +70-B3-D5 (hex) Monnit Corporation +A1E000-A1EFFF (base 16) Monnit Corporation + 450 South Simmons STE 670 + Kaysville UT 84037 + US + +70-B3-D5 (hex) DEUTA-WERKE GmbH +681000-681FFF (base 16) DEUTA-WERKE GmbH + Paffrather Str. 140 + Bergisch Gladbach North Rhine-Westphalia 51465 + DE + +70-B3-D5 (hex) Movicom Electric LLC +3B3000-3B3FFF (base 16) Movicom Electric LLC + Nauchny proezd, 20 + Moscow Moscow 117246 + RU + +70-B3-D5 (hex) Sicon srl +690000-690FFF (base 16) Sicon srl + Via Sila 1/3 + Isola Vicentina Vicenza 36033 + IT + +70-B3-D5 (hex) SMITEC S.p.A. +312000-312FFF (base 16) SMITEC S.p.A. + Via Carlo Ceresa, 10 + San Giovanni Bianco Bergamo 24015 + IT + +70-B3-D5 (hex) SCHEIBER +CFA000-CFAFFF (base 16) SCHEIBER + 2 BELLEVUE + SAINT PIERRE DU CHEMIN 85120 + FR + +70-B3-D5 (hex) Telerob Gesellschaft für Fernhantierungs +6D4000-6D4FFF (base 16) Telerob Gesellschaft für Fernhantierungs + Vogelsangstr. 8 + Ostfildern 73760 + DE + +70-B3-D5 (hex) Metrasens Limited +ED6000-ED6FFF (base 16) Metrasens Limited + 8 Beauchamp Business Centre,, Sparrowhawk Close + Malvern Worcestershire WR14 1GL + GB + +70-B3-D5 (hex) Perform3-D LLC +451000-451FFF (base 16) Perform3-D LLC + 411 Huronview Blvd STE 200 + Ann Arbor MI 48103 + US + +70-B3-D5 (hex) Aplex Technology Inc. +906000-906FFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +70-B3-D5 (hex) DesignA Electronics Limited +A63000-A63FFF (base 16) DesignA Electronics Limited + Unit 6 + Christchurch New Zealand 8011 + NZ + +70-B3-D5 (hex) Grayshift +71F000-71FFFF (base 16) Grayshift + 931 Monroe Dr NE, Suite A102-340 + Atlanta GA 30308 + US + +70-B3-D5 (hex) dongsheng +AFD000-AFDFFF (base 16) dongsheng + No. 2, Sec. 2, Beiyi Rd., Xindian Dist., + New Taipei City 231067 + TW + +70-B3-D5 (hex) Exemplar Medical, LLC +318000-318FFF (base 16) Exemplar Medical, LLC + 4521 Wornall Road, #106 + Kansas City MO 64111 + US + +70-B3-D5 (hex) HLT Micro +2B6000-2B6FFF (base 16) HLT Micro + Bld 6, 4th Park, Xitian, GM Distinct + shenzhen 511088 + CN + +70-B3-D5 (hex) Cucos Retail Systems GmbH +4CB000-4CBFFF (base 16) Cucos Retail Systems GmbH + Detmolder Straße 7 + Soest 59494 + DE + 70-B3-D5 (hex) YUYAMA MFG Co.,Ltd BBB000-BBBFFF (base 16) YUYAMA MFG Co.,Ltd 3-3-1 @@ -15353,9 +15974,6 @@ FC0000-FC0FFF (base 16) CODESYSTEM Co.,Ltd Petah Tikva Israel 49000 IL -70-B3-D5 (hex) Private -F7C000-F7CFFF (base 16) Private - 70-B3-D5 (hex) boekel AF8000-AF8FFF (base 16) boekel 855 pennsylvania blvd @@ -16703,12 +17321,6 @@ C3D000-C3DFFF (base 16) CISTECH Solutions HONGKONG 999077 HK -70-B3-D5 (hex) Shenzhen Rongda Computer Co.,Ltd -289000-289FFF (base 16) Shenzhen Rongda Computer Co.,Ltd - Room A616, Aoshida Building, Zhongkang Road, Futian District - Shenzhen Guangdong 518049 - CN - 70-B3-D5 (hex) FIBERNET LTD 041000-041FFF (base 16) FIBERNET LTD 9 Hakidma st. Hi-Tech City Park, @@ -16787,12 +17399,6 @@ C86000-C86FFF (base 16) Woodam Co., Ltd. Gimpo Gyeonggi-do 10048 KR -70-B3-D5 (hex) Aplex Technology Inc. -666000-666FFF (base 16) Aplex Technology Inc. - 2nd Floor,Tower3,District5,HongHuaLing industrial park, Nanshan District - Shenzhen Guangdong 518055 - CN - 70-B3-D5 (hex) ATEME 607000-607FFF (base 16) ATEME 6 rue Dewoitine @@ -17015,12 +17621,6 @@ C63000-C63FFF (base 16) Xentech Solutions Limited St Albans Hertfordshire AL36PF GB -70-B3-D5 (hex) Aplex Technology Inc. -106000-106FFF (base 16) Aplex Technology Inc. - 2nd Floor,Tower3,District5,HongHuaLing industrial park, Nanshan District - Shenzhen Guangdong 518055 - CN - 70-B3-D5 (hex) EREE Electronique D11000-D11FFF (base 16) EREE Electronique 6 avenu Dr Schweitzer @@ -17099,12 +17699,6 @@ F4F000-F4FFFF (base 16) Power Electronics Espana, S.L. Paterna Valencia 46980 ES -70-B3-D5 (hex) Aplex Technology Inc. -B33000-B33FFF (base 16) Aplex Technology Inc. - 2Q , NanYouTianAn industrial park Tower4 ,Nanshan District - Shenzhen Guangdong 518054 - CN - 70-B3-D5 (hex) Aplex Technology Inc. 3D9000-3D9FFF (base 16) Aplex Technology Inc. 2Q , NanYouTianAn industrial park Tower4 ,Nanshan District @@ -19679,6 +20273,255 @@ A79000-A79FFF (base 16) NOREYA Technology e.U. Dinkelsbuehl Bavaria 91550 DE +70-B3-D5 (hex) NAL Research Corporation +1B0000-1B0FFF (base 16) NAL Research Corporation + 11100 Endeavor Ct, Suite 300 + Manassas VA 20109 + US + +70-B3-D5 (hex) LLC NTZ Mekhanotronika +6C0000-6C0FFF (base 16) LLC NTZ Mekhanotronika + Pionerstroya, build 23a + Saint-Petersburg 198206 + RU + +70-B3-D5 (hex) AXING AG +CA6000-CA6FFF (base 16) AXING AG + Gewerbehaus Moskau + Ramsen 8262 + CH + +70-B3-D5 (hex) Akse srl +128000-128FFF (base 16) Akse srl + Via Aldo Moro, 39 + Reggio Emilia Italy 42124 + IT + +70-B3-D5 (hex) PNETWORKS +EF0000-EF0FFF (base 16) PNETWORKS + TEKNOPARK Bul. 1/1A No: 201 Pendik ?stanbul + Istanbul 34906 + TR + +70-B3-D5 (hex) Arwin Technology Limited +8C9000-8C9FFF (base 16) Arwin Technology Limited + Unit 215, 2/F, 19W, 19 Science Park West Avenue + Hong Kong 0 + HK + +70-B3-D5 (hex) Herholdt Controls srl +C6B000-C6BFFF (base 16) Herholdt Controls srl + Via Mestre 13 + Milan 20132 + IT + +70-B3-D5 (hex) Atlas Lighting Products +CB5000-CB5FFF (base 16) Atlas Lighting Products + 1406 S Mebane St + Burlington 27215 + US + +70-B3-D5 (hex) Weble Sàrl +96C000-96CFFF (base 16) Weble Sàrl + Rue du Jura 12 + Bussigny Vaud 1030 + CH + +70-B3-D5 (hex) Grossenbacher Systeme AG +CE8000-CE8FFF (base 16) Grossenbacher Systeme AG + Spinnereistrasse 10 + St. Gallen 9008 + CH + +70-B3-D5 (hex) G.S.D GROUP INC. +B01000-B01FFF (base 16) G.S.D GROUP INC. + 2010 RUE MICHELIN, SUITE 100 + LAVAL Quebec H7L 5C2 + CA + +70-B3-D5 (hex) Medicomp, Inc +F7C000-F7CFFF (base 16) Medicomp, Inc + 600 Atlantis Rd + Melbourne FL 32904 + US + +70-B3-D5 (hex) DIC Corporation +5C3000-5C3FFF (base 16) DIC Corporation + DIC Building,7-20,Nihonbashi 3-chome + Chuo-ku,Tokyo 103-8233 + JP + +70-B3-D5 (hex) YUYAMA MFG Co.,Ltd +CAD000-CADFFF (base 16) YUYAMA MFG Co.,Ltd + 3-3-1 + TOYONAKASHI OSAKA 561-0841 + JP + +70-B3-D5 (hex) Sono-Tek Corporation +5C2000-5C2FFF (base 16) Sono-Tek Corporation + 2012 Rte. 9W Bldg 3 + Milton NY 12547 + US + +70-B3-D5 (hex) Davitor AB +E60000-E60FFF (base 16) Davitor AB + Skordarevagen 5 + Kalmar 39353 + SE + +70-B3-D5 (hex) Shenzhen Rongda Computer Co.,Ltd +289000-289FFF (base 16) Shenzhen Rongda Computer Co.,Ltd + 905, Block B, DuoCaiKeChuan Park, No.5 Guanle Road + Longhua District Shenzhen, Guangdong 518110 + CN + +70-B3-D5 (hex) Breas Medical AB +CF9000-CF9FFF (base 16) Breas Medical AB + Företagsvägen 1 + Mölnlycke SE-435 33 + SE + +70-B3-D5 (hex) European Synchrotron Radiation Facility +160000-160FFF (base 16) European Synchrotron Radiation Facility + 71, avenue des Martyrs + Grenoble Isère 38000 + FR + +70-B3-D5 (hex) Radian Research, Inc. +9BC000-9BCFFF (base 16) Radian Research, Inc. + 3852 Fortune Drive + Lafayette IN 47905 + US + +70-B3-D5 (hex) Coloet S.r.l. +713000-713FFF (base 16) Coloet S.r.l. + Via Mascheroni, 20 + MILANO Italy 20145 + IT + +70-B3-D5 (hex) meoENERGY +7FA000-7FAFFF (base 16) meoENERGY + Glacisstraße 9/1 + Graz 8010 + AT + +70-B3-D5 (hex) VERTEL DIGITAL PRIVATE LIMITED +912000-912FFF (base 16) VERTEL DIGITAL PRIVATE LIMITED + C-98, SECTOR-10 + NOIDA Uttar Pradesh 201301 + IN + +70-B3-D5 (hex) ITALIANA PONTI RADIO SRL +452000-452FFF (base 16) ITALIANA PONTI RADIO SRL + VIA CA' BASSA 67 + VARESE VARESE 21100 + IT + +70-B3-D5 (hex) Stuyts Engineering Haarlem BV +D1D000-D1DFFF (base 16) Stuyts Engineering Haarlem BV + Hogeweg 40 + Zandvoort Noord-Holland 2042GH + NL + +70-B3-D5 (hex) sonatest +8FD000-8FDFFF (base 16) sonatest + 1175 Rue Lavigerie, Bur.90 + Quebec Quebec G1V 4P1 + CA + +70-B3-D5 (hex) IP Devices +5CE000-5CEFFF (base 16) IP Devices + Etrog 72 8 + Givat Zeev 9091700 + IL + +70-B3-D5 (hex) JESE Ltd +0E2000-0E2FFF (base 16) JESE Ltd + Unit 2 Gales + Newton Abbot Devon TQ13 8FD + GB + +70-B3-D5 (hex) IDZ Ltd +7F6000-7F6FFF (base 16) IDZ Ltd + 160 CITY ROAD + LONDON EC1V 2NX + GB + +70-B3-D5 (hex) Private Enterprise Scientific and Production Private EnterpriseSparing-Vist Center +076000-076FFF (base 16) Private Enterprise Scientific and Production Private EnterpriseSparing-Vist Center + 33 V.Velykoho Str. + Lviv 79026 + UA + +70-B3-D5 (hex) LinkAV Technology Co., Ltd +1F6000-1F6FFF (base 16) LinkAV Technology Co., Ltd + Room 401, 4F, Skyworth Digital Building, Songbai Rd, Baoan District + Shenzhen Guangdong 518108 + CN + +70-B3-D5 (hex) Aplex Technology Inc. +B33000-B33FFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +70-B3-D5 (hex) Aplex Technology Inc. +106000-106FFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +70-B3-D5 (hex) Aplex Technology Inc. +666000-666FFF (base 16) Aplex Technology Inc. + 501-5B01,Xintianxia phase 2 building,Wankecheng community,Bantian township,Longgang district + Shenzhen City Guangdong 518129 + CN + +70-B3-D5 (hex) FARHO DOMOTICA SL +ACE000-ACEFFF (base 16) FARHO DOMOTICA SL + POLIGONO DE TABAZA II, NAVES 9-13 + TABAZA ASTURIAS 33439 + ES + +70-B3-D5 (hex) The Engineerix Group +C71000-C71FFF (base 16) The Engineerix Group + 1418 Beech Ave 119A + McAllen TX 78501 + US + +70-B3-D5 (hex) Flextronics International Kft +1BC000-1BCFFF (base 16) Flextronics International Kft + 38. Zrinyi Str. + Zalaegerszeg Zala 8900 + HU + +70-B3-D5 (hex) Research Laboratory of Design Automation, Ltd. +223000-223FFF (base 16) Research Laboratory of Design Automation, Ltd. + 8 Birzhevoy Spusk + Taganrog 347900 + RU + +70-B3-D5 (hex) Private +315000-315FFF (base 16) Private + +70-B3-D5 (hex) JOLANYEE Technology Co., Ltd. +9D8000-9D8FFF (base 16) JOLANYEE Technology Co., Ltd. + 2F., No. 13, Sec. 1, Yonghe Rd. + Yonghe Dist., New Taipei City 234014 + TW + +70-B3-D5 (hex) SEASONS 4 INC +D5D000-D5DFFF (base 16) SEASONS 4 INC + 3601 LA GRANGE PKWY, SUITE 500 + TOANO VA 23168 + US + +70-B3-D5 (hex) VulcanForms +E0E000-E0EFFF (base 16) VulcanForms + 20 North Ave. + Burlington MA 01803 + US + 70-B3-D5 (hex) DISMUNTEL SAL 92C000-92CFFF (base 16) DISMUNTEL SAL Pol ind cotes @@ -21080,9 +21923,6 @@ C37000-C37FFF (base 16) Keycom Corp. Taipei Taiwan 11070 TW -70-B3-D5 (hex) Private -278000-278FFF (base 16) Private - 70-B3-D5 (hex) Arrowvale Electronics B07000-B07FFF (base 16) Arrowvale Electronics Shawbank Road @@ -21491,12 +22331,6 @@ BF3000-BF3FFF (base 16) CG-WIRELESS East Pittsburgh PA 15112-1242 US -70-B3-D5 (hex) PoolDigital GmbH & Co. KG -063000-063FFF (base 16) PoolDigital GmbH & Co. KG - Kaffeegasse, 7 - Halsenbach 56283 - DE - 70-B3-D5 (hex) HORIBA ABX SAS AB8000-AB8FFF (base 16) HORIBA ABX SAS rue du caducee @@ -22715,12 +23549,6 @@ DDF000-DDFFFF (base 16) AeroVision Avionics, Inc. Almelo Overijssel 7602 EA NL -70-B3-D5 (hex) Refecor Oy -DF7000-DF7FFF (base 16) Refecor Oy - Isokatu 8A1 - OULU FInland 90100 - FI - 70-B3-D5 (hex) ARD C89000-C89FFF (base 16) ARD MICROPOLIS @@ -24511,3 +25339,219 @@ B27000-B27FFF (base 16) Naval Group 40-42 Rue Du Docteur Finlay PARIS CEDEX 15 75732 FR + +70-B3-D5 (hex) Shanghai Armour Technology Co., Ltd. +8E5000-8E5FFF (base 16) Shanghai Armour Technology Co., Ltd. + Room 411, building 10, 471 Guiping Road, Xuhui District + Shanghai Shanghai 200233 + CN + +70-B3-D5 (hex) Hangzhou Weimu Technology Co.,Ltd. +373000-373FFF (base 16) Hangzhou Weimu Technology Co.,Ltd. + 3 / f, building 1, yongle village, cangqian street, yuhang district + Hangzhou Zhejiang 310000 + CN + +70-B3-D5 (hex) Xirgo Technologies LLC +CA0000-CA0FFF (base 16) Xirgo Technologies LLC + 188 Camino Ruiz + Camarillo CA 93012 + US + +70-B3-D5 (hex) Xirgo Technologies LLC +CEB000-CEBFFF (base 16) Xirgo Technologies LLC + 188 Camino Ruiz + Camarillo CA 93012 + US + +70-B3-D5 (hex) GreenFlux +A02000-A02FFF (base 16) GreenFlux + Mauritskade 63 + Amsterdam 1092 AD + NL + +70-B3-D5 (hex) Iylus Inc. +02C000-02CFFF (base 16) Iylus Inc. + 3100 Clarendon Blvd., Suite 200 + Arlington VA 22201 + US + +70-B3-D5 (hex) Coda Octopus Products Limited +4D9000-4D9FFF (base 16) Coda Octopus Products Limited + 38 S. Gyle Crescent, South Gyle Business Park + Edinburgh Scotland EH12 9EB + GB + +70-B3-D5 (hex) Walter Müller AG +0E4000-0E4FFF (base 16) Walter Müller AG + Russikerstrasse 37 + Fehraltorf Zürich 8320 + CH + +70-B3-D5 (hex) Sensoronic Co.,Ltd +D52000-D52FFF (base 16) Sensoronic Co.,Ltd + 1311ho, sambo techno tower, Jomaru-ro 385beongil, + Bucheon-si Gyeonggi-do 14556 + KR + +70-B3-D5 (hex) COONTROL Tecnologia em Combustão LTDA EPP +8E9000-8E9FFF (base 16) COONTROL Tecnologia em Combustão LTDA EPP + RUA ABRAHAN LINCOLS, 464, Jardim América + RIO DO SUL SANTA CATARINA 89160202 + BR + +70-B3-D5 (hex) Neusoft Reach Automotive Technology (Shenyang) Co.,Ltd +E42000-E42FFF (base 16) Neusoft Reach Automotive Technology (Shenyang) Co.,Ltd + No.2 Xinxiu Street, Hunnan District, Shenyang + Shenyang Liaoning 110000 + CN + +70-B3-D5 (hex) Private +278000-278FFF (base 16) Private + 600 Atlantis Rd + Melbourne FL 32904 + US + +70-B3-D5 (hex) YUYAMA MFG Co.,Ltd +196000-196FFF (base 16) YUYAMA MFG Co.,Ltd + 1-4-30 + MEISHINGUCHI,TOYONAKA OSAKA 561-0841 + JP + +70-B3-D5 (hex) Guan Show Technologe Co., Ltd. +829000-829FFF (base 16) Guan Show Technologe Co., Ltd. + No.127, Jianguo 1st Rd., Lingya Dist. + Kaohsiung City 802 + TW + +70-B3-D5 (hex) Thermokon Sensortechnik GmbH +581000-581FFF (base 16) Thermokon Sensortechnik GmbH + Platanenweg 1 + Mittenaar Hessen 35756 + DE + +70-B3-D5 (hex) PoolDigital GmbH & Co. KG +063000-063FFF (base 16) PoolDigital GmbH & Co. KG + Gablinger Weg 102 + Augsburg 86156 + DE + +70-B3-D5 (hex) Loma Systems s.r.o. +BC8000-BC8FFF (base 16) Loma Systems s.r.o. + Southwood + Farnborough Hampshire GU14 0NY + GB + +70-B3-D5 (hex) MECT SRL +2C5000-2C5FFF (base 16) MECT SRL + VIA E. FERMI 57/59 + ALPIGNANO string:TO 10091 + IT + +70-B3-D5 (hex) MB connect line GmbH Fernwartungssysteme +71A000-71AFFF (base 16) MB connect line GmbH Fernwartungssysteme + Winnettener Straße 6 + Dinkelsbuehl Bavaria 91550 + DE + +70-B3-D5 (hex) EIZO RUGGED SOLUTIONS +5B9000-5B9FFF (base 16) EIZO RUGGED SOLUTIONS + 442 Northlake Blvd Suite 1008 + Altamonte Springs FL 32701 + US + +70-B3-D5 (hex) ISG Nordic AB +DEF000-DEFFFF (base 16) ISG Nordic AB + Energigatan 9 + KUNGSBACKA Select State SE-43437 + SE + +70-B3-D5 (hex) CTROGERS LLC +474000-474FFF (base 16) CTROGERS LLC + 815 1st Ave #174 + Seattle WA 98104 + US + +70-B3-D5 (hex) Deep Secure Limited +DD0000-DD0FFF (base 16) Deep Secure Limited + 1 Nimrod House, Sandys Road + Malvern Worcestershire WR14 1JJ + GB + +70-B3-D5 (hex) Mi-Fi Networks Pvt Ltd +411000-411FFF (base 16) Mi-Fi Networks Pvt Ltd + No 13 A, Kalakshetra Road , Thiruvanmiyur + Chennai Tamil Nadu 600041 + IN + +70-B3-D5 (hex) CesiumAstro Inc. +E5F000-E5FFFF (base 16) CesiumAstro Inc. + 13412 Galleria Circle, Suite H-100 + Austin TX 78738 + US + +70-B3-D5 (hex) Druck Ltd. +EAA000-EAAFFF (base 16) Druck Ltd. + Firtree Lane, Groby, Leicester + Le6 0FH England + GB + +70-B3-D5 (hex) Panoramic Power +4ED000-4EDFFF (base 16) Panoramic Power + Atir Yeda 15 + Kfar Saba 4464312 + IL + +70-B3-D5 (hex) STENTORIUS by ADI +5B3000-5B3FFF (base 16) STENTORIUS by ADI + 41 - 47 Rue des frères Lumière + Neuilly sur Marne Ile-de-France 93330 + FR + +70-B3-D5 (hex) Codewerk GmbH +4D0000-4D0FFF (base 16) Codewerk GmbH + Siemensallee 75 + Karlsruhe 76187 + DE + +70-B3-D5 (hex) Orlaco Products B.V. +333000-333FFF (base 16) Orlaco Products B.V. + Albert Plesmanstraat 42 + Barneveld 3772MN + NL + +70-B3-D5 (hex) ScopeSensor Oy +DF7000-DF7FFF (base 16) ScopeSensor Oy + Teollisuustie 1 + Haukipudas 90830 + FI + +70-B3-D5 (hex) KBPR LLC +11E000-11EFFF (base 16) KBPR LLC + Raketny bulvar street 16 + Moscow Select State 129164 + RU + +70-B3-D5 (hex) Anello Photonics +96A000-96AFFF (base 16) Anello Photonics + 3964 Rivermark Plaza, Suite 144 + Santa Clara CA 95054 + US + +70-B3-D5 (hex) HORIZON.INC +F40000-F40FFF (base 16) HORIZON.INC + 1600 Aza-Shironoshita Asahi + Shin Asahi-cho Takashima, Shiga 520-1501 + JP + +70-B3-D5 (hex) SUS Corporation +1ED000-1EDFFF (base 16) SUS Corporation + 6F, S-patio Bldg. 14-25 Minami-cho, Suruga-ku, + Shizuoka city, Shizuoka 422-8067 + JP + +70-B3-D5 (hex) Lumiplan Duhamel +A0C000-A0CFFF (base 16) Lumiplan Duhamel + 2 rue de l'industrie + Domène Isère 38420 + FR diff --git a/hwdb.d/meson.build b/hwdb.d/meson.build index 6fcb364ac..7221a1ae9 100644 --- a/hwdb.d/meson.build +++ b/hwdb.d/meson.build @@ -4,6 +4,8 @@ # they are very long but quite repetitive and the parser is not very fast. # So we don't "test" them. hwdb_files_notest = files(''' + README + 20-dmi-id.hwdb 20-pci-vendor-model.hwdb 20-pci-classes.hwdb 20-usb-vendor-model.hwdb @@ -19,6 +21,7 @@ hwdb_files_notest = files(''' hwdb_files_test = files(''' 60-autosuspend.hwdb + 60-autosuspend-fingerprint-reader.hwdb 60-evdev.hwdb 60-input-id.hwdb 60-keyboard.hwdb @@ -64,9 +67,9 @@ endif ############################################################ run_target( - 'hwdb-update', - command : [hwdb_update_sh, meson.current_source_dir()]) + 'update-hwdb', + command : [update_hwdb_sh, meson.current_source_dir()]) run_target( - 'autosuspend-update', - command : [autosuspend_update_sh, project_source_root + '/tools/chromiumos']) + 'update-hwdb-autosuspend', + command : [update_hwdb_autosuspend_sh, project_source_root]) diff --git a/hwdb.d/parse_hwdb.py b/hwdb.d/parse_hwdb.py index ed07224b3..24964ff8d 100755 --- a/hwdb.d/parse_hwdb.py +++ b/hwdb.d/parse_hwdb.py @@ -33,7 +33,7 @@ try: OneOrMore, Combine, Or, Optional, Suppress, Group, nums, alphanums, printables, stringEnd, pythonStyleComment, - ParseBaseException) + ParseBaseException, __diag__) except ImportError: print('pyparsing is not available') sys.exit(77) @@ -50,6 +50,12 @@ except ImportError: # don't do caching on old python lru_cache = lambda: (lambda f: f) +__diag__.warn_multiple_tokens_in_named_alternation = True +__diag__.warn_ungrouped_named_tokens_in_collection = True +__diag__.warn_name_set_on_empty_Forward = True +__diag__.warn_on_multiple_string_args_to_oneof = True +__diag__.enable_debug_on_named_expressions = True + EOL = LineEnd().suppress() EMPTYLINE = LineEnd() COMMENTLINE = pythonStyleComment + EOL @@ -111,9 +117,9 @@ def hwdb_grammar(): def property_grammar(): ParserElement.setDefaultWhitespaceChars(' ') - dpi_setting = (Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ'))('SETTINGS*') + dpi_setting = Group(Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ'))('SETTINGS*') mount_matrix_row = SIGNED_REAL + ',' + SIGNED_REAL + ',' + SIGNED_REAL - mount_matrix = (mount_matrix_row + ';' + mount_matrix_row + ';' + mount_matrix_row)('MOUNT_MATRIX') + mount_matrix = Group(mount_matrix_row + ';' + mount_matrix_row + ';' + mount_matrix_row)('MOUNT_MATRIX') xkb_setting = Optional(Word(alphanums + '+-/@._')) props = (('MOUSE_DPI', Group(OneOrMore(dpi_setting))), @@ -121,20 +127,20 @@ 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')), - ('ID_INPUT_KEY', Literal('1')), - ('ID_INPUT_KEYBOARD', Literal('1')), - ('ID_INPUT_MOUSE', Literal('1')), - ('ID_INPUT_POINTINGSTICK', Literal('1')), - ('ID_INPUT_SWITCH', Literal('1')), - ('ID_INPUT_TABLET', Literal('1')), - ('ID_INPUT_TABLET_PAD', Literal('1')), - ('ID_INPUT_TOUCHPAD', Literal('1')), - ('ID_INPUT_TOUCHSCREEN', Literal('1')), - ('ID_INPUT_TRACKBALL', Literal('1')), + ('ID_AUTOSUSPEND', Or((Literal('0'), Literal('1')))), + ('ID_INPUT', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_ACCELEROMETER', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_JOYSTICK', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_KEY', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_KEYBOARD', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_MOUSE', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_POINTINGSTICK', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_SWITCH', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_TABLET', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_TABLET_PAD', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_TOUCHPAD', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_TOUCHSCREEN', Or((Literal('0'), Literal('1')))), + ('ID_INPUT_TRACKBALL', Or((Literal('0'), Literal('1')))), ('POINTINGSTICK_SENSITIVITY', INTEGER), ('POINTINGSTICK_CONST_ACCEL', REAL), ('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))), @@ -240,10 +246,19 @@ def check_one_keycode(prop, value): 'KBD_LCD_MENU' in key): error('Keycode {} unknown', key) +def check_wheel_clicks(properties): + pairs = (('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', 'MOUSE_WHEEL_CLICK_COUNT'), + ('MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL', 'MOUSE_WHEEL_CLICK_ANGLE'), + ('MOUSE_WHEEL_CLICK_COUNT_HORIZONTAL', 'MOUSE_WHEEL_CLICK_ANGLE_HORIZONTAL'), + ('MOUSE_WHEEL_CLICK_COUNT', 'MOUSE_WHEEL_CLICK_ANGLE')) + for pair in pairs: + if pair[0] in properties and pair[1] not in properties: + error('{} requires {} to be specified', *pair) + def check_properties(groups): grammar = property_grammar() for matches, props in groups: - prop_names = set() + seen_props = {} for prop in props: # print('--', prop) prop = prop.partition('#')[0].rstrip() @@ -253,9 +268,9 @@ def check_properties(groups): error('Failed to parse: {!r}', prop) continue # print('{!r}'.format(parsed)) - if parsed.NAME in prop_names: + if parsed.NAME in seen_props: error('Property {} is duplicated', parsed.NAME) - prop_names.add(parsed.NAME) + seen_props[parsed.NAME] = parsed.VALUE if parsed.NAME == 'MOUSE_DPI': check_one_default(prop, parsed.VALUE.SETTINGS) elif parsed.NAME == 'ACCEL_MOUNT_MATRIX': @@ -264,6 +279,8 @@ def check_properties(groups): val = parsed.VALUE if isinstance(parsed.VALUE, str) else parsed.VALUE[0] check_one_keycode(prop, val) + check_wheel_clicks(seen_props) + def print_summary(fname, groups): n_matches = sum(len(matches) for matches, props in groups) n_props = sum(len(props) for matches, props in groups) diff --git a/hwdb.d/pci.ids b/hwdb.d/pci.ids index 05c6b5d26..604fba5eb 100644 --- a/hwdb.d/pci.ids +++ b/hwdb.d/pci.ids @@ -1,8 +1,8 @@ # # List of PCI ID's # -# Version: 2020.11.14 -# Date: 2020-11-14 03:15:02 +# Version: 2021.03.22 +# Date: 2021-03-22 03:15:01 # # Maintained by Albert Pool, Martin Mares, and other volunteers from # the PCI ID Project at https://pci-ids.ucw.cz/. @@ -522,6 +522,7 @@ 1000 3040 9210-8i 1000 3080 9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA] 1000 30b0 9200-8e [LSI SAS 6Gb/s SAS/SATA PCIe x8 External HBA] + 1014 03ca IBM 6Gb SAS HBA [9212-4i4e] 1028 1f1c 6Gbps SAS HBA Adapter 1028 1f1d PERC H200 Adapter 1028 1f1e PERC H200 Integrated @@ -705,8 +706,8 @@ 1d49 0200 ThinkSystem 430-8i SAS/SATA 12Gb HBA 1d49 0202 ThinkSystem 430-8e SAS/SATA 12Gb HBA 1d49 0204 ThinkSystem 430-8i SAS/SATA 12Gb Dense HBA -# PCIe switch SES management endpoint - 00b2 PEX880xx PCIe Gen 4 Switch SES management endpoint + 00b2 PCIe Switch management endpoint + 1d49 0003 ThinkSystem 1611-8P PCIe Gen4 NVMe Switch Adapter 00be SAS3504 Fusion-MPT Tri-Mode RAID On Chip (ROC) 00bf SAS3404 Fusion-MPT Tri-Mode I/O Controller Chip (IOC) 00c0 SAS3324 PCI-Express Fusion-MPT SAS-3 @@ -873,6 +874,14 @@ 1d49 060e ThinkSystem RAID 940-32i 8GB Flash PCIe Gen4 12Gb Adapter 1d49 060f ThinkSystem RAID 940-8e 4GB Flash PCIe Gen4 12Gb Adapter 10e2 MegaRAID 12GSAS/PCIe Secure SAS39xx +# 9560 16 internal port RAID controller + 1000 4000 MegaRAID 9560-16i +# 9560 8 internal port RAID controller + 1000 4010 MegaRAID 9560-8i +# 9580 8 internal & 8 external port RAID controller + 1000 4020 MegaRAID 9580-8i8e +# MegaRAID 9562-16i 9562 16 internal port RAID controller + 1000 40b0 MegaRAID 9562-16i 1028 1ae0 PERC H755 Adapter 1028 1ae1 PERC H755 Front 1028 1ae2 PERC H755N Front @@ -907,6 +916,8 @@ 8086 0523 MegaRAID RAID Controller SRCS16 3050 SAS2008 PCI-Express Fusion-MPT SAS-2 6001 DX1 Multiformat Broadcast HD/SD Encoder/Decoder + c012 PEX880xx PCIe Gen 4 Switch + 1d49 0003 ThinkSystem 1611-8P PCIe Gen4 NVMe Switch Adapter 1001 Kolter Electronic 0010 PCI 1616 Measurement card with 32 digital I/O lines 0011 OPTO-PCI Opto-Isolated digital I/O board @@ -950,24 +961,35 @@ 1478 Navi 10 XL Upstream Port of PCI Express Switch 1479 Navi 10 XL Downstream Port of PCI Express Switch 154c Kryptos [Radeon RX 350] + 1462 7c28 MS-7C28 Motherboard 154e Garfield 1551 Arlene 1552 Pooky 1561 Anubis 15d8 Picasso 103c 8615 Pavilion Laptop 15-cw1xxx + 17aa 3181 ThinkCentre M75n IoT 17aa 5124 ThinkPad E595 + ea50 cc10 RXi2-BP 15dd Raven Ridge [Radeon Vega Series / Radeon Vega Mobile Series] 103c 83c6 Radeon Vega 8 Mobile + 1043 876b PRIME Motherboard 1458 d000 Radeon RX Vega 11 + ea50 cc10 RXi2-BP 15de Raven/Raven2/Fenghuang HDMI/DP Audio Controller 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME B450M-A Motherboard 17aa 5124 ThinkPad E595 + ea50 cc10 RXi2-BP 15df Raven/Raven2/Fenghuang/Renoir Cryptographic Coprocessor 103c 8615 Pavilion Laptop 15-cw1xxx + ea50 ce19 mCOM10-L1900 15ff Fenghuang [Zhongshan Subor Z+] 1607 Arden 1636 Renoir + 1638 Cezanne + 163f VanGogh + 164c Lucienne 1714 BeaverCreek HDMI Audio [Radeon HD 6500D and 6400G-6600G series] 103c 168b ProBook 4535s 3150 RV380/M24 [Mobility Radeon X600] @@ -1150,6 +1172,7 @@ 1179 ff50 Satellite P305D-S8995E 1458 a022 GA-MA770-DS3rev2.0 Motherboard 1458 a102 GA-880GMA-USB3 + 1462 7596 760GM-E51(MS-7596) Motherboard 17f2 5000 KI690-AM2 Motherboard 4384 SBx00 PCI to PCI Bridge 4385 SBx00 SMBus Controller @@ -1162,6 +1185,7 @@ 1179 ff50 Satellite P305D-S8995E 1458 4385 GA-MA770-DS3rev2.0 Motherboard 1462 7368 K9AG Neo2 + 1462 7596 760GM-E51(MS-7596) Motherboard 15d9 a811 H8DGU 174b 1001 PURE Fusion Mini 17f2 5000 KI690-AM2 Motherboard @@ -1212,6 +1236,7 @@ 1043 8389 M4A785TD Motherboard 105b 0e13 N15235/A74MX mainboard / AMD SB700 1458 b002 GA-MA770-DS3rev2.0 Motherboard + 1462 7596 760GM-E51(MS-7596) Motherboard 1849 4390 Motherboard (one of many) 4391 SB7x0/SB8x0/SB9x0 SATA Controller [AHCI mode] 103c 1609 ProLiant MicroServer N36L @@ -1235,6 +1260,7 @@ 1043 8443 M5A88-V EVO 105b 0e13 N15235/A74MX mainboard / AMD SB700 1458 5004 GA-880GMA-USB3 + 1462 7596 760GM-E51(MS-7596) Motherboard 15d9 a811 H8DGU 174b 1001 PURE Fusion Mini 4397 SB7x0/SB8x0/SB9x0 USB OHCI0 Controller @@ -1245,12 +1271,14 @@ 1043 8443 M5A88-V EVO 105b 0e13 N15235/A74MX mainboard / AMD SB700 1458 5004 GA-880GMA-USB3 + 1462 7596 760GM-E51(MS-7596) Motherboard 15d9 a811 H8DGU 174b 1001 PURE Fusion Mini 4398 SB7x0 USB OHCI1 Controller 1019 2120 A785GM-M 1043 82ef M3A78-EH Motherboard 105b 0e13 N15235/A74MX mainboard / AMD SB700 + 1462 7596 760GM-E51(MS-7596) Motherboard 15d9 a811 H8DGU 4399 SB7x0/SB8x0/SB9x0 USB OHCI2 Controller 1019 2120 A785GM-M @@ -1258,6 +1286,7 @@ 1043 8443 M5A88-V EVO 105b 0e13 N15235/A74MX mainboard / AMD SB700 1458 5004 GA-880GMA-USB3 + 1462 7596 760GM-E51(MS-7596) Motherboard 174b 1001 PURE Fusion Mini 439c SB7x0/SB8x0/SB9x0 IDE Controller 1002 4392 MSI MS-7713 motherboard @@ -1265,6 +1294,7 @@ 103c 1609 ProLiant MicroServer N36L 1043 82ef M3A78-EH Motherboard 105b 0e13 N15235/A74MX mainboard / AMD SB700 + 1462 7596 760GM-E51(MS-7596) Motherboard 439d SB7x0/SB8x0/SB9x0 LPC host controller 1019 2120 A785GM-M 103c 1609 ProLiant MicroServer N36L @@ -1272,6 +1302,7 @@ 1043 82ef M3A78-EH Motherboard 1043 8443 M5A88-V EVO 105b 0e13 N15235/A74MX mainboard / AMD SB700 + 1462 7596 760GM-E51(MS-7596) Motherboard 174b 1001 PURE Fusion Mini 43a0 SB700/SB800/SB900 PCI to PCI bridge (PCIE port 0) 43a1 SB700/SB800/SB900 PCI to PCI bridge (PCIE port 1) @@ -1757,7 +1788,7 @@ 5964 RV280 [Radeon 9200 SE] 1002 5964 Radeon 9200 SE, 64-bit 128MB DDR, 200/166MHz 1043 c006 Radeon 9200 SE / TD / 128M - 1458 4018 Radeon 9200 SE + 1458 4018 R92S128T (Radeon 9200 SE 128MB) 1458 4032 Radeon 9200 SE 128MB 147b 6191 R9200SE-DT 148c 2073 CN-AG92E @@ -1846,7 +1877,7 @@ 1002 5c63 Apple iBook G4 2004 144d c00c P30 notebook 5d44 RV280 [Radeon 9200 SE] (Secondary) - 1458 4019 Radeon 9200 SE (Secondary) + 1458 4019 R92S128T (Radeon 9200 SE 128MB Secondary) 1458 4032 Radeon 9200 SE 128MB 147b 6190 R9200SE-DT (Secondary) 174b 7c12 Radeon 9200 SE (Secondary) @@ -1883,7 +1914,7 @@ 5e6d RV410 [Radeon X700] (Secondary) 148c 2117 Bravo X700 (Secondary) 5f57 R423 [Radeon X800 XT] - 6600 Mars [Radeon HD 8670A/8670M/8750M] + 6600 Mars [Radeon HD 8670A/8670M/8750M / R7 M370] 103c 1952 ProBook 455 G1 6601 Mars [Radeon HD 8730M] 103c 2100 FirePro M4100 @@ -1900,8 +1931,11 @@ 6607 Mars LE [Radeon HD 8530M / R5 M240] 6608 Oland GL [FirePro W2100] 13cc 3d28 MXRT-2600 - 6610 Oland XT [Radeon HD 8670 / R7 250/350] + 6609 Oland GL [FirePro W2100 / Barco MXRT 2600] + 6610 Oland XT [Radeon HD 8670 / R5 340X OEM / R7 250/350/350X OEM] 1019 0030 Radeon HD 8670 + 1028 0081 Radeon R7 350X OEM + 1028 0083 Radeon R5 340X OEM 1028 2120 Radeon R7 250 1028 2322 Radeon R7 250 1462 2910 Radeon HD 8670 @@ -1911,7 +1945,15 @@ 1642 3c91 Radeon HD 8670 1642 3f09 Radeon R7 350 6611 Oland [Radeon HD 8570 / R5 430 OEM / R7 240/340 / Radeon 520 OEM] + 1028 1001 Radeon R5 430 OEM (1024 MByte) + 1028 1002 Radeon R5 430 OEM (2048 MByte) +# The 'AMD Radeon R5 430' instead of 240/340 is NOT a typo! It's actually correct. + 1028 1711 R5 430 OEM (2048 MByte) 1028 210b Radeon R5 240 OEM +# OEM-card for Dell; verified through AMD's own drivers (*.inf) and a TPU BIOS in database + 1028 2121 Radeon HD 8570 OEM +# OEM-card from Fujitsu; verified through AMD's own drivers (*.inf) + 10cf 1889 Radeon HD 8570 OEM 1642 1869 Radeon 520 OEM 174b 4248 Radeon R7 240 OEM 174b a240 Radeon R7 240 OEM @@ -1985,9 +2027,9 @@ 6667 Jet ULT [Radeon R5 M230] 666f Sun LE [Radeon HD 8550M / R5 M230] 66a0 Vega 20 [Radeon Instinct] - 66a1 Vega 20 + 66a1 Vega 20 WKS GL-XE [Radeon Pro VII] 66a2 Vega 20 - 66a3 Vega 20 + 66a3 Vega 20 [Radeon Pro Vega II/Radeon Pro Vega II Duo] 66a7 Vega 20 [Radeon Pro Vega 20] 66af Vega 20 [Radeon VII] 6704 Cayman PRO GL [FirePro V7900] @@ -2181,7 +2223,7 @@ 8086 2111 Radeon HD 6625M 6743 Whistler [Radeon E6760] 6749 Turks GL [FirePro V4900] - 15c3 2b06 MED-X4900 + 15c3 2b06 MED-X4900 (EIZO) 674a Turks GL [FirePro V3900] 13cc 3d22 MXRT-2500 15c3 0106 MED-X3900 @@ -2210,7 +2252,7 @@ 174b 7670 Radeon HD 7670 174b e181 Radeon HD 6670 1787 2309 Radeon HD 6670 - 6759 Turks PRO [Radeon HD 6570/7570/8550] + 6759 Turks PRO [Radeon HD 6570/7570/8550 / R5 230] 103c 3130 Radeon HD 6570 1043 0403 Radeon HD 6570 1462 2500 Radeon HD 6570 @@ -2219,9 +2261,15 @@ 1642 3a67 Radeon HD 6570 1682 3280 Radeon HD 7570 1682 3530 Radeon HD 8550 + 1682 5230 Radeon R5 230 series + 1682 6450 Radeon HD 6450 series 174b 7570 Radeon HD 7570 + 174b 8550 Radeon HD8550 OEM + 174b 8570 Radeon HD8550 OEM 174b e142 Radeon HD 6570 174b e181 Radeon HD 6570 + 1787 a230 Radeon R5 230 series + 1787 a450 Radeon HD 6450 series 1b0a 908f Radeon HD 6570 1b0a 9090 Radeon HD 6570 1b0a 9091 Radeon HD 6570 @@ -2579,6 +2627,7 @@ 1043 04dd STRIX R9 390 148c 2358 Radeon R9 390 174b e324 Sapphire Nitro R9 390 + 67b8 Hawaii XT [Radeon R9 290X Engineering Sample] 67b9 Vesuvius [Radeon R9 295X2] 67be Hawaii LE 67c0 Ellesmere [Radeon Pro WX 7100 Mobile] @@ -2614,6 +2663,7 @@ 1462 3418 Radeon RX 580 Armor 4G OC 1462 341b Radeon RX 570 Armor 8G OC 1462 341e Radeon RX 570 Armor 4G OC + 1462 809e Radeon RX 480 4GB 1462 8a92 Radeon RX 580 148c 2372 Radeon RX 480 [Red Dragon] 148c 2373 Radeon RX 470 @@ -2623,6 +2673,7 @@ 148c 2379 Radeon RX 570 4G [Red Dragon] 1682 9470 Radeon RX 470 1682 9480 Radeon RX 480 + 1682 9587 Radeon RX 590 FATBOY 8GB 1682 9588 Radeon RX 580 XTR 1682 c570 Radeon RX 570 1682 c580 Radeon RX 580 @@ -2894,11 +2945,17 @@ 6864 Vega 10 [Radeon Pro V340] 6867 Vega 10 XL [Radeon Pro Vega 56] 6868 Vega 10 [Radeon PRO WX 8100/8200] + 6869 Vega 10 XGA [Radeon Pro Vega 48] + 686a Vega 10 LEA + 686b Vega 10 XTXA [Radeon Pro Vega 64X] 686c Vega 10 [Radeon Instinct MI25 MxGPU] + 686d Vega 10 GLXTA + 686e Vega 10 GLXLA 687f Vega 10 XL/XT [Radeon RX Vega 56/64] 1002 0b36 RX Vega64 1002 6b76 RX Vega64 1458 230c Radeon RX VEGA 56 GAMING OC 8G + 1da2 e376 Radeon RX VEGA 56 Pulse 8GB OC HBM2 6880 Lexington [Radeon HD 6550M] 103c 163c Pavilion dv6 Radeon HD 6550M 6888 Cypress XT [FirePro V8800] @@ -3144,6 +3201,7 @@ 17af 3000 Radeon HD 6510 17af 3010 Radeon HD 5630 68da Redwood LE [Radeon HD 5550/5570/5630/6390/6490/7570] + 1462 8071 VR5550-MD1G (Radeon HD 5550) 148c 3000 Radeon HD 6390 148c 3001 Radeon HD 6490 1545 7570 Radeon HD 7570 @@ -3582,18 +3640,31 @@ 174b e329 Radeon R9 FURY 7310 Navi 10 [Radeon Pro W5700X] 7312 Navi 10 [Radeon Pro W5700] + 7314 Navi 10 USB 731f Navi 10 [Radeon RX 5600 OEM/5600 XT / 5700/5700 XT] 1458 2313 Radeon RX 5700 XT Gaming OC + 1682 5701 RX 5700 XT RAW II 1da2 e411 Radeon RX 5600 XT 7340 Navi 14 [Radeon RX 5500/5500M / Pro 5500M] 7341 Navi 14 [Radeon Pro W5500] 7347 Navi 14 [Radeon Pro W5500M] 734f Navi 14 [Radeon Pro W5300M] - 7360 Navi 12 [Radeon Pro 5600M] + 7360 Navi 12 [Radeon Pro 5600M / V520] + 7362 Navi 12 [Radeon Pro V520] + 7388 Arcturus GL-XL + 738c Arcturus GL-XL [AMD Instinct MI100] + 738e Arcturus GL-XL + 73a4 Navi 21 USB + 73af Navi 21 [Radeon RX 6900 XT] 73bf Navi 21 [Radeon RX 6800/6800 XT / 6900 XT] + 1eae 6701 XFX Speedster MERC 319 AMD Radeon RX 6800 XT Black 73c3 Navi 22 - 73df Navi 22 - 73ff Navi 23 + 73c4 Navi 22 USB + 73df Navi 22 [Radeon RX 6700/6700 XT / 6800M] + 73e0 Navi 23 + 73e1 Navi 23 + 73e4 Navi 23 USB + 73ff Navi 23 [Radeon RX 6600/6600 XT] 7833 RS350 Host Bridge 7834 RS350 [Radeon 9100 PRO/XT IGP] 7835 RS350M [Mobility Radeon 9000 IGP] @@ -3801,6 +3872,7 @@ 95cd RV620 GL [FirePro 2450] 95cf RV620 GL [FirePro 2260] 960f RS780 HDMI Audio [Radeon 3000/3100 / HD 3200/3300] + 1462 7596 760GM-E51(MS-7596) Motherboard 9610 RS780 [Radeon HD 3200] 1458 d000 GA-MA78GM-S2H Motherboard 9611 RS780C [Radeon 3100] @@ -3809,6 +3881,8 @@ 9614 RS780D [Radeon HD 3300] 9615 RS780E [Radeon HD 3200] 9616 RS780L [Radeon 3000] +# ID is probably a copy-paste error by a MSI developer from another mainboard, since all other ID numbers on this mainboard including the sub-device of this device has used subsystem ID 1462:7596 + 1462 7501 760GM-E51(MS-7596) Motherboard 9640 Sumo [Radeon HD 6550D] 9641 Sumo [Radeon HD 6620G] 9642 SuperSumo [Radeon HD 6370D] @@ -3848,6 +3922,7 @@ 9809 Wrestler [Radeon HD 7310] 980a Wrestler [Radeon HD 7290] 9830 Kabini [Radeon HD 8400 / R3 Series] + 1043 8623 AM1I-A Motherboard 9831 Kabini [Radeon HD 8400E] 9832 Kabini [Radeon HD 8330] 1849 9832 QC5000-ITX/PH @@ -3860,6 +3935,7 @@ 9839 Kabini [Radeon HD 8180] 983d Temash [Radeon HD 8250/8280G] 9840 Kabini HDMI/DP Audio + 1043 8623 AM1I-A Motherboard 1849 9840 QC5000-ITX/PH 9850 Mullins [Radeon R3 Graphics] 9851 Mullins [Radeon R4/R5 Graphics] @@ -4141,12 +4217,12 @@ 2646 0001 KNE100TX Fast Ethernet 000a 21230 Video Codec 000d PBXGB [TGA2] - 000f DEFPA FDDI PCI-to-PDQ Interface Chip [PFI] - 1011 def1 FDDI controller (DEFPA) - 103c def1 FDDI controller (3X-DEFPA) + 000f PCI-to-PDQ Interface Chip [PFI] FDDI (DEFPA) + 1011 def1 FDDIcontroller/PCI (DEFPA) + 103c def1 FDDIcontroller/PCI (3X-DEFPA) 0014 DECchip 21041 [Tulip Pass 3] 1186 0100 DE-530+ - 0016 DGLPB [OPPO] + 0016 ATMworks 350 Adapter [OPPO] (DGLPB) 0017 PV-PCI Graphics Controller (ZLXp-L) 0018 Memory Channel interface 0019 DECchip 21142/43 @@ -4609,6 +4685,7 @@ 1450 Family 17h (Models 00h-0fh) Root Complex 1451 Family 17h (Models 00h-0fh) I/O Memory Management Unit 1452 Family 17h (Models 00h-1fh) PCIe Dummy Host Bridge + ea50 ce19 mCOM10-L1900 1453 Family 17h (Models 00h-0fh) PCIe GPP Bridge 1454 Family 17h (Models 00h-0fh) Internal PCIe GPP Bridge 0 to Bus B 1455 Zeppelin/Renoir PCIe Dummy Function @@ -4663,6 +4740,7 @@ 149b Starship Reserved SSP 149c Matisse USB 3.0 Host Controller 1462 7c37 X570-A PRO motherboard + 149d Vangogh CVIP 1510 Family 14h Processor Root Complex 174b 1001 PURE Fusion Mini 1512 Family 14h Processor Root Port @@ -4677,6 +4755,7 @@ 1534 Family 16h Processor Function 4 1535 Family 16h Processor Function 5 1536 Family 16h Processor Root Complex + 1043 8623 AM1I-A Motherboard 1849 1536 QC5000-ITX/PH 1537 Kabini/Mullins PSP-Platform Security Processor 1538 Family 16h Processor Function 0 @@ -4747,28 +4826,40 @@ 15be Stoney Audio Processor 15d0 Raven/Raven2 Root Complex 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME B450M-A Motherboard 15d1 Raven/Raven2 IOMMU 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME B450M-A Motherboard + ea50 ce19 mCOM10-L1900 15d2 Raven/Raven2 PCIe Dummy Host Bridge 15d3 Raven/Raven2 PCIe GPP Bridge [6:0] 15d4 FireFlight USB 3.1 15d5 FireFlight USB 3.1 15da Raven/Raven2 PCIe Dummy Host Bridge 15db Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus A + ea50 ce19 mCOM10-L1900 15dc Raven/Raven2 Internal PCIe GPP Bridge 0 to Bus B + ea50 ce19 mCOM10-L1900 15de Raven/Raven2/FireFlight HD Audio Controller 15df Family 17h (Models 10h-1fh) Platform Security Processor + 1043 876b PRIME Motherboard 17aa 5124 ThinkPad E595 + ea50 ce19 mCOM10-L1900 15e0 Raven USB 3.1 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME Motherboard 17aa 5124 ThinkPad E595 + ea50 ce19 mCOM10-L1900 15e1 Raven USB 3.1 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME Motherboard 17aa 5124 ThinkPad E595 + ea50 ce19 mCOM10-L1900 15e2 Raven/Raven2/FireFlight/Renoir Audio Processor 17aa 5124 ThinkPad E595 15e3 Family 17h (Models 10h-1fh) HD Audio Controller 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 86c7 PRIME B450M-A Motherboard 17aa 5124 ThinkPad E595 15e4 Raven/Raven2/Renoir Sensor Fusion Hub 15e5 Raven2 USB 3.1 @@ -4837,6 +4928,8 @@ 1642 Renoir WLAN 1643 Renoir BT 1644 Renoir I2S + 1648 VanGogh Root Complex + 1649 VanGogh PSP/CCP 1700 Family 12h/14h Processor Function 0 1701 Family 12h/14h Processor Function 1 1702 Family 12h/14h Processor Function 2 @@ -4877,7 +4970,8 @@ 4c53 1030 PC5 mainboard 4c53 1040 CL7 mainboard 4c53 1060 PC7 mainboard - 2001 79c978 [HomePNA] +# Via AMD's own technical reference on their Am79C978 NICs; https://www.amd.com/system/files/TechDocs/22206.pdf + 2001 Am79C978 PCnet Home (HomePNA) 1/10 PCI Ethernet Adapter [Am79C971 PHY] 1092 0a78 Multimedia Home Network Adapter 1668 0299 ActionLink Home Network Adapter 2003 Am 1771 MBW [Alchemy] @@ -4896,6 +4990,8 @@ 2096 CS5536 [Geode companion] UDC 2097 CS5536 [Geode companion] UOC 209a CS5536 [Geode companion] IDE + 2625 Am79C973 [Lance/PCI PCNet/32] + 2627 Am79C975 [Lance/PCI PCNet/32] 3000 ELanSC520 Microcontroller 43a0 Hudson PCI to PCI bridge (PCIE port 0) 43a1 Hudson PCI to PCI bridge (PCIE port 1) @@ -4978,6 +5074,7 @@ 7801 FCH SATA Controller [AHCI mode] 103c 168b ProBook 4535s Notebook 103c 194e ProBook 455 G1 Notebook + 1043 8623 AM1I-A Motherboard 17aa 3988 Z50-75 1849 7801 QC5000-ITX/PH 7802 FCH SATA Controller [RAID mode] @@ -4989,11 +5086,13 @@ 7807 FCH USB OHCI Controller 103c 194e ProBook 455 G1 Notebook 103c 1985 Pavilion 17-e163sg Notebook PC + 1043 8623 AM1I-A Motherboard 17aa 3988 Z50-75 1849 7807 QC5000-ITX/PH 7808 FCH USB EHCI Controller 103c 194e ProBook 455 G1 Notebook 103c 1985 Pavilion 17-e163sg Notebook PC + 1043 8623 AM1I-A Motherboard 17aa 3988 Z50-75 1849 7808 QC5000-ITX/PH 7809 FCH USB OHCI Controller @@ -5003,6 +5102,7 @@ 780b FCH SMBus Controller 103c 194e ProBook 455 G1 Notebook 103c 1985 Pavilion 17-e163sg Notebook PC + 1043 8623 AM1I-A Motherboard 17aa 3988 Z50-75 1849 780b QC5000-ITX/PH 780c FCH IDE Controller @@ -5010,11 +5110,13 @@ 103c 194e ProBook 455 G1 Notebook 103c 1985 Pavilion 17-e163sg Notebook PC 1043 8444 F2A85-M Series + 1043 8576 AM1I-A Motherboard 17aa 3988 Z50-75 1849 8892 QC5000-ITX/PH 780e FCH LPC Bridge 103c 194e ProBook 455 G1 Notebook 103c 1985 Pavilion 17-e163sg Notebook PC + 1043 8623 AM1I-A Motherboard 17aa 3988 Z50-75 1849 780e QC5000-ITX/PH 780f FCH PCI Bridge @@ -5023,12 +5125,15 @@ 7814 FCH USB XHCI Controller 103c 194e ProBook 455 G1 Notebook 103c 1985 Pavilion 17-e163sg Notebook PC + 1043 8623 AM1I-A Motherboard 17aa 3988 Z50-75 1849 7814 QC5000-ITX/PH 7900 FCH SATA Controller [IDE mode] 7901 FCH SATA Controller [AHCI mode] 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME Motherboard 1462 7c37 X570-A PRO motherboard + ea50 ce19 mCOM10-L1900 7902 FCH SATA Controller [RAID mode] 7903 FCH SATA Controller [RAID mode] 7904 FCH SATA Controller [AHCI mode] @@ -5036,12 +5141,16 @@ 7908 FCH USB EHCI Controller 790b FCH SMBus Controller 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME Motherboard 1462 7c37 X570-A PRO motherboard 17aa 5124 ThinkPad E595 + ea50 ce19 mCOM10-L1900 790e FCH LPC Bridge 103c 8615 Pavilion Laptop 15-cw1xxx + 1043 876b PRIME B450M-A Motherboard 1462 7c37 X570-A PRO motherboard 17aa 5124 ThinkPad E595 + ea50 ce19 mCOM10-L1900 790f FCH PCI Bridge 7914 FCH USB XHCI Controller 9600 RS780 Host Bridge @@ -5626,6 +5735,7 @@ 1931 000a GlobeTrotter Fusion Quad Lite (PPP data) 1931 000b GlobeTrotter Fusion Quad Lite (GSM data) 807d 0035 PCI-USB2 (OHCI subsystem) + 8086 4d44 D850EMV2 motherboard 003b PCI to C-bus Bridge 003e NAPCCARD Cardbus Controller 0046 PowerVR PCX2 [midas] @@ -5656,6 +5766,7 @@ 14c2 0205 PTI-205N USB 2.0 Host Controller 1799 0002 Root Hub 807d 1043 PCI-USB2 (EHCI subsystem) + 8086 4d44 D850EMV2 motherboard 00e7 uPD72873 [Firewarden] IEEE1394a OHCI 1.1 Link/2-port PHY Controller 00f2 uPD72874 [Firewarden] IEEE1394a OHCI 1.1 Link/3-port PHY Controller 00f3 uPD6113x Multimedia Decoder/Processor [EMMA2] @@ -6830,6 +6941,7 @@ 0003 Control Video 0004 PlanB Video-In 0007 O'Hare I/O + 000b Apple Camera 000c DOS on Mac 000e Hydra Mac I/O 0010 Heathrow Mac I/O @@ -7000,6 +7112,7 @@ 103c 17e8 SN1000Q 16Gb Dual Port Fibre Channel Adapter 103c 1939 QMH2672 16Gb Dual Port Fibre Channel Adapter 103c 8002 3830C 16G Fibre Channel Host Bus Adapter + 1077 0241 QLE2670 16Gb Single Port Fibre Channel Adapter 2071 ISP2714-based 16/32Gb Fibre Channel to PCIe Adapter 1077 0283 QLE2764 Quad Port 32Gb Fibre Channel to PCIe Adapter 1077 029e QLE2694 Quad Port 16Gb Fibre Channel to PCIe Adapter @@ -7008,6 +7121,9 @@ 2081 ISP2814-based 64/32G Fibre Channel to PCIe Controller 1077 02e1 QLE2874 Quad Port 64GFC PCIe Gen4 x16 Adapter 1077 02e3 QLE2774 Quad Port 32GFC PCIe Gen4 x16 Adapter + 2089 ISP2854-based 64/32G Fibre Channel to PCIe Controller with StorCryption + 1077 02e8 QLE2884 Quad Port 64GFC PCIe Gen4 x16 Adapter with StorCryption + 1077 02ea QLE2784 Quad Port 32GFC PCIe Gen4 x16 Adapter with StorCryption 2100 QLA2100 64-bit Fibre Channel Adapter 1077 0001 QLA2100 64-bit Fibre Channel Adapter 2200 QLA2200 64-bit Fibre Channel Adapter @@ -7028,6 +7144,7 @@ 1590 0203 StoreFabric SN1600Q 32Gb Single Port Fibre Channel Host Bus Adapter 1590 0204 StoreFabric SN1600Q 32Gb Dual Port Fibre Channel Host Bus Adapter 1590 022d 5830C 32Gb Dual Port Fibre Channel Adapter + 193d 100d NIC-FC680i-Mb-2x16G 2281 ISP2812-based 64/32G Fibre Channel to PCIe Controller 1077 02e2 QLE2872 Dual Port 64GFC PCIe Gen4 x8 Adapter 1077 02e4 QLE2772 Dual Port 32GFC PCIe Gen4 x8 Adapter @@ -7037,6 +7154,11 @@ 1077 02f3 QLogic 2x32Gb QLE2772 FC HBA 1590 02d3 SN1610Q - 1P Enhanced 32GFC Single Port Fibre Channel Host Bus Adapter 1590 02d4 SN1610Q – 2P Enhanced 32GFC Dual Port Fibre Channel Host Bus Adapter + 2289 ISP2852-based 64/32G Fibre Channel to PCIe Controller with StorCryption + 1077 02e9 QLE2882 Dual Port 64GFC PCIe Gen4 x8 Adapter with StorCryption + 1077 02eb QLE2782 Dual Port 32GFC PCIe Gen4 x8 Adapter with StorCryption + 1077 02ef QLE2880 Single Port 64GFC PCIe Gen4 x8 Adapter with StorCryption + 1077 02f1 QLE2780 Single Port 32GFC PCIe Gen4 x8 Adapter with StorCryption 2300 QLA2300 64-bit Fibre Channel Adapter 2312 ISP2312-based 2Gb Fibre Channel to PCI-X HBA 103c 0131 2Gb Fibre Channel - Single port [A7538A] @@ -7129,6 +7251,8 @@ 1590 021f 10/25GbE 2P QL41262HMCU-HP Adapter 1590 0220 10/25GbE 2P QL41122HLRJ-HP Adapter 1590 02bd 10Gb 2P 524SFP+ NIC + 193d 1030 NIC-ETH681i-Mb-2x25G + 193d 1032 NIC-ETH682i-Mb-2x25G 8080 FastLinQ QL41000 Series 10/25/40/50GbE Controller (FCoE) 1077 0001 10GE 2P QL41162HxRJ-DE Adapter 1077 0002 10GE 2P QL41112HxCU-DE Adapter @@ -8567,6 +8691,7 @@ 10b5 2905 Alpermann+Velte PCI TS: Time Synchronisation Board 10b5 3196 Goramo PLX200SYN sync serial card 10b5 9050 PCI-I04 PCI Passive PC/CAN Interface + 12fe 0001 CAN-PCI/331 CAN bus controller 1369 8901 PCX11+ PCI 1369 8f01 VX222 1369 9401 PCX924 @@ -9975,7 +10100,7 @@ 0331 NV35 [GeForce FX 5900] 1043 8145 V9950GE 0332 NV35 [GeForce FX 5900XT] - 0333 NV38 [GeForce FX 5950 Ultra] + 0333 NV38 [GeForce FX 5950 Ultra / PCX 5950] 0334 NV35 [GeForce FX 5900ZT] 1462 9373 FX5900ZT-VTD128 (MS-8937) 0338 NV35GL [Quadro FX 3000] @@ -10737,6 +10862,7 @@ 0a21 GT216M [GeForce GT 330M] 0a22 GT216 [GeForce 315] 0a23 GT216 [GeForce 210] + 0a24 GT216 [GeForce 405] 0a26 GT216 [GeForce 405] 0a27 GT216 [GeForce 405] 0a28 GT216M [GeForce GT 230M] @@ -11871,6 +11997,7 @@ 1aeb TU116 High Definition Audio Controller 1aec TU116 USB 3.1 Host Controller 1aed TU116 USB Type-C UCSI Controller + 1aef GA102 High Definition Audio Controller 1b00 GP102 [TITAN X] 1b01 GP102 [GeForce GTX 1080 Ti 10GB] 1b02 GP102 [TITAN Xp] @@ -11879,6 +12006,7 @@ 1b07 GP102 [P102-100] 1b30 GP102GL [Quadro P6000] 1b38 GP102GL [Tesla P40] + 1b39 GP102GL [Tesla P10] 1b70 GP102GL 1b78 GP102GL 1b80 GP104 [GeForce GTX 1080] @@ -11933,8 +12061,8 @@ 1c2d GP106M 1c30 GP106GL [Quadro P2000] 1c31 GP106GL [Quadro P2200] - 1c35 GP106 - 1c36 GP106 + 1c35 GP106M [Quadro P2000 Mobile] + 1c36 GP106 [P106M] 1c60 GP106BM [GeForce GTX 1060 Mobile 6GB] 103c 8390 GeForce GTX 1060 Max-Q 6GB 1c61 GP106BM [GeForce GTX 1050 Ti Mobile] @@ -12055,6 +12183,7 @@ 1f08 TU106 [GeForce RTX 2060 Rev. A] 1f09 TU106 [GeForce GTX 1660 SUPER] 1f0a TU106 [GeForce GTX 1650] + 1f0b TU106 [CMP 40HX] 1f10 TU106M [GeForce RTX 2070 Mobile] 1f11 TU106M [GeForce RTX 2060 Mobile] 1f12 TU106M [GeForce RTX 2060 Max-Q] @@ -12080,14 +12209,17 @@ 1f98 TU117M [GeForce MX450] 1f99 TU117M 1f9c TU117M [GeForce MX450] + 1f9d TU117M [GeForce GTX 1650 Mobile / Max-Q] 1fae TU117GL 1fb8 TU117GLM [Quadro T2000 Mobile / Max-Q] 1fb9 TU117GLM [Quadro T1000 Mobile] + 1fbb TU117GLM [Quadro T500 Mobile] 1fbf TU117GL 1fd9 TU117BM [GeForce GTX 1650 Mobile Refresh] 1ff9 TU117GLM [Quadro T1000 Mobile] 20b0 GA100 [A100 SXM4 40GB] 20b1 GA100 [A100 PCIe 40GB] + 20b2 GA100 [A100 SXM4 80GB] 20be GA100 [GRID A100A] 20bf GA100 [GRID A100B] 20f1 GA100 [A100 PCIe 40GB] @@ -12096,34 +12228,59 @@ 2184 TU116 [GeForce GTX 1660] 2187 TU116 [GeForce GTX 1650 SUPER] 2188 TU116 [GeForce GTX 1650] + 2189 TU116 [CMP 30HX] 2191 TU116M [GeForce GTX 1660 Ti Mobile] 2192 TU116M [GeForce GTX 1650 Ti Mobile] 21ae TU116GL 21bf TU116GL + 21c2 TU116 21c4 TU116 [GeForce GTX 1660 SUPER] 21d1 TU116BM [GeForce GTX 1660 Ti Mobile] + 2200 GA102 2204 GA102 [GeForce RTX 3090] + 2205 GA102 [GeForce RTX 3080 20GB] 2206 GA102 [GeForce RTX 3080] + 10de 1467 GA102 [GeForce RTX 3080] 10de 146d GA102 [GeForce RTX 3080 20GB] 1462 3892 RTX 3080 10GB GAMING X TRIO + 2208 GA102 [GeForce RTX 3080 Ti] 222b GA102 [GeForce RTX 3090 Engineering Sample] 222f GA102 [GeForce RTX 3080 11GB / 12GB Engineering Sample] 2230 GA102GL [RTX A6000] + 2231 GA102GL + 2235 GA102GL [RTX A40] + 2236 GA102GL + 2237 GA102GL 223f GA102GL + 228b GA104 High Definition Audio Controller + 2302 GA103 + 2321 GA103 2482 GA104 [GeForce RTX 3070 Ti] 2484 GA104 [GeForce RTX 3070] 10de 146b GA104 [GeForce RTX 3070] 10de 14ae GA104 [GeForce RTX 3070 16GB] 2486 GA104 [GeForce RTX 3060 Ti] - 249c GA104M [GeForce RTX 3070 Mobile / Max-Q 8GB/16GB] + 249c GA104M [GeForce RTX 3080 Mobile / Max-Q 8GB/16GB] 249d GA104M [GeForce RTX 3070 Mobile / Max-Q] + 249f GA104M 24ac GA104 [GeForce RTX 30x0 Engineering Sample] 24ad GA104 [GeForce RTX 3060 Engineering Sample] 24af GA104 [GeForce RTX 3070 Engineering Sample] + 24b6 GA104 + 24b8 GA104 24bf GA104 [GeForce RTX 3070 Engineering Sample] - 24dc GA104M [GeForce RTX 3070 Mobile 16GB] + 24dc GA104M [GeForce RTX 3080 Mobile / Max-Q 8GB/16GB] 24dd GA104M [GeForce RTX 3070 Mobile / Max-Q] + 2501 GA106 [GeForce RTX 3060] + 2503 GA106 [GeForce RTX 3060] + 2505 GA106 + 2520 GA106M [GeForce RTX 3060 Mobile / Max-Q] 252f GA106 [GeForce RTX 3060 Engineering Sample] + 2560 GA106M [GeForce RTX 3060 Mobile / Max-Q] + 2583 GA107 [GeForce RTX 3050] + 25a0 GA107M [GeForce RTX 3050 Ti Mobile] + 25a2 GA107M [GeForce RTX 3050 Mobile] + 25a4 GA107 25af GA107 [GeForce RTX 3050 Engineering Sample] 10df Emulex Corporation 0720 OneConnect NIC (Skyhawk) @@ -12185,6 +12342,7 @@ 1590 0213 StoreFabric SN1200E 1-Port 16Gb Fibre Channel Adapter 1590 0214 StoreFabric SN1200E 2-Port 16Gb Fibre Channel Adapter 1590 022e Synergy 5330C 2-Port 32Gb Fibre Channel Mezz Card + 193d 1060 NIC-FC730i-Mb-2P f011 Saturn: LightPulse Fibre Channel Host Adapter f015 Saturn: LightPulse Fibre Channel Host Adapter f085 LP850 Fibre Channel Host Adapter @@ -12219,6 +12377,7 @@ 10df f419 LPe35002-M2-L 2-Port 32Gb PCIe Fibre Channel Adapter 1590 02d5 StoreFabric SN1610E 1-Port 32Gb Fibre Channel Adapter 1590 02d6 StoreFabric SN1610E 2-Port 32Gb Fibre Channel Adapter + f500 LPe37000/LPe38000 Series 32Gb/64Gb Fibre Channel Adapter f700 LP7000 Fibre Channel Host Adapter f701 LP7000 Fibre Channel Host Adapter Alternate ID (JX1:2-3, JX2:1-2) f800 LP8000 Fibre Channel Host Adapter @@ -12326,6 +12485,7 @@ 8111 Twist3 Frame Grabber 10ec Realtek Semiconductor Co., Ltd. 0139 RTL-8139/8139C/8139C+ Ethernet Controller + 3000 Killer E3000 2.5GbE Controller 5208 RTS5208 PCI Express Card Reader 5209 RTS5209 PCI Express Card Reader 5227 RTS5227 PCI Express Card Reader @@ -12348,6 +12508,7 @@ 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 1028 06e4 XPS 15 9550 + 1028 06e6 Latitude 11 5175 2-in-1 17aa 224f ThinkPad X1 Carbon 5th Gen 5260 RTS5260 PCI Express Card Reader 5286 RTS5286 PCI Express Card Reader @@ -12429,6 +12590,8 @@ 8e2e 7000 KF-230TX 8e2e 7100 KF-230TX/2 a0a0 0007 ALN-325C + 8161 RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller + 10ec 8168 TP-Link TG-3468 v4.0 Gigabit PCI Express Network Adapter 8167 RTL-8110SC/8169SC Gigabit Ethernet 105b 0e10 RTL-8110SC-GR on a N15235/A74MX mainboard 1458 e000 GA-MA69G-S3H Motherboard @@ -12440,6 +12603,7 @@ 1028 0283 Vostro 220 1028 04b2 Vostro 3350 1028 04da Vostro 3750 + 1028 05d7 Alienware X51 R2 1028 06f2 Latitude 3470 1028 06f3 Latitude 3570 1028 0869 Vostro 3470 @@ -12455,6 +12619,9 @@ 1043 83a3 M4A785/P7P55 Motherboard 1043 8432 P8P67 and other motherboards 1043 8505 P8 series motherboard + 1043 8554 H81M-C Motherboard + 1043 859e AM1I-A Motherboard + 1043 8677 PRIME B450M-A Motherboard 105b 0d7c D270S/D250S Motherboard 10ec 8168 RTL8111/8168 PCI Express Gigabit Ethernet controller 144d c652 RTL8168 on a NP300E5C series laptop @@ -12466,6 +12633,7 @@ 1462 7522 X58 Pro-E 1462 7c37 X570-A PRO motherboard 1775 11cc CC11/CL11 + 17aa 3098 ThinkCentre E73 17aa 3814 Z50-75 17aa 3823 Lenovo V130-15IGM Laptop - Type 81HL 17aa 5124 ThinkPad E595 @@ -12473,6 +12641,7 @@ 7470 3468 TG-3468 Gigabit PCI Express Network Adapter 8086 2055 NUC Kit DN2820FYKH 8086 d615 Desktop Board D510MO/D525MW + ea50 ce19 mCOM10-L1900 8169 RTL8169 PCI Gigabit Ethernet Controller 1025 0079 Aspire 5024WLMi 10bd 3202 EP-320G-TX1 32-bit PCI Gigabit Ethernet Adapter @@ -12489,6 +12658,14 @@ 16ec 011f USR997903 1734 1091 D2030-A1 a0a0 0449 AK86-L motherboard + 816a RTL8111xP UART #1 + ea50 ce19 mCOM10-L1900 + 816b RTL8111xP UART #2 + ea50 ce19 mCOM10-L1900 + 816c RTL8111xP IPMI interface + ea50 ce19 mCOM10-L1900 + 816d RTL811x EHCI host controller + ea50 ce19 mCOM10-L1900 8171 RTL8191SEvA Wireless LAN Controller 8172 RTL8191SEvB Wireless LAN Controller 8173 RTL8192SE Wireless LAN Controller @@ -12551,6 +12728,7 @@ 5005 Alveo U250 7038 FPGA Card XC7VX690T 17aa 402f FPGA XC7VX690T-3FFG1157E + 8019 Memory controller 8380 Ellips ProfiXpress Profibus Master 8381 Ellips Santos Frame Grabber d154 Copley Controls CAN card (PCI-CAN-02) @@ -12835,12 +13013,12 @@ 0336 K8M890CE Host Bridge 0340 PT900 Host Bridge 0351 K8T890CF Host Bridge - 0353 VX800 Host Bridge + 0353 VX800/820-Series Chipset Host-Bridge Controller 0364 CN896/VN896/P4M900 Host Bridge 1043 81ce P5VD2-VM mothervoard 0391 VT8371 [KX133] 0409 VX855/VX875 Host Bridge: Host Control - 0410 VX900 Host Bridge: Host Control + 0410 VX900 Series Host Bridge: Host Control 0415 VT6415 PATA IDE Host Controller 1043 838f Motherboard 0501 VT8501 [Apollo MVP4] @@ -12867,7 +13045,7 @@ # probably all K7VT2/4*/6 1849 0571 K7VT series Motherboards 0576 VT82C576 3V [Apollo Master] - 0581 CX700/VX700 RAID Controller + 0581 CX700/VX700/VX800/820-Series Serial ATA RAID-Controller # Upgrade bios to get correct ID: 5324 instead of 0581 1106 0581 Wrong IDE ID 0585 VT82C585VP [Apollo VP1/VPX] @@ -12925,7 +13103,7 @@ 1296 P4M800 Host Bridge 1308 PT894 Host Bridge 1314 CN700/VN800/P4M800CE/Pro Host Bridge - 1324 CX700/VX700 Host Bridge + 1324 CX700/VX700-Series Error Reporting 1327 P4M890 Host Bridge 1336 K8M890CE Host Bridge 1340 PT900 Host Bridge @@ -12933,7 +13111,7 @@ 1353 VX800/VX820 Error Reporting 1364 CN896/VN896/P4M900 Host Bridge 1409 VX855/VX875 Error Reporting - 1410 VX900 Error Reporting + 1410 VX900 Series Error Reporting 1571 VT82C576M/VT82C586 1595 VT82C595/97 [Apollo VP2/97] 1732 VT1732 [Envy24 II] PCI Multi-Channel Audio Controller @@ -12950,7 +13128,7 @@ 2296 P4M800 Host Bridge 2308 PT894 Host Bridge 2314 CN700/VN800/P4M800CE/Pro Host Bridge - 2324 CX700/VX700 Host Bridge + 2324 CX700/VX700-Series Host Interface Control 2327 P4M890 Host Bridge 2336 K8M890CE Host Bridge 2340 PT900 Host Bridge @@ -12958,22 +13136,23 @@ 2353 VX800/VX820 Host Bus Control 2364 CN896/VN896/P4M900 Host Bridge 2409 VX855/VX875 Host Bus Control - 2410 VX900 CPU Bus Controller + 2410 VX900 Series CPU Bus Controller 287a VT8251 PCI to PCI Bridge 287b VT8251 Host Bridge 287c VT8251 PCIE Root Port 287d VT8251 PCIE Root Port 287e VT8237/8251 Ultra VLINK Controller 3022 CLE266 - 3038 VT82xx/62xx UHCI USB 1.1 Controller + 3038 VT82xx/62xx/VX700/8x0/900 UHCI USB 1.1 Controller 0925 1234 onboard UHCI USB 1.1 Controller 1019 0985 P6VXA Motherboard 1019 0a81 L7VTA v1.0 Motherboard (KT400-8235) 1043 8080 A7V333 motherboard - 1043 808c VT6202 USB2.0 4 port controller + 1043 808c VT62xx USB1.1 4 port controller 1043 80a1 A7V8X-X motherboard 1043 80ed A7V600/K8V-X/A8V Deluxe motherboard 1179 0001 Magnia Z310 + 1234 0925 MVP3 USB Controller 1458 5004 GA-7VAX Mainboard 1462 5901 KT6 Delta-FIS2R (MS-6590) 1462 7020 K8T NEO 2 motherboard @@ -13091,7 +13270,7 @@ 3101 VT8653 Host Bridge 3102 VT8662 Host Bridge 3103 VT8615 Host Bridge - 3104 USB 2.0 + 3104 USB 2.0 EHCI-Compliant Host-Controller 0925 1234 onboard EHCI USB 2.0 Controller 1019 0a81 L7VTA v1.0 Motherboard (KT400-8235) 1043 808c A7V8X motherboard @@ -13204,11 +13383,11 @@ 3269 KT880 Host Bridge 3282 K8T800Pro Host Bridge 3287 VT8251 PCI to ISA Bridge - 3288 VT8237A/VT8251 HDA Controller + 3288 VX900/VT8xxx High Definition Audio Controller 19da a179 ZBOX VD01 3290 K8M890 Host Bridge 3296 P4M800 Host Bridge - 3324 CX700/VX700 Host Bridge + 3324 CX700/VX700-Series DRAM Bus Control 3327 P4M890 Host Bridge 3336 K8M890CE Host Bridge 3337 VT8237A PCI to ISA Bridge @@ -13217,8 +13396,9 @@ 3344 CN700/P4M800 Pro/P4M800 CE/VN800 Graphics [S3 UniChrome Pro] 3349 VT8251 AHCI/SATA 4-Port Controller 3351 VT3351 Host Bridge - 3353 VX800 PCI to PCI Bridge + 3353 VX800/820 PCI to PCI Bridge 3364 CN896/VN896/P4M900 Host Bridge + 3365 VT630x IEEE 1394 Host Controller [Fire II/M] 3371 CN896/VN896/P4M900 [Chrome 9 HC] 3372 VT8237S PCI to ISA Bridge 337a VT8237A PCI to PCI Bridge @@ -13227,12 +13407,12 @@ 1043 8374 M5A88-V EVO 1043 8384 P8P67 Deluxe Motherboard 3409 VX855/VX875 DRAM Bus Control - 3410 VX900 DRAM Bus Control + 3410 VX900 Series DRAM Bus Control 19da a179 ZBOX nano VD01 - 3432 VL80x xHCI USB 3.0 Controller + 3432 VL800/801 xHCI USB 3.0 Controller 3456 VX11 Standard Host Bridge 345b VX11 Miscellaneous Bus - 3483 VL805 USB 3.0 Host Controller + 3483 VL805/806 xHCI USB 3.0 Controller 3a01 VX11 Graphics [Chrome 645/640] 4149 VIA VT6420 (ATA133) Controller 4204 K8M800 Host Bridge @@ -13247,7 +13427,7 @@ 4296 P4M800 Host Bridge 4308 PT894 Host Bridge 4314 CN700/VN800/P4M800CE/Pro Host Bridge - 4324 CX700/VX700 Host Bridge + 4324 CX700/VX700-Series Power Management and Testing Control 4327 P4M890 Host Bridge 4336 K8M890CE Host Bridge 4340 PT900 Host Bridge @@ -13255,7 +13435,7 @@ 4353 VX800/VX820 Power Management Control 4364 CN896/VN896/P4M900 Host Bridge 4409 VX855/VX875 Power Management Control - 4410 VX900 Power Management and Chip Testing Control + 4410 VX900 Series Power Management and Chip Testing Control 19da a179 ZBOX nano VD01 5030 VT82C596 ACPI [Apollo PRO] 5122 VX855/VX875 Chrome 9 HCM Integrated Graphics @@ -13264,7 +13444,7 @@ 5287 VT8251 Serial ATA Controller 5290 K8M890 I/O APIC Interrupt Controller 5308 PT894 I/O APIC Interrupt Controller - 5324 VX800 Serial ATA and EIDE Controller + 5324 CX700M2/VX700/VX800/820-Series Serial ATA & EIDE-Controller 5327 P4M890 I/O APIC Interrupt Controller 5336 K8M890CE I/O APIC Interrupt Controller 5340 PT900 I/O APIC Interrupt Controller @@ -13273,7 +13453,7 @@ 5364 CN896/VN896/P4M900 I/O APIC Interrupt Controller 5372 VT8237/8251 Serial ATA Controller 5409 VX855/VX875 APIC and Central Traffic Control - 5410 VX900 APIC and Central Traffic Control + 5410 VX900 Series APIC and Central Traffic Control 6100 VT85C100A [Rhine II] 6287 SATA RAID Controller 6290 K8M890CE Host Bridge @@ -13281,7 +13461,7 @@ 6353 VX800/VX820 Scratch Registers 6364 CN896/VN896/P4M900 Security Device 6409 VX855/VX875 Scratch Registers - 6410 VX900 Scratch Registers + 6410 VX900 Series Scratch Registers 19da a179 ZBOX nano VD01 7122 VX900 Graphics [Chrome9 HD] 7204 K8M800 Host Bridge @@ -13299,7 +13479,7 @@ 7296 P4M800 Host Bridge 7308 PT894 Host Bridge 7314 CN700/VN800/P4M800CE/Pro Host Bridge - 7324 CX700/VX700 Host Bridge + 7324 CX700/VX700-Series North-South Module Interface Control 7327 P4M890 Host Bridge 7336 K8M890CE Host Bridge 7340 PT900 Host Bridge @@ -13307,17 +13487,17 @@ 7353 VX800/VX820 North-South Module Interface Control 7364 CN896/VN896/P4M900 Host Bridge 7409 VX855/VX875 North-South Module Interface Control - 7410 VX900 North-South Module Interface Control + 7410 VX900 Series North-South Module Interface Control 19da a179 ZBOX nano VD01 8231 VT8231 [PCI-to-ISA Bridge] 8235 VT8235 ACPI 8305 VT8363/8365 [KT133/KM133 AGP] - 8324 CX700/VX700 PCI to ISA Bridge + 8324 CX700/VX700-Series Bus Control and Power Management 8353 VX800/VX820 Bus Control and Power Management 8391 VT8371 [KX133 AGP] 8400 MVP4 8409 VX855/VX875 Bus Control and Power Management - 8410 VX900 Bus Control and Power Management + 8410 VX900 Series Bus Control and Power Management 19da a179 ZBOX VD01 8500 KLE133/PLE133/PLE133T 8501 VT8501 [Apollo MVP4 AGP] @@ -13333,19 +13513,19 @@ 8a26 KL133/KL133A/KM133/KM133A [S3 ProSavage] 8d01 PN133/PN133T [S3 Twister] 8d04 KM266/P4M266/P4M266A/P4N266 [S3 ProSavageDDR] - 9001 VX900 Serial ATA Controller + 9001 VX900 Series Serial-ATA Controller 9082 Standard AHCI 1.0 SATA Controller 9140 HDMI Audio Device 9201 USB3.0 Controller - 9530 Secure Digital Memory Card Controller - 95d0 SDIO Host Controller + 9530 VX800/820/900 Series Secure Digital Memory Card Controller + 95d0 VX800/820/900 Series SDIO Host Controller a208 PT890 PCI to PCI Bridge Controller a238 K8T890 PCI to PCI Bridge Controller a327 P4M890 PCI to PCI Bridge Controller - a353 VX8xx South-North Module Interface Control + a353 VX8xx/900 Series South-North Module Interface Control a364 CN896/VN896/P4M900 PCI to PCI Bridge Controller - a409 VX855/VX875 USB Device Controller - a410 VX900 PCI Express Root Port 0 + a409 VX855/VX875/VX900 Series USB Device Controller + a410 VX900 Series PCI Express Root Port 0 b091 VT8633 [Apollo Pro266 AGP] b099 VT8366/A/7 [Apollo KT266/A/333 AGP] b101 VT8653 AGP Bridge @@ -13357,34 +13537,35 @@ b168 VT8235 PCI Bridge b188 VT8237/8251 PCI bridge [K8M890/K8T800/K8T890 South] 147b 1407 KV8-MAX3 motherboard - b198 VT8237/VX700 PCI Bridge + b198 VT8237/CX700/VX700-Series PCI to PCI Bridge b213 VPX/VPX2 I/O APIC Interrupt Controller b353 VX855/VX875/VX900 PCI to PCI Bridge - b410 VX900 PCI Express Root Port 1 + b410 VX900 Series PCI Express Root Port 1 b999 [K8T890 North / VT8237 South] PCI Bridge c208 PT890 PCI to PCI Bridge Controller c238 K8T890 PCI to PCI Bridge Controller c327 P4M890 PCI to PCI Bridge Controller c340 PT900 PCI to PCI Bridge Controller - c353 VX800/VX820 PCI Express Root Port + c353 VX800/820-Series PCI-Express Root (PCI-to-PCI Virtual Bridge) c364 CN896/VN896/P4M900 PCI to PCI Bridge Controller c409 VX855/VX875 EIDE Controller - c410 VX900 PCI Express Root Port 2 + c410 VX900 Series PCI Express Root Port 2 d104 VT8237R USB UDCI Controller d208 PT890 PCI to PCI Bridge Controller d213 VPX/VPX2 PCI to PCI Bridge Controller d238 K8T890 PCI to PCI Bridge Controller d340 PT900 PCI to PCI Bridge Controller - d410 VX900 PCI Express Root Port 3 + d410 VX900 Series PCI Express Root Port 3 e208 PT890 PCI to PCI Bridge Controller e238 K8T890 PCI to PCI Bridge Controller e340 PT900 PCI to PCI Bridge Controller - e353 VX800/VX820 PCI Express Root Port - e410 VX900 PCI Express Physical Layer Electrical Sub-block + e353 VX800/820-Series PCI-Express Root Port 0 + e410 VX900 Series PCI Express Physical Layer Electrical Sub-block f208 PT890 PCI to PCI Bridge Controller f238 K8T890 PCI to PCI Bridge Controller f340 PT900 PCI to PCI Bridge Controller - f353 VX800/VX820 PCI Express Root Port + f353 VX800/820-Series PCI-Express Root Port 1 + f410 VX900 Series PCI UART Port 0-3 1107 Stratus Computers 0576 VIA VT82C570MV [Apollo] (Wrong vendor ID!) 1108 Proteon, Inc. @@ -14019,7 +14200,7 @@ 0002 Dual PCI to RapidIO Bridge 000b POET Serial RapidIO Bridge 000d POET PSDMS Device -1135 Fuji Xerox Co Ltd +1135 FUJIFILM Business Innovation Corp. 0001 Printer controller 1136 Momentum Data Systems 0002 PCI-JTAG @@ -14492,6 +14673,7 @@ 1172 Altera Corporation 00a7 Stratix V 0530 Stratix IV + 646c KT-500/KT-521 board 1173 Adobe Systems, Inc 1174 Bridgeport Machines 1175 Mitron Computer Inc. @@ -14502,6 +14684,7 @@ 1179 Toshiba Corporation 0102 Extended IDE Controller 0103 EX-IDE Type-B + 010e PXP04 NVMe SSD 010f NVMe Controller 0110 NVMe SSD Controller Cx5 1028 1ffb Express Flash NVMe 960G (RI) U.2 (CD5) @@ -14513,7 +14696,9 @@ 1d49 4039 Thinksystem U.2 CM5 NVMe SSD 1d49 403a Thinksystem AIC CM5 NVMe SSD 0113 BG3 NVMe SSD Controller + 1179 0001 Toshiba KBG30ZMS128G 128GB NVMe SSD 0115 XG4 NVMe SSD Controller + 011a XG6 NVMe SSD Controller 0404 DVD Decoder card 0406 Tecra Video Capture device 0407 DVD Decoder card (Version 2) @@ -14873,6 +15058,7 @@ 11aa Actel # Nee Galileo Technology, Inc. 11ab Marvell Technology Group Ltd. + 0100 88F3700 [Armada 3700 Family] ARM SoC 0146 GT-64010/64010A System Controller 0f53 88E6318 Link Street network controller 11ab MV88SE614x SATA II PCI-E controller @@ -15089,6 +15275,8 @@ 6480 MV64460/64461/64462 System Controller 1775 c200 C2K CompactPCI single board computer 6485 MV64460/64461/64462 System Controller, Revision B + 6820 88F6820 [Armada 385] ARM SoC + 6828 88F6828 [Armada 388] ARM SoC 7042 88SX7042 PCI-e 4-port SATA-II 16b8 434b Tempo SATA E4P 7810 MV78100 [Discovery Innovation] ARM SoC @@ -15104,7 +15292,7 @@ 11ad 0003 LNE100TX 11ad f003 LNE100TX 11ad ffff LNE100TX - 1385 f004 FA310TX + 1385 f004 FA310/TX LAN 10/100 PCI Ethernet Adapter 2646 f002 KNE110TX EtheRx Fast Ethernet c115 LNE100TX [Linksys EtherFast 10/100] 11ad c001 LNE100TX [ver 2.0] @@ -15421,6 +15609,7 @@ 8073 PM8073 Tachyon SPCve 12G 16-port SAS/SATA controller 8531 PM8531 PFX 24xG3 Fanout PCIe Switches 8546 PM8546 B-FEIP PSX 96xG3 PCIe Storage Switch + 8562 PM8562 Switchtec PFX-L 32xG3 Fanout-Lite PCIe Gen3 Switch 11f9 I-Cube Inc 11fa Kasan Electronics Company, Ltd. 11fb Datel Inc @@ -15809,6 +15998,7 @@ a000 2000 Parallel Port a000 6000 SPI a000 7000 Local Bus + ea50 1c10 RXi2-BP 125c Aurora Technologies, Inc. 0101 Saturn 4520P 0640 Aries 16000P @@ -15940,6 +16130,7 @@ 0820 SM820 Lynx3D 0910 SM910 2262 SM2262/SM2262EN SSD Controller + 2263 SM2263EN/SM2263XT SSD Controller 1270 Olympus Optical Co., Ltd. 1271 GW Instruments 1272 Telematics International @@ -16157,9 +16348,9 @@ 1281 Yokogawa Electric Corporation 1282 Davicom Semiconductor, Inc. 6585 DM562P V90 Modem - 9009 Ethernet 100/10 MBit + 9009 DM9009 Ethernet Controller 9100 21x4x DEC-Tulip compatible 10/100 Ethernet - 9102 21x4x DEC-Tulip compatible 10/100 Ethernet + 9102 DM9102 Fast Ethernet Controller # Subsystem ID is main ID reveresed. 0291 8212 DM9102A (DM9102AE, SM9102AF) Ethernet 100/10 MBit 9132 Ethernet 100/10 MBit @@ -16177,6 +16368,7 @@ 8888 IT8888F/G PCI to ISA Bridge with SMB [Golden Gate] 8889 IT8889F PCI to ISA Bridge 8892 IT8892E PCIe to PCI Bridge + 8086 200d DH61CR motherboard 8893 IT8893E PCIe to PCI Bridge e886 IT8330G 1284 Sahara Networks, Inc. @@ -16407,6 +16599,7 @@ 2304 PI7C9X2G304 EL/SL PCIe2 3-Port/4-Lane Packet Switch 2404 PI7C9X2G404 EL/SL PCIe2 4-Port/4-Lane Packet Switch 2608 PI7C9X2G608GP PCIe2 6-Port/8-Lane Packet Switch + ea50 cc10 RXi2-BP 400a PI7C9X442SL PCI Express Bridge Port 400e PI7C9X442SL USB OHCI Controller 400f PI7C9X442SL USB EHCI Controller @@ -16417,6 +16610,7 @@ 8150 PCI to PCI Bridge 8152 PI7C8152A/PI7C8152B/PI7C8152BI PCI-to-PCI Bridge 8154 PI7C8154A/PI7C8154B/PI7C8154BI PCI-to-PCI Bridge + 8619 PI7C9X2G1616PR PCIe2 16-Port/16-Lane Packet Switch e110 PI7C9X110 PCI Express to PCI bridge 1775 11cc CC11/CL11 CompactPCI Bridge e111 PI7C9X111SL PCIe-to-PCI Reversible Bridge @@ -16451,12 +16645,13 @@ 12ea Zuken 12eb Aureal Semiconductor 0001 Vortex 1 + 0000 0300 Terasound A3D PCI 104d 8036 AU8820 Vortex Digital Audio Processor 1092 2000 Sonic Impact A3D 1092 2100 Sonic Impact A3D 1092 2110 Sonic Impact A3D 1092 2200 Sonic Impact A3D - 122d 1002 AU8820 Vortex Digital Audio Processor + 122d 1002 SC 338-A3D 12eb 0001 AU8820 Vortex Digital Audio Processor 5053 3355 Montego 50b2 1111 XLerate @@ -16744,12 +16939,14 @@ 134f Algo System Co Ltd 1350 Systec Co. Ltd 1351 Sonix Inc -# nee Thales Idatys -1353 Vierling Communication SAS +# nee Vierling Communication SAS, nee Thales Idatys +1353 dbeeSet Technology 0002 Proserver 0003 PCI-FUT 0004 PCI-S0 0005 PCI-FUT-S0 + 0006 OTDU-1U (FPGA Zynq-7000) + 0007 OTDU-EX 1354 Dwave System Inc 1355 Kratos Analytical Ltd 1356 The Logical Co @@ -17458,6 +17655,8 @@ 1414 Microsoft Corporation 0001 MN-120 (ADMtek Centaur-C based) 0002 MN-130 (ADMtek Centaur-P based) +# Virtual Video Card Device for Windows Remote Desktop (RDP) + 008c Basic Render Driver 5353 Hyper-V virtual VGA 5801 XMA Decoder (Xenon) 5802 SATA Controller - CdRom (Xenon) @@ -18257,9 +18456,12 @@ a544 Exynos 8890 PCIe Root Complex a800 XP941 PCIe SSD a802 NVMe SSD Controller SM951/PM951 - a804 NVMe SSD Controller SM961/PM961 + 144d a801 PM963 2.5" NVMe PCIe SSD + a804 NVMe SSD Controller SM961/PM961/SM963 + 144d a801 SM963 2.5" NVMe PCIe SSD a808 NVMe SSD Controller SM981/PM981/PM983 1d49 403b Thinksystem U.2 PM983 NVMe SSD + a80a NVMe SSD Controller PM9A1/980PRO a820 NVMe SSD Controller 171X 1028 1f95 Express Flash NVMe XS1715 SSD 400GB 1028 1f96 Express Flash NVMe XS1715 SSD 800GB @@ -18323,6 +18525,22 @@ 1028 2097 EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 1.92TB 1028 2098 EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 3.84TB 1028 2099 EMC PowerEdge Express Flash Ent NVMe AGN SED RI U.2 Gen4 7.68TB + 1028 2118 Ent NVMe v2 AGN FIPS MU U.2 1.6TB + 1028 2119 Ent NVMe v2 AGN MU U.2 1.6TB + 1028 2120 Ent NVMe v2 AGN FIPS MU U.2 3.2T + 1028 2121 Ent NVMe v2 AGN MU U.2 3.2TB + 1028 2122 Ent NVMe v2 AGN FIPS MU U.2 6.4TB + 1028 2123 Ent NVMe v2 AGN MU U.2 6.4TB + 1028 2124 Ent NVMe v2 AGN FIPS MU U.2 6.4TB + 1028 2125 Ent NVMe v2 AGN MU U.2 12.8TB + 1028 2126 Ent NVMe v2 AGN FIPS RI U.2 1.92TB + 1028 2127 Ent NVMe v2 AGN RI U.2 1.92TB + 1028 2128 Ent NVMe v2 AGN FIPS RI U.2 3.84TB + 1028 2129 Ent NVMe v2 AGN RI U.2 3.84TB + 1028 2130 Ent NVMe v2 AGN FIPS RI U.2 7.68TB + 1028 2131 Ent NVMe v2 AGN RI U.2 7.68TB + 1028 2132 Ent NVMe v2 AGN FIPS RI U.2 15.36TB + 1028 2133 Ent NVMe v2 AGN RI U.2 15.36TB ecec Exynos 8895 PCIe Root Complex 144e OLITEC 144f Askey Computer Corp. @@ -18334,6 +18552,7 @@ 1456 Advanced Hardware Architectures 1457 Nuera Communications Inc 1458 Gigabyte Technology Co., Ltd + 3483 USB 3.0 Controller (VIA VL80x-based xHCI Controller) 1459 DOOIN Electronics 145a Escalate Networks Inc 145b PRAIM SRL @@ -18350,6 +18569,8 @@ e836 M115S Hybrid Analog/DVB PAL/SECAM/NTSC Tuner f436 AVerTV Hybrid+FM 1462 Micro-Star International Co., Ltd. [MSI] +# VIA Driver-inf + 3483 MSI USB 3.0 (VIA VL80x-based xHCI USB Controller) aaf0 Radeon RX 580 Gaming X 8G 1463 Fast Corporation 1464 Interactive Circuits & Systems Ltd @@ -18771,7 +18992,7 @@ 103c 0890 NC6000 laptop 103c 099c NX6110/NC6120 10cf 1279 LifeBook E8010D - 165f NetXtreme BCM5720 2-port Gigabit Ethernet PCIe + 165f NetXtreme BCM5720 Gigabit Ethernet PCIe 1028 04f7 PowerEdge R320 server 1028 08fd PowerEdge R6515/R7515 LOM 1028 08ff PowerEdge Rx5xx LOM Board @@ -18861,6 +19082,7 @@ 103c 339d Ethernet 10Gb 2-port 530SFP+ Adapter 193d 1003 530F-B 193d 1006 530F-L + 193d 100f NIC-ETH522i-Mb-2x10G 1690 NetXtreme BCM57760 Gigabit Ethernet PCIe 1691 NetLink BCM57788 Gigabit Ethernet PCIe 1028 04aa XPS 8300 @@ -18887,6 +19109,7 @@ 16a0 NetLink BCM5785 Fast Ethernet 16a1 BCM57840 NetXtreme II 10 Gigabit Ethernet 1043 866e PEB-10G/57840-2T 10GBase-T Network Adapter + 193d 100b NIC-ETH521i-Mb-4x10G 16a2 BCM57840 NetXtreme II 10/20-Gigabit Ethernet 103c 1916 FlexFabric 20Gb 2-port 630FLB Adapter 103c 1917 FlexFabric 20Gb 2-port 630M Adapter @@ -19006,12 +19229,12 @@ 16d4 BCM57402 NetXtreme-E Ethernet Partition 16d5 BCM57407 NetXtreme-E 10GBase-T Ethernet Controller 16d6 BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller + 14e4 1202 BCM957412M4122C OCP 1x25G Type1 wRoCE 14e4 4120 NetXtreme E-Series Advanced Dual-port 10Gb SFP+ Ethernet Network Daughter Card 14e4 4126 NetXtreme-E Dual-port 10G SFP+ Ethernet OCP 3.0 Adapter (BCM957412N4120C) 152d 8b20 BCM57412 NetXtreme-E 10Gb RDMA Ethernet Controller 152d 8b22 BCM57412 NetXtreme-E 25Gb RDMA Ethernet Controller 16d7 BCM57414 NetXtreme-E 10Gb/25Gb RDMA Ethernet Controller - 14e4 1202 BCM957412M4122C OCP 1x25G Type1 wRoCE 14e4 1402 BCM957414A4142CC 10Gb/25Gb Ethernet PCIe 14e4 1404 BCM957414M4142C OCP 2x25G Type1 wRoCE 14e4 4140 NetXtreme E-Series Advanced Dual-port 25Gb SFP28 Network Daughter Card @@ -19073,16 +19296,26 @@ 1750 BCM57508 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 14e4 2100 NetXtreme-E Dual-port 100G QSFP56 Ethernet PCIe4.0 x16 Adapter (BCM957508-P2100G) 14e4 5208 NetXtreme-E Dual-port 100G QSFP56 Ethernet OCP 3.0 Adapter (BCM957508-N2100G) + 14e4 df24 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet 1751 BCM57504 NetXtreme-E 10Gb/25Gb/40Gb/50Gb/100Gb/200Gb Ethernet 1752 BCM57502 NetXtreme-E 10Gb/25Gb/40Gb/50Gb Ethernet 1800 BCM57502 NetXtreme-E Ethernet Partition 1801 BCM57504 NetXtreme-E Ethernet Partition 1802 BCM57508 NetXtreme-E Ethernet Partition + 14e4 df24 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet Partition 1803 BCM57502 NetXtreme-E RDMA Partition 1804 BCM57504 NetXtreme-E RDMA Partition - 1805 BCM57508 NetXtreme-E RDMA Partition + 1805 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Partition + 14e4 df24 NetXtreme-E NGM2100D BCM57508 2x100G KR Mezz RDMA Partition 1806 BCM5750X NetXtreme-E Ethernet Virtual Function + 14e4 df24 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet Virtual Function 1807 BCM5750X NetXtreme-E RDMA Virtual Function + 14e4 df24 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Virtual Function + 1808 BCM5750X NetXtreme-E Ethernet Virtual Function + 14e4 df24 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz Ethernet Virtual Function + 1809 BCM5750X NetXtreme-E RDMA Virtual Function + 14e4 df24 BCM57508 NetXtreme-E NGM2100D 2x100G KR Mezz RDMA Virtual Function + 2711 BCM2711 PCIe Bridge 3352 BCM3352 3360 BCM3360 4210 BCM4210 iLine10 HomePNA 2.0 @@ -19845,6 +20078,7 @@ 9260 RCIM-II Real-Time Clock & Interrupt Module 9271 RCIM-III Real-Time Clock & Interrupt Module (PCIe) 9272 Pulse Width Modulator Card + 9273 RCIM-IV Real-Time Clock & Interrupt Module (PCIe) 9277 5 Volt Delta Sigma Converter Card 9278 10 Volt Delta Sigma Converter Card 9287 Analog Output Card @@ -20136,12 +20370,20 @@ 15b3 0021 MCX4421A-ACQN ConnectX-4 Lx EN OCP,2x25G 15b3 0025 ConnectX-4 Lx 25 GbE Dual Port SFP28 rNDC 193d 100a 620F-B +# NIC-ETH540F-LP-2P SFP+ Ethernet Card + 193d 1023 NIC-ETH540F-LP-2P + 193d 1031 NIC-ETH640i-Mb-2x25G +# NIC-ETH640F-3S-2P OCP3.0 Card + 193d 1083 NIC-ETH640F-3S-2P +# NIC-ETH540F-3S-2P OCP3.0 2x10G Card + 193d 1084 NIC-ETH540F-3S-2P 1016 MT27710 Family [ConnectX-4 Lx Virtual Function] 1017 MT27800 Family [ConnectX-5] 15b3 0006 ConnectX®-5 EN network interface card, 100GbE single-port QSFP28, PCIe3.0 x16, tall bracket; MCX515A-CCAT 15b3 0007 Mellanox ConnectX®-5 MCX516A-CCAT 15b3 0020 ConnectX®-5 EN network interface card, 10/25GbE dual-port SFP28, PCIe3.0 x8, tall bracket ; MCX512A-ACAT 15b3 0068 ConnectX®-5 EN network interface card for OCP2.0, Type 1, with host management, 25GbE dual-port SFP28, PCIe3.0 x8, no bracket Halogen free ; MCX542B-ACAN + 193d 1051 NIC-IB1040i-Mb-2P 1018 MT27800 Family [ConnectX-5 Virtual Function] 1019 MT28800 Family [ConnectX-5 Ex] 15b3 0008 ConnectX-5 Ex EN network interface card, 100GbE dual-port QSFP28, PCIe4.0 x16, tall bracket; MCX516A-CDAT @@ -20262,14 +20504,17 @@ 15b7 Sandisk Corp 2001 Skyhawk Series NVME SSD 5001 WD Black NVMe SSD - 5002 WD Black 2018 / PC SN720 NVMe SSD - 5003 WD Black 2018 / PC SN520 NVMe SSD + 5002 WD Black 2018/SN750 / PC SN720 NVMe SSD + 5003 WD Blue SN500 / PC SN520 NVMe SSD 5004 PC SN520 NVMe SSD 5005 PC SN520 NVMe SSD - 5006 WD Black 2019/PC SN750 NVMe SSD + 5006 WD Black SN750 / PC SN730 NVMe SSD 5009 WD Blue SN550 NVMe SSD 15b7 5009 WD Blue SN550 NVMe SSD + 500b PC SN530 NVMe SSD + 1414 500b Xbox Series X 500d WD Ultrastar DC SN340 NVMe SSD + 5011 WD Black SN850 15b8 ADDI-DATA GmbH 1001 APCI1516 SP controller (16 digi outputs) 1003 APCI1032 SP controller (32 digi inputs w/ opto coupler) @@ -20575,6 +20820,9 @@ 2086 CryptoServer Se-Series Hardware Security Module c040 CryptoServer CSe-Series Hardware Security Module c051 CryptoServer Se-Series Gen2 Hardware Security Module + c070 u.trust Anchor Hardware Security Module cs7.2 Series + c071 u.trust Anchor Hardware Security Module cs7.3 Series + c072 u.trust Anchor Hardware Security Module cs7.3 Series Virtual Function # nee Atheros Communications, Inc. 168c Qualcomm Atheros 0007 AR5210 Wireless Network Adapter [AR5000 802.11a] @@ -21020,6 +21268,7 @@ ab08 21x4x DEC-Tulip compatible 10/100 Ethernet ab09 21x4x DEC-Tulip compatible 10/100 Ethernet 173b Altima (nee Broadcom) + 0001 AC1002 PCI Gigabit Ethernet controller 03e8 AC1000 Gigabit Ethernet 03e9 AC1001 Gigabit Ethernet 03ea AC9100 Gigabit Ethernet @@ -21067,6 +21316,10 @@ 0245 PCA7428CE_F1 - Analog Inputs isolated 0303 PCD-7006C Digital Input & Output PCI Card 0800 PCD8006 - PCIe digital Inputs/Outputs + 0840 PCA-8428 General-purpose multifunctional PCIe card with 8 analog inputs and 2 analog outputs + 0841 PCA-8429 General-purpose multifunctional PCIe card with 8 analog inputs + 0842 PCA-8438 General-purpose multifunctional PCIe card with 16 analog inputs and 2 analog outputs + 0843 PCA-8439 General-purpose multifunctional PCIe card with 16 analog inputs ff00 CTU CAN FD PCIe Card 1761 Pickering Interfaces Ltd 1771 InnoVISION Multimedia Ltd. @@ -21246,6 +21499,7 @@ 9750 GL9750 SD Host Controller e763 GL9763E eMMC Controller 17aa Lenovo + 3181 ThinkCentre M75n IoT 402b Intel 82599ES 10Gb 2-port Server Adapter X520-2 17ab Phillips Components 17af Hightech Information System Ltd. @@ -21275,6 +21529,7 @@ 0400 Datacenter Technologies QDF2432 PCI Express Root Port 0401 Datacenter Technologies QDF2400 PCI Express Root Port 1000 QCS405 PCIe Root Complex + 1101 QCA6390 Wireless Network Adapter [AX500-DBS (2x2)] 17cc NetChip Technology, Inc 2280 USB 2.0 17cd Cadence Design Systems, Inc. @@ -22302,7 +22557,19 @@ 19e5 d136 Hi1822 SP580 (4*25GE) 19e5 d141 Hi1822 SP583 (4*25GE) 19e5 d146 Hi1822 SP585 (4*25GE) + 3714 ES3000 V5 NVMe PCIe SSD + 19e5 5312 NVMe SSD ES3500P V5 2000GB 2.5" U.2 371e Hi1822 Family Virtual Bridge + 3754 ES3000 V6 NVMe PCIe SSD + 19e5 6122 NVMe SSD ES3600P V6 1600GB 2.5" U.2 + 19e5 6123 NVMe SSD ES3600P V6 3200GB 2.5" U.2 + 19e5 6124 NVMe SSD ES3600P V6 6400GB 2.5" U.2 + 19e5 6141 NVMe SSD ES3800P V6 800GB 2.5" U.2 + 19e5 6142 NVMe SSD ES3800P V6 1600GB 2.5" U.2 + 19e5 6212 NVMe SSD ES3500P V6 1920GB 2.5" U.2 + 19e5 6213 NVMe SSD ES3500P V6 3840GB 2.5" U.2 + 19e5 6214 NVMe SSD ES3500P V6 7680GB 2.5" U.2 + 19e5 6215 NVMe SSD ES3500P V6 15360GB 2.5" U.2 375e Hi1822 Family Virtual Function 379e Hi1822 Family Virtual Function a120 HiSilicon PCIe Root Port with Gen4 @@ -22397,6 +22664,7 @@ 1a4a SLAC National Accelerator Lab TID-AIR 1000 MCOR Power Supply Controller 1010 AMC EVR - Stockholm Timing Board + 1020 PGPCard - Gen3 Cameralink Interface 1030 PGPCard - Gen3 GIGe Interface 2000 PGPCard - 4 Lane 2001 PGPCard - 8 Lane Plus EVR @@ -22631,6 +22899,7 @@ 1242 ASM1142 USB 3.1 Host Controller 1343 ASM1143 USB 3.1 Host Controller 2142 ASM2142 USB 3.1 Host Controller + 1462 7a72 H270 PC MATE 3242 ASM3242 USB 3.2 Host Controller 1b26 Netcope Technologies, a.s. c132 COMBO-LXT155 @@ -22662,6 +22931,7 @@ 000b QEMU PCIe Expander bridge 000c QEMU PCIe Root port 000d QEMU XHCI Host Controller + 0010 QEMU NVM Express Controller 0100 QXL paravirtual graphic card 1af4 1100 QEMU Virtual Machine 1b37 Signal Processing Devices Sweden AB @@ -22696,6 +22966,8 @@ 0601 NumaChip N601 0602 NumaChip N602 1b4b Marvell Technology Group Ltd. +# device 1b4b:0100 reports incorrect vendor id due to hw erratum (correct is 11ab) + 0100 88F3700 [Armada 3700 Family] ARM SoC 0640 88SE9128 SATA III 6Gb/s RAID Controller 2241 88NR2241 Non-Volatile memory controller 1028 2112 BOSS-N1 Monolithic @@ -22712,12 +22984,14 @@ 9172 88SE9172 SATA 6Gb/s Controller 9178 88SE9170 PCIe SATA 6Gb/s Controller 917a 88SE9172 SATA III 6Gb/s RAID Controller + 9182 88SE9182 PCIe 2.0 x2 2-port SATA 6 Gb/s Controller 9183 88SS9183 PCIe SSD Controller 9192 88SE9172 SATA III 6Gb/s RAID Controller 91a0 88SE912x SATA 6Gb/s Controller [IDE mode] 91a4 88SE912x IDE Controller + 9215 88SE9215 PCIe 2.0 x1 4-port SATA 6 Gb/s Controller 9220 88SE9220 PCIe 2.0 x2 2-port SATA 6 Gb/s RAID Controller - 9230 88SE9230 PCIe SATA 6Gb/s Controller + 9230 88SE9230 PCIe 2.0 x2 4-port SATA 6 Gb/s RAID Controller 1028 1fd6 BOSS-S1 Adapter 1028 1fdf BOSS-S1 Modular 1028 1fe2 BOSS-S1 Adapter @@ -22777,6 +23051,7 @@ 2402 Ultrastar DC SN640 NVMe SSD 2404 Ultrastar DC SN640 NVMe SSD 2500 Ultrastar DC SN840 NVMe SSD + 2600 Ultrastar DC ZN540 ZNS NVMe SSD 3714 PC SN730 NVMe SSD 3734 PC SN730 NVMe SSD 1b9a XAVi Technologies Corp. @@ -22857,9 +23132,17 @@ 1002 PM1553-5 (PC/104+ MIL-STD-1553 Interface Card) 1004 AB3000 Series Rugged Computer 1005 PE1000 (Multi-Protocol PCIe/104 Interface Card) + 1006 webCS Wireless Aircraft Communications Server + 1007 AB3000 Series Rugged Computer (Series N) + 1008 ME1000 mPCIe Avionics Interface Card + 100a NG1 Series Avionics Converter 1101 OmniBus II PCIe Multi-Protocol Interface Card 1102 OmniBusBox II Multi-Protocol Interface Core 1103 OmniBus II cPCIe/PXIe Multi-Protocol Interface Card + 1200 NG3 Series Mil-Std-1553 Interface + 1201 NG3 Series ARINC 429 Interface + 1202 NG3 Series Avionics Discrete & Serial Interface + 1203 NG3 Series Avionics Discrete Interface 1bd4 Inspur Electronic Information Industry Co., Ltd. 0911 Arria10_PCIe_F10A1150 1bee IXXAT Automation GmbH @@ -22892,6 +23175,7 @@ 001b FD720 001c FD922 001d Vega + 001f FD940 1c28 Lite-On IT Corp. / Plextor 0122 M6e PCI Express SSD [Marvell 88SS9183] # previously Fiberblaze @@ -22952,16 +23236,21 @@ 1284 PC300 NVMe Solid State Drive 512GB 1285 PC300 NVMe Solid State Drive 1TB 1327 BC501 NVMe Solid State Drive 512GB + 1339 BC511 1504 SC300 512GB M.2 2280 SATA Solid State Drive + 1527 PC401 NVMe Solid State Drive 256GB 243b PE6110 NVMe Solid State Drive 1c5c 0100 PE6110 NVMe Solid State Drive 2839 PE8000 Series NVMe Solid State Drive 1c5c 0100 PE8000 Series NVMe Solid State Drive 1c5f Beijing Memblaze Technology Co. Ltd. - 000d PBlaze5 520/526 AIC - 003d PBlaze5 920/926 AIC - 010d PBlaze5 520/526 U.2 - 013d PBlaze5 920/926 U.2 + 000d PBlaze5 520/526 + 003d PBlaze5 920/926 + 003e PBlaze6 6920 + 1c5f 0a31 NVMe SSD PBlaze6 6920 3840GB 2.5" U.2 + 1c5f 0a41 NVMe SSD PBlaze6 6920 7680GB 2.5" U.2 + 1c5f 4a31 NVMe SSD PBlaze6 6920 3200GB 2.5" U.2 + 1c5f 4a41 NVMe SSD PBlaze6 6920 6400GB 2.5" U.2 0540 PBlaze4 NVMe SSD 0550 PBlaze5 700/900 0555 PBlaze5 510/516 @@ -23039,12 +23328,14 @@ 0009 ExaNIC X25 000a ExaNIC X100 000b ExaNIC V9P + 000c ExaNIC V9P-3 0100 ExaDISK FX1 1cf0 Akitio 1cf7 Subspace Dynamics 1d00 Pure Storage 1d05 Tongfang Hongkong Limited 1d0f Amazon.com, Inc. + 8061 NVMe EBS Controller cd01 NVMe SSD Controller ec20 Elastic Network Adapter (ENA) efa0 Elastic Fabric Adapter (EFA) @@ -23175,6 +23466,9 @@ 1014 AR-MAN-U280 [Manitou Class Accelerator for U280] 1015 AR-ARK-BBDEV-FX0 [Arkville 32B DPDK Baseband Device] 1016 AR-ARK-BBDEV-FX1 [Arkville 64B DPDK Baseband Device] + 1017 AR-ARK-FX1 [Arkville 64B Multi-Homed Primary Endpoint] + 1018 AR-ARK-FX1 [Arkville 64B Multi-Homed Secondary Endpoint] + 1019 AR-ARK-FX1 [Arkville 64B Multi-Homed Tertiary Endpoint] 4200 A5PL-E1-10GETI [10 GbE Ethernet Traffic Instrument] 1d72 Xiaomi 1d78 DERA Storage @@ -23198,11 +23492,13 @@ 0101 Codensity D400 SSD 0102 Codensity D408 PCIe Gen4 NVMe SSD 0202 Codensity T408 Video Encoding-Decoding Accelerator -1d87 Fuzhou Rockchip Electronics Co., Ltd +# nee Fuzhou Rockchip Electronics Co., Ltd +1d87 Rockchip Electronics Co., Ltd 0100 RK3399 PCI Express Root Port 1808 RK1808 Neural Network Processor Card + 3566 RK3568 Remote Signal Processor 1d8f Enyx -1d93 YADRO (KNS Group) +1d93 YADRO 1d94 Chengdu Haiguang IC Design Co., Ltd. 1450 Root Complex 1451 I/O Memory Management Unit @@ -23258,61 +23554,68 @@ 1dd8 4000 Naples 100Gb 2-port QSFP28 x16 8GB 1dd8 4001 Naples 100Gb 2-port QSFP28 x16 4GB 1dd8 4002 Naples 25Gb 2-port SFP28 x8 4GB - 1dd8 4007 DSP DSC-25 10/25G 2p OCP Card - 1dd8 4008 DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC + 1dd8 4007 DSP DSC-25 Ent 10/25G OCP3 Card + 1dd8 4008 DSP DSC-25 10/25G 2p SFP28 Card 1dd8 400a DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card 1dd8 400c DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card - 1dd8 400d DSP DSC-100 100G 2p QSFP28 Card + 1dd8 400d DSP DSC-100 Ent 100Gb Card + 1dd8 400e DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card 1001 DSC Virtual Downstream Port 1dd8 4000 Naples 100Gb 2-port QSFP28 x16 8GB 1dd8 4001 Naples 100Gb 2-port QSFP28 x16 4GB 1dd8 4002 Naples 25Gb 2-port SFP28 x8 4GB - 1dd8 4007 DSP DSC-25 10/25G 2p OCP Card - 1dd8 4008 DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC + 1dd8 4007 DSP DSC-25 Ent 10/25G OCP3 Card + 1dd8 4008 DSP DSC-25 10/25G 2p SFP28 Card 1dd8 400a DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card 1dd8 400c DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card - 1dd8 400d DSP DSC-100 100G 2p QSFP28 Card + 1dd8 400d DSP DSC-100 Ent 100Gb Card + 1dd8 400e DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card 1002 DSC Ethernet Controller 1dd8 4000 Naples 100Gb 2-port QSFP28 x16 8GB 1dd8 4001 Naples 100Gb 2-port QSFP28 x16 4GB 1dd8 4002 Naples 25Gb 2-port SFP28 x8 4GB - 1dd8 4007 DSP DSC-25 10/25G 2p OCP Card - 1dd8 4008 DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC + 1dd8 4007 DSP DSC-25 Ent 10/25G OCP3 Card + 1dd8 4008 DSP DSC-25 10/25G 2p SFP28 Card 1dd8 400a DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card 1dd8 400c DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card - 1dd8 400d DSP DSC-100 100G 2p QSFP28 Card + 1dd8 400d DSP DSC-100 Ent 100Gb Card + 1dd8 400e DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card 1003 DSC Ethernet Controller VF 1dd8 4000 Naples 100Gb 2-port QSFP28 x16 8GB 1dd8 4001 Naples 100Gb 2-port QSFP28 x16 4GB 1dd8 4002 Naples 25Gb 2-port SFP28 x8 4GB - 1dd8 4007 DSP DSC-25 10/25G 2p OCP Card - 1dd8 4008 DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC + 1dd8 4007 DSP DSC-25 Ent 10/25G OCP3 Card + 1dd8 4008 DSP DSC-25 10/25G 2p SFP28 Card 1dd8 400a DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card 1dd8 400c DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card - 1dd8 400d DSP DSC-100 100G 2p QSFP28 Card + 1dd8 400d DSP DSC-100 Ent 100Gb Card + 1dd8 400e DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card 1004 DSC Management Controller 1dd8 4000 Naples 100Gb 2-port QSFP28 x16 8GB 1dd8 4001 Naples 100Gb 2-port QSFP28 x16 4GB 1dd8 4002 Naples 25Gb 2-port SFP28 x8 4GB - 1dd8 4007 DSP DSC-25 10/25G 2p OCP Card - 1dd8 4008 DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC + 1dd8 4007 DSP DSC-25 Ent 10/25G OCP3 Card + 1dd8 4008 DSP DSC-25 10/25G 2p SFP28 Card 1dd8 400a DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card 1dd8 400c DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card - 1dd8 400d DSP DSC-100 100G 2p QSFP28 Card + 1dd8 400d DSP DSC-100 Ent 100Gb Card + 1dd8 400e DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card 1007 DSC Storage Accelerator 1dd8 4000 Naples 100Gb 2-port QSFP28 x16 8GB 1dd8 4001 Naples 100Gb 2-port QSFP28 x16 4GB 1dd8 4002 Naples 25Gb 2-port SFP28 x8 4GB - 1dd8 4007 DSP DSC-25 10/25G 2p OCP Card - 1dd8 4008 DSC-25 10/25G 2-port SFP28 x8 4GB RAM 8GB eMMC + 1dd8 4007 DSP DSC-25 Ent 10/25G OCP3 Card + 1dd8 4008 DSP DSC-25 10/25G 2p SFP28 Card 1dd8 400a DSC-100 40/100G 2-port 8G RAM 16G eMMC G1 Services Card 1dd8 400c DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card - 1dd8 400d DSP DSC-100 100G 2p QSFP28 Card + 1dd8 400d DSP DSC-100 Ent 100Gb Card + 1dd8 400e DSC-25 10/25G 2-port 4G RAM 8G eMMC G1 Services Card 1de0 Groq - 0000 Q100 Tensor Streaming Processor +# rename due to conflict with a term in use by another company for an entirely different product. + 0000 TSP100 Tensor Streaming Processor 1de1 Tekram Technology Co.,Ltd. 0391 TRM-S1040 [DC-315 / DC-395 series] - 2020 DC-390 + 2020 DC-390 Series SCSI Adapter [AMD Am53C974] 690c 690c dc29 DC290 1de5 Eideticom, Inc @@ -23329,6 +23632,42 @@ e00a eMAG PCI Express Root Port 5 e00b eMAG PCI Express Root Port 6 e00c eMAG PCI Express Root Port 7 +# Root Complex A (RCA) + e100 Altra PCI Express Root Complex A +# RCA port 0 + e101 Altra PCI Express Root Port a0 +# RCA port 1 + e102 Altra PCI Express Root Port a1 +# RCA port 2 + e103 Altra PCI Express Root Port a2 +# RAC port 3 + e104 Altra PCI Express Root Port a3 +# RCA port 4 + e105 Altra PCI Express Root Port a4 +# RCA port 5 + e106 Altra PCI Express Root Port a5 +# RCA port 6 + e107 Altra PCI Express Root Port a6 +# RCA port 7 + e108 Altra PCI Express Root Port a7 +# Root Complex B (RCB) + e110 Altra PCI Express Root Complex B +# RCB port 0 + e111 Altra PCI Express Root Port b0 +# RCB port 1 + e112 Altra PCI Express Root Port b1 +# RCB port 2 + e113 Altra PCI Express Root Port b2 +# RCB port 3 + e114 Altra PCI Express Root Port b3 +# RCB port 4 + e115 Altra PCI Express Root Port b4 +# RCB port 5 + e116 Altra PCI Express Root Port b5 +# RCB port 6 + e117 Altra PCI Express Root Port b6 +# RCB port 7 + e118 Altra PCI Express Root Port b7 1df3 Ethernity Networks 0201 ACE-NIC40 Programmable Network Accelerator 1df3 0001 ENA1040 @@ -23352,6 +23691,8 @@ 0206 ACE-NIC200 Programmable Network Accelerator 1df3 0000 Maintenance Mode 1df3 0001 ENA2200F + 0207 ACE-NIC50RN Programmable Network Accelerator + 0208 ACE-NIC100RN Programmable Network Accelerator 1df7 opencpi.org 0001 ml605 0002 alst4 @@ -23400,6 +23741,7 @@ 0002 T11 [CloudBlazer] 0003 T10s [CloudBlazer] 8011 I10 [CloudBlazer] + 8012 I10L [CloudBlazer] # nee Thinci, Inc 1e38 Blaize, Inc 0102 Xplorer X1600 @@ -23440,11 +23782,13 @@ 1601 NVMe SSD Controller MAP1601 1e4c GSI Technology # Associative Processing Unit (APU) - 0010 APU [Leda-G] + 0010 APU [Leda] 1e4c 0120 SE120 1e57 Beijing Panyi Technology Co., Ltd 0100 The device has already been deleted. 0000 0100 PY8800 64GB Accelerator +1e60 Hailo Technologies Ltd. + 2864 Hailo-8 AI Processor 1e6b Axiado Corp. 1e7b Dataland 1e7c Brainchip Inc @@ -23456,10 +23800,19 @@ # aka SED Systems 1e94 Calian SED 1e95 Solid State Storage Technology Corporation +1ea0 Tencent Technology (Shenzhen) Company Limited + 2a16 Cloud Intelligent Inference Controller 1eab Hefei DATANG Storage Technology Co.,LTD. + 300a NVMe SSD Controller 300A + 300b NVMe SSD Controller 300B 1eae XFX Limited 1eb1 VeriSilicon Inc 1001 Video Accelerator +1ed3 Yeston +1ed8 Digiteq Automotive + 0101 FG4 PCIe Frame Grabber +1ed9 Myrtle.ai +1ee9 SUSE LLC # nee Tumsan Oy 1fc0 Ascom (Finland) Oy 0300 E2200 Dual E1/Rawpipe Card @@ -23541,7 +23894,11 @@ 2348 Racore 2010 8142 100VG/AnyLAN 2646 Kingston Technology Company, Inc. + 0010 HyperX Predator PCIe AHCI SSD + 2262 KC2000 NVMe SSD 2263 A2000 NVMe SSD + 5008 U-SNS8154P3 NVMe SSD + 500d OM3PDP3 NVMe SSD 270b Xantel Corporation 270f Chaintech Computer Co. Ltd 2711 AVID Technology Inc. @@ -23706,7 +24063,8 @@ 7053 CH353 PCI Dual Serial and Parallel Ports Controller 7073 CH356 PCI Quad Serial and Parallel Ports Controller 7173 CH355 PCI Quad Serial Port Controller -434e CAST Navigation LLC +434e Cornelis Networks +43bc Tiger Lake-H PCIe Root Port #5 4444 Internext Compression Inc 0016 iTVC16 (CX23416) Video Decoder 0070 0003 WinTV PVR 250 @@ -24292,6 +24650,7 @@ 0100 2nd Generation Core Processor Family DRAM Controller 1028 04aa XPS 8300 1043 844d P8P67/P8H67 Series Motherboard + 8086 200d DH61CR motherboard 0101 Xeon E3-1200/2nd Generation Core Processor Family PCI Express Root Port 1028 04b2 Vostro 3350 106b 00dc MacBookPro8,2 [Core i7, 15", 2011] @@ -24371,15 +24730,24 @@ 1043 844d P8B WS Motherboard 0172 Xeon E3-1200 v2/3rd Gen Core processor Graphics Controller 0176 3rd Gen Core processor Graphics Controller + 0201 Arctic Sound 0284 Comet Lake PCH-LP LPC Premium Controller/eSPI Controller 02a3 Comet Lake PCH-LP SMBus Host Controller 02a4 Comet Lake SPI (flash) Controller 02a6 Comet Lake North Peak + 02b0 Comet Lake PCI Express Root Port #9 + 02b1 Comet Lake PCI Express Root Port #10 + 02b3 Comet Lake PCI Express Root Port #12 + 02b4 Comet Lake PCI Express Root Port #13 + 02b8 Comet Lake PCI Express Root Port #1 + 02bc Comet Lake PCI Express Root Port #5 + 02c5 Comet Lake Serial IO I2C Host Controller 02c8 Comet Lake PCH-LP cAVS 02d3 Comet Lake SATA AHCI Controller 02e0 Comet Lake Management Engine Interface 02e8 Serial IO I2C Host Controller 02e9 Comet Lake Serial IO I2C Host Controller + 02ea Comet Lake PCH-LP LPSS: I2C Controller #2 02ed Comet Lake PCH-LP USB 3.1 xHCI Host Controller 02ef Comet Lake PCH-LP Shared SRAM 02f0 Comet Lake PCH-LP CNVi WiFi @@ -24418,7 +24786,9 @@ 0406 Haswell Integrated Graphics Controller 040a Xeon E3-1200 v3 Processor Integrated Graphics Controller 0412 Xeon E3-1200 v3/4th Gen Core Processor Integrated Graphics Controller + 1028 05d7 Alienware X51 R2 103c 1998 EliteDesk 800 G1 + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 0416 4th Gen Core Processor Integrated Graphics Controller 17aa 220e ThinkPad T440p @@ -24478,9 +24848,12 @@ 06ab Comet Lake PCH Serial IO SPI Controller #1 06ac Comet Lake PCI Express Root Port #21 06b0 Comet Lake PCI Express Root Port #9 + 06bd Comet Lake PCIe Port #6 06c0 Comet Lake PCI Express Root Port #17 06c8 Comet Lake PCH cAVS + 06d2 Comet Lake SATA AHCI Controller 06e0 Comet Lake HECI Controller + 06e3 Comet Lake Keyboard and Text (KT) Redirection 06e8 Comet Lake PCH Serial IO I2C Controller #0 06e9 Comet Lake PCH Serial IO I2C Controller #1 06ea Comet Lake PCH Serial IO I2C Controller #2 @@ -24965,7 +25338,7 @@ 1028 1fe9 Express Flash NVMe 4.0TB HHHL AIC (P4600) 0b26 Thunderbolt 4 Bridge [Goshen Ridge 2020] 0b27 Thunderbolt 4 USB Controller [Goshen Ridge 2020] - 0b60 NVMe DC SSD [3DNAND, Beta Rock Controller] + 0b60 NVMe DC SSD [3DNAND, Sentinel Rock Controller] 1028 2060 NVMe SED MU U.2 1.6TB (P5600) 1028 2061 NVMe SED MU U.2 3.2TB (P5600) 1028 2062 NVMe SED MU U.2 6.4TB (P5600) @@ -24978,6 +25351,9 @@ 1028 2102 NVMe RI U.2 1.92TB (P5500) 1028 2103 NVMe RI U.2 3.84TB (P5500) 1028 2104 NVMe RI U.2 7.68TB (P5500) + 8086 8008 NVMe Datacenter SSD [3DNAND] SE 2.5" U.2 (P5510) + 8086 8d08 NVMe Datacenter SSD [3DNAND] VE 2.5" U.2 (P5316) + 8086 8d1d NVMe Datacenter SSD [3DNAND] VE E1.L 9.5/18mm (P5316) 0be0 Atom Processor D2xxx/N2xxx Integrated Graphics Controller 0be1 Atom Processor D2xxx/N2xxx Integrated Graphics Controller 105b 0d7c D270S/D250S Motherboard @@ -25005,7 +25381,9 @@ 0bf6 Atom Processor D2xxx/N2xxx DRAM Controller 0bf7 Atom Processor D2xxx/N2xxx DRAM Controller 0c00 4th Gen Core Processor DRAM Controller + 1028 05d7 Alienware X51 R2 103c 1998 EliteDesk 800 G1 + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 0c01 Xeon E3-1200 v3/4th Gen Core Processor PCI Express x16 Controller 0c04 Xeon E3-1200 v3/4th Gen Core Processor DRAM Controller @@ -25793,6 +26171,9 @@ 8086 4532 Desktop Board D815EEA2/D815EFV 8086 4541 D815EEA Motherboard 8086 4557 D815EGEW Mainboard + 1136 Thunderbolt 4 Bridge [Maple Ridge 4C 2020] + 1137 Thunderbolt 4 NHI [Maple Ridge 4C 2020] + 1138 Thunderbolt 4 USB Controller [Maple Ridge 4C 2020] 1161 82806AA PCI64 Hub Advanced Programmable Interrupt Controller 8086 1161 82806AA PCI64 Hub APIC 1162 Xscale 80200 Big Endian Companion Chip @@ -26026,6 +26407,7 @@ 1503 82579V Gigabit Network Connection 1043 849c P8P67 Deluxe Motherboard 10cf 161c LIFEBOOK E752 + 8086 200d DH61CR motherboard 1507 Ethernet Express Module X520-P2 1508 82598EB Gigabit BX Network Connection 1509 82580 Gigabit Network Connection @@ -26093,6 +26475,8 @@ 18d4 0c07 I350 1Gb 2-port RJ45 OCP Mezz Card MOP41-I-1GT2 193d 1005 360T-B 193d 1007 360T-L +# NIC-ETH360T-3S-4P OCP3.0 4x1G Base-T Card + 193d 1080 NIC-ETH360T-3S-4P 1bd4 001d 1G base-T QP EP014Ti1 Adapter 1bd4 0035 1G base-T QP EP014Ti1 Adapter 8086 0001 Ethernet Server Adapter I350-T4 @@ -26245,6 +26629,7 @@ 156f Ethernet Connection I219-LM 1028 06dc Latitude E7470 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 1570 Ethernet Connection I219-V 1571 Ethernet Virtual Function 700 Series 1572 Ethernet Controller X710 for 10GbE SFP+ @@ -26263,7 +26648,12 @@ 17aa 0000 ThinkServer X710 AnyFabric for 10GbE SFP+ 17aa 4001 ThinkServer X710-4 AnyFabric for 10GbE SFP+ 17aa 4002 ThinkServer X710-2 AnyFabric for 10GbE SFP+ + 193d 1020 NIC-ETH561F-sL-4x10G + 193d 1021 NIC-ETH561F-sL-2x10G +# NIC-ETH561F-3S-2P OCP3.0 2x10G SFP+ Card + 193d 1081 NIC-ETH561F-3S-2P 19e5 d11c Ethernet 2-port X710 10Gb SFP+ Adapter SP330 + 1bd4 0042 10G SFP+ DP EP102Fi4 Adapter 1bd4 0056 Ethernet Network Adapter X710-BM2 for OCP NIC 3.0 8086 0000 Ethernet Converged Network Adapter X710 8086 0001 Ethernet Converged Network Adapter X710-4 @@ -26296,6 +26686,7 @@ 1577 DSL6540 Thunderbolt 3 NHI [Alpine Ridge 4C 2015] 1578 DSL6540 Thunderbolt 3 Bridge [Alpine Ridge 4C 2015] 157b I210 Gigabit Network Connection + ea50 cc10 RXi2-BP 157c I210 Gigabit Backplane Connection 157d DSL5110 Thunderbolt 2 NHI (Low Power) [Win Ridge 2C 2014] 157e DSL5110 Thunderbolt 2 Bridge (Low Power) [Win Ridge 2C 2014] @@ -26308,6 +26699,7 @@ 1059 0170 RD-01213 10GbE interface 1590 0000 Ethernet 2-port 563i Adapter 1590 00f8 Ethernet 2-port 563i Adapter + 193d 100e NIC-ETH561i-Mb-4x10G 8086 0000 Ethernet Converged Network Adapter XL710-Q2 1583 Ethernet Controller XL710 for 40GbE QSFP+ 1028 0000 Ethernet 40G 2P XL710 QSFP+ rNDC @@ -26392,6 +26784,7 @@ 1591 Ethernet Controller E810-C for backplane 1592 Ethernet Controller E810-C for QSFP 1137 02bf E810CQDA2 2x100 GbE QSFP28 PCIe NIC + 8086 0001 Ethernet Network Adapter E810-C-Q1 8086 0002 Ethernet Network Adapter E810-C-Q2 8086 0004 Ethernet Network Adapter E810-C-Q2 8086 0005 Ethernet Network Adapter E810-C-Q1 for OCP3.0 @@ -26400,6 +26793,8 @@ 8086 000a Ethernet Network Adapter E810-C-Q1 for OCP 8086 000b Ethernet 100G 2P E810-C Adapter 8086 000c Ethernet 100G 2P E810-C OCP + 8086 000d Ethernet Network Adapter E810-L-Q2 for OCP 3.0 + 8086 000e Ethernet Network Adapter E810-2C-Q2 1593 Ethernet Controller E810-C for SFP 1137 02c3 E810XXVDA4 4x25/10 GbE SFP28 PCIe NIC 8086 0002 Ethernet Network Adapter E810-L-2 @@ -26444,6 +26839,7 @@ 15b6 DSL6540 USB 3.1 Controller [Alpine Ridge] 15b7 Ethernet Connection (2) I219-LM 15b8 Ethernet Connection (2) I219-V + 1462 7a72 H270 PC MATE 15b9 Ethernet Connection (3) I219-LM 15bb Ethernet Connection (7) I219-LM 15bc Ethernet Connection (7) I219-V @@ -26513,6 +26909,10 @@ 1137 0000 X710TLG GbE RJ45 PCIe NIC 1137 02c1 X710T2LG 2x10 GbE RJ45 PCIe NIC 1137 02c2 X710T4LG 4x10 GbE RJ45 PCIe NIC + 1137 02d9 Ethernet Network Adapter X710-T2L OCP 3.0 + 1137 02da Ethernet Network Adapter X710-T4L OCP 3.0 +# NIC-ETH565T-3S-2P OCP3.0 2x10G Base-T Card + 193d 1082 NIC-ETH565T-3S-2P 8086 0000 Ethernet Network Adapter X710-TL 8086 0001 Ethernet Network Adapter X710-T4L 8086 0002 Ethernet Network Adapter X710-T4L @@ -26578,18 +26978,20 @@ 18a0 C4xxx Series QAT 18a1 C4XXX Series QAT Virtual Function 1900 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers - 1901 6th-9th Gen Core Processor PCIe Controller (x16) + 1901 6th-10th Gen Core Processor PCIe Controller (x16) 1902 HD Graphics 510 1903 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Thermal Subsystem 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 1028 06e4 XPS 15 9550 + 1028 06e6 Latitude 11 5175 2-in-1 103c 825b OMEN-17-w001nv 17aa 225d ThinkPad T480 1904 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers 1028 06dc Latitude E7470 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 17aa 382a B51-80 Laptop 1905 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x8) 1906 HD Graphics 510 @@ -26598,12 +27000,14 @@ 1909 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor PCIe Controller (x4) 190c Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 190f Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers 1910 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers 1028 06e4 XPS 15 9550 103c 825b OMEN-17-w001nv 1911 Xeon E3-1200 v5/v6 / E3-1500 v5 / 6th/7th/8th Gen Core Processor Gaussian Mixture Model 1028 0869 Vostro 3470 + 1462 7a72 H270 PC MATE 17aa 2247 ThinkPad T570 17aa 224f ThinkPad X1 Carbon 5th Gen 17aa 225d ThinkPad T480 @@ -26612,15 +27016,18 @@ 1028 06dc Latitude E7470 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 1918 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers 1919 Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Imaging Unit 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 191b HD Graphics 530 1028 06e4 XPS 15 9550 103c 825b OMEN-17-w001nv 191d HD Graphics P530 191e HD Graphics 515 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 191f Xeon E3-1200 v5/E3-1500 v5/6th Gen Core Processor Host Bridge/DRAM Registers 1921 HD Graphics 520 1926 Iris Graphics 540 @@ -26732,6 +27139,7 @@ 1c02 6 Series/C200 Series Chipset Family 6 port Desktop SATA AHCI Controller 1028 04aa XPS 8300 1043 844d P8 series motherboard + 8086 200d DH61CR motherboard 8086 7270 Server Board S1200BT Family 1c03 6 Series/C200 Series Chipset Family 6 port Mobile SATA AHCI Controller 1028 04a3 Precision M4600 @@ -26782,6 +27190,7 @@ 17aa 21cf ThinkPad T520 # Realtek ALC888 audio codec 8086 2008 DQ67SW board + 8086 200d DH61CR motherboard 8086 7270 Apple MacBookPro8,2 [Core i7, 15", 2011] 1c22 6 Series/C200 Series Chipset Family SMBus Controller 1028 04a3 Precision M4600 @@ -26790,6 +27199,7 @@ 1028 04da Vostro 3750 1043 844d P8 series motherboard 17aa 21cf ThinkPad T520 + 8086 200d DH61CR motherboard 8086 7270 Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2 1c24 6 Series/C200 Series Chipset Family Thermal Management Controller 1c25 6 Series/C200 Series Chipset Family DMI to PCI Bridge @@ -26800,6 +27210,7 @@ 1028 04da Vostro 3750 1043 844d P8 series motherboard 17aa 21cf ThinkPad T520 + 8086 200d DH61CR motherboard 8086 7270 Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2 1c27 6 Series/C200 Series Chipset Family USB Universal Host Controller #1 8086 7270 Apple MacBookPro8,2 [Core i7, 15", 2011] @@ -26812,6 +27223,7 @@ 1028 04da Vostro 3750 1043 844d P8 series motherboard 17aa 21cf ThinkPad T520 + 8086 200d DH61CR motherboard 8086 7270 Server Board S1200BT Family / Apple MacBook Pro 8,1/8,2 1c33 6 Series/C200 Series Chipset Family LAN Controller 1c35 6 Series/C200 Series Chipset Family VECI Controller @@ -26822,6 +27234,7 @@ 1028 04da Vostro 3750 1043 844d P8 series motherboard 17aa 21cf ThinkPad T520 + 8086 200d DH61CR motherboard 8086 7270 Apple MacBookPro8,2 [Core i7, 15", 2011] 1c3b 6 Series/C200 Series Chipset Family MEI Controller #2 1c3c 6 Series/C200 Series Chipset Family IDE-r Controller @@ -26865,6 +27278,7 @@ 1c5a Upgraded Q67 Express Chipset LPC Controller 1c5b 6 Series/C200 Series Chipset Family LPC Controller 1c5c H61 Express Chipset LPC Controller + 8086 200d DH61CR motherboard 1c5d 6 Series/C200 Series Chipset Family LPC Controller 1c5e 6 Series/C200 Series Chipset Family LPC Controller 1c5f 6 Series/C200 Series Chipset Family LPC Controller @@ -27328,6 +27742,7 @@ 147b 0507 TH7II-RAID 8086 4532 Desktop Board D815EEA2/D815EFV 8086 4557 D815EGEW Mainboard + 8086 4d44 D850EMV2 motherboard 8086 5744 S845WD1-E mainboard 2443 82801BA/BAM SMBus Controller 1014 01c6 Netvista A40/A40p @@ -27369,6 +27784,7 @@ 147b 0507 TH7II-RAID 8086 4557 D815EGEW Mainboard 8086 4656 Desktop Board D815EFV + 8086 4d44 D850EMV2 motherboard 2446 82801BA/BAM AC'97 Modem Controller 1025 1016 Travelmate 612 TX 104d 80df Vaio PCG-FX403 @@ -27443,6 +27859,7 @@ 15d9 3280 Supermicro P4SBE Mainboard 8086 4532 Desktop Board D815EEA2/D815EFV 8086 4557 D815EGEW Mainboard + 8086 4d44 D850EMV2 motherboard 8086 5744 S845WD1-E mainboard 244c 82801BAM ISA Bridge (LPC) 244e 82801 PCI Bridge @@ -27945,6 +28362,7 @@ 1cb8 0002 Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, TC6600 Fixed Port 1cb8 0003 Omni-Path HFI Adapter 100 Series, 2 Port, 2 PCIe x16, Earth Simulation QSFP28 1cb8 0004 Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16, TC4600E QSFP28 + 434e 0001 Omni-Path HFI 100 Series, 1 Port, OCP 3.0 Adapter 8086 2628 Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x16 8086 2629 Omni-Path HFI Adapter 100 Series, 1 Port, PCIe x8 8086 262a Omni-Path HFI Adapter 100 Series, 2 Ports, Split PCIe x16 @@ -28066,6 +28484,7 @@ 103c 0934 Compaq nw8240/nx8220 103c 0944 Compaq nc6220 Notebook PC 103c 099c NX6110/NC6120 + 1043 82d9 Asus Eee PC 900 104d 81b7 Vaio VGN-S3XP a304 81b7 Vaio VGN-S3XP e4bf 0ccd CCD-CALYPSO @@ -28508,6 +28927,7 @@ 277c 82975X Memory Controller Hub 1043 8178 P5WDG2 WS Professional motherboard 277d 82975X PCI Express Root Port + 2780 82915G/GV/GL/910GL [Grantsdale] Graphics Device 2782 82915G Integrated Graphics Controller 1043 2582 P5GD1-VW Mainboard 1734 105b Scenic W620 @@ -29469,6 +29889,7 @@ 1028 022f Inspiron 1525 103c 30c0 Compaq 6710b 103c 30c1 Compaq 6910p + 103c 30c5 Compaq 8510p 103c 30cc Pavilion dv6700 103c 30d9 Presario C700 1043 1017 X58LE @@ -29524,6 +29945,7 @@ 2a41 Mobile 4 Series Chipset PCI Express Graphics Port e4bf cc4d CCM-BOOGIE 2a42 Mobile 4 Series Chipset Integrated Graphics Controller + 1028 02aa Dell Inspiron 1545 17aa 2112 ThinkPad T400 e4bf cc4d CCM-BOOGIE 2a43 Mobile 4 Series Chipset Integrated Graphics Controller @@ -29939,8 +30361,8 @@ 8086 4210 Dual Band Wireless AC 3165 3166 Dual Band Wireless-AC 3165 Plus Bluetooth 8086 4210 Dual Band Wireless-AC 3165 - 3184 UHD Graphics 605 - 3185 UHD Graphics 605 + 3184 GeminiLake [UHD Graphics 605] + 3185 GeminiLake [UHD Graphics 600] 318c Celeron/Pentium Silver Processor Dynamic Platform and Thermal Framework Processor Participant 318e Celeron/Pentium Silver Processor NorthPeak 3190 Celeron/Pentium Silver Processor Gaussian Mixture Model @@ -29950,6 +30372,8 @@ 17aa 380b V130-15IGM Laptop (Lenovo) - Type 81HL 319a Celeron/Pentium Silver Processor Trusted Execution Engine Interface 31a2 Celeron/Pentium Silver Processor Integrated Sensor Solution + 31a8 Celeron/Pentium Silver Processor USB 3.0 xHCI Controller + 1849 31a8 Celeron/Pentium Silver Processor USB 3.0 xHCI Controller 31ac Celeron/Pentium Silver Processor Serial IO I2C Host Controller 31ae Celeron/Pentium Silver Processor Serial IO I2C Host Controller 31bc Celeron/Pentium Silver Processor Serial IO UART Host Controller @@ -29967,6 +30391,8 @@ 31da Gemini Lake PCI Express Root Port 31db Gemini Lake PCI Express Root Port 31dc AC 1550i Wireless + 31e3 Celeron/Pentium Silver Processor SATA Controller + 31e8 Celeron/Pentium Silver Processor LPC Controller 31ee Celeron/Pentium Silver Processor Serial IO UART Host Controller 31f0 Gemini Lake Host Bridge 3200 GD31244 PCI-X SATA HBA @@ -30052,19 +30478,22 @@ 34aa Ice Lake-LP Serial IO SPI Controller #0 34ab Ice Lake-LP Serial IO SPI Controller #1 34b0 Ice Lake-LP PCI Express Root Port #9 + 34b7 Ice Lake-LP PCI Express Root Port #16 34bc Ice Lake-LP PCI Express Root Port #5 34c5 Ice Lake-LP Serial IO I2c Controller #4 34c6 Ice Lake-LP Serial IO I2c Controller #5 - 34c8 Smart Sound Technology Audio Controller + 34c8 Ice Lake-LP Smart Sound Technology Audio Controller 34d3 Ice Lake-LP SATA Controller [AHCI mode] - 34e0 Management Engine Interface + 34e0 Ice Lake-LP Management Engine 34e8 Ice Lake-LP Serial IO I2C Controller #0 34e9 Ice Lake-LP Serial IO I2C Controller #1 34ea Ice Lake-LP Serial IO I2C Controller #2 34eb Ice Lake-LP Serial IO I2C Controller #3 34ed Ice Lake-LP USB 3.1 xHCI Host Controller + 34ef Ice Lake-LP DRAM Controller 34f0 Killer Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW) 34f8 Ice Lake-LP SD Controller + 34fc Ice Lake-LP Integrated Sensor Solution 3500 6311ESB/6321ESB PCI Express Upstream Port 103c 31fe ProLiant DL140 G3 15d9 9680 X7DBN Motherboard @@ -30678,16 +31107,17 @@ 3e81 8th Gen Core Processor PCIe Controller (x16) 3e85 8th Gen Core Processor PCIe Controller (x8) 3e89 8th Gen Core Processor PCIe Controller (x4) - 3e91 8th Gen Core Processor Gaussian Mixture Model - 3e92 UHD Graphics 630 (Desktop) + 3e90 CoffeeLake-S GT1 [UHD Graphics 610] + 3e91 CoffeeLake-S GT2 [UHD Graphics 630] + 3e92 CometLake-S GT2 [UHD Graphics 630] 1028 0869 Vostro 3470 - 3e93 UHD Graphics 610 - 3e96 HD Graphics P630 - 3e98 UHD Graphics 630 (Desktop 9 Series) - 3e9b UHD Graphics 630 (Mobile) - 3ea0 UHD Graphics 620 (Whiskey Lake) + 3e93 CoffeeLake-S GT1 [UHD Graphics 610] + 3e96 CoffeeLake-S GT2 [UHD Graphics P630] + 3e98 CoffeeLake-S GT2 [UHD Graphics 630] + 3e9b CoffeeLake-H GT2 [UHD Graphics 630] + 3ea0 WhiskeyLake-U GT2 [UHD Graphics 620] 1028 089e Inspiron 5482 - 3ea5 Iris Plus Graphics 655 + 3ea5 CoffeeLake-U GT3e [Iris Plus Graphics 655] 3ec2 8th Gen Core Processor Host Bridge/DRAM Registers 1028 0869 Vostro 3470 1043 8694 PRIME H310M-D @@ -30715,6 +31145,7 @@ 4032 5400 Chipset IOxAPIC 4035 5400 Chipset FBD Registers 4036 5400 Chipset FBD Registers + 4041 NVMe Datacenter SSD [Optane] 4100 Moorestown Graphics and Video 4108 Atom Processor E6xx Integrated Graphics Controller 4109 Atom Processor E6xx Integrated Graphics Controller @@ -30728,6 +31159,13 @@ 4115 Atom Processor E6xx PCI Host Bridge #2 4116 Atom Processor E6xx PCI Host Bridge #3 4117 Atom Processor E6xx PCI Host Bridge #4 + 4140 NVMe Datacenter SSD [Optane] + 1028 2134 NVMe Datacenter SSD [Optane] SED 400GB 2.5" U.2 (P5800X) + 1028 2135 NVMe Datacenter SSD [Optane] SED 800GB 2.5" U.2 (P5800X) + 1028 2136 NVMe Datacenter SSD [Optane] SED 1.6GB 2.5" U.2 (P5800X) + 1028 2137 NVMe Datacenter SSD [Optane] 400GB 2.5" U.2 (P5800X) + 1028 2138 NVMe Datacenter SSD [Optane] 800GB 2.5" U.2 (P5800X) + 1028 2139 NVMe Datacenter SSD [Optane] 1.6TB 2.5" U.2 (P5800X) 4220 PRO/Wireless 2200BG [Calexico2] Network Connection 103c 0934 Compaq nw8240/nx8220 103c 12f6 nc6120/nc6220/nw8240/nx8220 @@ -30817,9 +31255,29 @@ 8086 1216 WiMAX/WiFi Link 5150 ABG 8086 1311 WiMAX/WiFi Link 5150 AGN 8086 1316 WiMAX/WiFi Link 5150 ABG + 438b Tiger Lake-H LPC/eSPI Controller + 43a3 Tiger Lake-H SMBus Controller + 43a4 Tiger Lake-H SPI Controller + 43b0 Tiger Lake-H PCI Express Root Port #9 + 43bc Tiger Lake-H PCI Express Root Port #5 + 43c8 Tiger Lake-H HD Audio Controller + 43e0 Tiger Lake-H Management Engine Interface + 43e8 Tiger Lake-H Serial IO I2C Controller #0 + 43ed Tiger Lake-H USB 3.2 Gen 2x1 xHCI Host Controller + 43ef Tiger Lake-H Shared SRAM + 43f0 Wi-Fi 6 AX201 444e Turbo Memory Controller 467f Volume Management Device NVMe RAID Controller + 4680 AlderLake-S GT1 + 46a0 AlderLake-P GT2 + 4905 DG1 [Iris Xe MAX Graphics] + 4906 DG1 [Iris Xe Pod] + 4907 SG1 [Server GPU SG-18M] + 4908 DG1 [Iris Xe Graphics] 4c3d Volume Management Device NVMe RAID Controller + 4f80 DG2 + 4f81 DG2 + 4f82 DG2 5001 LE80578 5002 LE80578 Graphics Processor Unit 5009 LE80578 Video Display Controller @@ -30872,6 +31330,7 @@ 8086 0001 EtherExpress PRO/100 Server Ethernet Adapter 530d 80310 (IOP) IO Processor 5502 Ethernet Controller (2) I225-LMvP + 5504 Ethernet Controller I226-K 5845 QEMU NVM Express Controller 1af4 1100 QEMU Virtual Machine 5900 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers @@ -30886,9 +31345,11 @@ 590c Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers 590f Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers 1462 7a68 B250 KRAIT GAMING (MS-7A68) + 1462 7a72 H270 PC MATE 5910 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers 5911 Xeon E3-1200 v6/7th Gen Core Processor Gaussian Mixture Model 5912 HD Graphics 630 + 1462 7a72 H270 PC MATE 5914 Xeon E3-1200 v6/7th Gen Core Processor Host Bridge/DRAM Registers 17aa 225d ThinkPad T480 5916 HD Graphics 620 @@ -31269,6 +31730,7 @@ 1993 0ded mGuard-PCI AV#2 1993 0dee mGuard-PCI AV#1 1993 0def mGuard-PCI AV#0 + 8603 Ice Lake-LP Dynamic Tuning Processor Participant 87c0 UHD Graphics 617 8800 Platform Controller Hub EG20T PCI Express Port 8801 Platform Controller Hub EG20T Packet Hub @@ -31297,8 +31759,10 @@ 8818 Platform Controller Hub EG20T Controller Area Network (CAN) Controller 8819 Platform Controller Hub EG20T IEEE 1588 Hardware Assist 8a0d Ice Lake Thunderbolt 3 NHI #1 + 8a12 Ice Lake-LP Processor Host Bridge/DRAM Registers 8a13 Ice Lake Thunderbolt 3 USB Controller 8a17 Ice Lake Thunderbolt 3 NHI #0 + 8a19 Image Signal Processor 8a1d Ice Lake Thunderbolt 3 PCI Express Root Port #0 8a1f Ice Lake Thunderbolt 3 PCI Express Root Port #1 8a21 Ice Lake Thunderbolt 3 PCI Express Root Port #2 @@ -31311,7 +31775,9 @@ 8c00 8 Series/C220 Series Chipset Family 4-port SATA Controller 1 [IDE mode] 8c01 8 Series Chipset Family 4-port SATA Controller 1 [IDE mode] - Mobile 8c02 8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] + 1028 05d7 Alienware X51 R2 103c 1998 EliteDesk 800 G1 + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 8c03 8 Series/C220 Series Chipset Family 6-port SATA Controller 1 [AHCI mode] 103c 1909 ZBook 15 @@ -31328,6 +31794,7 @@ 103c 1998 EliteDesk 800 G1 1043 8534 ASUS H81I-PLUS 17aa 220e ThinkPad T440p + 17aa 3098 ThinkCentre E73 8c11 8 Series/C220 Series Chipset Family PCI Express Root Port #1 8c12 8 Series/C220 Series Chipset Family PCI Express Root Port #2 103c 1998 EliteDesk 800 G1 @@ -31340,47 +31807,59 @@ 8c18 8 Series/C220 Series Chipset Family PCI Express Root Port #5 8c19 8 Series/C220 Series Chipset Family PCI Express Root Port #5 8c1a 8 Series/C220 Series Chipset Family PCI Express Root Port #6 + 17aa 3098 ThinkCentre E73 8c1b 8 Series/C220 Series Chipset Family PCI Express Root Port #6 8c1c 8 Series/C220 Series Chipset Family PCI Express Root Port #7 8c1d 8 Series/C220 Series Chipset Family PCI Express Root Port #7 8c1e 8 Series/C220 Series Chipset Family PCI Express Root Port #8 8c1f 8 Series/C220 Series Chipset Family PCI Express Root Port #8 8c20 8 Series/C220 Series Chipset High Definition Audio Controller + 1028 05d7 Alienware X51 R2 103c 1909 ZBook 15 103c 1998 EliteDesk 800 G1 17aa 220e ThinkPad T440p 17aa 309f ThinkCentre M83 8c21 8 Series/C220 Series Chipset High Definition Audio Controller 8c22 8 Series/C220 Series Chipset Family SMBus Controller + 1028 05d7 Alienware X51 R2 103c 1909 ZBook 15 103c 1998 EliteDesk 800 G1 17aa 220e ThinkPad T440p + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 8c23 8 Series Chipset Family CHAP Counters 8c24 8 Series Chipset Family Thermal Management Controller 8c26 8 Series/C220 Series Chipset Family USB EHCI #1 + 1028 05d7 Alienware X51 R2 103c 1909 ZBook 15 103c 1998 EliteDesk 800 G1 17aa 220e ThinkPad T440p 17aa 2210 ThinkPad T540p + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 2210 17aa ThinkPad T540p 8c2d 8 Series/C220 Series Chipset Family USB EHCI #2 + 1028 05d7 Alienware X51 R2 103c 1909 ZBook 15 103c 1998 EliteDesk 800 G1 17aa 220e ThinkPad T440p + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 8c31 8 Series/C220 Series Chipset Family USB xHCI + 1028 05d7 Alienware X51 R2 103c 1909 ZBook 15 103c 1998 EliteDesk 800 G1 17aa 220e ThinkPad T440p + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 8c33 8 Series/C220 Series Chipset Family LAN Controller 8c34 8 Series/C220 Series Chipset Family NAND Controller 8c3a 8 Series/C220 Series Chipset Family MEI Controller #1 + 1028 05d7 Alienware X51 R2 103c 1909 ZBook 15 103c 1998 EliteDesk 800 G1 17aa 220e ThinkPad T440p + 17aa 3098 ThinkCentre E73 17aa 309f ThinkCentre M83 8c3b 8 Series/C220 Series Chipset Family MEI Controller #2 8c3c 8 Series/C220 Series Chipset Family IDE-r Controller @@ -31397,6 +31876,7 @@ 8c48 8 Series/C220 Series Chipset Family LPC Controller 8c49 HM86 Express LPC Controller 8c4a H87 Express LPC Controller + 1028 05d7 Alienware X51 R2 8c4b HM87 Express LPC Controller 8c4c Q85 Express LPC Controller 17aa 309f ThinkCentre M83 @@ -31419,6 +31899,7 @@ 8c5a 8 Series/C220 Series Chipset Family LPC Controller 8c5b 8 Series/C220 Series Chipset Family LPC Controller 8c5c H81 Express LPC Controller + 17aa 3098 ThinkCentre E73 8c5d 8 Series/C220 Series Chipset Family LPC Controller 8c5e 8 Series/C220 Series Chipset Family LPC Controller 8c5f 8 Series/C220 Series Chipset Family LPC Controller @@ -31537,32 +32018,44 @@ 9622 Integrated RAID 9641 Integrated RAID 96a1 Integrated RAID + 9a01 11th Gen Core Processor PCIe Controller #1 + 9a03 TigerLake-LP Dynamic Tuning Processor Participant 9a09 11th Gen Core Processor PCIe Controller 9a0b Volume Management Device NVMe RAID Controller - 9a13 Tiger Lake-LP Thunderbolt USB Controller + 9a0d Tiger Lake-LP Telemetry Aggregator + 9a0f 11th Gen Core Processor PCIe Controller #0 + 9a11 GNA Scoring Accelerator module + 9a13 Tiger Lake-LP Thunderbolt 4 USB Controller 9a14 11th Gen Core Processor Host Bridge/DRAM Registers - 9a17 Tiger Lake-H Thunderbolt USB Controller - 9a1b Tiger Lake-LP Thunderbolt NHI #0 - 9a1d Tiger Lake-LP Thunderbolt NHI #1 - 9a1f Tiger Lake-H Thunderbolt NHI #0 - 9a21 Tiger Lake-H Thunderbolt NHI #1 - 9a23 Tiger Lake-LP Thunderbolt PCI Express Root Port #0 - 9a25 Tiger Lake-LP Thunderbolt PCI Express Root Port #1 - 9a27 Tiger Lake-LP Thunderbolt PCI Express Root Port #2 - 9a29 Tiger Lake-LP Thunderbolt PCI Express Root Port #3 - 9a2b Tiger Lake-H Thunderbolt PCI Express Root Port #0 - 9a2d Tiger Lake-H Thunderbolt PCI Express Root Port #1 - 9a2f Tiger Lake-H Thunderbolt PCI Express Root Port #2 - 9a31 Tiger Lake-H Thunderbolt PCI Express Root Port #3 + 9a17 Tiger Lake-H Thunderbolt 4 USB Controller + 9a1b Tiger Lake-LP Thunderbolt 4 NHI #0 + 9a1d Tiger Lake-LP Thunderbolt 4 NHI #1 + 9a1f Tiger Lake-H Thunderbolt 4 NHI #0 + 9a21 Tiger Lake-H Thunderbolt 4 NHI #1 + 9a23 Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #0 + 9a25 Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #1 + 9a26 11th Gen Core Processor Host Bridge/DRAM Registers + 9a27 Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #2 + 9a29 Tiger Lake-LP Thunderbolt 4 PCI Express Root Port #3 + 9a2b Tiger Lake-H Thunderbolt 4 PCI Express Root Port #0 + 9a2d Tiger Lake-H Thunderbolt 4 PCI Express Root Port #1 + 9a2f Tiger Lake-H Thunderbolt 4 PCI Express Root Port #2 + 9a31 Tiger Lake-H Thunderbolt 4 PCI Express Root Port #3 9a33 Tiger Lake Trace Hub - 9a49 Iris Xe Graphics - 9b41 UHD Graphics + 9a36 11th Gen Core Processor Host Bridge/DRAM Registers + 9a49 TigerLake GT2 [Iris Xe Graphics] + 9a60 TigerLake GT2 [Iris Xe Graphics] + 9a68 Tiger Lake-H UHD Graphics + 9b41 CometLake-U GT2 [UHD Graphics] 9b44 10th Gen Core Processor Host Bridge/DRAM Registers + 9b53 Comet Lake-S 6c Host Bridge/DRAM Controller 9b54 10th Gen Core Processor Host Bridge/DRAM Registers 9b61 Comet Lake-U v1 4c Host Bridge/DRAM Controller + 9b63 10th Gen Core Processor Host Bridge/DRAM Registers 9b64 10th Gen Core Processor Host Bridge/DRAM Registers - 9bc4 UHD Graphics - 9bc8 UHD Graphics 630 + 9bc4 CometLake-H GT2 [UHD Graphics] + 9bc5 CometLake-S GT2 [UHD Graphics 630] + 9bc8 CometLake-S GT2 [UHD Graphics 630] 9c00 8 Series SATA Controller 1 [IDE mode] 9c01 8 Series SATA Controller 1 [IDE mode] 9c02 8 Series SATA Controller 1 [AHCI mode] @@ -31671,6 +32164,7 @@ 9d03 Sunrise Point-LP SATA Controller [AHCI mode] 1025 115f Acer Aspire E5-575G 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 17aa 225d ThinkPad T480 @@ -31686,6 +32180,7 @@ 9d16 Sunrise Point-LP PCI Express Root Port #7 9d17 Sunrise Point-LP PCI Express Root Port #8 9d18 Sunrise Point-LP PCI Express Root Port #9 + 17aa 2247 ThinkPad T570 17aa 382a B51-80 Laptop 9d19 Sunrise Point-LP PCI Express Root Port #10 9d1a Sunrise Point-LP PCI Express Root Port #11 @@ -31693,8 +32188,10 @@ 1025 115f Acer Aspire E5-575G 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 17aa 224f ThinkPad X1 Carbon 5th Gen 17aa 225d ThinkPad T480 17aa 382a B51-80 Laptop @@ -31702,6 +32199,7 @@ 1025 115f Acer Aspire E5-575G 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 17aa 2247 ThinkPad T570 @@ -31717,6 +32215,7 @@ 1025 115f Acer Aspire E5-575G 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 17aa 2247 ThinkPad T570 @@ -31726,6 +32225,7 @@ 1025 115f Acer Aspire E5-575G 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 17aa 2247 ThinkPad T570 @@ -31734,12 +32234,15 @@ 17aa 382a B51-80 Laptop 9d32 CSI-2 Host Controller 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 9d35 Sunrise Point-LP Integrated Sensor Hub 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 9d3a Sunrise Point-LP CSME HECI #1 1025 115f Acer Aspire E5-575G 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 17aa 2247 ThinkPad T570 @@ -31748,14 +32251,17 @@ 17aa 382a B51-80 Laptop 9d3d Sunrise Point-LP Active Management Technology - SOL 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 9d43 Sunrise Point-LP LPC Controller 17aa 382a B51-80 Laptop 9d46 LPC/eSPI Controller 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 9d48 Sunrise Point-LP LPC Controller 1028 06dc Latitude E7470 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 9d4e Sunrise Point LPC Controller/eSPI Controller 17aa 225d ThinkPad T480 9d50 Sunrise Point LPC Controller @@ -31767,14 +32273,17 @@ 9d60 Sunrise Point-LP Serial IO I2C Controller #0 1025 115f Acer Aspire E5-575G 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 17aa 225d ThinkPad T480 8086 9d60 100 Series PCH/Sunrise Point PCH I2C0 [Skylake/Kaby Lake LPSS I2C] 9d61 Sunrise Point-LP Serial IO I2C Controller #1 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 9d62 Sunrise Point-LP Serial IO I2C Controller #2 1028 06d6 Latitude 7275 tablet + 1028 06e6 Latitude 11 5175 2-in-1 9d63 Sunrise Point-LP Serial IO I2C Controller #3 9d64 Sunrise Point-LP Serial IO I2C Controller #4 9d65 Sunrise Point-LP Serial IO I2C Controller #5 @@ -31782,8 +32291,10 @@ 9d70 Sunrise Point-LP HD Audio 1028 06d6 Latitude 7275 tablet 1028 06dc Latitude E7470 + 1028 06e6 Latitude 11 5175 2-in-1 1028 06f3 Latitude 3570 103c 8079 EliteBook 840 G3 + 17aa 2247 ThinkPad T570 17aa 382a B51-80 Laptop 9d71 Sunrise Point-LP HD Audio 1025 1094 Acer Aspire E5-575G @@ -31849,6 +32360,7 @@ a0a9 Tiger Lake-LP Serial IO UART Controller #1 a0ab Tiger Lake-LP Serial IO SPI Controller #1 a0b0 Tiger Lake-LP PCI Express Root Port #9 + a0bd Tigerlake PCH-LP PCI Express Root Port #6 a0bf Tiger Lake-LP PCI Express Root Port #8 a0c5 Tiger Lake-LP Serial IO I2C Controller #4 a0c6 Tiger Lake-LP Serial IO I2C Controller #5 @@ -32036,16 +32548,20 @@ a252 Lewisburg SSATA Controller [AHCI mode] a256 Lewisburg SSATA Controller [RAID mode] a282 200 Series PCH SATA controller [AHCI mode] + 1462 7a72 H270 PC MATE a286 200 Series PCH SATA controller [RAID mode] a290 200 Series PCH PCI Express Root Port #1 a291 200 Series PCH PCI Express Root Port #2 a292 200 Series PCH PCI Express Root Port #3 a293 200 Series PCH PCI Express Root Port #4 a294 200 Series PCH PCI Express Root Port #5 + 1462 7a72 H270 PC MATE a295 200 Series PCH PCI Express Root Port #6 a296 200 Series PCH PCI Express Root Port #7 + 1462 7a72 H270 PC MATE a297 200 Series PCH PCI Express Root Port #8 a298 200 Series PCH PCI Express Root Port #9 + 1462 7a72 H270 PC MATE a299 200 Series PCH PCI Express Root Port #10 a29a 200 Series PCH PCI Express Root Port #11 a29b 200 Series PCH PCI Express Root Port #12 @@ -32055,7 +32571,9 @@ a29f 200 Series PCH PCI Express Root Port #16 a2a0 200 Series/Z370 Chipset Family P2SB a2a1 200 Series/Z370 Chipset Family Power Management Controller + 1462 7a72 H270 PC MATE a2a3 200 Series/Z370 Chipset Family SMBus Controller + 1462 7a72 H270 PC MATE a2a4 200 Series/Z370 Chipset Family SPI Controller a2a5 200 Series/Z370 Chipset Family Gigabit Ethernet Controller a2a6 200 Series/Z370 Chipset Family Trace Hub @@ -32064,10 +32582,14 @@ a2a9 200 Series/Z370 Chipset Family Serial IO SPI Controller #0 a2aa 200 Series/Z370 Chipset Family Serial IO SPI Controller #1 a2af 200 Series/Z370 Chipset Family USB 3.0 xHCI Controller + 1462 7a72 H270 PC MATE a2b1 200 Series PCH Thermal Subsystem + 1462 7a72 H270 PC MATE a2ba 200 Series PCH CSME HECI #1 + 1462 7a72 H270 PC MATE a2bb 200 Series PCH CSME HECI #2 a2c4 200 Series PCH LPC Controller (H270) + 1462 7a72 H270 PC MATE a2c5 200 Series PCH LPC Controller (Z270) a2c6 200 Series PCH LPC Controller (Q270) a2c7 200 Series PCH LPC Controller (Q250) @@ -32089,6 +32611,8 @@ a2ed 200 Series PCH PCI Express Root Port #23 a2ee 200 Series PCH PCI Express Root Port #24 a2f0 200 Series PCH HD Audio + 1462 7a72 H270 PC MATE + 1462 fa72 H270 PC MATE a304 H370 Chipset LPC/eSPI Controller 1028 0869 Vostro 3470 a305 Z390 Chipset LPC/eSPI Controller @@ -32102,6 +32626,7 @@ a324 Cannon Lake PCH SPI Controller 1028 0869 Vostro 3470 a328 Cannon Lake PCH Serial IO UART Host Controller + a32b Cannon Lake PCH SPI Host Controller a32c Cannon Lake PCH PCI Express Root Port #21 a32d Cannon Lake PCH PCI Express Root Port #22 a32e Cannon Lake PCH PCI Express Root Port #23 @@ -32147,7 +32672,9 @@ a379 Cannon Lake PCH Thermal Controller 1028 0869 Vostro 3470 a382 400 Series Chipset Family SATA AHCI Controller + a3a1 Memory controller a3a3 Comet Lake PCH-V SMBus Host Controller + a3af Comet Lake PCH-V USB Controller a3b1 Comet Lake PCH-V Thermal Subsystem a620 6400/6402 Advanced Memory Buffer (AMB) abc0 Omni-Path Fabric Switch Silicon 100 Series @@ -32188,29 +32715,60 @@ d157 Core Processor System Control and Status Registers d158 Core Processor Miscellaneous Registers f1a5 SSD 600P Series +# M.2 22 x 80mm, NVMe + 8086 390a SSDPEKKW256G7 256GB f1a6 SSD Pro 7600p/760p/E 6100p Series 8086 390b SSD Pro 7600p/760p/E 6100p Series [NVM Express] f1a8 SSD 660P Series 8088 Beijing Wangxun Technology Co., Ltd. 0101 WX1860A2 Gigabit Ethernet Controller 8088 0201 Dual-Port Ethernet Network Adaptor SF200T + 8088 4201 Dual-Port Ethernet Network Adaptor SF200T (WOL) + 8088 8201 Dual-Port Ethernet Network Adaptor SF200T (NCSI) + 8088 c201 Dual-Port Ethernet Network Adaptor SF200T (WOL, NCSI) 0102 WX1860A2S Gigabit Ethernet Controller 8088 0210 Dual-Port Ethernet Network Adaptor SF200T-S 0103 WX1860A4 Gigabit Ethernet Controller 8088 0401 Qual-Port Ethernet Network Adaptor SF400T 8088 0440 Qual-Port Ethernet Network Adaptor SF400-OCP + 8088 4103 Quad-Port Ethernet Network Adaptor SF400T (WOL) + 8088 8103 Quad-Port Ethernet Network Adaptor SF400T (NCSI) + 8088 c103 Quad-Port Ethernet Network Adaptor SF400T (WOL, NCSI) 0104 WX1860A4S Gigabit Ethernet Controller 8088 0410 Qual-Port Ethernet Network Adaptor SF400T-S 0105 WX1860AL2 Gigabit Ethernet Controller 8088 0202 Dual-Port Ethernet Network Adaptor SF200HT + 8088 4202 Dual-Port Ethernet Network Adaptor SF200HT (WOL) + 8088 8202 Dual-Port Ethernet Network Adaptor SF200HT (NCSI) + 8088 c202 Dual-Port Ethernet Network Adaptor SF200HT (WOL, NCSI) 0106 WX1860AL2S Gigabit Ethernet Controller 8088 0220 Dual-Port Ethernet Network Adaptor SF200HT-S 0107 WX1860AL4 Gigabit Ethernet Controller 8088 0402 Qual-Port Ethernet Network Adaptor SF400HT + 8088 4402 Quad-Port Ethernet Network Adaptor SF400HT (WOL) + 8088 8402 Quad-Port Ethernet Network Adaptor SF400HT (NCSI) + 8088 c402 Quad-Port Ethernet Network Adaptor SF400HT (WOL, NCSI) 0108 WX1860AL4S Gigabit Ethernet Controller 8088 0420 Qual-Port Ethernet Network Adaptor SF400HT-S + 0109 WX1860-LC Gigabit Ethernet Controller + 010a WX1860A1 Gigabit Ethernet Controller +# add new device ID + 010b WX1860AL1 Gigabit Ethernet Controller + 8088 0102 Single-Port Ethernet Network Adaptor SF100HT + 8088 4102 Single-Port Ethernet Network Adaptor SF100HT (WOL) + 8088 8102 Single-Port Ethernet Network Adaptor SF100HT (NCSI) + 8088 c102 Single-Port Ethernet Network Adaptor SF100HT (WOL, NCSI) + 0111 WX1860A2 Ethernet Controller Virtual Function + 0113 WX1860A4 Ethernet Controller Virtual Function + 0115 WX1860AL2 Ethernet Controller Virtual Function + 0117 WX1860AL4 Ethernet Controller Virtual Function + 0119 WX1860-LC Gigabit Ethernet Controller Virtual Function + 011a WX1860A1 Gigabit Ethernet Controller Virtual Function + 011b WX1860AL1 Gigabit Ethernet Controller Virtual Function + 1000 Ethernet Controller RP1000 Virtual Function for 10GbE SFP+ 1001 Ethernet Controller RP1000 for 10GbE SFP+ 8088 0000 Ethernet Network Adaptor RP1000 for 10GbE SFP+ + 2000 Ethernet Controller RP2000 Virtual Function for 10GbE SFP+ 2001 Ethernet Controller RP2000 for 10GbE SFP+ 8088 2000 Ethernet Network Adaptor RP2000 for 10GbE SFP+ 80ee InnoTek Systemberatung GmbH @@ -32733,6 +33291,7 @@ 0001 SG2010 PCI over Starfabric Bridge 0002 SG2010 PCI to Starfabric Gateway 0003 SG1010 Starfabric Switch and PCI Bridge +9a11 Tiger Lake-H Gaussian & Neural Accelerator 9d32 Beijing Starblaze Technology Co. Ltd. 0000 STAR1000 PCIe NVMe SSD Controller 1001 STAR1000P PCIe NVMe SSD Controller @@ -32952,7 +33511,7 @@ deda XIMEA 4021 MT camera e000 Winbond e000 W89C940 -e159 Tiger Jet Network Inc. +e159 Tiger Jet Network Inc. / ICP DAS 0001 Tiger3XX Modem/ISDN interface 0059 0001 128k ISDN-S/T Adapter 0059 0003 128k ISDN-U Adapter @@ -32983,6 +33542,7 @@ ea01 Eagle Technology 0046 PCI-766 Analog Output Card 0052 PCI-703 Analog I/O Card 0800 PCI-800 Digital I/O Card +ea50 Emerson Automation Solutions # The main chip of all these devices is by Xilinx -> It could also be a Xilinx ID. ea60 RME 9896 Digi32 @@ -33096,6 +33656,7 @@ f1d0 AJA Video eb23 Kona 1 eb24 Kona HDMI eb25 Corvid 44 12g + eb26 T-Tap Pro efac Xena SD-MM/SD-22-MM facd Xena HD-MM f5f5 F5 Networks, Inc. diff --git a/hwdb.d/pnp_id_registry.html b/hwdb.d/pnp_id_registry.html index 797a79691..607efd8e0 100644 --- a/hwdb.d/pnp_id_registry.html +++ b/hwdb.d/pnp_id_registry.html @@ -108,9 +108,9 @@ Alpha Telecom IncATD09/26/1997 Alpha-Top CorporationATP12/04/1996 AlphaView LCDALV11/01/2008 - Alpine Electronics, Inc.APE01/22/2013 - Alps Electric Company LtdALP11/29/1996 - Alps Electric IncAUI11/29/1996 + ALPS ALPINE CO., LTD.APE01/22/2013 + ALPS ALPINE CO., LTD.ALP11/29/1996 + ALPS ALPINE CO., LTD.AUI11/29/1996 Alta Research CorporationARC11/29/1996 Altec CorporationALC08/04/1998 Altec LansingALJ01/13/2000 @@ -2465,6 +2465,13 @@ MILCOTSMLC07/15/2020 NZXT (PNP same EDID)_NXT07/15/2020 Unicompute Technology Co., Ltd.UTC10/19/2020 + TECHNOGYM S.p.A.TGW01/08/2021 + Clover ElectronicsCLR02/02/2021 + Kyokko Communication System Co., Ltd.KTS02/18/2021 + Terumo CorporationTMO02/02/2021 + Micro-Star Int'l Co., Ltd.CND02/17/2021 + Newline Interactive Inc.NWL12/03/2020 + CORSAIR MEMORY Inc.CRM02/05/2021 diff --git a/hwdb.d/usb.ids b/hwdb.d/usb.ids index 02e2ef420..d16618808 100644 --- a/hwdb.d/usb.ids +++ b/hwdb.d/usb.ids @@ -9,8 +9,8 @@ # The latest version can be obtained from # http://www.linux-usb.org/usb.ids # -# Version: 2020.08.26 -# Date: 2020-08-26 20:34:09 +# Version: 2021.02.19 +# Date: 2021-02-19 20:34:10 # # Vendors, devices and interfaces. Please keep sorted. @@ -1523,6 +1523,7 @@ 0155 5800 XpressMusic (Multimedia mode) 0156 5800 XpressMusic (Storage mode) 0157 5800 XpressMusic (Imaging mode) + 0189 N810 Internet Tablet WiMAX 0199 6700 Classic (msc) 019a 6700 Classic (PC Suite) 019b 6700 Classic (mtp) @@ -1530,7 +1531,7 @@ 01b1 6303 classic Phone (Mass storage mode) 01b2 6303 classic Phone (Printing and media mode) 01c7 N900 (Storage Mode) - 01c8 N900 (PC-Suite Mode) + 01c8 N900/N950 (PC-Suite Mode) 0228 5530 XpressMusic 023a 6730 Classic 026a N97 (mass storage) @@ -1550,7 +1551,8 @@ 03c1 C7-00 (Media transfer mode) 03c2 Sim 03cd C7-00 (Nokia Suite mode) - 03d1 N950 + 03d1 N950 (Storage Mode) + 03d2 N950 (PC Suite mode) 0400 7600 Phone Parent 0401 6650 GSM Phone 0402 6255 Phone Parent @@ -1581,7 +1583,7 @@ 0423 6682 Phone Parent 0428 6230i Modem 0429 6230i MultiMedia Card - 0431 770 Internet Tablet + 0431 770/N800 Internet Tablet 0432 N90 Phone Parent 0435 E70 (IP Passthrough/RNDIS mode) 0436 E60 (IP Passthrough/RNDIS mode) @@ -1615,7 +1617,9 @@ 04f9 6300 (PC Suite mode) 0508 E65 (PC Suite mode) 0509 E65 (Storage mode) - 0518 N9 Phone + 0518 N9 (Storage mode) + 0519 N9 (RNDIS/Ethernet mode) + 051a N9 (PC Suite mode) 054d C2-01 0600 Digital Pen SU-1B 0610 CS-15 (Internet Stick 3G modem) @@ -8752,6 +8756,7 @@ 05fc Harman 0001 Soundcraft Si Multi Digital Card 0010 Soundcraft Si MADI combo card + 0021 Soundcraft Signature 12 MTK 7849 Harman/Kardon SoundSticks 05fd InterAct, Inc. 0239 SV-239 HammerHead Digital @@ -22447,6 +22452,9 @@ 32b3 TEXA d1a6 TXT Multihub d1a7 TXT Multihub +3310 MUDITA Sp. z o.o. + 0100 Pure + 0101 Pure tethering 3333 InLine 3333 2 port KVM switch model 60652K 3334 AEI @@ -22458,6 +22466,9 @@ ffff Mio DigiWalker Sync 3344 Leaguer Microelectronics (LME) 3744 OEM PC Remote +3384 System76 + 0000 Thelio Io (thelio-io) + 0001 Launch Configurable Keyboard (launch_1) 348f ISY 2322 Wireless Presenter 3504 Micro Star diff --git a/man/bootup.xml b/man/bootup.xml index 781e53919..431d19a48 100644 --- a/man/bootup.xml +++ b/man/bootup.xml @@ -92,10 +92,10 @@ - cryptsetup-pre.target + cryptsetup-pre.target veritysetup-pre.target | (various low-level v - API VFS mounts: (various cryptsetup devices...) + API VFS mounts: (various cryptsetup/veritysetup devices...) mqueue, configfs, | | debugfs, ...) v | | cryptsetup.target | @@ -105,7 +105,7 @@ | v local-fs-pre.target | | | (network file systems) | swap.target | | v v | | | v | remote-cryptsetup.target | - | | (various low-level (various mounts and | | | + | | (various low-level (various mounts and | remote-veritysetup.target | | | services: udevd, fsck services...) | | remote-fs.target | | tmpfiles, random | | | / | | seed, sysctl, ...) v | | / @@ -303,7 +303,8 @@ emergency.service | | | (conflicts with (conflicts with all system all file system services) mounts, swaps, - | cryptsetup + | cryptsetup/ + | veritysetup | devices, ...) | | v v diff --git a/man/less-variables.xml b/man/common-variables.xml similarity index 55% rename from man/less-variables.xml rename to man/common-variables.xml index 3b32673f3..29922aa85 100644 --- a/man/less-variables.xml +++ b/man/common-variables.xml @@ -7,6 +7,80 @@ Environment + + $SYSTEMD_LOG_LEVEL + + The maximum log level of emitted messages (messages with a higher + log level, i.e. less important ones, will be suppressed). Either one of (in order of decreasing + importance) emerg, alert, crit, + err, warning, notice, + info, debug, or an integer in the range 0…7. See + syslog3 + for more information. + + + + + $SYSTEMD_LOG_COLOR + + A boolean. If true, messages written to the tty will be colored + according to priority. + + This setting is only useful when messages are written directly to the terminal, because + journalctl1 and + other tools that display logs will color messages based on the log level on their own. + + + + + $SYSTEMD_LOG_TIME + + A boolean. If true, log messages will be prefixed with a + timestamp. + + This setting is only useful when messages are written directly to the terminal or a file, because + journalctl1 and + other tools that display logs will attach timestamps based on the entry metadata on their own. + + + + + $SYSTEMD_LOG_LOCATION + + A boolean. If true, messages will be prefixed with a filename + and line number in the source code where the message originates. + + Note that the log location is often attached as metadata to journal entries anyway. Including it + directly in the message text can nevertheless be convenient when debugging programs. + + + + + $SYSTEMD_LOG_TID + + A boolean. If true, messages will be prefixed with the current + numerical thread ID (TID). + + Note that the this information is attached as metadata to journal entries anyway. Including it + directly in the message text can nevertheless be convenient when debugging programs. + + + + + $SYSTEMD_LOG_TARGET + + The destination for log messages. One of + console (log to the attached tty), console-prefixed (log to + the attached tty but with prefixes encoding the log level and "facility", see syslog3, + kmsg (log to the kernel circular log buffer), journal (log to + the journal), journal-or-kmsg (log to the journal if available, and to kmsg + otherwise), auto (determine the appropriate log target automatically, the default), + null (disable log output). + + + + $SYSTEMD_PAGER @@ -69,15 +143,15 @@ Takes a boolean argument. When true, the "secure" mode of the pager is enabled; if false, disabled. If $SYSTEMD_PAGERSECURE is not set at all, secure mode is enabled - if the effective UID is not the same as the owner of the login session, see geteuid2 and - sd_pid_get_owner_uid3. + if the effective UID is not the same as the owner of the login session, see + geteuid2 + and sd_pid_get_owner_uid3. In secure mode, will be set when invoking the pager, and the pager shall disable commands that open or create new files or start new subprocesses. When $SYSTEMD_PAGERSECURE is not set at all, pagers which are not known to implement secure mode will not be used. (Currently only - less1 implements - secure mode.) + less1 + implements secure mode.) Note: when commands are invoked with elevated privileges, for example under sudo8 or @@ -94,10 +168,11 @@ $SYSTEMD_COLORS - The value must be a boolean. Controls whether colorized output should be - generated. This can be specified to override the decision that systemd makes based - on $TERM and what the console is connected to. - + Takes a boolean argument. When true, systemd and related utilities + will use colors in their output, otherwise the output will be monochrome. Additionally, the variable can + take one of the following special values: 16, 256 to restrict the use + of colors to the base 16 or 256 ANSI colors, respectively. This can be specified to override the automatic + decision based on $TERM and what the console is connected to. + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ + +%entities; +]> @@ -26,23 +29,65 @@ Description - The /etc/hostname file configures the - name of the local system that is set during boot using the - sethostname2 - system call. It should contain a single newline-terminated - hostname string. Comments (lines starting with a `#') are ignored. - The hostname may be a free-form string up to 64 characters in length; - however, it is recommended that it consists only of 7-bit ASCII lower-case - characters and no spaces or dots, and limits itself to the format allowed - for DNS domain name labels, even though this is not a strict - requirement. + The /etc/hostname file configures the name of the local system. Unless + overridden as described in the next section, + systemd1 will set this + hostname during boot using the + sethostname2 system + call. + + The file should contain a single newline-terminated hostname string. Comments (lines starting with + a #) are ignored. The hostname should be composed of up to 64 7-bit ASCII lower-case + alphanumeric characters or hyphens forming a valid DNS domain name. It is recommended that this name + contains only a single label, i.e. without any dots. Invalid characters will be filtered out in an + attempt to make the name valid, but obviously it is recommended to use a valid name and not rely on this + filtering. You may use - hostnamectl1 - to change the value of this file during runtime from the command - line. Use - systemd-firstboot1 - to initialize it on mounted (but not booted) system images. + hostnamectl1 to change + the value of this file during runtime from the command line. Use + systemd-firstboot1 to + initialize it on mounted (but not booted) system images. + + + + Hostname semantics + + systemd1 and the + associated tools will obtain the hostname in the following ways: + + If the kernel commandline parameter systemd.hostname= specifies a + valid hostname, + systemd1 will use it + to set the hostname during early boot, see + kernel-command-line7, + + + Otherwise, the "static" hostname specified by /etc/hostname as + described above will be used. + + Otherwise, a transient hostname may be set during runtime, for example based on + information in a DHCP lease, see + systemd-hostnamed.service8. + Both NetworkManager and + systemd-networkd.service8 + allow this. Note that + systemd-hostnamed.service8 + gives higher priority to the static hostname, so the transient hostname will only be used if the static + hostname is not configured. + + Otherwise, a fallback hostname configured at compilation time will be used + (&FALLBACK_HOSTNAME;). + + + + + Effectively, the static hostname has higher priority than a transient hostname, which has higher + priority than the fallback hostname. Transient hostnames are equivalent, so setting a new transient + hostname causes the previous transient hostname to be forgotten. The hostname specified on the kernel + command line is like a transient hostname, with the exception that it has higher priority when the + machine boots. Also note that those are the semantics implemented by systemd tools, but other programs + may also set the hostname. diff --git a/man/hostnamectl.xml b/man/hostnamectl.xml index 8c00867e7..8be897290 100644 --- a/man/hostnamectl.xml +++ b/man/hostnamectl.xml @@ -1,6 +1,9 @@ + "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ + +%entities; +]> Description - hostnamectl may be used to query and - change the system hostname and related settings. + hostnamectl may be used to query and change the system hostname and related + settings. - This tool distinguishes three different hostnames: the - high-level "pretty" hostname which might include all kinds of - special characters (e.g. "Lennart's Laptop"), the static hostname - which is used to initialize the kernel hostname at boot (e.g. - "lennarts-laptop"), and the transient hostname which is a fallback - value received from network configuration. If a static hostname is - set, and is valid (something other than localhost), then the - transient hostname is not used. + systemd-hostnamed.service8 + and this tool distinguish three different hostnames: the high-level "pretty" hostname which might include + all kinds of special characters (e.g. "Lennart's Laptop"), the "static" hostname which is the + user-configured hostname (e.g. "lennarts-laptop"), and the transient hostname which is a fallback value + received from network configuration (e.g. "node12345678"). If a static hostname is set to a valid value, + then the transient hostname is not used. Note that the pretty hostname has little restrictions on the characters and length used, while the static and transient hostnames are limited to the usually accepted characters of Internet domain names, and 64 characters at maximum (the latter being a Linux limitation). - The static hostname is stored in - /etc/hostname, see - hostname5 - for more information. The pretty hostname, chassis type, and icon - name are stored in /etc/machine-info, see - machine-info5. - Use - systemd-firstboot1 - to initialize the system hostname for mounted (but not booted) - system images. + systemd-firstboot1 to + initialize the system hostname for mounted (but not booted) system images. @@ -86,9 +79,13 @@ still following the validity rules of the specific name. This simplification of the hostname string is not done if only the transient and/or static hostnames are set, and the pretty hostname is left untouched. - Pass the empty string as the - hostname to reset the selected hostnames to their default - (usually localhost). + The static and transient hostnames must each be either a single DNS label (a string composed of + 7-bit ASCII lower-case characters and no spaces or dots, limited to the format allowed for DNS domain + name labels), or a sequence of such labels separated by single dots that forms a valid DNS FQDN. The + hostname must be at most 64 characters, which is a Linux limitation (DNS allows longer names). + + Pass the empty string as the hostname to reset the selected hostnames to + their default (usually &FALLBACK_HOSTNAME;). diff --git a/man/html.in b/man/html.in index c142f581d..3ae02bd77 100755 --- a/man/html.in +++ b/man/html.in @@ -6,7 +6,7 @@ if [ -z "$1" ]; then exit 1 fi -# make sure the rules have been regenerated (in case man/update-man-rules was just run) +# make sure the rules have been regenerated (in case update-man-rules was just run) ninja -C "@BUILD_ROOT@" version.h target="man/$1.html" diff --git a/man/journalctl.xml b/man/journalctl.xml index 379344170..4be2ed347 100644 --- a/man/journalctl.xml +++ b/man/journalctl.xml @@ -992,7 +992,7 @@ code is returned. - + Examples diff --git a/man/journald.conf.xml b/man/journald.conf.xml index 959815a8f..86137a951 100644 --- a/man/journald.conf.xml +++ b/man/journald.conf.xml @@ -28,6 +28,9 @@ /run/systemd/journald.conf.d/*.conf /usr/lib/systemd/journald.conf.d/*.conf /etc/systemd/journald@NAMESPACE.conf + /etc/systemd/journald@NAMESPACE.conf.d/*.conf + /run/systemd/journald@NAMESPACE.conf.d/*.conf + /usr/lib/systemd/journald@NAMESPACE.conf.d/*.conf @@ -41,8 +44,9 @@ The systemd-journald instance managing the default namespace is configured by /etc/systemd/journald.conf and associated drop-ins. Instances managing other - namespaces read /etc/systemd/journald@NAMESPACE.conf with - the namespace identifier filled in. This allows each namespace to carry a distinct configuration. See + namespaces read /etc/systemd/journald@NAMESPACE.conf + and associated drop-ins with the namespace identifier filled in. This allows each namespace to carry + a distinct configuration. See systemd-journald.service8 for details about journal namespaces. diff --git a/man/kernel-command-line.xml b/man/kernel-command-line.xml index 7a4109916..f546a1161 100644 --- a/man/kernel-command-line.xml +++ b/man/kernel-command-line.xml @@ -356,11 +356,14 @@ + veritytab= + rd.veritytab= roothash= systemd.verity= rd.systemd.verity= systemd.verity_root_data= systemd.verity_root_hash= + systemd.verity.root_options= Configures the integrity protection root hash for the root file system, and other related parameters. For details, see diff --git a/man/localectl.xml b/man/localectl.xml index 7f7e5775c..9fa34854e 100644 --- a/man/localectl.xml +++ b/man/localectl.xml @@ -185,7 +185,7 @@ otherwise. - + See Also diff --git a/man/loginctl.xml b/man/loginctl.xml index d3745ce52..56a86e56e 100644 --- a/man/loginctl.xml +++ b/man/loginctl.xml @@ -334,13 +334,14 @@ - When used with kill-session - or kill-user, choose which signal to send - to selected processes. Must be one of the well known signal - specifiers, such as SIGTERM, - SIGINT or SIGSTOP. - If omitted, defaults to - SIGTERM. + When used with kill-session or kill-user, + choose which signal to send to selected processes. Must be one of the well known signal specifiers, + such as SIGTERM, SIGINT or SIGSTOP. + If omitted, defaults to SIGTERM. + + The special value help will list the known values and the program will exit + immediately, and the special value list will list known values along with the + numerical signal numbers and the program will exit immediately. @@ -414,7 +415,7 @@ Apr 09 14:40:30 laptop login[2325]: LOGIN ON tty3 BY fatima - + See Also diff --git a/man/machine-info.xml b/man/machine-info.xml index c42f6e221..3de681004 100644 --- a/man/machine-info.xml +++ b/man/machine-info.xml @@ -37,12 +37,10 @@ file without implementing a shell compatible execution engine. - /etc/machine-info contains metadata - about the machine that is set by the user or administrator. - - Depending on the operating system other configuration files - might be checked for machine information as well, however only as - fallback. + /etc/machine-info contains metadata about the machine that is set by the user + or administrator. The settings configured here have the highest precedence. When not set, appropriate + values may be determined automatically, based on the information about the hardware or other + configuration files. It is thus completely fine for this file to not be present. You may use hostnamectl1 @@ -102,13 +100,11 @@ as well as the special chassis types vm and container for - virtualized systems that lack an immediate physical chassis. - Note that many systems allow detection of the chassis type - automatically (based on firmware information or suchlike). - This setting (if set) shall take precedence over automatically - detected information and is useful to override misdetected - configuration or to manually configure the chassis type where - automatic detection is not available. + virtualized systems that lack an immediate physical chassis. + + Note that most systems allow detection of the chassis type automatically (based on firmware + information or suchlike). This setting should only be used to override a misdetection or to manually + configure the chassis type where automatic detection is not available. diff --git a/man/machinectl.xml b/man/machinectl.xml index 902684955..ad47b6102 100644 --- a/man/machinectl.xml +++ b/man/machinectl.xml @@ -699,17 +699,7 @@ . - - - - - When used with kill, choose - which signal to send to selected processes. Must be one of the - well-known signal specifiers, such as - SIGTERM, SIGINT or - SIGSTOP. If omitted, defaults to - SIGTERM. - + @@ -990,7 +980,7 @@ otherwise. - + See Also diff --git a/man/man.in b/man/man.in index 12eb332ee..40b7476bc 100755 --- a/man/man.in +++ b/man/man.in @@ -6,7 +6,7 @@ if [ -z "$1" ]; then exit 1 fi -# make sure the rules have been regenerated (in case man/update-man-rules was just run) +# make sure the rules have been regenerated (in case update-man-rules was just run) ninja -C "@BUILD_ROOT@" version.h page="$(echo "$1" | sed 's/\./\\./')" diff --git a/man/meson.build b/man/meson.build index f555d629d..3cae8446c 100644 --- a/man/meson.build +++ b/man/meson.build @@ -198,38 +198,6 @@ run_target( ############################################################ -if dbus_docs.length() > 0 - custom_target( - 'update-dbus-docs', - output : 'update-dbus-docs', - command : [update_dbus_docs_py, - '--build-dir=@0@'.format(project_build_root), - '@INPUT@'], - input : dbus_docs) - - if conf.get('BUILD_MODE') == 'BUILD_MODE_DEVELOPER' - test('dbus-docs-fresh', - update_dbus_docs_py, - args : ['--build-dir=@0@'.format(project_build_root), - '--test'] + dbus_docs) - endif -endif - -############################################################ - -if git.found() - custom_target( - 'update-man-rules', - output : 'update-man-rules', - command : ['sh', '-c', - 'cd @0@ && '.format(meson.build_root()) + - 'python3 @0@/tools/update-man-rules.py $(git ls-files ":/man/*.xml") >t && '.format(project_source_root) + - 'mv t @0@/rules/meson.build'.format(meson.current_source_dir())], - depend_files : custom_entities_ent) -endif - -############################################################ - configure_file( input : 'man.in', output : 'man', diff --git a/man/networkctl.xml b/man/networkctl.xml index 466bba47f..ee204a60c 100644 --- a/man/networkctl.xml +++ b/man/networkctl.xml @@ -104,7 +104,7 @@ carrier the link has a carrier, or for bond or bridge master, all bonding or bridge slave - network interfaces are enslaved to the master. + network interfaces are enslaved to the master diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index 65aecb625..dcce2095e 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -70,6 +70,18 @@ is false. Defaults to yes. + + RouteTable= + Defines the route table name. Takes a whitespace-separated list of the pairs of + route table name and number. The route table name and number in each pair are separated with a + colon, i.e., name:number. + The route table name must not be default, main, or + local, as these route table names are predefined with route table number 253, + 254, and 255, respectively. The route table number must be an integer in the range 1…4294967295. + This setting can be specified multiple times. If an empty string is specified, then the list + specified earlier are cleared. Defaults to unset. + + diff --git a/man/oomd.conf.xml b/man/oomd.conf.xml index 35a0686bc..6156c98fb 100644 --- a/man/oomd.conf.xml +++ b/man/oomd.conf.xml @@ -48,28 +48,40 @@ - SwapUsedLimitPercent= + SwapUsedLimit= - Sets the limit for swap usage on the system before systemd-oomd will - take action. If the percentage of swap used on the system is more than what is defined here, - systemd-oomd will act on eligible descendant cgroups, starting from the ones with the - highest swap usage to the lowest swap usage. Which cgroups are monitored and what - action gets taken depends on what the unit has configured for ManagedOOMSwap=. - Takes a percentage value between 0% and 100%, inclusive. Defaults to 90%. + Sets the limit for swap usage on the system before systemd-oomd + will take action. If the fraction of swap used on the system is more than what is defined here, + systemd-oomd will act on eligible descendant control groups, starting from the + ones with the highest swap usage to the lowest swap usage. Which control groups are monitored and + what action gets taken depends on what the unit has configured for + ManagedOOMSwap=. Takes a value specified in percent (when suffixed with "%"), + permille ("‰") or permyriad ("‱"), between 0% and 100%, inclusive. Defaults to 90%. - DefaultMemoryPressureLimitPercent= + DefaultMemoryPressureLimit= - Sets the limit for memory pressure on the unit's cgroup before systemd-oomd - will take action. A unit can override this value with ManagedOOMMemoryPressureLimitPercent=. - The memory pressure for this property represents the fraction of time in a 10 second window in which all tasks - in the cgroup were delayed. For each monitored cgroup, if the memory pressure on that cgroup exceeds the - limit set for more than 30 seconds, systemd-oomd will act on eligible descendant cgroups, - starting from the ones with the most reclaim activity to the least reclaim activity. Which cgroups are - monitored and what action gets taken depends on what the unit has configured for - ManagedOOMMemoryPressure=. Takes a percentage value between 0% and 100%, inclusive. - Defaults to 60%. + Sets the limit for memory pressure on the unit's control group before + systemd-oomd will take action. A unit can override this value with + ManagedOOMMemoryPressureLimit=. The memory pressure for this property represents + the fraction of time in a 10 second window in which all tasks in the control group were delayed. For + each monitored control group, if the memory pressure on that control group exceeds the limit set for + longer than the duration set by DefaultMemoryPressureDurationSec=, + systemd-oomd will act on eligible descendant control groups, starting from the + ones with the most reclaim activity to the least reclaim activity. Which control groups are monitored + and what action gets taken depends on what the unit has configured for + ManagedOOMMemoryPressure=. Takes a fraction specified in the same way as + SwapUsedLimit= above. Defaults to 60%. + + + + DefaultMemoryPressureDurationSec= + + Sets the amount of time a unit's control group needs to have exceeded memory pressure + limits before systemd-oomd will take action. Memory pressure limits are defined by + DefaultMemoryPressureLimit= and ManagedOOMMemoryPressureLimit=. + Defaults to 30 seconds when this property is unset or set to 0. diff --git a/man/org.freedesktop.hostname1.xml b/man/org.freedesktop.hostname1.xml index f8e199cea..3a5088ede 100644 --- a/man/org.freedesktop.hostname1.xml +++ b/man/org.freedesktop.hostname1.xml @@ -62,6 +62,9 @@ node /org/freedesktop/hostname1 { readonly s Hostname = '...'; readonly s StaticHostname = '...'; readonly s PrettyHostname = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s DefaultHostname = '...'; + readonly s HostnameSource = '...'; readonly s IconName = '...'; readonly s Chassis = '...'; readonly s Deployment = '...'; @@ -78,6 +81,10 @@ node /org/freedesktop/hostname1 { readonly s OperatingSystemCPEName = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s HomeURL = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s HardwareVendor = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s HardwareModel = '...'; }; interface org.freedesktop.DBus.Peer { ... }; interface org.freedesktop.DBus.Introspectable { ... }; @@ -85,6 +92,10 @@ node /org/freedesktop/hostname1 { }; + + + + @@ -113,6 +124,10 @@ node /org/freedesktop/hostname1 { + + + + @@ -133,6 +148,10 @@ node /org/freedesktop/hostname1 { + + + + Whenever the hostname or other metadata is changed via the daemon, @@ -144,55 +163,63 @@ node /org/freedesktop/hostname1 { Semantics - The static (configured) hostname is the one configured in - /etc/hostname. It is chosen by the local user. It is not always in sync with the - current hostname as returned by the + The StaticHostname property exposes the "static" hostname configured in + /etc/hostname. It is not always in sync with the current hostname as returned by the gethostname3 - system call. If no hostname is configured this property will be the empty string. Setting this property - to the empty string will remove /etc/hostname. This property should be an - internet-style hostname, 7-bit lowercase ASCII, no special chars/spaces. + system call. If no static hostname is configured this property will be the empty string. - The transient (dynamic) hostname is the one configured via the kernel's + When systemd1 or + systemd-hostnamed.service8 + set the hostname, this static hostname has the highest priority. + + The Hostname property exposes the actual hostname configured in the kernel via sethostname3. - It can be different from the static hostname if DHCP or mDNS have been configured to change the name - based on network information. - This property is never empty. If no hostname is set this will default to - &FALLBACK_HOSTNAME; (configurable at compilation time). Setting this property to the - empty string will reset the dynamic hostname to the static hostname. If no static hostname is - configured the dynamic hostname will be reset to &FALLBACK_HOSTNAME;. This property - should be an internet-style hostname, 7-bit lowercase ASCII, no special chars/spaces. + It can be different from the static hostname. This property is never empty. - The pretty hostname is a free-form UTF-8 hostname for presentation to the - user. User interfaces should ensure that the pretty hostname and the static hostname stay in sync. - I.e. when the former is Lennart’s Computer the latter should be - lennarts-computer. If no pretty hostname is set this setting will be the empty - string. Applications should then find a suitable fallback, such as the dynamic hostname. + The PrettyHostname property exposes the pretty hostname + which is a free-form UTF-8 hostname for presentation to the user. User interfaces should ensure that the + pretty hostname and the static hostname stay in sync. E.g. when the former is Lennart’s + Computer the latter should be lennarts-computer. If no pretty hostname is + set this setting will be the empty string. Applications should then find a suitable fallback, such as the + dynamic hostname. - The icon name is a name following the XDG icon naming spec. If not set, - information such as the chassis type (see below) is used to find a suitable fallback icon name - (i.e. computer-laptop vs. computer-desktop is picked based on the - chassis information). If no such data is available, the empty string is returned. In that case an application - should fall back to a replacement icon, for example computer. If this property is set - to the empty string, the automatic fallback name selection is enabled again. + The DefaultHostname property exposes the default hostname (configured through + os-release5, or a + fallback set at compilation time). - The chassis type should be one of the currently defined chassis types: - desktop, laptop, server, - tablet, handset, as well as the special chassis types - vm and container for virtualized systems. Note that in most cases - the chassis type will be determined automatically from DMI/SMBIOS/ACPI firmware information. Writing to - this setting is hence useful only to override misdetected chassis types, or to configure the chassis type if - it could not be auto-detected. Set this property to the empty string to reenable the automatic detection of - the chassis type from firmware information. + The HostnameSource property exposes the origin of the currently configured + hostname. One of static (set from /etc/hostname), + transient (a non-permanent hostname from an external source), + default (the value from os-release or the the compiled-in + fallback). + + The IconName property exposes the icon name following the + XDG icon naming spec. If not set, information such as the chassis type (see below) is used to find a + suitable fallback icon name (i.e. computer-laptop + vs. computer-desktop is picked based on the chassis information). If no such data is + available, the empty string is returned. In that case an application should fall back to a replacement + icon, for example computer. If this property is set to the empty string, the automatic + fallback name selection is enabled again. + + The Chassis property exposes a chassis type, one of the + currently defined chassis types: desktop, laptop, + server, tablet, handset, as well as the special + chassis types vm and container for virtualized systems. Note that + in most cases the chassis type will be determined automatically from DMI/SMBIOS/ACPI firmware + information. Writing to this setting is hence useful only to override misdetected chassis types, or to + configure the chassis type if it could not be auto-detected. Set this property to the empty string to + reenable the automatic detection of the chassis type from firmware information. Note that systemd-hostnamed starts only on request and terminates after a short idle period. This effectively means that PropertyChanged messages are not sent out for changes made directly on the files (as in: administrator edits the files with vi). This is the intended behavior: manual configuration changes should require manual reloading. - The transient (dynamic) hostname maps directly to the kernel hostname. This hostname should be - assumed to be highly dynamic, and hence should be watched directly, without depending on - PropertyChanged messages from systemd-hostnamed. To accomplish - this, open /proc/sys/kernel/hostname and + The transient (dynamic) hostname exposed by the Hostname property maps directly + to the kernel hostname. This hostname should be assumed to be highly dynamic, and hence should be watched + directly, without depending on PropertyChanged messages from + systemd-hostnamed. To accomplish this, open + /proc/sys/kernel/hostname and poll3 for SIGHUP which is triggered by the kernel every time the hostname changes. Again: this is special for the transient (dynamic) hostname, and does not apply to the configured (fixed) @@ -206,15 +233,17 @@ node /org/freedesktop/hostname1 { for that. For more information on these files and syscalls see the respective man pages. - Methods and Properties + Methods - SetHostname() sets the transient (dynamic) hostname which is exposed by the - Hostname property. If empty, the transient hostname is set to the static hostname. - + SetHostname() sets the transient (dynamic) hostname, which is used if no + static hostname is set. This value must be an internet-style hostname, 7-bit lowercase ASCII, no + special chars/spaces. An empty string will unset the transient hostname. SetStaticHostname() sets the static hostname which is exposed by the - StaticHostname property. If empty, the built-in default of - &FALLBACK_HOSTNAME; is used. + StaticHostname property. When called with an empty argument, the static + configuration in /etc/hostname is removed. Since the static hostname has the + highest priority, calling this function usually affects also the Hostname property + and the effective hostname configured in the kernel. SetPrettyHostname() sets the pretty hostname which is exposed by the PrettyHostname property. @@ -287,10 +316,6 @@ node /org/freedesktop/hostname1 { with nss-myhostname3. - A client that wants to change the local hostname for DHCP/mDNS should invoke - SetHostname("newname", false) as soon as the name is available and afterwards reset it via - SetHostname(""). - Here are some recommendations to follow when generating a static (internet) hostname from a pretty name: @@ -309,8 +334,8 @@ node /org/freedesktop/hostname1 { Limit the hostname to 63 chars, which is the length of a DNS label. If after stripping special chars the empty string is the result, you can pass this - as-is to systemd-hostnamed in which case it will automatically use - &FALLBACK_HOSTNAME;. + as-is to systemd-hostnamed in which case it will automatically use a suitable + fallback. Uppercase charaacters should be replaced with their lowercase equivalents. diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index ad27b226b..bf7a5fa34 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -102,12 +102,19 @@ node /org/freedesktop/login1 { in b interactive); FlushDevices(in b interactive); PowerOff(in b interactive); + PowerOffWithFlags(in t flags); Reboot(in b interactive); + RebootWithFlags(in t flags); Halt(in b interactive); + HaltWithFlags(in t flags); Suspend(in b interactive); + SuspendWithFlags(in t flags); Hibernate(in b interactive); + HibernateWithFlags(in t flags); HybridSleep(in b interactive); + HybridSleepWithFlags(in t flags); SuspendThenHibernate(in b interactive); + SuspendThenHibernateWithFlags(in t flags); CanPowerOff(out s result); CanReboot(out s result); CanHalt(out s result); @@ -291,18 +298,32 @@ node /org/freedesktop/login1 { + + + + + + + + + + + + + + @@ -525,8 +546,19 @@ node /org/freedesktop/login1 { using an RTC timer and hibernated. The only argument is the polkit interactivity boolean interactive (see below). The main purpose of these calls is that they enforce polkit policy and hence allow powering off/rebooting/suspending/hibernating even by unprivileged - users. They also enforce inhibition locks. UIs should expose these calls as the primary mechanism to - poweroff/reboot/suspend/hibernate the machine. + users. They also enforce inhibition locks for non-privileged users. UIs should expose these calls + as the primary mechanism to poweroff/reboot/suspend/hibernate the machine. Methods + PowerOffWithFlags(), RebootWithFlags(), + HaltWithFlags(), SuspendWithFlags(), + HibernateWithFlags(), HybridSleepWithFlags() and + SuspendThenHibernateWithFlags() add flags to allow for + extendability, defined as follows: + +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + + When the flags is 0 then these methods behave just like the versions + without flags. When SD_LOGIND_ROOT_CHECK_INHIBITORS (0x01) is set, active + inhibitors are honoured for privileged users too. SetRebootParameter() sets a parameter for a subsequent reboot operation. See the description of reboot in diff --git a/man/org.freedesktop.portable1.xml b/man/org.freedesktop.portable1.xml new file mode 100644 index 000000000..e6d2f4f53 --- /dev/null +++ b/man/org.freedesktop.portable1.xml @@ -0,0 +1,427 @@ + + + + + + + org.freedesktop.portable1 + systemd + + + + org.freedesktop.portable1 + 5 + + + + org.freedesktop.portable1 + The D-Bus interface of systemd-portabled + + + + Introduction + + + systemd-portabled.service8 + is a system service that may be used to attach, detach and inspect portable services. This page describes the + D-Bus interface. + + + + The Manager Object + + The service exposes the following interfaces on the Manager object on the bus: + + +node /org/freedesktop/portable1 { + interface org.freedesktop.portable1.Manager { + methods: + GetImage(in s image, + out o object); + ListImages(out a(ssbtttso) UNNAMED); + GetImageOSRelease(in s image, + out a{ss} os_release); + GetImageMetadata(in s image, + in as matches, + out s image, + out ay os_release, + out a{say} units); + GetImageState(in s image, + out s state); + AttachImage(in s image, + in as matches, + in s profile, + in b runtime, + in s copy_mode, + out a(sss) changes); + DetachImage(in s image, + in b runtime, + out a(sss) changes); + ReattachImage(in s image, + in as matches, + in s profile, + in b runtime, + in s copy_mode, + out a(sss) changes_removed, + out a(sss) changes_updated); + RemoveImage(in s image); + MarkImageReadOnly(in s image, + in b read_only); + SetImageLimit(in s image, + in t limit); + SetPoolLimit(in t limit); + properties: + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s PoolPath = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t PoolUsage = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t PoolLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly as Profiles = ['...', ...]; + }; + interface org.freedesktop.DBus.Peer { ... }; + interface org.freedesktop.DBus.Introspectable { ... }; + interface org.freedesktop.DBus.Properties { ... }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Methods + + GetImage() may be used to get the image object path of the image with the + specified name. + + ListImages() returns an array of all currently known images. The + structures in the array consist of the following fields: image name, type, read-only flag, creation + time, modification time, current disk space, usage and image object path. + + GetImageOSRelease() retrieves the OS release information of an image. + This method returns an array of key value pairs read from the + os-release5 file in + the image and is useful to identify the operating system used in a portable service. + + GetImageMetadata() retrieves metadata associated with an image. + This method returns the image name, the image's os-release + 5 content in the form of a (streamable) array of bytes, + and a list of portable units contained in the image, in the form of a string (unit name) and + an array of bytes with the content. + + GetImageState() retrieves the image state as one of the following + strings: + + detached + + attached + + attached-runtime + + enabled + + enabled-runtime + + running + + running-runtime + + + AttachImage() attaches a portable image to the system. + This method takes an image path or name, a list of strings that will be used to search for + unit files inside the image (partial or complete matches), a string indicating which + portable profile to use for the image (see Profiles property for + a list of available profiles), a boolean indicating whether to attach the image only + for the current boot session, and a string representing the preferred copy mode + (whether to copy the image or to just symlink it) with the following possible values: + + (null) + + copy + + symlink + + This method returns the list of changes applied to the system (for example, which unit was + added and is now available as a system service). Each change is represented as a triplet of + strings: the type of change applied, the path on which it was applied, and the source + (if any). The type of change applied will be one of the following possible values: + + copy + + symlink + + write + + mkdir + + Note that an image cannot be attached if a unit that it contains is already present + on the system. + + DetachImage() detaches a portable image from the system. + This method takes an image path or name, and a boolean indicating whether the image to + detach was attached only for the current boot session or persistently. This method + returns the list of changes applied to the system (for example, which unit was removed + and is no longer available as a system service). Each change is represented as a triplet of + strings: the type of change applied, the path on which it was applied, and the source + (if any). The type of change applied will be one of the following possible values: + + unlink + + Note that an image cannot be detached if a unit that it contains is running. + + ReattachImage() combines the effects of the + AttachImage() method and the DetachImage() method. + The difference is that it is allowed to reattach an image while one or more of its units + are running. The reattach operation will fail if no matching image is attached. + The input parameters match the AttachImage() method, and the return + parameters are the combination of the return parameters of the + DetachImage() method (first array, units that were removed) and the + AttachImage() method (second array, units that were updated or added). + + RemoveImage() removes the image with the specified name. + + MarkImageReadOnly() toggles the read-only flag of an image. + + SetPoolLimit() sets an overall quota limit on the pool of images. + + SetImageLimit() sets a per-image quota limit. + + + + Properties + + PoolPath specifies the file system path where images are written to. + + PoolUsage specifies the current usage size of the image pool in bytes. + + PoolLimit specifies the size limit of the image pool in bytes. + + Profiles specifies the available runtime profiles for portable services. + + + + + The Image Object + + The service exposes the following interfaces on the Image object on the bus: + + +node /org/freedesktop/portable1 { + interface org.freedesktop.portable1.Image { + methods: + GetOSRelease(out a{ss} UNNAMED); + GetMetadata(in as matches, + out s image, + out ay os_release, + out a{say} units); + GetState(out s UNNAMED); + Attach(in as matches, + in s profile, + in b runtime, + in s copy_mode, + out a(sss) changes); + Detach(in b runtime, + out a(sss) changes); + Reattach(in as matches, + in s profile, + in b runtime, + in s copy_mode, + out a(sss) changes_removed, + out a(sss) changes_updated); + Remove(); + MarkReadOnly(in b read_only); + SetLimit(in t limit); + properties: + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s Name = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s Path = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s Type = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly b ReadOnly = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t CreationTimestamp = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t ModificationTimestamp = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t Usage = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t Limit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t UsageExclusive = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly t LimitExclusive = ...; + }; + interface org.freedesktop.DBus.Peer { ... }; + interface org.freedesktop.DBus.Introspectable { ... }; + interface org.freedesktop.DBus.Properties { ... }; +}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Methods + + The following methods implement the same operation as the respective methods on the + Manager object (see above). However, these methods operate on the image + object and hence does not take an image name parameter. Invoking the methods directly on the Manager + object has the advantage of not requiring a GetImage() call to get the image object + for a specific image name. Calling the methods on the Manager object is hence a round trip + optimization. List of methods: + + GetOSRelease() + + GetMetadata() + + GetState() + + Attach() + + Detach() + + Reattach() + + Remove() + + MarkReadOnly() + + SetLimit() + + + + + Properties + + Name specifies the image name. + + Path specifies the file system path where image is stored. + + Type specifies the image type. + + ReadOnly specifies whether the image is read-only. + + CreationTimestamp specifies the image creation timestamp. + + ModificationTimestamp specifies the image modification timestamp. + + Usage specifies the image disk usage. + + Limit specifies the image disk usage limit. + + UsageExclusive specifies the image disk usage (exclusive). + + LimitExclusive specifies the image disk usage limit (exclusive). + + + + + Versioning + + These D-Bus interfaces follow + the usual interface versioning guidelines. + + diff --git a/man/org.freedesktop.resolve1.xml b/man/org.freedesktop.resolve1.xml index 41562360a..860a14877 100644 --- a/man/org.freedesktop.resolve1.xml +++ b/man/org.freedesktop.resolve1.xml @@ -329,7 +329,7 @@ node /org/freedesktop/resolve1 { Alternatively, leave both the service name and type empty and specify the full domain name of the SRV record (i.e. prefixed with the service type) in the domain parameter. (No IDNA - coversion is applied in this mode.) + conversion is applied in this mode.) The family parameter of the ResolveService() method encodes diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index 78fd0b337..aff43217e 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -116,6 +116,17 @@ node /org/freedesktop/systemd1 { SetUnitProperties(in s name, in b runtime, in a(sv) properties); + BindMountUnit(in s name, + in s source, + in s destination, + in b read_only, + in b mkdir); + MountImageUnit(in s name, + in s source, + in s destination, + in b read_only, + in b mkdir, + in a(ss) options); RefUnit(in s name); UnrefUnit(in s name); StartTransientUnit(in s name, @@ -165,6 +176,7 @@ node /org/freedesktop/systemd1 { UnsetEnvironment(in as names); UnsetAndSetEnvironment(in as names, in as assignments); + EnqueueMarkedJobs(out ao jobs); ListUnitFiles(out a(ss) unit_files); ListUnitFilesByPatterns(in as states, in as patterns, @@ -767,6 +779,10 @@ node /org/freedesktop/systemd1 { + + + + @@ -833,6 +849,8 @@ node /org/freedesktop/systemd1 { + + @@ -1156,6 +1174,17 @@ node /org/freedesktop/systemd1 { the "Try" flavor is used in which case a service that isn't running is not affected by the restart. The "ReloadOrRestart" flavors attempt a reload if the unit supports it and use a restart otherwise. + EnqueueMarkedJobs() creates reload/restart jobs for units which have been + appropriately marked, see Marks property above. This is equivalent to calling + TryRestartUnit() or ReloadOrTryRestartUnit() for the marked + units. + + BindMountUnit() can be used to bind mount new files or directories into + a running service mount namespace. + + MountImageUnit() can be used to mount new images into a running service + mount namespace. + KillUnit() may be used to kill (i.e. send a signal to) all processes of a unit. It takes the unit name, an enum who and a UNIX signal number to send. The who enum is one of @@ -1664,6 +1693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { readonly b IgnoreOnIsolate = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b NeedDaemonReload = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly as Markers = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t JobTimeoutUSec = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -1948,6 +1979,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -2139,8 +2172,16 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { NeedDaemonReload is a boolean that indicates whether the configuration file this unit is loaded from (i.e. FragmentPath or SourcePath) has - changed since the configuration was read and hence whether a configuration reload is - recommended. + changed since the configuration was read and hence whether a configuration reload is recommended. + + + Markers is an array of string flags that can be set using + SetUnitProperties() to indicate that the service should be reloaded or + restarted. Currently known values are needs-restart and + needs-reload. Package scripts may use the first to mark units for later restart when + a new version of the package is installed. Configuration management scripts may use the second to mark + units for a later reload when the configuration is adjusted. Those flags are not set by the manager, + except to unset as appropriate when when the unit is stopped, restarted, or reloaded. JobTimeoutUSec maps directly to the corresponding configuration setting in the unit file. @@ -2193,6 +2234,15 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { interface org.freedesktop.systemd1.Service { methods: + BindMount(in s source, + in s destination, + in b read_only, + in b mkdir); + MountImage(in s source, + in s destination, + in b read_only, + in b mkdir, + in a(ss) options); GetProcesses(out a(sus) processes); AttachProcesses(in s subcgroup, in au pids); @@ -2419,7 +2469,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s ManagedOOMMemoryPressure = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") - readonly s ManagedOOMMemoryPressureLimitPercent = '...'; + readonly u ManagedOOMMemoryPressureLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s ManagedOOMPreference = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as Environment = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -2513,6 +2565,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s RootVerity = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(sba(ss)) ExtensionImages = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly a(ssba(ss)) MountImages = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i OOMScoreAdjust = ...; @@ -2613,6 +2667,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as InaccessiblePaths = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as ExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as NoExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t MountFlags = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateTmp = ...; @@ -2635,6 +2693,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateMounts = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b PrivateIPC = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectHome = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectSystem = '...'; @@ -2719,6 +2779,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s IPCNamespacePath = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -2938,7 +3000,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { - + + + @@ -3012,24 +3076,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { - - - - - - - - - - - - - - @@ -3124,6 +3174,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -3144,6 +3198,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -3228,6 +3284,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -3252,6 +3310,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -3494,7 +3556,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { - + + + @@ -3588,6 +3652,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -3688,6 +3754,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -3710,6 +3780,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -3794,6 +3866,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + @@ -3810,6 +3884,17 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + Methods + + BindMount() and MountImage() implement the same operations + as the respective methods on the Manager object (see above). However, these + methods operate on the service object and hence do not take a unit name parameter. Invoking the methods + directly on the Manager object has the advantage of not requiring a GetUnit() call + to get the unit object for a specific unit name. Calling the methods on the Manager object is hence a round + trip optimization. + + Properties @@ -3895,6 +3980,17 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { ControlGroup indicates the control group path the processes of this service unit are placed in. + + The following properties map 1:1 to corresponding settings in the unit file: + RootDirectory + RootImage + RootImageOptions + RootVerity + RootHash + RootHashSignature + MountImages + ExtensionImages + see systemd.exec(5) for their meaning. @@ -4146,7 +4242,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s ManagedOOMMemoryPressure = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") - readonly s ManagedOOMMemoryPressureLimitPercent = '...'; + readonly u ManagedOOMMemoryPressureLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s ManagedOOMPreference = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as Environment = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -4240,6 +4338,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s RootVerity = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(sba(ss)) ExtensionImages = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly a(ssba(ss)) MountImages = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i OOMScoreAdjust = ...; @@ -4340,6 +4440,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as InaccessiblePaths = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as ExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as NoExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t MountFlags = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateTmp = ...; @@ -4362,6 +4466,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateMounts = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b PrivateIPC = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectHome = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectSystem = '...'; @@ -4446,6 +4552,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s IPCNamespacePath = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -4693,7 +4801,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - + + + @@ -4767,24 +4877,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - - - - - - - - - - - - - - @@ -4879,6 +4975,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + @@ -4899,6 +4999,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -4983,6 +5085,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -5251,7 +5355,9 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { - + + + @@ -5345,6 +5451,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -5445,6 +5553,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + @@ -5467,6 +5579,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -5551,6 +5665,8 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + @@ -5827,7 +5943,9 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s ManagedOOMMemoryPressure = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") - readonly s ManagedOOMMemoryPressureLimitPercent = '...'; + readonly u ManagedOOMMemoryPressureLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s ManagedOOMPreference = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as Environment = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -5921,6 +6039,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s RootVerity = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(sba(ss)) ExtensionImages = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly a(ssba(ss)) MountImages = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i OOMScoreAdjust = ...; @@ -6021,6 +6141,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as InaccessiblePaths = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as ExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as NoExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t MountFlags = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateTmp = ...; @@ -6043,6 +6167,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateMounts = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b PrivateIPC = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectHome = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectSystem = '...'; @@ -6127,6 +6253,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s IPCNamespacePath = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -6302,7 +6430,9 @@ node /org/freedesktop/systemd1/unit/home_2emount { - + + + @@ -6376,24 +6506,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { - - - - - - - - - - - - - - @@ -6488,6 +6604,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + @@ -6508,6 +6628,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -6592,6 +6714,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -6778,7 +6902,9 @@ node /org/freedesktop/systemd1/unit/home_2emount { - + + + @@ -6872,6 +6998,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -6972,6 +7100,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + @@ -6994,6 +7126,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -7078,6 +7212,8 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + @@ -7475,7 +7611,9 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s ManagedOOMMemoryPressure = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") - readonly s ManagedOOMMemoryPressureLimitPercent = '...'; + readonly u ManagedOOMMemoryPressureLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s ManagedOOMPreference = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as Environment = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -7569,6 +7707,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s RootVerity = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(sba(ss)) ExtensionImages = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly a(ssba(ss)) MountImages = [...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i OOMScoreAdjust = ...; @@ -7669,6 +7809,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as InaccessiblePaths = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as ExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly as NoExecPaths = ['...', ...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly t MountFlags = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateTmp = ...; @@ -7691,6 +7835,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b PrivateMounts = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly b PrivateIPC = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectHome = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s ProtectSystem = '...'; @@ -7775,6 +7921,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s IPCNamespacePath = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly i KillSignal = ...; @@ -7936,7 +8084,9 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { - + + + @@ -8010,24 +8160,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { - - - - - - - - - - - - - - @@ -8122,6 +8258,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + @@ -8142,6 +8282,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -8226,6 +8368,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -8398,7 +8542,9 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { - + + + @@ -8492,6 +8638,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -8592,6 +8740,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + @@ -8614,6 +8766,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -8698,6 +8852,8 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + @@ -8948,7 +9104,9 @@ node /org/freedesktop/systemd1/unit/system_2eslice { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s ManagedOOMMemoryPressure = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") - readonly s ManagedOOMMemoryPressureLimitPercent = '...'; + readonly u ManagedOOMMemoryPressureLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s ManagedOOMPreference = '...'; }; interface org.freedesktop.DBus.Peer { ... }; interface org.freedesktop.DBus.Introspectable { ... }; @@ -9083,7 +9241,9 @@ node /org/freedesktop/systemd1/unit/system_2eslice { - + + + @@ -9223,7 +9383,9 @@ node /org/freedesktop/systemd1/unit/system_2eslice { - + + + @@ -9383,7 +9545,9 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s ManagedOOMMemoryPressure = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") - readonly s ManagedOOMMemoryPressureLimitPercent = '...'; + readonly u ManagedOOMMemoryPressureLimit = ...; + @org.freedesktop.DBus.Property.EmitsChangedSignal("false") + readonly s ManagedOOMPreference = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KillMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -9534,7 +9698,9 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { - + + + @@ -9700,7 +9866,9 @@ node /org/freedesktop/systemd1/unit/session_2d1_2escope { - + + + diff --git a/man/os-release.xml b/man/os-release.xml index 674180679..e6162bdac 100644 --- a/man/os-release.xml +++ b/man/os-release.xml @@ -317,6 +317,35 @@ + + DEFAULT_HOSTNAME= + + A string specifying the hostname if + hostname5 is not + present and no other configuration source specifies the hostname. Must be either a single DNS label + (a string composed of 7-bit ASCII lower-case characters and no spaces or dots, limited to the format + allowed for DNS domain name labels), or a sequence of such labels separated by single dots that forms + a valid DNS FQDN. The hostname must be at most 64 characters, which is a Linux limitation (DNS allows + longer names). + + See + org.freedesktop.hostname15 + for a description of how + systemd-hostnamed.service8 + determines the fallback hostname. + + + + SYSEXT_LEVEL= + + A lower-case string (mostly numeric, no spaces or other characters outside of 0–9, + a–z, ".", "_" and "-") identifying the operating system extensions support level, to indicate which + extension images are supported (See: + systemd-sysext8). + Example: SYSEXT_LEVEL=2 or + SYSEXT_LEVEL=15.14. + + If you are reading this file from C code or a shell script diff --git a/man/portablectl.xml b/man/portablectl.xml index 3653207d7..2dae537a4 100644 --- a/man/portablectl.xml +++ b/man/portablectl.xml @@ -155,6 +155,20 @@ to be used in case the unit names do not match the image name as described in the attach. + + reattach IMAGE [PREFIX…] + + Detaches an existing portable service image from the host, and immediately attaches it again. + This is useful in case the image was replaced. Running units are not stopped during the process. Partial matching, + to allow for different versions in the image name, is allowed: only the part before the first _ + character has to match. If the new image doesn't exist, the existing one will not be detached. The parameters + follow the same syntax as the attach command. + + If and/or are passed, the portable service(s) are + immediately stopped if removed, started and/or enabled if added, or restarted if updated. Prefixes are also + accepted, in the same way as described in the attach case. + + inspect IMAGE [PREFIX…] @@ -328,7 +342,8 @@ - Immediately start/stop the portable service after attaching/before detaching. + Immediately start/stop/restart the portable service after attaching/before + detaching/after upgrading. @@ -413,12 +428,13 @@ On success, 0 is returned, a non-zero failure code otherwise. - + See Also systemd1, + org.freedesktop.portable15, systemd-portabled.service8 diff --git a/man/repart.d.xml b/man/repart.d.xml index 6e31843a0..66debd336 100644 --- a/man/repart.d.xml +++ b/man/repart.d.xml @@ -492,12 +492,19 @@ Encrypt= - Takes a boolean parameter, defaulting to false. If true the partition will be + Takes one of off, key-file, + tpm2 and key-file+tpm2 (alternatively, also accepts a boolean + value, which is mapped to off when false, and key-file when + true). Defaults to off. If not off the partition will be formatted with a LUKS2 superblock, before the blocks configured with CopyBlocks= are copied in or the file system configured with Format= is created. - The LUKS2 UUID is automatically derived from the partition UUID in a stable fashion. A single - key is added to the LUKS2 superblock, configurable with the switch to + The LUKS2 UUID is automatically derived from the partition UUID in a stable fashion. If + key-file or key-file+tpm2 is used a key is added to the LUKS2 + superblock, configurable with the switch to + systemd-repart. If tpm2 or key-file+tpm2 is + used a key is added to the LUKS2 superblock that is enrolled to the local TPM2 chip, as configured + with the and options to systemd-repart. When used this slightly alters the size allocation logic as the implicit, minimal size limits @@ -627,7 +634,8 @@ SizeMaxBytes=64M systemd1, systemd-repart8, - sfdisk8 + sfdisk8, + systemd-cryptenroll1 diff --git a/man/resolvectl.xml b/man/resolvectl.xml index fb6cae7b9..6dd467445 100644 --- a/man/resolvectl.xml +++ b/man/resolvectl.xml @@ -55,7 +55,19 @@ query HOSTNAME|ADDRESS - Resolve domain names, IPv4 and IPv6 addresses. + Resolve domain names, as well as IPv4 and IPv6 addresses. When used in conjunction + with or (see below), resolves low-level DNS + resource records. + + If a single-label domain name is specified it is searched for according to the configured + search domains — unless or + / are specified, both of which turn this logic + off. + + If an international domain name is specified, it is automatically translated according to IDNA + rules when resolved via classic DNS — but not for look-ups via MulticastDNS or LLMNR. If + / is used IDNA translation is turned off and domain + names are processed as specified. @@ -204,7 +216,7 @@ Specifies the network interface to execute the query on. This may either be specified as numeric interface index or as network interface string (e.g. en0). Note that this option has no effect if system-wide DNS configuration (as configured in /etc/resolv.conf or - /etc/systemd/resolve.conf) in place of per-link configuration is used. + /etc/systemd/resolved.conf) in place of per-link configuration is used. @@ -233,11 +245,19 @@ CLASS CLASS - Specifies the DNS resource record type (e.g. A, AAAA, MX, …) and class (e.g. IN, ANY, …) to - look up. If these options are used a DNS resource record set matching the specified class and type is - requested. The class defaults to IN if only a type is specified. - The special value help may be used to list known values. - + When used in conjunction with the query command, specifies the DNS + resource record type (e.g. A, AAAA, MX, …) and class (e.g. IN, ANY, …) to look up. If these options + are used a DNS resource record set matching the specified class and type is requested. The class + defaults to IN if only a type is specified. The special value help may be used to + list known values. + + Without these options resolvectl query provides high-level domain name to + address and address to domain name resolution. With these options it provides low-level DNS resource + record resolution. The search domain logic is automatically turned off when these options are used, + i.e. specified domain names need to be fully qualified domain names. Moreover, IDNA internal domain + name translation is turned off as well, i.e. international domain names should be specified in + xn--… notation, unless look-up in MulticastDNS/LLMNR is desired, in which case + UTF-8 characters should be used. @@ -262,12 +282,73 @@ returned. + + BOOL + + Takes a boolean parameter; used in conjunction with query. If true + (the default), DNSSEC validation is applied as usual — under the condition that it is enabled for the + network and for systemd-resolved.service as a whole. If false, DNSSEC validation + is disabled for the specific query, regardless of whether it is enabled for the network or in the + service. Note that setting this option to true does not force DNSSEC validation on systems/networks + where DNSSEC is turned off. This option is only suitable to turn off such validation where otherwise + enabled, not enable validation where otherwise disabled. + + + + BOOL + + Takes a boolean parameter; used in conjunction with query. If true + (the default), select domains are resolved on the local system, among them + localhost and _gateway or entries from + /etc/hosts. If false these domains are not resolved locally, and either fail (in + case of localhost or _gateway and suchlike) or go to the + network via regular DNS/mDNS/LLMNR lookups (in case of /etc/hosts + entries). + + + + BOOL + + Takes a boolean parameter; used in conjunction with query. If true + (the default), lookups use the local DNS resource record cache. If false, lookups are routed to the + network instead, regardless if already available in the local cache. + + + + BOOL + + Takes a boolean parameter; used in conjunction with query. If true + (the default), lookups are answered from locally registered LLMNR or mDNS resource records, if + defined. If false, locally registered LLMNR/mDNS records are not considered for the lookup + request. + + + + BOOL + + Takes a boolean parameter; used in conjunction with query. If true + (the default), lookups for DS and DNSKEY are answered from the local DNSSEC trust anchors if + possible. If false, the local trust store is not considered for the lookup request. + + + + BOOL + + Takes a boolean parameter; used in conjunction with query. If true + (the default), lookups are answered via DNS, LLMNR or mDNS network requests if they cannot be + synthesized locally, or be answered from the local cache, zone or trust anchors (see above). If false, + the request is not answered from the network and will thus fail if none of the indicated sources can + answer them. + + BOOL - Takes a boolean parameter. If true (the default), any specified single-label hostnames will be - searched in the domains configured in the search domain list, if it is non-empty. Otherwise, the search domain - logic is disabled. + Takes a boolean parameter. If true (the default), any specified single-label + hostnames will be searched in the domains configured in the search domain list, if it is + non-empty. Otherwise, the search domain logic is disabled. Note that this option has no effect if + is used (see above), in which case the search domain logic is + unconditionally turned off. diff --git a/man/resolved.conf.xml b/man/resolved.conf.xml index 35a5740c9..3fdf5de58 100644 --- a/man/resolved.conf.xml +++ b/man/resolved.conf.xml @@ -251,8 +251,16 @@ request. Be aware that turning off caching comes at a performance penalty, which is particularly high when DNSSEC is used. If no-negative, only positive answers are cached. - Note that caching is turned off implicitly if the configured DNS server is on a host-local IP address - (such as 127.0.0.1 or ::1), in order to avoid duplicate local caching. + Note that caching is turned off by default for host-local DNS servers. + See CacheFromLocalhost= for details. + + + + CacheFromLocalhost= + Takes a boolean as argument. If no (the default), and response cames from + host-local IP address (such as 127.0.0.1 or ::1), the result wouldn't be cached in order to avoid + potential duplicate local caching. + diff --git a/man/rules/meson.build b/man/rules/meson.build index cacbbd75b..7ef26cb2c 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -1,6 +1,8 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + # Do not edit. Generated by update-man-rules.py. # Update with: -# ninja -C build man/update-man-rules +# ninja -C build update-man-rules manpages = [ ['binfmt.d', '5', [], 'ENABLE_BINFMT'], ['bootctl', '1', [], 'ENABLE_EFI'], @@ -55,6 +57,7 @@ manpages = [ ['org.freedesktop.login1', '5', [], 'ENABLE_LOGIND'], ['org.freedesktop.machine1', '5', [], 'ENABLE_MACHINED'], ['org.freedesktop.oom1', '5', [], 'ENABLE_OOMD'], + ['org.freedesktop.portable1', '5', [], 'ENABLE_PORTABLED'], ['org.freedesktop.resolve1', '5', [], 'ENABLE_RESOLVE'], ['org.freedesktop.systemd1', '5', [], ''], ['org.freedesktop.timedate1', '5', [], 'ENABLE_TIMEDATED'], @@ -220,6 +223,7 @@ manpages = [ 'sd_bus_open_system_remote', 'sd_bus_open_system_with_description', 'sd_bus_open_user', + 'sd_bus_open_user_machine', 'sd_bus_open_user_with_description', 'sd_bus_open_with_description'], ''], @@ -265,10 +269,7 @@ manpages = [ 'sd_bus_get_current_slot', 'sd_bus_get_current_userdata'], ''], - ['sd_bus_get_fd', - '3', - ['sd_bus_get_events', 'sd_bus_get_timeout', 'sd_bus_set_fd'], - ''], + ['sd_bus_get_fd', '3', ['sd_bus_get_events', 'sd_bus_get_timeout'], ''], ['sd_bus_get_n_queued_read', '3', ['sd_bus_get_n_queued_write'], ''], ['sd_bus_get_name_creds', '3', ['sd_bus_get_owner_creds'], ''], ['sd_bus_get_name_machine_id', '3', [], ''], @@ -408,7 +409,7 @@ manpages = [ 'sd_bus_release_name_async', 'sd_bus_request_name_async'], ''], - ['sd_bus_send', '3', ['sd_bus_send_to'], ''], + ['sd_bus_send', '3', ['sd_bus_message_send', 'sd_bus_send_to'], ''], ['sd_bus_set_address', '3', ['sd_bus_get_address', 'sd_bus_set_exec'], ''], ['sd_bus_set_close_on_exit', '3', ['sd_bus_get_close_on_exit'], ''], ['sd_bus_set_connected_signal', '3', ['sd_bus_get_connected_signal'], ''], @@ -426,6 +427,7 @@ manpages = [ 'sd_bus_set_trusted'], ''], ['sd_bus_set_exit_on_disconnect', '3', ['sd_bus_get_exit_on_disconnect'], ''], + ['sd_bus_set_fd', '3', [], ''], ['sd_bus_set_method_call_timeout', '3', ['sd_bus_get_method_call_timeout'], @@ -582,6 +584,10 @@ manpages = [ 'SD_EVENT_PRIORITY_NORMAL', 'sd_event_source_get_priority'], ''], + ['sd_event_source_set_ratelimit', + '3', + ['sd_event_source_get_ratelimit', 'sd_event_source_is_ratelimited'], + ''], ['sd_event_source_set_userdata', '3', ['sd_event_source_get_userdata'], ''], ['sd_event_source_unref', '3', @@ -821,6 +827,7 @@ manpages = [ '8', ['systemd-coredump.socket', 'systemd-coredump@.service'], 'ENABLE_COREDUMP'], + ['systemd-cryptenroll', '1', [], 'HAVE_LIBCRYPTSETUP'], ['systemd-cryptsetup-generator', '8', [], 'HAVE_LIBCRYPTSETUP'], ['systemd-cryptsetup@.service', '8', @@ -924,7 +931,7 @@ manpages = [ '8', ['systemd-random-seed'], 'ENABLE_RANDOMSEED'], - ['systemd-rc-local-generator', '8', [], 'HAVE_SYSV_COMPAT'], + ['systemd-rc-local-generator', '8', ['rc-local.service'], 'HAVE_SYSV_COMPAT'], ['systemd-remount-fs.service', '8', ['systemd-remount-fs'], ''], ['systemd-repart', '8', ['systemd-repart.service'], 'ENABLE_REPART'], ['systemd-resolved.service', '8', ['systemd-resolved'], 'ENABLE_RESOLVE'], @@ -945,6 +952,7 @@ manpages = [ 'systemd-suspend-then-hibernate.service'], ''], ['systemd-sysctl.service', '8', ['systemd-sysctl'], ''], + ['systemd-sysext', '8', ['systemd-sysext.service'], ''], ['systemd-system-update-generator', '8', [], ''], ['systemd-system.conf', '5', @@ -1118,6 +1126,7 @@ manpages = [ ['systemd-user-runtime-dir', 'user-runtime-dir@.service'], ''], ['userdbctl', '1', [], 'ENABLE_USERDB'], - ['vconsole.conf', '5', [], 'ENABLE_VCONSOLE'] + ['vconsole.conf', '5', [], 'ENABLE_VCONSOLE'], + ['veritytab', '5', [], 'HAVE_LIBCRYPTSETUP'] ] # Really, do not edit. diff --git a/man/sd-bus.xml b/man/sd-bus.xml index 05fce44ac..f43af8978 100644 --- a/man/sd-bus.xml +++ b/man/sd-bus.xml @@ -54,9 +54,9 @@ sd_bus_call_method3, sd_bus_call_method_async3, sd_bus_can_send3, +sd_bus_close3, sd_bus_creds_get_pid3, sd_bus_creds_new_from_pid3, -sd_bus_close3, sd_bus_default3, sd_bus_emit_interfaces_added3, sd_bus_emit_interfaces_added_strv3, @@ -83,19 +83,19 @@ sd_bus_get_fd3, sd_bus_get_method_call_timeout3, sd_bus_get_n_queued_read3, -sd_bus_get_name_machine_id3, sd_bus_get_name_creds3, +sd_bus_get_name_machine_id3, sd_bus_get_owner_creds3, sd_bus_get_property3, -sd_bus_get_property_trivial3, sd_bus_get_property_string3, sd_bus_get_property_strv3, +sd_bus_get_property_trivial3, sd_bus_get_scope3, sd_bus_get_tid3, sd_bus_get_unique_name3, sd_bus_interface_name_is_valid3, -sd_bus_is_monitor3, sd_bus_is_bus_client3, +sd_bus_is_monitor3, sd_bus_is_server3, sd_bus_list_names3, sd_bus_message_append3, @@ -130,10 +130,11 @@ sd_bus_message_read_strv3, sd_bus_message_rewind3, sd_bus_message_seal3, +sd_bus_message_send3, sd_bus_message_set_allow_interactive_authorization3, sd_bus_message_set_destination3, -sd_bus_message_set_sender3, sd_bus_message_set_expect_reply3, +sd_bus_message_set_sender3, sd_bus_message_skip3, sd_bus_message_verify_type3, sd_bus_negotiate_fds3, @@ -142,8 +143,8 @@ sd_bus_process3, sd_bus_query_sender_creds3, sd_bus_query_sender_privilege3, -sd_bus_reply_method_return3, sd_bus_reply_method_error3, +sd_bus_reply_method_return3, sd_bus_request_name3, sd_bus_send3, sd_bus_send_to3, diff --git a/man/sd-event.xml b/man/sd-event.xml index a28c9b87e..1bcf4e32a 100644 --- a/man/sd-event.xml +++ b/man/sd-event.xml @@ -56,6 +56,7 @@ sd_event_source_get_pending3, sd_event_source_set_description3, sd_event_source_set_prepare3, + sd_event_source_set_ratelimit3, sd_event_wait3, sd_event_get_fd3, sd_event_set_watchdog3, @@ -147,6 +148,7 @@ sd_event_source_get_pending3, sd_event_source_set_description3, sd_event_source_set_prepare3, + sd_event_source_set_ratelimit3, sd_event_wait3, sd_event_get_fd3, sd_event_set_watchdog3, diff --git a/man/sd_bus_add_match.xml b/man/sd_bus_add_match.xml index 1ce1c1367..3de7a6a53 100644 --- a/man/sd_bus_add_match.xml +++ b/man/sd_bus_add_match.xml @@ -94,13 +94,13 @@ connection object bus. The syntax of the match rule expression passed in match is described in the D-Bus Specification. The specified handler - function callback is called for eaching incoming message matching the specified expression, + function callback is called for each incoming message matching the specified expression, the userdata parameter is passed as-is to the callback function. The match is installed synchronously when connected to a bus broker, i.e. the call sends a control message requested the match to be added to the broker and waits until the broker confirms the match has been installed successfully. sd_bus_add_match_async() operates very similar to - sd_bus_match_signal(), however it installs the match asynchronously, in a non-blocking + sd_bus_add_match(), however it installs the match asynchronously, in a non-blocking fashion: a request is sent to the broker, but the call does not wait for a response. The install_callback function is called when the response is later received, with the response message from the broker as parameter. If this function is specified as NULL a default diff --git a/man/sd_bus_add_object.xml b/man/sd_bus_add_object.xml index 00e411073..31a3344bb 100644 --- a/man/sd_bus_add_object.xml +++ b/man/sd_bus_add_object.xml @@ -294,11 +294,12 @@ returns zero, an error reply is sent back to the caller indicating no matching object for the request was found. - Note that you can return a positive integer from a callback without + Note that you can return a positive integer from a method callback without immediately sending a reply. This informs sd-bus this callback will take responsibility for replying to the request without forcing the callback to produce a reply immediately. This allows a callback to perform any number of asynchronous operations required to construct a reply. - However, if producing a reply takes too long, the method call will time out at the caller. + However, if producing a reply takes too long, the method call will time out at the caller. This is + only available to methods and not properties. If a callback was invoked to handle a request that expects a reply and the callback returns a negative value, the value is interpreted as a negative errno-style error code and sent diff --git a/man/sd_bus_default.xml b/man/sd_bus_default.xml index 4ae26414e..f4b1d6a79 100644 --- a/man/sd_bus_default.xml +++ b/man/sd_bus_default.xml @@ -24,6 +24,7 @@ sd_bus_open_with_description sd_bus_open_user sd_bus_open_user_with_description + sd_bus_open_user_machine sd_bus_open_system sd_bus_open_system_with_description sd_bus_open_system_remote @@ -73,6 +74,12 @@ const char *description + + int sd_bus_open_user_machine + sd_bus **bus + const char *machine + + int sd_bus_open_system sd_bus **bus @@ -187,14 +194,24 @@ work for the root user on the remote machine. sd_bus_open_system_machine() connects to the system bus in the specified - machine, where machine is the name of a local - container. See + machine, where machine is the name of a local container, + possibly prefixed by a user name and a separating @. If the container name is + specified as the special string .host the connection is made to the local system. This + is useful to connect to the local system bus as specific user, e.g. foobar@.host to + connect to the local system bus as local user foobar. If the @ + syntax is used either the left-hand side or the right-hand side may be omitted (but not both) in which + case the local user name or .host is implied. If the @ syntax is + not used the connection is always made as root user. See sd_bus_set_address3 for a description of the address syntax, and machinectl1 for more information about the "machine" concept. Note that connections into local containers are only available to privileged processes at this time. + sd_bus_open_user_machine() is similar to + sd_bus_open_system_machine(), but connects to the user bus of the root user, or if + the @ syntax is used, of the specified user. + These calls allocate a bus connection object and initiate the connection to a well-known bus of some form. An alternative to using these high-level calls is to create an unconnected bus @@ -210,6 +227,7 @@ Reference ownership The functions sd_bus_open(), sd_bus_open_user(), + sd_bus_open_user_machine(), sd_bus_open_system(), sd_bus_open_system_remote(), and sd_bus_open_system_machine() return a new diff --git a/man/sd_bus_error.xml b/man/sd_bus_error.xml index af2238e74..bfc5caf4e 100644 --- a/man/sd_bus_error.xml +++ b/man/sd_bus_error.xml @@ -266,7 +266,7 @@ former. This function cannot fail, as no new memory is allocated. Note that if e is not set (or NULL) dst is initializated to SD_BUS_ERROR_NULL. Moreover, if dst is NULL no - operation is executed on it and and resources held by e are freed and reset. Returns a + operation is executed on it and resources held by e are freed and reset. Returns a converted errno-like, negative error code. sd_bus_error_is_set() will return a diff --git a/man/sd_bus_get_fd.xml b/man/sd_bus_get_fd.xml index 689bba6f3..2c0ec8fc0 100644 --- a/man/sd_bus_get_fd.xml +++ b/man/sd_bus_get_fd.xml @@ -22,7 +22,6 @@ sd_bus_get_fd - sd_bus_set_fd sd_bus_get_events sd_bus_get_timeout @@ -39,13 +38,6 @@ sd_bus *bus - - int sd_bus_set_fd - sd_bus *bus - int input_fd - int output_fd - - int sd_bus_get_events sd_bus *bus @@ -69,11 +61,6 @@ object was configured with the sd_bus_set_fd() function, then the input_fd file descriptor used in that call is returned. - sd_bus_set_fd() sets the file descriptors used to communicate from a - message bus object. Both input_fd and output_fd - must be valid file descriptors. The same file descriptor may be used as both the input and the - output file descriptor. This function must be called before the bus is started. - sd_bus_get_events() returns the I/O events to wait for, suitable for passing to poll() or a similar call. Returns a combination of POLLIN, POLLOUT, … events, or negative on error. @@ -92,7 +79,7 @@ care should be taken to use a division that rounds up to ensure the I/O polling operation doesn't sleep for shorter than necessary, which might result in unintended busy looping (alternatively, use - ppoll3 + ppoll2 instead of plain poll(), which understands timeouts with nano-second granularity). @@ -122,9 +109,6 @@ On success, sd_bus_get_fd() returns the file descriptor used for communication. On failure, it returns a negative errno-style error code. - On success, sd_bus_set_fd() returns a non-negative integer. On - failure, it returns a negative errno-style error code. - On success, sd_bus_get_events() returns the I/O event mask to use for I/O event watching. On failure, it returns a negative errno-style error code. @@ -164,13 +148,6 @@ return. - - -EBADF - - An invalid file descriptor was passed to - sd_bus_set_fd(). - - -ENOPKG @@ -191,6 +168,7 @@ sd_bus_process3, sd_bus_attach_event3, sd_bus_wait3, + sd_bus_set_fd3, poll3 diff --git a/man/sd_bus_message_open_container.xml b/man/sd_bus_message_open_container.xml index 27b953ecc..89c75f0e9 100644 --- a/man/sd_bus_message_open_container.xml +++ b/man/sd_bus_message_open_container.xml @@ -100,8 +100,13 @@ Return Value - On success, these functions return a non-negative integer. On failure, they return a negative - errno-style error code. + On success, these functions return a non-negative integer. + sd_bus_message_open_container() and sd_bus_message_close_container() + return 0. + sd_bus_message_enter_container() returns 1 if it successfully opened a new container, and 0 if + that was not possible because the end of the currently open container or message was reached. + sd_bus_message_exit_container() returns 1 on success. + On failure, all of these functions return a negative errno-style error code. Errors diff --git a/man/sd_bus_message_read.xml b/man/sd_bus_message_read.xml index 12a2c77ea..0b921258d 100644 --- a/man/sd_bus_message_read.xml +++ b/man/sd_bus_message_read.xml @@ -74,7 +74,7 @@ should be read. See the table below for a complete list of allowed arguments and their types. Note that, if the basic type is a pointer (e.g., const char * in the case of a string), the argument is a pointer to a pointer, and also the pointer value that is written is only borrowed and the contents must - be copied if they are to be used after the end of the messages lifetime. If the type is + be copied if they are to be used after the end of the message's lifetime. If the type is h (UNIX file descriptor), the descriptor is not duplicated by this call and the returned descriptor remains in possession of the message object, and needs to be duplicated by the caller in order to keep an open reference to it after the message object is freed. diff --git a/man/sd_bus_message_read_basic.xml b/man/sd_bus_message_read_basic.xml index 443fcdaad..bd5a149a2 100644 --- a/man/sd_bus_message_read_basic.xml +++ b/man/sd_bus_message_read_basic.xml @@ -58,12 +58,12 @@ type is 's', the object passed in p should have type const char **. Note that, if the basic type is a pointer (e.g., const char * in the case of a string), the pointer is only borrowed and the contents must - be copied if they are to be used after the end of the messages lifetime. Similarly, during the lifetime - of such a pointer, the message must not be modified. If type is + be copied if they are to be used after the end of the message's lifetime. Similarly, during the + lifetime of such a pointer, the message must not be modified. If type is 'h' (UNIX file descriptor), the descriptor is not duplicated by this call and the - returned descriptor remains in possession of the message object, and needs to be duplicated by the caller - in order to keep an open reference to it after the message object is freed (for example by calling - fcntl(fd, FD_DUPFD_CLOEXEC, 3)). See the table below for a complete list of + returned descriptor remains in possession of the message object, and needs to be duplicated by the + caller in order to keep an open reference to it after the message object is freed (for example by + calling fcntl(fd, FD_DUPFD_CLOEXEC, 3)). See the table below for a complete list of allowed types. diff --git a/man/sd_bus_message_read_strv.xml b/man/sd_bus_message_read_strv.xml index a90ae8409..50580d86b 100644 --- a/man/sd_bus_message_read_strv.xml +++ b/man/sd_bus_message_read_strv.xml @@ -36,11 +36,13 @@ Description - sd_bus_message_read_strv() gives access to an array of strings in message - m. The "read pointer" in the message must be right before an array of strings. On - success, a pointer to the NULL-terminated array of strings is returned in the output - parameter l. Note that ownership of this array is transferred to the caller. - Hence, the caller is responsible for freeing this array and its contents. + sd_bus_message_read_strv() gives access to an array of string-like items in + message m. The "read pointer" in the message must be right before an array of + strings (D-Bus type as), object paths (D-Bus type ao), or + signatures (D-Bus type ag). On success, a pointer to a + NULL-terminated array of strings is returned in the output parameter + l. Note that ownership of this array is transferred to the caller. Hence, the + caller is responsible for freeing this array and its contents. @@ -73,6 +75,13 @@ The message cannot be parsed. + + + -ENXIO + + The message "read pointer" is not right before an array of the appropriate type. + + diff --git a/man/sd_bus_process.xml b/man/sd_bus_process.xml index 09b3c50dd..193c16c6a 100644 --- a/man/sd_bus_process.xml +++ b/man/sd_bus_process.xml @@ -46,7 +46,7 @@ queued incoming messages are dispatched to registered callbacks. Each time it is invoked a single operation is executed. It returns zero when no operations were pending and positive if a message was processed. When zero is returned the caller should synchronously poll for I/O events before calling into - sd_bus_process() again. For that either user the simple, synchronous + sd_bus_process() again. For that either use the simple, synchronous sd_bus_wait3 call, or hook up the bus connection object to an external or manual event loop using sd_bus_get_fd3. diff --git a/man/sd_bus_query_sender_creds.xml b/man/sd_bus_query_sender_creds.xml index d0769e8c8..47cc33670 100644 --- a/man/sd_bus_query_sender_creds.xml +++ b/man/sd_bus_query_sender_creds.xml @@ -50,7 +50,8 @@ interested in. See sd_bus_creds_new_from_pid3 for a list of possible flags. First, this message checks if the requested credentials are attached to the - message itself. If not but the message contains the pid of the sender, this function tries to figure out + message itself. If not, but the message contains the pid of the sender and the caller specified the + SD_BUS_CREDS_AUGMENT flag, this function tries to figure out the missing credentials via other means (starting from the pid). If the pid isn't available but the message has a sender, this function calls sd_bus_get_name_creds3 diff --git a/man/sd_bus_reply_method_return.xml b/man/sd_bus_reply_method_return.xml index 76e4adecd..b9003e829 100644 --- a/man/sd_bus_reply_method_return.xml +++ b/man/sd_bus_reply_method_return.xml @@ -76,6 +76,8 @@ Message call is not attached to a bus. + + Message m is not a method reply message. diff --git a/man/sd_bus_request_name.xml b/man/sd_bus_request_name.xml index ea4ea2279..28fda406a 100644 --- a/man/sd_bus_request_name.xml +++ b/man/sd_bus_request_name.xml @@ -100,7 +100,7 @@ is sent to the bus broker, and the call waits until the broker responds. sd_bus_request_name_async() is an asynchronous version of - sd_bus_release_name(). Instead of waiting for the request to complete, the request message is + sd_bus_request_name(). Instead of waiting for the request to complete, the request message is enqueued. The specified callback will be called when the broker's response is received. If the parameter is specified as NULL a default implementation is used instead which will terminate the connection when the name cannot be acquired. The function returns a slot object in its diff --git a/man/sd_bus_send.xml b/man/sd_bus_send.xml index c4c623a1e..315ad077e 100644 --- a/man/sd_bus_send.xml +++ b/man/sd_bus_send.xml @@ -19,6 +19,7 @@ sd_bus_send sd_bus_send_to + sd_bus_message_send Queue a D-Bus message for transfer @@ -41,6 +42,11 @@ const char *destination uint64_t *cookie + + + int sd_bus_message_send + sd_bus_message *m + @@ -76,6 +82,10 @@ call fails. sd_bus_process3 should be invoked to write out any queued message data to the transport. + + sd_bus_message_send() is the same as sd_bus_send() but + without the first and last argument. sd_bus_message_send(m) is equivalent to + sd_bus_send(sd_bus_message_get_bus(m), m, NULL). diff --git a/man/sd_bus_set_fd.xml b/man/sd_bus_set_fd.xml new file mode 100644 index 000000000..14c87a2ae --- /dev/null +++ b/man/sd_bus_set_fd.xml @@ -0,0 +1,120 @@ + + + + + + + + + sd_bus_set_fd + systemd + + + + sd_bus_set_fd + 3 + + + + sd_bus_set_fd + + Set the file descriptors to use for bus communication + + + + + #include <systemd/sd-bus.h> + + + int sd_bus_set_fd + sd_bus *bus + int input_fd + int output_fd + + + + + + Description + + sd_bus_set_fd() sets the file descriptors used to communicate by a bus + connection object. Both input_fd and output_fd must be + valid file descriptors, referring to stream-based file objects (e.g. a stream socket, a pair of pipes or + FIFOs, or a even a TTY device). input_fd must be readable, and + output_fd must be writable. The same file descriptor may be used (and typically is + used) as both the input and the output file descriptor. This function must be called before the bus + connection is started via + sd_bus_start3. + + The bus connection object will take possession of the passed file descriptors and will close them + automatically when it is freed. Use + sd_bus_set_close_on_exit3 + to turn off this behaviour. + + + + Return Value + + On success, sd_bus_set_fd() returns a non-negative integer. On + failure, it returns a negative errno-style error code. + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + An invalid bus object was passed. + + + + -ECHILD + + The bus connection was allocated in a parent process and is being reused + in a child process after fork(). + + + + -EBADF + + An invalid file descriptor was passed to + sd_bus_set_fd(). + + + + -ENOPKG + + The bus cannot be resolved. + + + + -EPERM + + The bus connection has already been started. + + + + + + + + + See Also + + + systemd1, + sd-bus3, + sd_bus_get_fd3, + sd_bus_start3 + + + + diff --git a/man/sd_bus_wait.xml b/man/sd_bus_wait.xml index 005602d04..5858be106 100644 --- a/man/sd_bus_wait.xml +++ b/man/sd_bus_wait.xml @@ -45,7 +45,7 @@ function is supposed to be called whenever sd_bus_process3 returns zero, indicating that no work is pending on the connection. Internally, this call invokes ppoll3, to wait for I/O on + project='man-pages'>ppoll2, to wait for I/O on the bus connection. If the timeout_sec parameter is specified, the call will block at most for the specified amount of time in µs. Pass UINT64_MAX to permit it to sleep indefinitely. diff --git a/man/sd_event_source_set_enabled.xml b/man/sd_event_source_set_enabled.xml index cf00695fd..c8ae169c1 100644 --- a/man/sd_event_source_set_enabled.xml +++ b/man/sd_event_source_set_enabled.xml @@ -147,7 +147,8 @@ sd_event_add_child3, sd_event_add_inotify3, sd_event_add_defer3, - sd_event_source_unref3 + sd_event_source_unref3, + sd_event_source_set_ratelimit3 diff --git a/man/sd_event_source_set_ratelimit.xml b/man/sd_event_source_set_ratelimit.xml new file mode 100644 index 000000000..754bfbe3b --- /dev/null +++ b/man/sd_event_source_set_ratelimit.xml @@ -0,0 +1,148 @@ + + + + + + + + sd_event_source_set_ratelimit + systemd + + + + sd_event_source_set_ratelimit + 3 + + + + sd_event_source_set_ratelimit + sd_event_source_get_ratelimit + sd_event_source_is_ratelimited + + Configure rate limiting on event sources + + + + + #include <systemd/sd-event.h> + + + int sd_event_source_set_ratelimit + sd_event_source *source + uint64_t interval_usec + unsigned burst + + + + int sd_event_source_get_ratelimit + sd_event_source *source + uint64_t* ret_interval_usec + unsigned* ret_burst + + + + int sd_event_source_is_ratelimited + sd_event_source *source + + + + + + + Description + + sd_event_source_set_ratelimit() may be used to enforce rate limiting on an + event source. When used an event source will be temporarily turned off when it fires more often then a + specified burst number within a specified time interval. This is useful as simple mechanism to avoid + event source starvation if high priority event sources fire very frequently. + + Pass the event source to operate on as first argument, a time interval in microseconds as second + argument and a maximum dispatch limit ("burst") as third parameter. Whenever the event source is + dispatched more often than the specified burst within the specified interval it is placed in a mode + similar to being disabled with + sd_event_source_set_enabled3 + and the SD_EVENT_OFF parameter. However it is disabled only temporarily – once the + specified interval is over regular operation resumes. It is again disabled temporarily once the specified rate + limiting is hit the next time. If either the interval or the burst value are specified as zero, rate + limiting is turned off. By default event sources do not have rate limiting enabled. Note that rate + limiting and disabling via sd_event_source_set_enabled() are independent of each + other, and an event source will only effect event loop wake-ups and is dispatched while it both is + enabled and rate limiting is not in effect. + + sd_event_source_get_ratelimit() may be used to query the current rate limiting + parameters set on the event source object source. The previously set interval and + burst vales are returned in the second and third argument. + + sd_event_source_is_ratelimited() may be used to query whether the event source + is currently affected by rate limiting, i.e. it has recently hit the rate limit and is currently + temporarily disabled due to that. + + Rate limiting is currently implemented for I/O, timer, signal, defer and inotify event + sources. + + + + Return Value + + On success, sd_event_source_set_ratelimit() and + sd_event_source_get_ratelimit() return a non-negative integer. On failure, they + return a negative errno-style error code. sd_event_source_is_ratelimited returns + zero if rate limiting is currently not in effect and greater than zero if it is in effect; it returns a + negative errno-style error code on failure. + + + Errors + + Returned errors may indicate the following problems: + + + + -EINVAL + + source is not a valid pointer to an + sd_event_source object. + + + + + -ECHILD + + The event loop has been created in a different process. + + + + -EDOM + + It was attempted to use the rate limiting feature on an event source type that does + not support rate limiting. + + + + -ENOEXEC + + sd_event_source_get_ratelimit() was called on a event source + that doesn't have rate limiting configured. + + + + + + + + + + See Also + + + sd-event3, + sd_event_add_io3, + sd_event_add_time3, + sd_event_add_signal3, + sd_event_add_inotify3, + sd_event_add_defer3, + sd_event_source_set_enabled3 + + + + diff --git a/man/sd_journal_get_fd.xml b/man/sd_journal_get_fd.xml index 52360c76c..6ca45c4e8 100644 --- a/man/sd_journal_get_fd.xml +++ b/man/sd_journal_get_fd.xml @@ -151,18 +151,18 @@ else { poll() and sd_journal_process() into one. - sd_journal_reliable_fd() may be used to - check whether the wakeup events from the file descriptor returned - by sd_journal_get_fd() are known to be - immediately triggered. On certain file systems where file change - events from the OS are not available (such as NFS) changes need to - be polled for repeatedly, and hence are detected only with a - certain latency. This call will return a positive value if the - journal changes are detected immediately and zero when they need - to be polled for and hence might be noticed only with a certain - latency. Note that there is usually no need to invoke this function - directly as sd_journal_get_timeout() on these - file systems will ask for timeouts explicitly anyway. + sd_journal_reliable_fd() may be used to check whether the wake-up events from + the file descriptor returned by sd_journal_get_fd() are known to be quickly + triggered. On certain file systems where file change events from the OS are not available (such as NFS) + changes need to be polled for repeatedly, and hence are detected only with a considerable latency. This + call will return a positive value if the journal changes are detected quickly and zero when they need to + be polled for. Note that there is usually no need to invoke this function directly as + sd_journal_get_timeout() will request appropriate timeouts anyway. + + Note that all of the above change notification interfaces do not report changes + instantly. Latencies are introduced for multiple reasons: as mentioned certain storage backends require + time-based polling, in other cases wake-ups are optimized by coalescing events, and the OS introduces + additional IO/CPU scheduling latencies. diff --git a/man/sd_journal_query_unique.xml b/man/sd_journal_query_unique.xml index 26188f9e7..81ee55b57 100644 --- a/man/sd_journal_query_unique.xml +++ b/man/sd_journal_query_unique.xml @@ -116,7 +116,7 @@ Return Value sd_journal_query_unique() returns 0 on success or a negative errno-style error - code. sd_journal_enumerate_unique() and and + code. sd_journal_enumerate_unique() and sd_journal_query_available_unique() return a positive integer if the next field data has been read, 0 when no more fields remain, or a negative errno-style error code. sd_journal_restart_unique() doesn't return anything. diff --git a/man/standard-conf.xml b/man/standard-conf.xml index 69cd7b0c0..f02b9b059 100644 --- a/man/standard-conf.xml +++ b/man/standard-conf.xml @@ -41,33 +41,31 @@ Configuration Directories and Precedence - The default configuration is defined during compilation, so a - configuration file is only needed when it is necessary to deviate - from those defaults. By default, the configuration file in - /etc/systemd/ contains commented out entries - showing the defaults as a guide to the administrator. This file - can be edited to create local overrides. - + The default configuration is set during compilation, so configuration is only needed when it is + necessary to deviate from those defaults. Initially, the main configuration file in + /etc/systemd/ contains commented out entries showing the defaults as a guide to the + administrator. Local overrides can be created by editing this file or by creating drop-ins, as described + below. Using drop-ins for local configuration is recommended over modifications to the main configuration + file. - When packages need to customize the configuration, they can install configuration snippets in - /usr/lib/systemd/*.conf.d/ or /usr/local/lib/systemd/*.conf.d/. - The main configuration file is read before any of the configuration directories, and has the lowest - precedence; entries in a file in any configuration directory override entries in the single configuration - file. Files in the *.conf.d/ configuration subdirectories are sorted by their - filename in lexicographic order, regardless of in which of the subdirectories they reside. When multiple - files specify the same option, for options which accept just a single value, the entry in the file with - the lexicographically latest name takes precedence. For options which accept a list of values, entries - are collected as they occur in files sorted lexicographically. + In addition to the "main" configuration file, drop-in configuration snippets are read from + /usr/lib/systemd/*.conf.d/, /usr/local/lib/systemd/*.conf.d/, + and /etc/systemd/*.conf.d/. Those drop-ins have higher precedence and override the + main configuration file. Files in the *.conf.d/ configuration subdirectories are + sorted by their filename in lexicographic order, regardless of in which of the subdirectories they + reside. When multiple files specify the same option, for options which accept just a single value, the + entry in the file sorted last takes precedence, and for options which accept a list of values, entries + are collected as they occur in the sorted files. - Files in /etc/ are reserved for the local administrator, who may use this - logic to override the configuration files installed by vendor packages. It is recommended to prefix all - filenames in those subdirectories with a two-digit number and a dash, to simplify the ordering of the - files. + When packages need to customize the configuration, they can install drop-ins under + /usr/. Files in /etc/ are reserved for the local administrator, + who may use this logic to override the configuration files installed by vendor packages. Drop-ins have to + be used to override package drop-ins, since the main configuration file has lower precedence. It is + recommended to prefix all filenames in those subdirectories with a two-digit number and a dash, to + simplify the ordering of the files. - To disable a configuration file supplied by the vendor, the - recommended way is to place a symlink to - /dev/null in the configuration directory in - /etc/, with the same filename as the vendor - configuration file. + To disable a configuration file supplied by the vendor, the recommended way is to place a symlink + to /dev/null in the configuration directory in /etc/, with the + same filename as the vendor configuration file. diff --git a/man/standard-options.xml b/man/standard-options.xml index 64274ce8f..d42f3296c 100644 --- a/man/standard-options.xml +++ b/man/standard-options.xml @@ -35,6 +35,15 @@ Do not query the user for authentication for privileged operations. + + BOOL + + + Enable or disable printing of the legend, i.e. column headers and the footer with hints. The + legend is printed by default, unless disabled with or similar. + + + @@ -52,4 +61,29 @@ Before each file, the filename is printed as a comment. + + + MODE + + Shows output formatted as JSON. Expects one of short (for the + shortest possible output without any redundant whitespace or line breaks), pretty + (for a pretty version of the same, with indentation and line breaks) or off (to turn + off JSON output, the default). + + + + + + + + When used with kill, choose which signal to send to selected processes. Must + be one of the well-known signal specifiers such as SIGTERM, + SIGINT or SIGSTOP. If omitted, defaults to + . + + The special value help will list the known values and the program will exit + immediately, and the special value list will list known values along with the + numerical signal numbers and the program will exit immediately. + + diff --git a/man/systemctl.xml b/man/systemctl.xml index 0b8d0e377..8402b9508 100644 --- a/man/systemctl.xml +++ b/man/systemctl.xml @@ -230,10 +230,11 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: Current Time Service could not be Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output error (5) - The dot ("●") uses color on supported terminals to summarize the unit state at a glance. White - indicates an inactive or deactivating state. Red indicates a - failed or error state and green indicates an - active, reloading or activating state. + The dot ("●") uses color on supported terminals to summarize the unit state at a glance. Along with + its color, its shape varies according to its state: inactive or + maintenance is a white circle ("○"), active is a green dot ("●"), + deactivating is a white dot, failed or error is + a red cross ("×"), and reloading is a green clockwise circle arrow ("↻"). The "Loaded:" line in the output will show loaded if the unit has been loaded into @@ -550,6 +551,41 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err + + bind UNIT PATH [PATH] + + Bind mounts a file or directory from the host into the specified unit's view. The first path + argument is the source file or directory on the host, the second path argument is the destination file or + directory in the unit's view. When the latter is omitted, the destination path in the unit's view is the same as + the source path on the host. When combined with the switch, a ready-only bind + mount is created. When combined with the switch, the destination path is first created + before the mount is applied. Note that this option is currently only supported for units that run within a mount + namespace (e.g.: with , , etc.). This command supports bind + mounting directories, regular files, device nodes, AF_UNIX socket nodes, as well as FIFOs. + The bind mount is ephemeral, and it is undone as soon as the current unit process exists. + Note that the namespace mentioned here, where the bind mount will be added to, is the one where the main service + process runs, as other processes run in distinct namespaces (e.g.: , + , etc.) + + + + mount-image UNIT IMAGE [PATH [PARTITION_NAME:MOUNT_OPTIONS]] + + Mounts an image from the host into the specified unit's view. The first path argument is the source + image on the host, the second path argument is the destination directory in the unit's view (ie: inside + /). Any following argument is interpreted as a + colon-separated tuple of partition name and comma-separated list of mount options for that partition. The format is the + same as the service setting. When combined with the switch, a + ready-only mount is created. When combined with the switch, the destination path is first + created before the mount is applied. Note that this option is currently only supported for units that run within a mount + namespace (e.g.: with , , etc.). + Note that the namespace mentioned here, where the image mount will be added to, is the one where the main service + process runs, as other processes run in distinct namespaces (e.g.: , + , etc.). Example: + systemctl mount-image foo.service /tmp/img.raw /var/lib/image root:ro,nosuid + systemctl mount-image --mkdir bar.service /tmp/img.raw /var/lib/baz/img + + service-log-level SERVICE [LEVEL] @@ -757,9 +793,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err For more information on the preset policy format, see systemd.preset5. - For more information on the concept of presets, please consult the - Preset - document. + @@ -1120,7 +1154,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err import-environment - VARIABLE… + VARIABLE… @@ -1131,6 +1165,11 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err arguments are passed, the entire environment block inherited by the systemctl process is imported. In this mode, any inherited invalid environment variables are quietly ignored. + + Importing of the full inherited environment block (calling this command without any + arguments) is deprecated. A shell will set dozens of variables which only make sense locally and + are only meant for processes which are descendants of the shell. Such variables in the global + environment block are confusing to other processes. @@ -1846,17 +1885,34 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err - - + - When system shutdown or a sleep state is requested, ignore inhibitor locks. Applications can establish - inhibitor locks to avoid that certain important operations (such as CD burning or suchlike) are interrupted - by system shutdown or a sleep state. Any user may take these locks and privileged users may override these - locks. If any locks are taken, shutdown and sleep state requests will normally fail (unless privileged) and a - list of active locks is printed. However, if is specified, the - established locks are ignored and not shown, and the operation attempted anyway, possibly requiring - additional privileges. + When system shutdown or sleep state is request, this option controls how to deal with + inhibitor locks. It takes one of auto, yes or + no. Defaults to auto, which will behave like + yes for interactive invocations (i.e. from a TTY) and no + for non-interactive invocations. + yes will let the request respect inhibitor locks. + no will let the request ignore inhibitor locks. + + Applications can establish inhibitor locks to avoid that certain important operations + (such as CD burning or suchlike) are interrupted by system shutdown or a sleep state. Any user may + take these locks and privileged users may override these locks. + If any locks are taken, shutdown and sleep state requests will normally fail (unless privileged) + and a list of active locks is printed. + However, if no is specified or auto is specified on a + non-interactive requests, the established locks are ignored and not shown, and the operation + attempted anyway, possibly requiring additional privileges. + May be overridden by . + + + + + + + + Shortcut for . @@ -2011,21 +2067,9 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err is defined. If omitted, defaults to . - - - - - - - When used with kill, choose which - signal to send to selected processes. Must be one of the - well-known signal specifiers such as SIGTERM, SIGINT or - SIGSTOP. If omitted, defaults to - . - - + @@ -2216,21 +2260,73 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err - Takes one of pretty (the default), - us, µs, utc. - Changes the format of printed timestamps. - pretty: Day YYYY-MM-DD HH:MM:SS TZ - us or µs: Day YYYY-MM-DD HH:MM:SS.UUUUUU TZ - utc: Day YYYY-MM-DD HH:MM:SS UTC - us+utc or µs+utc: Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC + Change the format of printed timestamps. The following values may be used: + + + + + (this is the default) + Day YYYY-MM-DD HH:MM:SS TZ + + + + + + + + Day YYYY-MM-DD HH:MM:SS.UUUUUU TZ + + + + + + + Day YYYY-MM-DD HH:MM:SS UTC + + + + + + + + Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC + + + + + + When used with bind, creates the destination file or directory before + applying the bind mount. Note that even though the name of this option suggests that it is suitable only for + directories, this option also creates the destination file node to mount over if the object to mount is not + a directory, but a regular file, device node, socket or FIFO. + + + + + + Only allowed with reload-or-restart. Enqueues restart jobs for all + units that have the needs-restart mark, and reload jobs for units that have the + needs-reload mark. When a unit marked for reload does not support reload, restart + will be queued. Those properties can be set using set-property Marks. + + Unless is used, systemctl will wait for the + queued jobs to finish. + + + + + + When used with bind, creates a read-only bind mount. + + - + @@ -2311,12 +2407,17 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err - - - - - - + + + + + + + + + + + diff --git a/man/systemd-analyze.xml b/man/systemd-analyze.xml index 01df7da19..4da066e05 100644 --- a/man/systemd-analyze.xml +++ b/man/systemd-analyze.xml @@ -334,7 +334,7 @@ $ eog targets.svg definition (one of glibc, systemd, LSB, or BSD), see the Process Exit Codes section in systemd.exec5. - If no additional arguments are specified, all known statuses are are shown. Otherwise, only the + If no additional arguments are specified, all known statuses are shown. Otherwise, only the definitions for the specified codes are shown. @@ -782,7 +782,7 @@ Service b@0.service not loaded, b.socket cannot be started. otherwise. - + See Also diff --git a/man/systemd-coredump.xml b/man/systemd-coredump.xml index 4ac6de1ee..117b9eb6d 100644 --- a/man/systemd-coredump.xml +++ b/man/systemd-coredump.xml @@ -32,28 +32,12 @@ Description - systemd-coredump@.service is a system service that can acquire core - dumps from the kernel and handle them in various ways. The systemd-coredump - executable does the actual work. It is invoked twice: once as the handler by the kernel, and the - second time in the systemd-coredump@.service to actually write the data to - the journal. - - When the kernel invokes systemd-coredump to handle a core dump, it runs - in privileged mode, and will connect to the socket created by the - systemd-coredump.socket unit, which in turn will spawn an unprivileged - systemd-coredump@.service instance to process the core dump. Hence - systemd-coredump.socket and systemd-coredump@.service - are helper units which do the actual processing of core dumps and are subject to normal service - management. - - Core dumps can be written to the journal or saved as a file. Once saved they can be retrieved - for further processing, for example in - gdb1. - - - By default, systemd-coredump will log the core dump including a backtrace - if possible to the journal and store the core dump itself in an external file in - /var/lib/systemd/coredump. + systemd-coredump@.service is a system service to process core dumps. It will + log a summary of the event to + systemd-journald.service8, + including information about the process identifier, owner, the signal that killed the process, and the + stack trace if possible. It may also save the core dump for later processing. See the "Information about + the crashed process" section below. The behavior of a specific program upon reception of a signal is governed by a few factors which are described in detail in @@ -61,14 +45,46 @@ In particular, the core dump will only be processed when the related resource limits are sufficient. - It is also possible to invoke systemd-coredump with - option. In this case, systemd-coredump expects - a journal entry in the journal - Journal Export Format - on standard input. The entry should contain a MESSAGE= field and any additional - metadata fields the caller deems reasonable. systemd-coredump will append - additional metadata fields in the same way it does for core dumps received from the kernel. In - this mode, no core dump is stored in the journal. + Core dumps can be written to the journal or saved as a file. In both cases, they can be retrieved + for further processing, for example in + gdb1. + See coredumpctl1, + in particular the list and debug verbs. + + By default, systemd-coredump will log the core dump to the journal, including a + backtrace if possible, and store the core dump (an image of the memory contents of the process) itself in + an external file in /var/lib/systemd/coredump. These core dumps are deleted after a + few days by default; see /usr/lib/tmpfiles.d/systemd.conf for details. Note that the + removal of core files from the file system and the purging of journal entries are independent, and the + core file may be present without the journal entry, and journal entries may point to since-removed core + files. Some metadata is attached to core files in the form of extended attributes, so the core files are + useful for some purposes even without the full metadata available in the journal entry. + + + Invocation of <command>systemd-coredump</command> + + The systemd-coredump executable does the actual work. It is invoked twice: + once as the handler by the kernel, and the second time in the + systemd-coredump@.service to actually write the data to the journal and process + and save the core file. + + When the kernel invokes systemd-coredump to handle a core dump, it runs in + privileged mode, and will connect to the socket created by the + systemd-coredump.socket unit, which in turn will spawn an unprivileged + systemd-coredump@.service instance to process the core dump. Hence + systemd-coredump.socket and systemd-coredump@.service are + helper units which do the actual processing of core dumps and are subject to normal service + management. + + It is also possible to invoke systemd-coredump with + option. In this case, systemd-coredump expects a + journal entry in the journal + Journal Export Format + on standard input. The entry should contain a MESSAGE= field and any additional + metadata fields the caller deems reasonable. systemd-coredump will append additional + metadata fields in the same way it does for core dumps received from the kernel. In this mode, no core + dump is stored in the journal. + @@ -98,7 +114,7 @@ handler must be installed on the sender side. For example, in case of python1, this means a sys.excepthook must be installed, see - systemd-coredump-python. + systemd-coredump-python. The behavior of systemd-coredump itself is configured through the configuration file @@ -111,27 +127,284 @@ Resources used by core dump files are restricted in two ways. Parameters like maximum size of acquired core dumps and files can be set in files /etc/systemd/coredump.conf and snippets mentioned above. In addition the storage time of core dump files is restricted by systemd-tmpfiles, - corresponding settings are by default in /usr/lib/tmpfiles.d/systemd.conf. + corresponding settings are by default in /usr/lib/tmpfiles.d/systemd.conf. The default is + to delete core dumps after a few days; see the above file for details. Disabling coredump processing - To disable potentially resource-intensive processing by systemd-coredump, - set Storage=none -ProcessSizeMax=0 in + To disable potentially resource-intensive processing by systemd-coredump, set + Storage=none ProcessSizeMax=0 in coredump.conf5. - Usage - Data stored in the journal can be viewed with - journalctl1 - as usual. - coredumpctl1 - can be used to retrieve saved core dumps independent of their location, to display information and to process - them e.g. by passing to the GNU debugger (gdb). + Information about the crashed process + + coredumpctl1 can + be used to retrieve saved core dumps independently of their location, to display information, and to + process them e.g. by passing to the GNU debugger (gdb). + + Data stored in the journal can be also viewed with + journalctl1 as usual + (or from any other process, using the + sd-journal3 API). + The relevant messages have MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1: + $ journalctl MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1 -o verbose +… +MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1 +COREDUMP_PID=552351 +COREDUMP_UID=1000 +COREDUMP_GID=1000 +COREDUMP_SIGNAL_NAME=SIGSEGV +COREDUMP_SIGNAL=11 +COREDUMP_TIMESTAMP=1614342930000000 +COREDUMP_COMM=Web Content +COREDUMP_EXE=/usr/lib64/firefox/firefox +COREDUMP_USER_UNIT=app-gnome-firefox-552136.scope +COREDUMP_CMDLINE=/usr/lib64/firefox/firefox -contentproc -childID 5 -isForBrowser … +COREDUMP_CGROUP=/user.slice/user-1000.slice/user@1000.service/app.slice/app-….scope +COREDUMP_FILENAME=/var/lib/systemd/coredump/core.Web….552351.….zst +… + + + The following fields are saved (if known) with the journal entry + + + + COREDUMP_UID= + COREDUMP_PID= + COREDUMP_GID= + The process number (PID), owner user number (UID), and group number (GID) of the + crashed process. + + When the crashed process was part of a container (or in a process or user namespace in + general), those are the values as seen outside, in the namespace where + systemd-coredump is running. + + + + + COREDUMP_TIMESTAMP= + The time of the crash as reported by the kernel (in µs since the epoch). + + + + + COREDUMP_RLIMIT= + The core file size soft resource limit, see + getrlimit2. + + + + + COREDUMP_UNIT= + COREDUMP_SLICE= + The system unit and slice names. + + When the crashed process was in container, those are the units names + outside, in the main system manager. + + + + + COREDUMP_CGROUP= + Control group information in the format used in + /proc/self/cgroup. On systems with the unified cgroup hierarchy, this is a + single path prefixed with 0::, and multiple paths prefixed with controller numbers + on legacy systems. + + When the crashed process was in a container, this is the full path, as seen outside of the + container. + + + + + COREDUMP_OWNER_UID= + COREDUMP_USER_UNIT= + The numerical UID of the user owning the login session or systemd user unit of the + crashed process, and the user manager unit. Both fields are only present for user processes. + + + When the crashed process was in container, those are the values outside, + in the main system. + + + + + COREDUMP_SIGNAL_NAME= + COREDUMP_SIGNAL= + + The terminating signal name (with the SIG prefix + kill1 + expects signal names without the prefix; kill2 uses + the prefix; all systemd tools accept signal names both with and without the prefix. + ) and numerical value. (Both are included because signal numbers vary by + architecture.) + + + + + COREDUMP_CWD= + COREDUMP_ROOT= + + The current working directory and root directory of the crashed process. + + When the crashed process is in a container, those paths are relative to the root of the + container's mount namespace. + + + + + COREDUMP_OPEN_FDS= + + Information about open file descriptors, in the following format: + fd:/path/to/file +pos: ... +flags: ... +... + +fd:/path/to/file +pos: ... +flags: ... +... + + + The first line contains the file descriptor number fd and the path, + while subsequent lines show the contents of + /proc/pid/fdinfo/fd. + + + + + COREDUMP_EXE= + + The destination of the /proc/pid/exe + symlink. + + When the crashed process is in a container, that path is relative to the root of the + container's mount namespace. + + + + COREDUMP_COMM= + COREDUMP_PROC_STATUS= + COREDUMP_PROC_MAPS= + COREDUMP_PROC_LIMITS= + COREDUMP_PROC_MOUNTINFO= + COREDUMP_ENVIRON= + + Fields that map the per-process entries in the /proc/ + filesystem: /proc/pid/comm (the command name + associated with the process), /proc/pid/exe (the + filename of the executed command), /proc/pid/status + (various metadata about the process), /proc/pid/maps + (memory regions visible to the process and their access permissions), + /proc/pid/limits (the soft and hard resource limits), + /proc/pid/mountinfo (mount points in the process's + mount namespace), /proc/pid/environ + (the environment block of the crashed process). + + See + proc5 + for more information. + + + + COREDUMP_HOSTNAME= + + The system hostname. + + When the crashed process was in container, this is the container hostname. + + + + + COREDUMP_CONTAINER_CMDLINE= + + For processes running in a container, the commandline of the process spawning the + container (the first parent process with a different mount namespace). + + + + COREDUMP= + + When the core is stored in the journal, the core image itself. + + + + + COREDUMP_FILENAME= + + When the core is stored externally, the path the the core file. + + + + + COREDUMP_TRUNCATED= + + Set to 1 when the saved coredump was truncated. (A partial core + image may still be processed by some tools, though obviously not all information is available.) + + + + + MESSAGE= + + The message generated by systemd-coredump that includes the + backtrace if it was successfully generated. When systemd-coredump is invoked with + , this field is provided by the caller. + + + + Various other fields exist in the journal entry, but pertain to the logging process, + i.e. systemd-coredump, not the crashed process. See + systemd.journal-fields7. + + + The following fields are saved (if known) with the external file listed in + COREDUMP_FILENAME= as extended attributes: + + + + user.coredump.pid + user.coredump.uid + user.coredump.gid + user.coredump.signal + user.coredump.timestamp + user.coredump.rlimit + user.coredump.hostname + user.coredump.comm + user.coredump.exe + + Those are the same as COREDUMP_PID=, + COREDUMP_UID=, COREDUMP_GID=, + COREDUMP_SIGNAL=, COREDUMP_TIMESTAMP=, + COREDUMP_RLIMIT=, COREDUMP_HOSTNAME=, + COREDUMP_COMM=, and COREDUMP_EXE=, described above. + + + + + Those can be viewed using + getfattr1. + For the core file described in the journal entry shown above: + $ getfattr --absolute-names -d /var/lib/systemd/coredump/core.Web….552351.….zst +# file: /var/lib/systemd/coredump/core.Web….552351.….zst +user.coredump.pid="552351" +user.coredump.uid="1000" +user.coredump.gid="1000" +user.coredump.signal="11" +user.coredump.timestamp="1614342930000000" +user.coredump.comm="Web Content" +user.coredump.exe="/usr/lib64/firefox/firefox" +… + + diff --git a/man/systemd-cryptenroll.xml b/man/systemd-cryptenroll.xml new file mode 100644 index 000000000..93acdd02a --- /dev/null +++ b/man/systemd-cryptenroll.xml @@ -0,0 +1,284 @@ + + + + + + + + systemd-cryptenroll + systemd + + + + systemd-cryptenroll + 1 + + + + systemd-cryptenroll + Enroll PKCS#11, FIDO2, TPM2 token/devices to LUKS2 encrypted volumes + + + + + systemd-cryptenroll OPTIONS DEVICE + + + + + Description + + systemd-cryptenroll is a tool for enrolling hardware security tokens and devices into a + LUKS2 encrypted volume, which may then be used to unlock the volume during boot. Specifically, it supports + tokens and credentials of the following kind to be enrolled: + + + PKCS#11 security tokens and smartcards that may carry an RSA key pair (e.g. various YubiKeys) + + FIDO2 security tokens that implement the hmac-secret extension (most FIDO2 keys, including YubiKeys) + + TPM2 security devices + + Recovery keys. These are similar to regular passphrases, however are randomly generated + on the computer and thus generally have higher entropy than user chosen passphrases. Their character + set has been designed to ensure they are easy to type in, while having high entropy. They may also be + scanned off screen using QR codes. Recovery keys may be used for unlocking LUKS2 volumes wherever + passphrases are accepted. They are intended to be used in combination with an enrolled hardware + security token, as a recovery option when the token is lost. + + Regular passphrases + + + In addition, the tool may be used to enumerate currently enrolled security tokens and wipe a subset + of them. The latter may be combined with the enrollment operation of a new security token, in order to + update or replace enrollments. + + The tool supports only LUKS2 volumes, as it stores token meta-information in the LUKS2 JSON token + area, which is not available in other encryption formats. + + + + Options + + The following options are understood: + + + + + + Enroll a regular password/passphrase. This command is mostly equivalent to + cryptsetup luksAddKey, however may be combined with + in one call, see below. + + + + + + Enroll a recovery key. Recovery keys are most identical to passphrases, but are + computer generated instead of human chosen, and thus have a guaranteed high entropy. The key uses a + character set that is easy to type in, and may be scanned off screen via a QR code. + + + + URI + + Enroll a PKCS#11 security token or smartcard (e.g. a YubiKey). Expects a PKCS#11 + smart card URI referring to the token. Alternatively the special value auto may + be specified, in order to automatically determine the URI of a currently plugged in security token + (of which there must be exactly one). The special value list may be used to + enumerate all suitable PKCS#11 tokens currently plugged in. The security token must contain an RSA + key pair which is used to encrypt the randomly generated key that is used to unlock the LUKS2 + volume. The encrypted key is then stored in the LUKS2 JSON token header area. + + In order to unlock a LUKS2 volume with an enrolled PKCS#11 security token, specify the + option in the respective /etc/crypttab line: + + myvolume /dev/sda1 - pkcs11-uri=auto + + See + crypttab5 for a + more comprehensive example of a systemd-cryptenroll invocation and its matching + /etc/crypttab line. + + + + PATH + + Enroll a FIDO2 security token that implements the hmac-secret + extension (e.g. a YubiKey). Expects a hidraw device referring to the FIDO2 + device (e.g. /dev/hidraw1). Alternatively the special value + auto may be specified, in order to automatically determine the device node of a + currently plugged in security token (of which there must be exactly one). The special value + list may be used to enumerate all suitable FIDO2 tokens currently plugged in. Note + that many hardware security tokens that implement FIDO2 also implement the older PKCS#11 + standard. Typically FIDO2 is preferable, given it's simpler to use and more modern. + + In order to unlock a LUKS2 volume with an enrolled FIDO2 security token, specify the + option in the respective /etc/crypttab line: + + myvolume /dev/sda1 - fido2-device=auto + + See + crypttab5 for a + more comprehensive example of a systemd-cryptenroll invocation and its matching + /etc/crypttab line. + + + + PATH + + Enroll a TPM2 security chip. Expects a device node path referring to the TPM2 chip + (e.g. /dev/tpmrm0). Alternatively the special value auto may + be specified, in order to automatically determine the device node of a currently discovered TPM2 + device (of which there must be exactly one). The special value list may be used to + enumerate all suitable TPM2 devices currently discovered. + + In order to unlock a LUKS2 volume with an enrolled TPM2 security chip, specify the + option in the respective /etc/crypttab line: + + myvolume /dev/sda1 - tpm2-device=auto + + See + crypttab5 for a + more comprehensive example of a systemd-cryptenroll invocation and its matching + /etc/crypttab line. + + Use (see below) to configure which TPM2 PCR indexes to bind the + enrollment to. + + + + PCR + + Configures the TPM2 PCRs (Platform Configuration Registers) to bind the enrollment + requested via to. Takes a comma separated list of numeric PCR indexes + in the range 0…23. If not used, defaults to PCR 7 only. If an empty string is specified, binds the + enrollment to no PCRs at all. PCRs allow binding the enrollment to specific software versions and + system state, so that the enrolled unlocking key is only accessible (may be "unsealed") if specific + trusted software and/or configuration is used. + + + Well-known PCR Definitions + + + + + + + + PCR + Explanation + + + + + + 0 + Core system firmware executable code; changes on firmware updates + + + + 1 + Core system firmware data/host platform configuration; typically contains serial and model numbers, changes on basic hardware/CPU/RAM replacements + + + + 2 + Extended or pluggable executable code; includes option ROMs on pluggable hardware + + + + 3 + Extended or pluggable firmware data; includes information about pluggable hardware + + + + 4 + Boot loader; changes on boot loader updates + + + + 5 + GPT/Partition table; changes when the partitions are added, modified or removed + + + + 6 + Power state events; changes on system suspend/sleep + + + + 7 + Secure boot state; changes when UEFI SecureBoot mode is enabled/disabled + + + + 8 + sd-boot8 measures the kernel command line in this PCR. + + + +
+ +
+ + + SLOT + + Wipes one or more LUKS2 key slots. Takes a comma separated list of numeric slot + indexes, or the special strings all (for wiping all key slots), + empty (for wiping all key slots that are unlocked by an empty passphrase), + password (for wiping all key slots that are unlocked by a traditional passphrase), + recovery (for wiping all key slots that are unlocked by a recovery key), + pkcs11 (for wiping all key slots that are unlocked by a PKCS#11 token), + fido2 (for wiping all key slots that are unlocked by a FIDO2 token), + tpm2 (for wiping all key slots that are unlocked by a TPM2 chip), or any + combination of these strings or numeric indexes, in which case all slots matching either are + wiped. As safety precaution an operation that wipes all slots without exception (so that the volume + cannot be unlocked at all anymore, unless the volume key is known) is refused. + + This switch may be used alone, in which case only the requested wipe operation is executed. It + may also be used in combination with any of the enrollment options listed above, in which case the + enrollment is completed first, and only when successful the wipe operation executed — and the newly + added slot is always excluded from the wiping. Combining enrollment and slot wiping may thus be used to + update existing enrollments: + + systemd-cryptenroll /dev/sda1 --wipe-slot=tpm2 --tpm2-device=auto + + The above command will enroll the TPM2 chip, and then wipe all previously created TPM2 + enrollments on the LUKS2 volume, leaving only the newly created one. Combining wiping and enrollment + may also be used to replace enrollments of different types, for example for changing from a PKCS#11 + enrollment to a FIDO2 one: + + systemd-cryptenroll /dev/sda1 --wipe-slot=pkcs11 --fido2-device=auto + + Or for replacing an enrolled empty password by TPM2: + + systemd-cryptenroll /dev/sda1 --wipe-slot=empty --tpm2-device=auto + + + + + +
+ +
+ + + Exit status + + On success, 0 is returned, a non-zero failure code otherwise. + + + + See Also + + systemd1, + systemd-cryptsetup@.service8, + crypttab5, + cryptsetup8 + + + +
diff --git a/man/systemd-cryptsetup-generator.xml b/man/systemd-cryptsetup-generator.xml index 4284f78c4..e5c193f69 100644 --- a/man/systemd-cryptsetup-generator.xml +++ b/man/systemd-cryptsetup-generator.xml @@ -228,6 +228,7 @@ systemd1, crypttab5, systemd-cryptsetup@.service8, + systemd-cryptenroll1, cryptsetup8, systemd-fstab-generator8 diff --git a/man/systemd-cryptsetup@.service.xml b/man/systemd-cryptsetup@.service.xml index 216db7467..c70d6a9d3 100644 --- a/man/systemd-cryptsetup@.service.xml +++ b/man/systemd-cryptsetup@.service.xml @@ -50,13 +50,14 @@ If a key file is explicitly configured (via the third column in - /etc/crypttab), a key read from it is used. If a PKCS#11 token is configured - (using the pkcs11-uri= option) the key is decrypted before use. + /etc/crypttab), a key read from it is used. If a PKCS#11 token, FIDO2 token or + TPM2 device is configured (using the pkcs11-uri=, fido2-device=, + tpm2-device= options) the key is decrypted before use. If no key file is configured explicitly this way, a key file is automatically loaded from /etc/cryptsetup-keys.d/volume.key and /run/cryptsetup-keys.d/volume.key, if present. Here - too, if a PKCS#11 token is configured, any key found this way is decrypted before + too, if a PKCS#11/FIDO2/TPM2 token/device is configured, any key found this way is decrypted before use. If the try-empty-password option is specified it is then attempted @@ -77,6 +78,7 @@ systemd1, systemd-cryptsetup-generator8, crypttab5, + systemd-cryptenroll1, cryptsetup8
diff --git a/man/systemd-detect-virt.xml b/man/systemd-detect-virt.xml index 09491f7f1..654cf9b84 100644 --- a/man/systemd-detect-virt.xml +++ b/man/systemd-detect-virt.xml @@ -94,7 +94,7 @@ powervm - IBM PowerVM hypervisor - comes as firmware with some IBM POWER servers + IBM PowerVM hypervisor — comes as firmware with some IBM POWER servers diff --git a/man/systemd-dissect.xml b/man/systemd-dissect.xml index ed2153f76..caaf68dca 100644 --- a/man/systemd-dissect.xml +++ b/man/systemd-dissect.xml @@ -162,15 +162,6 @@ operation begins. - - MODE - - Shows output formatted as JSON. Expects one of short (for the - shortest possible output without any redundant whitespace or line breaks), pretty - (for a pretty version of the same, with indentation and line breaks) or off (to turn - off json output). - - @@ -216,7 +207,7 @@ Takes one of disabled, loop, all, crypto. If disabled the image is - accessed with empty block discarding turned off. if loop discarding is enabled if + accessed with empty block discarding turned off. If loop discarding is enabled if operating on a regular file. If crypt discarding is enabled even on encrypted file systems. If all discarding is unconditionally enabled. @@ -226,17 +217,21 @@ - Configure various aspects of Verity data integrity for the OS - image. expects a hex-encoding top-level Verity hash to use for setting - up the Verity integrity protection. expects the path to a file - containing a PKCS#7 signature file for the hash. This signature is passed to the kernel during - activation, which will match it against signature keys available in the kernel - keyring. expects the path to a file with the Verity data to use for - the OS image, in case it is stored in a detached file. It is recommended to embed the Verity data - directly in the image, using the Verity mechanisms in the Discoverable Partitions Specification. + Configure various aspects of Verity data integrity for the OS image. Option + specifies a hex-encoded top-level Verity hash to use for setting up the + Verity integrity protection. Option specifies the path to a file + containing a PKCS#7 signature for the hash. This signature is passed to the kernel during activation, + which will match it against signature keys available in the kernel keyring. Option + specifies a path to a file with the Verity data to use for the OS + image, in case it is stored in a detached file. It is recommended to embed the Verity data directly + in the image, using the Verity mechanisms in the Discoverable Partitions Specification. + + + +
diff --git a/man/systemd-firstboot.xml b/man/systemd-firstboot.xml index a1607abb8..100192490 100644 --- a/man/systemd-firstboot.xml +++ b/man/systemd-firstboot.xml @@ -237,8 +237,8 @@ - Copy locale, keymap, time zone and root password from - the host. This is equivalent to specifying + Copy locale, keymap, time zone, root password and shell from the host. This is + equivalent to specifying , , , diff --git a/man/systemd-fstab-generator.xml b/man/systemd-fstab-generator.xml index ec8f5c988..3c5a5cc50 100644 --- a/man/systemd-fstab-generator.xml +++ b/man/systemd-fstab-generator.xml @@ -82,9 +82,20 @@ root= - Takes the root filesystem to mount in the - initrd. root= is honored by the - initrd. + Configures the operating system's root filesystem to mount when running in the + initrd. This accepts a device node path (usually /dev/disk/by-uuid/… or + /dev/disk/by-label/… or similar), or the special values gpt-auto + and tmpfs. + + Use gpt-auto to explicitly request automatic root file system discovery via + systemd-gpt-auto-generator8. + + Use tmpfs in order to mount a tmpfs5 file + system as root file system of the OS. This is useful in combination with + mount.usr= (see below) in order to combine a volatile root file system with a + separate, immutable /usr/ file system. Also see + systemd.volatile= below. @@ -193,10 +204,19 @@ or any other resources stored in the root file system are physically removed. It's thus safe to boot a system that is normally operated in non-volatile mode temporarily into volatile mode, without losing data. - Note that with the exception of overlay mode, enabling this setting will only work - correctly on operating systems that can boot up with only /usr/ mounted, and are able to - automatically populate /etc/, and also /var/ in case of - systemd.volatile=yes. + Note that with the exception of overlay mode, enabling this setting will + only work correctly on operating systems that can boot up with only /usr/ + mounted, and are able to automatically populate /etc/, and also + /var/ in case of systemd.volatile=yes. + + Also see root=tmpfs above, for a method to combine a + tmpfs file system with a regular /usr/ file system (as + configured via mount.usr=). The main distinction between + systemd.volatile=yes, and root=tmpfs in combination + mount.usr= is that the former operates on top of a regular root file system and + temporarily obstructs the files and directories above its /usr/ subdirectory, + while the latter does not hide any files, but simply mounts a unpopulated tmpfs as root file system + and combines it with a user picked /usr/ file system. @@ -218,6 +238,7 @@ systemd.mount5, systemd.swap5, systemd-cryptsetup-generator8, + systemd-gpt-auto-generator8, kernel-command-line7 diff --git a/man/systemd-hostnamed.service.xml b/man/systemd-hostnamed.service.xml index c0c46b660..0e42f671c 100644 --- a/man/systemd-hostnamed.service.xml +++ b/man/systemd-hostnamed.service.xml @@ -51,9 +51,15 @@ + The static hostname is stored in /etc/hostname, see + hostname5 for more + information. The pretty hostname, chassis type, and icon name are stored in + /etc/machine-info, see + machine-info5. + The tool - hostnamectl1 - is a command line client to this service. + hostnamectl1 is a + command line client to this service. See org.freedesktop.hostname15 diff --git a/man/systemd-inhibit.xml b/man/systemd-inhibit.xml index 2fee0ede8..f6595f1e2 100644 --- a/man/systemd-inhibit.xml +++ b/man/systemd-inhibit.xml @@ -141,7 +141,7 @@ doing so. - + See Also diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml index 21e59440a..6a27bab1e 100644 --- a/man/systemd-nspawn.xml +++ b/man/systemd-nspawn.xml @@ -801,46 +801,59 @@ - Assign the specified network interface to the - container. This will remove the specified interface from the - calling namespace and place it in the container. When the - container terminates, it is moved back to the host namespace. - Note that implies - . This option may be used - more than once to add multiple network interfaces to the - container. + Assign the specified network interface to the container. This will remove the + specified interface from the calling namespace and place it in the container. When the container + terminates, it is moved back to the calling namespace. Note that + implies . This option may be + used more than once to add multiple network interfaces to the container. + + Note that any network interface specified this way must already exist at the time the container + is started. If the container shall be started automatically at boot via a + systemd-nspawn@.service unit file instance, it might hence make sense to add a + unit file drop-in to the service instance + (e.g. /etc/systemd/system/systemd-nspawn@foobar.service.d/50-network.conf) with + contents like the following: + + [Unit] +Wants=sys-subsystem-net-devices-ens1.device +After=sys-subsystem-net-devices-ens1.device + + This will make sure that activation of the container service will be delayed until the + ens1 network interface has shown up. This is required since hardware probing is + fully asynchronous, and network interfaces might be discovered only later during the boot process, + after the container would normally be started without these explicit dependencies. + - Create a macvlan interface - of the specified Ethernet network interface and add it to the - container. A macvlan interface is a virtual - interface that adds a second MAC address to an existing - physical Ethernet link. The interface in the container will be - named after the interface on the host, prefixed with - mv-. Note that - implies - . This option may be used - more than once to add multiple network interfaces to the - container. + Create a macvlan interface of the specified Ethernet network + interface and add it to the container. A macvlan interface is a virtual interface + that adds a second MAC address to an existing physical Ethernet link. The interface in the container + will be named after the interface on the host, prefixed with mv-. Note that + implies . This option may be + used more than once to add multiple network interfaces to the container. + + As with , the underlying Ethernet network interface must + already exist at the time the container is started, and thus similar unit file drop-ins as described + above might be useful. - Create an ipvlan interface - of the specified Ethernet network interface and add it to the - container. An ipvlan interface is a virtual - interface, similar to a macvlan interface, - which uses the same MAC address as the underlying interface. - The interface in the container will be named after the - interface on the host, prefixed with iv-. - Note that implies - . This option may be used - more than once to add multiple network interfaces to the - container. + Create an ipvlan interface of the specified Ethernet network + interface and add it to the container. An ipvlan interface is a virtual interface, + similar to a macvlan interface, which uses the same MAC address as the underlying + interface. The interface in the container will be named after the interface on the host, prefixed + with iv-. Note that implies + . This option may be used more than once to add multiple network + interfaces to the container. + + As with , the underlying Ethernet network interface must + already exist at the time the container is started, and thus similar unit file drop-ins as described + above might be useful. @@ -907,7 +920,11 @@ this option is used, the host side of the Ethernet link will use the vb- prefix instead of ve-. Regardless of the used naming prefix the same network interface name length limits imposed by Linux apply, along with the complications this creates (for details see - above). + above). + + As with , the underlying bridge network interface must + already exist at the time the container is started, and thus similar unit file drop-ins as described + above might be useful. @@ -1003,7 +1020,11 @@ If the special value all is passed, all capabilities are retained. If the special value of help is passed, the program will print known - capability names and exit. + capability names and exit. + + This option sets the bounding set of capabilities which + also limits the ambient capabilities as given with the + . @@ -1015,7 +1036,32 @@ above). If the special value of help is passed, the program will print known - capability names and exit. + capability names and exit. + + This option sets the bounding set of capabilities which + also limits the ambient capabilities as given with the + . + + + + + + Specify one or more additional capabilities to + pass in the inheritable and ambient set to the program started + within the container. The value all is not + supported for this setting. + + All capabilities specified here must be in the set + allowed with the and + options. Otherwise, an + error message will be shown. + + This option cannot be combined with the boot mode of the + container (as requested via ). + + If the special value of help is + passed, the program will print known capability names and + exit. @@ -1457,7 +1503,7 @@ - + Examples diff --git a/man/systemd-oomd.service.xml b/man/systemd-oomd.service.xml index 9cb9c6076..ebd2467ee 100644 --- a/man/systemd-oomd.service.xml +++ b/man/systemd-oomd.service.xml @@ -56,8 +56,8 @@ You will need a kernel compiled with PSI support. This is available in Linux 4.20 and above. - The system must also have swap enabled for systemd-oomd to function correctly. With swap - enabled, the system spends enough time swapping pages to let systemd-oomd react. + It is highly recommended for the system to have swap enabled for systemd-oomd to function + optimally. With swap enabled, the system spends enough time swapping pages to let systemd-oomd react. Without swap, the system enters a livelocked state much more quickly and may prevent systemd-oomd from responding in a reasonable amount of time. See "In defence of swap: common misconceptions" diff --git a/man/systemd-portabled.service.xml b/man/systemd-portabled.service.xml index ce91b4fcb..23906f266 100644 --- a/man/systemd-portabled.service.xml +++ b/man/systemd-portabled.service.xml @@ -43,7 +43,8 @@ See Also systemd1, - portablectl1 + portablectl1, + org.freedesktop.portable15 diff --git a/man/systemd-pstore.service.xml b/man/systemd-pstore.service.xml index 306f1099b..66ad5572c 100644 --- a/man/systemd-pstore.service.xml +++ b/man/systemd-pstore.service.xml @@ -34,10 +34,10 @@ thus preserving the existing information contained in the pstore, and clearing pstore storage for future error events. - Linux provides a persistent storage file system, pstore, that can store - error records when the kernel dies (or reboots or powers-off). These records in - turn can be referenced to debug kernel problems (currently the kernel stuffs - the tail of the dmesg, which also contains a stack backtrace, into pstore). + Linux provides a persistent storage file system, pstore, that can store error records when the + kernel dies (or reboots or powers-off). These records in turn can be referenced to debug kernel problems + (currently the kernel stores the tail of the kernel log, which also contains a stack backtrace, into + pstore). The pstore file system supports a variety of backends that map onto persistent storage, such as the ACPI ERST and UEFI variables. The pstore backends @@ -48,7 +48,7 @@ pstore. The pstore service is independent of the kdump service. In cloud environments - specifically, host and guest filesystems are on remote filesystems (eg. iSCSI + specifically, host and guest filesystems are on remote filesystems (e.g. iSCSI or NFS), thus kdump relies (implicitly and/or explicitly) upon proper operation of networking software *and* hardware *and* infrastructure. Thus it may not be possible to capture a kernel coredump to a file since writes over the network @@ -59,9 +59,9 @@ debugging. The systemd-pstore executable does the actual work. Upon starting, - the pstore.conf file is read and the /sys/fs/pstore + the pstore.conf file is read and the /sys/fs/pstore/ directory contents are processed according to the options. Pstore files are written to the - journal, and optionally saved into /var/lib/systemd/pstore. + journal, and optionally saved into /var/lib/systemd/pstore/. @@ -83,17 +83,14 @@ - Controlling kernel parameters + Kernel parameters The kernel has two parameters, /sys/module/kernel/parameters/crash_kexec_post_notifiers and - /sys/module/printk/parameters/always_kmsg_dump, - that control writes into pstore. - The crash_kexec_post_notifiers parameter enables the kernel to write - dmesg (including stack trace) into pstore upon a panic or crash, and - printk.always_kmsg_dump parameter enables the kernel to write dmesg - upon a normal shutdown (shutdown, reboot, halt). These kernel - parameters are managed via the + /sys/module/printk/parameters/always_kmsg_dump, that control writes into pstore. + The first enables storing of the kernel log (including stack trace) into pstore upon a panic or crash, + and the second enables storing of the kernel log upon a normal shutdown (shutdown, reboot, halt). These + parameters can be managed via the tmpfiles.d5 mechanism, specifically the file /usr/lib/tmpfiles/systemd-pstore.conf. diff --git a/man/systemd-rc-local-generator.xml b/man/systemd-rc-local-generator.xml index 9e175247f..f0e38ead4 100644 --- a/man/systemd-rc-local-generator.xml +++ b/man/systemd-rc-local-generator.xml @@ -19,28 +19,44 @@ systemd-rc-local-generator - Compatibility generator for starting &RC_LOCAL_PATH; during boot + rc-local.service + Compatibility generator and service to start &RC_LOCAL_PATH; during boot /usr/lib/systemd/system-generators/systemd-rc-local-generator + rc-local.service Description - systemd-rc-local-generator is a generator that checks whether - &RC_LOCAL_PATH; exists and is executable, and if it is pulls the + systemd-rc-local-generator is a generator that checks whether + &RC_LOCAL_PATH; exists and is executable, and if it is, pulls the rc-local.service unit into the boot process. This unit is responsible for running - this script during late boot. Note that the script will be run with slightly different semantics than the - original System V version, which was run "last" in the boot process, which is a concept that does not - translate to systemd. The script is run after network.target, but in parallel with - most other regular system services. + this script during late boot. The script is run after network.target, but in + parallel with most other regular system services. + + Note that rc-local.service runs with slightly different semantics than the + original System V version, which was executed "last" in the boot process, which is a concept that does + not translate to systemd. + + Also note that rc-local.service is ordered after + network.target, which does not mean that the network is functional, see + systemd.special7. + If the script requires a configured network connection, it may be desirable to pull in and order it after + network-online.target with a drop-in: + + # /etc/systemd/system/rc-local.service.d/network.conf +[Unit] +Wants=network-online.target +After=network-online.target + Support for &RC_LOCAL_PATH; is provided for compatibility with specific System V systems only. However, it is strongly recommended to avoid making use of this script today, and instead provide proper unit files with appropriate dependencies for any scripts to run during the boot process. - Note that the path to the script is set a compile time and varies between distributions. + Note that the path to the script is set at compile time and varies between distributions. systemd-rc-local-generator implements systemd.generator7. diff --git a/man/systemd-repart.xml b/man/systemd-repart.xml index 16add32b2..a5a0890c5 100644 --- a/man/systemd-repart.xml +++ b/man/systemd-repart.xml @@ -278,15 +278,6 @@ and graphic illustrating the changes applied. - - MODE - - Shows output formatted as JSON. Expects one of short (for the - shortest possible output without any redundant whitespace or line breaks), pretty - (for a pretty version of the same, with indentation and line breaks) or off (to turn - off json output). - - @@ -300,25 +291,46 @@ Takes a file system path. Configures the encryption key to use when setting up LUKS2 - volumes configured with the Encrypt= setting in partition files. Should refer to a - regular file containing the key, or an AF_UNIX stream socket in the file - system. In the latter case a connection is made to it and the key read from it. If this switch is not - specified the empty key (i.e. zero length key) is used. This behaviour is useful for setting up encrypted - partitions during early first boot that receive their user-supplied password only in a later setup - step. + volumes configured with the Encrypt=key-file setting in partition files. Should + refer to a regular file containing the key, or an AF_UNIX stream socket in the + file system. In the latter case a connection is made to it and the key read from it. If this switch + is not specified the empty key (i.e. zero length key) is used. This behaviour is useful for setting + up encrypted partitions during early first boot that receive their user-supplied password only in a + later setup step. + + + + + + + Configures the TPM2 device and list of PCRs to use for LUKS2 volumes configured with + the Encrypt=tpm2 option. These options take the same parameters as the identically + named options to + systemd-cryptenroll1 + and have the same effect on partitions where TPM2 enrollment is requested. + + + + + Exit status + + On success, 0 is returned, a non-zero failure code otherwise. + + See Also systemd1, repart.d5, - machine-id5 + machine-id5, + systemd-cryptenroll1 diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml index 12aefd5a8..ed6214cd6 100644 --- a/man/systemd-resolved.service.xml +++ b/man/systemd-resolved.service.xml @@ -87,7 +87,7 @@ Synthetic Records - systemd-resolved synthetizes DNS resource records (RRs) for the following + systemd-resolved synthesizes DNS resource records (RRs) for the following cases: @@ -115,8 +115,8 @@ Protocols and Routing - Lookup requests are routed to the available DNS servers, LLMNR, and MulticastDNS interfaces - according to the following rules: + The lookup requests that systemd-resolved.service receives are routed to the + available DNS servers, LLMNR, and MulticastDNS interfaces according to the following rules: Names for which synthetic records are generated (the local hostname, @@ -126,10 +126,10 @@ Single-label names are resolved using LLMNR on all local interfaces where LLMNR is enabled. Lookups for IPv4 addresses are only sent via LLMNR on IPv4, and lookups for IPv6 addresses are - only sent via LLMNR on IPv6. Note that lookups for single-label synthetized names are not routed to + only sent via LLMNR on IPv6. Note that lookups for single-label synthesized names are not routed to LLMNR, MulticastDNS or unicast DNS. - Queries for the address records (A and AAAA) of single-label non-synthetized names are + Queries for the address records (A and AAAA) of single-label non-synthesized names are resolved via unicast DNS using search domains. 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, @@ -172,7 +172,8 @@ resolved.conf5 for a description of globally configured DNS settings. - The following query routing logic applies for unicast DNS traffic: + The following query routing logic applies for unicast DNS lookups initiated by + systemd-resolved.service: If a name to look up matches (that is: is equal to or has as suffix) any of the @@ -203,7 +204,7 @@ determined based on the configured DNS domains for a link: if there's a route-only domain other than ~., it defaults to false, otherwise to true. - Effectively this means: in order to support single-label non-synthetized names, define appropriate + Effectively this means: in order to support single-label non-synthesized names, define appropriate search domains. In order to preferably route all DNS queries not explicitly matched by routing domain configuration to a specific link, configure a ~. route-only domain on it. This will ensure that other links will not be considered for these queries (unless they too carry such a routing @@ -223,19 +224,33 @@ This section provides a short summary of differences in the stub resolver implemented by nss-resolve8 together - with systemd-resolved and the tranditional stub resolver implemented in - nss-dns8. + with systemd-resolved and the traditional stub resolver implemented in + nss-dns. Some names are always resolved internally (see Synthetic Records above). Traditionally - they would be resolved by nss-files, and only if provided in - /etc/hosts. + they would be resolved by nss-files if provided in + /etc/hosts. But note that the details of how a query is constructed are under the + control of the client library. nss-dns will first try to resolve names using + search domains and even if those queries are routed to systemd-resolved, it will + send them out over the network using the usual rules for multi-label name routing For + example, if /etc/nsswitch.conf has nameserver 127.0.0.53 +search foobar.com barbar.com + and we look up localhost, nss-dns will send + the following queries to systemd-resolved listening on 127.0.0.53:53: first + localhost.foobar.com, then localhost.barbar.com, and finally + localhost. If (hopefully) the first two queries fail, + systemd-resolved will synthesize an answer for the third query. + + When using nss-dns with any search domains, it is thus crucial to always + configure nss-files with higher priority and provide mappings for names that + should not be resolved using search domains.. Single-label names are not resolved for A and AAAA records using unicast DNS (unless overridden with ResolveUnicastSingleLabel=, see resolved.conf5). This is similar to the option being set in - resolv.conf5. + resolv.conf5. Search domains are not used for suffixing of multi-label names. @@ -246,13 +261,13 @@ has failed, as absolute, while other names would be resolved in opposite order. The ndots option in /etc/resolv.conf was used to control how many dots the name needs to have to be resolved as relative first. This stub resolver does not implement - this at all: multi-label names are only resolved as FQDNs. (There are currently more than 1500 - top-level domain names defined, and new ones are added regularly, often using "attractive" names that - are also likely to be used locally. Not looking up multi-label names in this fashion avoids fragility - in both directions: a valid global name could be obscured by a local name, and resolution of a relative - local name could suddenly break when a new top-level domain is created, or when a new subdomain of a - top-level domain in registered. Resolving any given name as either relative or absolute avoids this - ambiguity.) + this at all: multi-label names are only resolved as FQDNs.There are currently more than + 1500 top-level domain names defined, and new ones are added regularly, often using "attractive" names + that are also likely to be used locally. Not looking up multi-label names in this fashion avoids + fragility in both directions: a valid global name could be obscured by a local name, and resolution of + a relative local name could suddenly break when a new top-level domain is created, or when a new + subdomain of a top-level domain in registered. Resolving any given name as either relative or absolute + avoids this ambiguity.) This resolver has a notion of the special .local domain used for MulticastDNS, and will not route queries with that suffix to unicast DNS servers unless explicitly @@ -270,8 +285,8 @@ Environment variables $LOCALDOMAIN and $RES_OPTIONS described in - resolv.conf5 are not - supported currently. + resolv.conf5 + are not supported currently. diff --git a/man/systemd-suspend.service.xml b/man/systemd-suspend.service.xml index e4a6de548..c525a3bda 100644 --- a/man/systemd-suspend.service.xml +++ b/man/systemd-suspend.service.xml @@ -56,7 +56,10 @@ pre, the second either suspend, hibernate, hybrid-sleep, or suspend-then-hibernate - depending on the chosen action. + depending on the chosen action. An environment variable called SYSTEMD_SLEEP_ACTION + will be set and contain the sleep action that is processing. This is primarily helpful for + suspend-then-hibernate where the value of the variable will be suspend, hibernate, + or suspend-after-failed-hibernate in cases where hibernation has failed. Immediately after leaving system suspend and/or hibernation the same executables are run, but the first argument is now post. All executables in this directory are diff --git a/man/systemd-sysext.xml b/man/systemd-sysext.xml new file mode 100644 index 000000000..ad6a401c7 --- /dev/null +++ b/man/systemd-sysext.xml @@ -0,0 +1,243 @@ + + + + + + + + systemd-sysext + systemd + + + + systemd-sysext + 8 + + + + systemd-sysext + systemd-sysext.service + Activates System Extension Images + + + + + systemd-sysext + OPTIONS + + + systemd-sysext.service + + + + + Description + + systemd-sysext activates/deactivates system extension images. System extension + images may – dynamically at runtime — extend the /usr/ and + /opt/ directory hierarchies with additional files. This is particularly useful on + immutable system images where a /usr/ and/or /opt/ hierarchy + residing on a read-only file system shall be extended temporarily at runtime without making any + persistent modifications. + + System extension images should contain files and directories similar in fashion to regular + operating system tree. When one or more system extension images are activated, their + /usr/ and /opt/ hierarchies are combined via + overlayfs with the same hierarchies of the host OS, and the host + /usr/ and /opt overmounted with it ("merging"). When they are + deactivated, the mount point is disassembled — again revealing the unmodified original host version of + the hierarchy ("unmerging"). Merging thus makes the extension's resources suddenly appear below the + /usr/ and /opt/ hierarchies as if they were included in the + base OS image itself. Unmerging makes them disappear again, leaving in place only the files that were + shipped with the base OS image itself. + + Files and directories contained in the extension images outside of the /usr/ + and /opt/ hierarchies are not merged, and hence have no effect + when included in a system extension image. In particular, files in the /etc/ and + /var/ included in a system extension image will not appear in + the respective hierarchies after activation. + + System extension images are strictly read-only, and the host /usr/ and + /opt/ hierarchies become read-only too while they are activated. + + System extensions are supposed to be purely additive, i.e. they are supposed to include only files + that do not exist in the underlying basic OS image. However, the underlying mechanism (overlayfs) also + allows removing files, but it is recommended not to make use of this. + + System extension images may be provided in the following formats: + + + Plain directories or btrfs subvolumes containing the OS tree + Disk images with a GPT disk label, following the Discoverable Partition Specification + Disk images lacking a partition table, with a naked Linux file system (e.g. squashfs or ext4) + + + These image formats are the same ones that + systemd-nspawn1 + supports via it's / switches and those that the + service manager supports via /. Similar to + them they may optionally carry Verity authentication information. + + System extensions are automatically looked for in the directories + /etc/extensions/, /run/extensions/, + /var/lib/extensions/, /usr/lib/extensions/ and + /usr/local/lib/extensions/. The first two listed directories are not suitable for + carrying large binary images, however are still useful for carrying symlinks to them. The primary place + for installing system extensions is /var/lib/extensions/. Any directories found in + these search directories are considered directory based extension images, any files with the + .raw suffix are considered disk image based extension images. + + During boot OS extension images are activated automatically, if the + systemd-sysext.service is enabled. Note that this service runs only after the + underlying file systems where system extensions are searched are mounted. This means they are not + suitable for shipping resources that are processed by subsystems running in earliest boot. Specifically, + OS extension images are not suitable for shipping system services or + systemd-sysusers8 + definitions. See Portable Services for a simple + mechanism for shipping system services in disk images, in a similar fashion to OS extensions. Note the + different isolation on these two mechanisms: while system extension directly extend the underlying OS + image with additional files that appear in a way very similar to as if they were shipped in the OS image + itself and thus imply no security isolation, portable services imply service level sandboxing in one way + or another. The systemd-sysext.service service is guaranteed to finish start-up + before basic.target is reached; i.e. at the time regular services initialize (those + which do not use DefaultDependencies=no), the files and directories system extensions + provide are available in /usr/ and /opt/ and may be + accessed. + + Note that there is no concept of enabling/disabling installed system extension images: all + installed extension images are automatically activated at boot. + + A simple mechanism for version compatibility is enforced: a system extension image must carry a + /usr/lib/extension-release.d/extension-release.$name + file, which must match its image name, that is compared with the host os-release + file: the contained ID= fields have to match, as well as the + SYSEXT_LEVEL= field (if defined). If the latter is not defined, the + VERSION_ID= field has to match instead. System extensions should not ship a + /usr/lib/os-release file (as that would be merged into the host + /usr/ tree, overriding the host OS version data, which is not desirable). The + extension-release file follows the same format and semantics, and carries the same + content, as the os-release file of the OS, but it describes the resources carried + in the extension image. + + + + Uses + + The primary use case for system images are immutable environments where debugging and development + tools shall optionally be made available, but not included in the immutable base OS image itself + (e.g. strace and gdb shall be an optionally installable + addition in order to make debugging/development easier). System extension images should not be + misunderstood as a generic software packaging framework, as no dependency scheme is available: system + extensions should carry all files they need themselves, except for those already shipped in the + underlying host system image. Typically, system extension images are built at the same time as the base + OS image — within the same build system. + + Another use case for the system extension concept is temporarily overriding OS supplied resources + with newer ones, for example to install a locally compiled development version of some low-level + component over the immutable OS image without doing a full OS rebuild or modifying the nominally + immutable image. (e.g. "install" a locally built package with DESTDIR=/var/lib/extensions/mytest + make install && systemd-sysext refresh, making it available in + /usr/ as if it was installed in the OS image itself.) This case works regardless if + the underlying host /usr/ is managed as immutable disk image or is a traditional + package manager controlled (i.e. writable) tree. + + + + Commands + + The following commands are understood: + + + + + + When invoked without any command verb, or when is specified + the current merge status is shown, separately for both /usr/ and + /opt/. + + + + + Merges all currently installed system extension images into + /usr/ and /opt/, by overmounting these hierarchies with an + overlayfs file system combining the underlying hierarchies with those included in + the extension images. This command will fail if the hierarchies are already merged. + + + + + Unmerges all currently installed system extension images from + /usr/ and /opt/, by unmounting the + overlayfs file systems created by + prior. + + + + + A combination of and : if already + mounted the existing overlayfs instance is unmounted temporarily, and then + replaced by a new version. This command is useful after installing/removing system extension images, + in order to update the overlayfs file system accordingly. If no system extensions + are installed when this command is executed, the equivalent of is + executed, without establishing any new overlayfs instance. Note that currently + there's a brief moment where neither the old nor the new overlayfs file system is + mounted. This implies that all resources supplied by a system extension will briefly disappear — even + if it exists continuously during the refresh operation. + + + + + + A brief list of installed extension images is shown. + + + + + + + + + Options + + + + + + Operate relative to the specified root directory, i.e. establish the + overlayfs mount not on the top-level host /usr/ and + /opt/ hierarchies, but below some specified root directory. + + + + + + When merging system extensions into /usr/ and + /opt/, ignore version incompatibilities, i.e. force merging regardless of + whether the version information included in the extension images matches the host or + not. + + + + + + + + + + Exit status + + On success, 0 is returned. + + + + See Also + + systemd1, + systemd-nspawn1 + + + + diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml index 075666ac6..d39928ec2 100644 --- a/man/systemd-system.conf.xml +++ b/man/systemd-system.conf.xml @@ -31,7 +31,9 @@ /etc/systemd/system.conf.d/*.conf, /run/systemd/system.conf.d/*.conf, /usr/lib/systemd/system.conf.d/*.conf - /etc/systemd/user.conf, + + ~/.config/systemd/user.conf, + /etc/systemd/user.conf, /etc/systemd/user.conf.d/*.conf, /run/systemd/user.conf.d/*.conf, /usr/lib/systemd/user.conf.d/*.conf @@ -40,16 +42,16 @@ Description - When run as a system instance, systemd interprets the - configuration file system.conf and the files - in system.conf.d directories; when run as a - user instance, systemd interprets the configuration file - user.conf and the files in - user.conf.d directories. These configuration - files contain a few settings controlling basic manager - operations. See - systemd.syntax7 - for a general description of the syntax. + When run as a system instance, systemd interprets the configuration file + system.conf and the files in system.conf.d directories; when + run as a user instance, it interprets the configuration file user.conf (either in + the home directory of the user, or if not found, under /etc/systemd/) and the files + in user.conf.d directories. These configuration files contain a few settings + controlling basic manager operations. + + See + systemd.syntax7 for a + general description of the syntax. @@ -321,11 +323,10 @@ DefaultEnvironment= - Sets manager environment variables passed to - all executed processes. Takes a space-separated list of - variable assignments. See - environ7 - for details about environment variables. + Configures environment variables passed to all executed processes. Takes a + space-separated list of variable assignments. See environ7 for + details about environment variables. Example: @@ -337,6 +338,20 @@ VAR3. + + ManagerEnvironment= + + Takes the same arguments as DefaultEnvironment=, see above. Sets + environment variables just for the manager process itself. These variables are not inherited by + processes spawned by the service manager, use DefaultEnvironment= for that. Note + that these variables are merged into the existing environment block. In particular, in case of the + system manager, this includes variables set by the kernel based on the kernel command line. + + Setting environment variables for the manager process may be useful to modify its behaviour. + See ENVIRONMENT for a descriptions of some + variables understood by systemd. + + DefaultCPUAccounting= DefaultBlockIOAccounting= diff --git a/man/systemd-time-wait-sync.service.xml b/man/systemd-time-wait-sync.service.xml index 28f55a184..cd26ae4f0 100644 --- a/man/systemd-time-wait-sync.service.xml +++ b/man/systemd-time-wait-sync.service.xml @@ -29,15 +29,17 @@ Description - systemd-time-wait-sync is a system service that delays the start of units that depend on - time-sync.target until the system time has been synchronized with an accurate time source by + systemd-time-wait-sync is a system service that delays the start of units that + are ordered after time-sync.target (see + systemd.special7 for + details) until the system time has been synchronized with an accurate remote reference time source by systemd-timesyncd.service. - systemd-timesyncd.service notifies on successful synchronization. - systemd-time-wait-sync also tries to detect when the kernel marks the time as synchronized, - but this detection is not reliable and is intended only as a fallback for other services that can be used to - synchronize time (e.g., ntpd, chronyd). - + systemd-timesyncd.service notifies systemd-time-wait-sync + about successful synchronization. systemd-time-wait-sync also tries to detect when + the kernel marks the system clock as synchronized, but this detection is not reliable and is intended + only as a fallback for compatibility with alternative NTP services that can be used to synchronize time + (e.g., ntpd, chronyd). diff --git a/man/systemd-timesyncd.service.xml b/man/systemd-timesyncd.service.xml index ff14c4066..9ab4af976 100644 --- a/man/systemd-timesyncd.service.xml +++ b/man/systemd-timesyncd.service.xml @@ -29,35 +29,42 @@ Description - systemd-timesyncd is a system service - that may be used to synchronize the local system clock with a - remote Network Time Protocol server. It also saves the local time - to disk every time the clock has been synchronized and uses this - to possibly advance the system realtime clock on subsequent - reboots to ensure it monotonically advances even if the system - lacks a battery-buffered RTC chip. + systemd-timesyncd is a system service that may be used to synchronize the + local system clock with a remote Network Time Protocol (NTP) server. It also saves the local time to disk + every time the clock has been synchronized and uses this to possibly advance the system realtime clock on + subsequent reboots to ensure it (roughly) monotonically advances even if the system lacks a + battery-buffered RTC chip. - The systemd-timesyncd service - specifically implements only SNTP. This minimalistic - service will set the system clock for large offsets or - slowly adjust it for smaller deltas. More complex use - cases are not covered by systemd-timesyncd. + The systemd-timesyncd service implements SNTP only. This minimalistic service + will step the system clock for large offsets or slowly adjust it for smaller deltas. Complex use cases + that require full NTP support (and where SNTP is not sufficient) are not covered by + systemd-timesyncd. - The NTP servers contacted are determined from the global - settings in - timesyncd.conf5, - the per-link static settings in .network - files, and the per-link dynamic settings received over DHCP. See - systemd.network5 - for more details. + The NTP servers contacted are determined from the global settings in + timesyncd.conf5, the + per-link static settings in .network files, and the per-link dynamic settings + received over DHCP. See + systemd.network5 for + further details. timedatectl1's - set-ntp command may be used to enable and - start, or disable and stop this service. + set-ntp command may be used to enable and start, or disable and stop this + service. timedatectl1's timesync-status or show-timesync command can be used to show the current status of this service. + + systemd-timesyncd initialization delays the start of units that are ordered + after time-set.target (see + systemd.special7 for + details) until the local time has been updated from /var/lib/systemd/timesync/clock + (see below) in order to make it roughly monotonic. It does not delay other units until synchronization + with an accurate reference time sources has been reached. Use + systemd-time-wait-sync.service8 + to achieve that, which will delay start of units that are ordered after + time-sync.target until synchronization to an accurate reference clock is + reached. @@ -68,9 +75,10 @@ /var/lib/systemd/timesync/clock - The modification time of this file indicates the timestamp of the last successful - synchronization (or at least the systemd build date, in case synchronization was not - possible). + The modification time ("mtime") of this file indicates the timestamp of the last successful + synchronization (or at least the systemd build date, in case synchronization was not possible). It + is used to ensure that the system clock remains roughly monotonic across reboots, in case no local + RTC is available. @@ -80,7 +88,7 @@ A file that is touched on each successful synchronization, to assist systemd-time-wait-sync and other applications to detecting synchronization - events. + with accurate reference clocks. @@ -95,6 +103,7 @@ systemd.network5, systemd-networkd.service8, systemd-time-wait-sync.service8, + systemd.special7, timedatectl1, localtime5, hwclock8 diff --git a/man/systemd-tmpfiles.xml b/man/systemd-tmpfiles.xml index 90c262668..5f97e3702 100644 --- a/man/systemd-tmpfiles.xml +++ b/man/systemd-tmpfiles.xml @@ -48,23 +48,20 @@ Description - systemd-tmpfiles creates, deletes, and - cleans up volatile and temporary files and directories, based on - the configuration file format and location specified in - tmpfiles.d5. - + systemd-tmpfiles creates, deletes, and cleans up volatile and temporary files + and directories, using the configuration file format and location specified in + tmpfiles.d5. It must + be invoked with one or more options , , and + , to select the respective subset of operations. - If invoked with no arguments, it applies all directives from all configuration - files. When invoked with , - arguments specified on the command line are used instead of the configuration file - PATH. Otherwise, if one or more absolute filenames are - passed on the command line, only the directives in these files are applied. If - - is specified instead of a filename, directives are read from - standard input. If only the basename of a configuration file is specified, all - configuration directories as specified in - tmpfiles.d5 - are searched for a matching file and the file found that has the highest priority is - executed. + By default, directives from all configuration files are applied. When invoked with + , arguments specified on the command line are + used instead of the configuration file PATH. Otherwise, if one or more + absolute filenames are passed on the command line, only the directives in these files are applied. If + - is specified instead of a filename, directives are read from standard input. If only + the basename of a configuration file is specified, all configuration directories as specified in + tmpfiles.d5 are + searched for a matching file and the file found that has the highest priority is executed. System services (systemd-tmpfiles-setup.service, systemd-tmpfiles-setup-dev.service, @@ -81,6 +78,12 @@ system instance, such as the one typically configured for /tmp/, will thus also affect files created by the user instance if they are placed in /tmp/, even if the user instance's time-based cleanup is turned off. + + To re-apply settings after configuration has been modified, simply restart + systemd-tmpfiles-clean.service, which will apply any settings which can be safely + executed at runtime. To debug systemd-tmpfiles, it may be useful to invoke it + directly from the command line with increased log level (see $SYSTEMD_LOG_LEVEL + below). @@ -227,6 +230,24 @@ systemd-tmpfiles --remove --create + + Environment + + + + + + + + + + + + + + + + Unprivileged --cleanup operation diff --git a/man/systemd-userdbd.service.xml b/man/systemd-userdbd.service.xml index a6234be21..a65d1909b 100644 --- a/man/systemd-userdbd.service.xml +++ b/man/systemd-userdbd.service.xml @@ -50,7 +50,7 @@ group records. Internally it talks to all other user/group record services running on the system in parallel and forwards any information discovered. This simplifies clients substantially since they need to talk to a single service only instead of all of them in - parallel. io.systemd.NameSeviceSwitch provides compatibility with classic UNIX/glibc + parallel. io.systemd.NameServiceSwitch provides compatibility with classic UNIX/glibc NSS user records, i.e. converts struct passwd and struct group records as acquired with APIs such as getpwnam1 to JSON diff --git a/man/systemd-veritysetup-generator.xml b/man/systemd-veritysetup-generator.xml index d2736a7fd..bf5e705f8 100644 --- a/man/systemd-veritysetup-generator.xml +++ b/man/systemd-veritysetup-generator.xml @@ -54,7 +54,7 @@ Takes a boolean argument. Defaults to yes. If no, disables the generator entirely. rd.systemd.verity= is honored only by the initial RAM disk (initrd) while systemd.verity= is honored by both the host system and the - initrd. + initrd. @@ -81,6 +81,17 @@ (see above). + + systemd.verity_root_options= + + Takes a comma-separated list of dm-verity options. Expects the following options + , , , + , and + . See + veritysetup8 for more + details. + + diff --git a/man/systemd.device.xml b/man/systemd.device.xml index 255ca3373..596d334d5 100644 --- a/man/systemd.device.xml +++ b/man/systemd.device.xml @@ -26,11 +26,10 @@ Description - A unit configuration file whose name ends in - .device encodes information about a device unit - as exposed in the - sysfs/udev7 - device tree. + A unit configuration file whose name ends in .device encodes information about a + device unit as exposed in the + sysfs/udev7 device + tree. This may be used to define dependencies between devices and other units. This unit type has no specific options. See systemd.unit5 @@ -40,14 +39,10 @@ sections. A separate [Device] section does not exist, since no device-specific options may be configured. - systemd will dynamically create device units for all kernel - devices that are marked with the "systemd" udev tag (by default - all block and network devices, and a few others). This may be used - to define dependencies between devices and other units. To tag a - udev device, use TAG+="systemd" in the udev - rules file, see - udev7 - for details. + systemd will dynamically create device units for all kernel devices that are marked with the + systemd udev tag (by default all block and network devices, and a few others). Note + that if systemd-udev.service is not running, no device units will be + available (for example in a typical container). Device units are named after the /sys/ and /dev/ paths they control. Example: the @@ -57,6 +52,10 @@ name see systemd.unit5. + To tag a udev device, use TAG+="systemd" in the udev rules file, see + udev7 for details. + + Device units will be reloaded by systemd whenever the corresponding device generates a changed event. Other units can use ReloadPropagatedFrom= to react diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml index a9d863bfd..5bb9af3e7 100644 --- a/man/systemd.exec.xml +++ b/man/systemd.exec.xml @@ -117,6 +117,20 @@ The MountAPIVFS= and PrivateUsers= settings are particularly useful in conjunction with RootDirectory=. For details, see below. + If RootDirectory=/RootImage= are used together with + NotifyAccess= the notification socket is automatically mounted from the host into + the root environment, to ensure the notification interface can work correctly. + + Note that services using RootDirectory=/RootImage= will + not be able to log via the syslog or journal protocols to the host logging infrastructure, unless the + relevant sockets are mounted from the host, specifically: + + + Mounting logging sockets into root environment + + BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout + + @@ -159,50 +173,11 @@ mount8. - Valid partition names follow the Discoverable - Partitions Specification. - - - Accepted partition names - - - - - - Partition Name - - - - - root - - - root-secondary - - - home - - - srv - - - esp - - - xbootldr - - - tmp - - - var - - - usr - - - -
+ Valid partition names follow the Discoverable Partitions Specification: + root, usr, home, srv, + esp, xbootldr, tmp, + var. @@ -275,15 +250,20 @@ MountAPIVFS= Takes a boolean argument. If on, a private mount namespace for the unit's processes is created - and the API file systems /proc/, /sys/, and /dev/ - are mounted inside of it, unless they are already mounted. Note that this option has no effect unless used in - conjunction with RootDirectory=/RootImage= as these three mounts are + and the API file systems /proc/, /sys/, /dev/ and + /run/ (as an empty tmpfs) are mounted inside of it, unless they are + already mounted. Note that this option has no effect unless used in conjunction with + RootDirectory=/RootImage= as these four mounts are generally mounted in the host anyway, and unless the root directory is changed, the private mount namespace - will be a 1:1 copy of the host's, and include these three mounts. Note that the /dev/ file + will be a 1:1 copy of the host's, and include these four mounts. Note that the /dev/ file system of the host is bind mounted if this option is used without PrivateDevices=. To run the service with a private, minimal version of /dev/, combine this option with PrivateDevices=. + In order to allow propagating mounts at runtime in a safe manner, /run/systemd/propagate + on the host will be used to set up new mounts, and /run/host/incoming/ in the private namespace + will be used as an intermediate step to store them before being moved to the final mount point. + @@ -305,8 +285,11 @@ Filesystem. It is generally recommended to run most system services with this option set to invisible. This option is implemented via file system namespacing, and thus cannot be used with services that shall be able to install mount points in the host file system - hierarchy. It also cannot be used for services that need to access metainformation about other users' - processes. This option implies MountAPIVFS=. + hierarchy. Note that the root user is unaffected by this option, so to be effective it has to be used + together with User= or DynamicUser=yes, and also without the + CAP_SYS_PTRACE capability, which also allows a process to bypass this feature. It + cannot be used for services that need to access metainformation about other users' processes. This + option implies MountAPIVFS=. If the kernel doesn't support per-mount point mount options this setting remains without effect, and the unit's processes will be able to access and see other process @@ -319,10 +302,10 @@ ProcSubset= Takes one of all (the default) and pid. If - the latter all files and directories not directly associated with process management and introspection - are made invisible in the /proc/ file system configured for the unit's - processes. This controls the subset= mount option of the procfs - instance for the unit. For further details see pid, all files and directories not directly associated with process management and + introspection are made invisible in the /proc/ file system configured for the + unit's processes. This controls the subset= mount option of the + procfs instance for the unit. For further details see The /proc Filesystem. Note that Linux exposes various kernel APIs via /proc/, which are made unavailable with this setting. Since these APIs are used frequently this option is @@ -414,11 +397,53 @@ + + + ExtensionImages= + + This setting is similar to MountImages= in that it mounts a file + system hierarchy from a block device node or loopback file, but instead of providing a destination path, + an overlay will be set up. This option expects a whitespace separated list of mount definitions. Each + definition consists of a source path, optionally followed by a colon and a list of mount options. + + A read-only OverlayFS will be set up on top of /usr/ and + /opt/ hierarchies from the root. The order in which the images are listed + will determine the order in which the overlay is laid down: images specified first to last will result + in overlayfs layers bottom to top. + + Mount options may be defined as a single comma-separated list of options, in which case they + will be implicitly applied to the root partition on the image, or a series of colon-separated tuples + of partition name and mount options. Valid partition names and mount options are the same as for + RootImageOptions= setting described above. + + Each mount definition may be prefixed with -, in which case it will be + ignored when its source path does not exist. The source argument is a path to a block device node or + regular file. If the source path contains a :, it needs to be escaped as + \:. The device node or file system image file needs to follow the same rules as + specified for RootImage=. Any mounts created with this option are specific to the + unit, and are not visible in the host's mount table. + + These settings may be used more than once, each usage appends to the unit's list of image + paths. If the empty string is assigned, the entire list of mount paths defined prior to this is + reset. + + When DevicePolicy= is set to closed or + strict, or set to auto and DeviceAllow= is + set, then this setting adds /dev/loop-control with rw mode, + block-loop and block-blkext with rwm mode + to DeviceAllow=. See + systemd.resource-control5 + for the details about DevicePolicy= or DeviceAllow=. Also, see + PrivateDevices= below, as it may change the setting of + DevicePolicy=. + + +
- Credentials + User/Group Identity @@ -634,16 +659,25 @@ CapabilityBoundingSet=~CAP_B CAP_C setgid bits, or filesystem capabilities). This is the simplest and most effective way to ensure that a process and its children can never elevate privileges again. Defaults to false, but certain settings override this and ignore the value of this setting. This is the case when - SystemCallFilter=, SystemCallArchitectures=, - RestrictAddressFamilies=, RestrictNamespaces=, - PrivateDevices=, ProtectKernelTunables=, - ProtectKernelModules=, ProtectKernelLogs=, - ProtectClock=, MemoryDenyWriteExecute=, - RestrictRealtime=, RestrictSUIDSGID=, DynamicUser= - or LockPersonality= are specified. Note that even if this setting is overridden by them, - systemctl show shows the original value of this setting. - Also see No New Privileges - Flag. + DynamicUser=, + LockPersonality=, + MemoryDenyWriteExecute=, + PrivateDevices=, + ProtectClock=, + ProtectHostname=, + ProtectKernelLogs=, + ProtectKernelModules=, + ProtectKernelTunables=, + RestrictAddressFamilies=, + RestrictNamespaces=, + RestrictRealtime=, + RestrictSUIDSGID=, + SystemCallArchitectures=, + SystemCallFilter=, or + SystemCallLog= are specified. Note that even if this setting is overridden + by them, systemctl show shows the original value of this setting. Also see + No New + Privileges Flag. @@ -747,8 +781,8 @@ CapabilityBoundingSet=~CAP_B CAP_C enforcement. For example, time limits specified for LimitCPU= will be rounded up implicitly to multiples of 1s. For LimitNICE= the value may be specified in two syntaxes: if prefixed with + or -, the value is understood as - regular Linux nice value in the range -20..19. If not prefixed like this the value is understood as - raw resource limit parameter in the range 0..40 (with 0 being equivalent to 1). + regular Linux nice value in the range -20…19. If not prefixed like this the value is understood as + raw resource limit parameter in the range 0…40 (with 0 being equivalent to 1). Note that most process resource limits configured with these options are per-process, and processes may fork in order to acquire a new set of resources that are accounted independently of the @@ -1340,6 +1374,8 @@ StateDirectory=aaa/bbb ccc ReadWritePaths= ReadOnlyPaths= InaccessiblePaths= + ExecPaths= + NoExecPaths= Sets up a new file system namespace for executed processes. These options may be used to limit access a process has to the file system. Each setting takes a space-separated list of paths @@ -1361,12 +1397,18 @@ StateDirectory=aaa/bbb ccc BindPaths=, or BindReadOnlyPaths= inside it. For a more flexible option, see TemporaryFileSystem=. + Content in paths listed in NoExecPaths= are not executable even if the usual + file access controls would permit this. Nest ExecPaths= inside of + NoExecPaths= in order to provide executable content within non-executable + directories. + Non-directory paths may be specified as well. These options may be specified more than once, in which case all paths listed will have limited access from within the namespace. If the empty string is assigned to this option, the specific list is reset, and all prior assignments have no effect. - Paths in ReadWritePaths=, ReadOnlyPaths= and - InaccessiblePaths= may be prefixed with -, in which case they will be + Paths in ReadWritePaths=, ReadOnlyPaths=, + InaccessiblePaths=, ExecPaths= and + NoExecPaths= may be prefixed with -, in which case they will be ignored when they do not exist. If prefixed with + the paths are taken relative to the root directory of the unit, as configured with RootDirectory=/RootImage=, instead of relative to the root directory of the host (see above). When combining - and @@ -1389,6 +1431,15 @@ StateDirectory=aaa/bbb ccc CapabilityBoundingSet=~CAP_SYS_ADMIN or SystemCallFilter=~@mount. + Simple allow-list example using these directives: + [Service] +ReadOnlyPaths=/ +ReadWritePaths=/var /run +InaccessiblePaths=-/lost+found +NoExecPaths=/ +ExecPaths=/usr/sbin/my_daemon /usr/lib /usr/lib64 + + @@ -1424,14 +1475,13 @@ BindReadOnlyPaths=/var/lib/systemd executed processes and mounts private /tmp/ and /var/tmp/ directories inside it that are not shared by processes outside of the namespace. This is useful to secure access to temporary files of the process, but makes sharing between processes via - /tmp/ or /var/tmp/ impossible. If this is enabled, all - temporary files created by a service in these directories will be removed after the service is - stopped. Defaults to false. It is possible to run two or more units within the same private - /tmp/ and /var/tmp/ namespace by using the - JoinsNamespaceOf= directive, see - systemd.unit5 for - details. This setting is implied if DynamicUser= is set. For this setting the same - restrictions regarding mount propagation and privileges apply as for + /tmp/ or /var/tmp/ impossible. If true, all temporary files + created by a service in these directories will be removed after the service is stopped. Defaults to + false. It is possible to run two or more units within the same private /tmp/ and + /var/tmp/ namespace by using the JoinsNamespaceOf= directive, + see systemd.unit5 + for details. This setting is implied if DynamicUser= is set. For this setting the + same restrictions regarding mount propagation and privileges apply as for ReadOnlyPaths= and related calls, see above. Enabling this setting has the side effect of adding Requires= and After= dependencies on all mount units necessary to access /tmp/ and /var/tmp/. Moreover an @@ -1460,14 +1510,14 @@ BindReadOnlyPaths=/var/lib/systemd unit (see above), and set DevicePolicy=closed (see systemd.resource-control5 for details). Note that using this setting will disconnect propagation of mounts from the service to the host - (propagation in the opposite direction continues to work). This means that this setting may not be used for + (propagation in the opposite direction continues to work). This means that this setting may not be used for services which shall be able to install mount points in the main mount namespace. The new /dev/ will be mounted read-only and 'noexec'. The latter may break old programs which try to set up executable memory by using mmap2 of /dev/zero instead of using MAP_ANON. For this setting the same restrictions regarding mount propagation and privileges apply as for ReadOnlyPaths= and - related calls, see above. If turned on and if running in user mode, or in system mode, but without the + related calls, see above. If turned on and if running in user mode, or in system mode, but without the CAP_SYS_ADMIN capability (e.g. setting User=), NoNewPrivileges=yes is implied. @@ -1526,6 +1576,53 @@ BindReadOnlyPaths=/var/lib/systemd + + PrivateIPC= + + Takes a boolean argument. If true, sets up a new IPC namespace for the executed processes. + Each IPC namespace has its own set of System V IPC identifiers and its own POSIX message queue file system. + This is useful to avoid name clash of IPC identifiers. Defaults to false. It is possible to run two or + more units within the same private IPC namespace by using the JoinsNamespaceOf= directive, + see systemd.unit5 for + details. + + Note that IPC namespacing does not have an effect on + AF_UNIX sockets, which are the most common + form of IPC used on Linux. Instead, AF_UNIX + sockets in the file system are subject to mount namespacing, and + those in the abstract namespace are subject to network namespacing. + IPC namespacing only has an effect on SysV IPC (which is mostly + legacy) as well as POSIX message queues (for which + AF_UNIX/SOCK_SEQPACKET + sockets are typically a better replacement). IPC namespacing also + has no effect on POSIX shared memory (which is subject to mount + namespacing) either. See + ipc_namespaces7 for + the details. + + Note that the implementation of this setting might be impossible (for example if IPC namespaces are + not available), and the unit should be written in a way that does not solely rely on this setting for + security. + + + + + + IPCNamespacePath= + + Takes an absolute file system path refererring to a Linux IPC namespace + pseudo-file (i.e. a file like /proc/$PID/ns/ipc or a bind mount or symlink to + one). When set the invoked processes are added to the network namespace referenced by that path. The + path has to point to a valid namespace file at the moment the processes are forked off. If this + option is used PrivateIPC= has no effect. If this option is used together with + JoinsNamespaceOf= then it only has an effect if this unit is started before any of + the listed units that have PrivateIPC= or + IPCNamespacePath= configured, as otherwise the network namespace of those + units is reused. + + + + PrivateUsers= @@ -1573,6 +1670,10 @@ BindReadOnlyPaths=/var/lib/systemd the system into the service, it is hence not suitable for services that need to take notice of system hostname changes dynamically. + If this setting is on, but the unit doesn't have the CAP_SYS_ADMIN + capability (e.g. services for which User= is set), + NoNewPrivileges=yes is implied. + @@ -1586,7 +1687,9 @@ BindReadOnlyPaths=/var/lib/systemd clock, and DeviceAllow=char-rtc r is implied. This ensures /dev/rtc0, /dev/rtc1, etc. are made read-only to the service. See systemd.resource-control5 - for the details about DeviceAllow=. + for the details about DeviceAllow=. If this setting is on, but the unit + doesn't have the CAP_SYS_ADMIN capability (e.g. services for which + User= is set), NoNewPrivileges=yes is implied. @@ -1603,13 +1706,14 @@ BindReadOnlyPaths=/var/lib/systemd sysctl.d5 mechanism. Few services need to write to these at runtime; it is hence recommended to turn this on for most services. For this setting the same restrictions regarding mount propagation and privileges apply as for - ReadOnlyPaths= and related calls, see above. Defaults to off. If turned on and if running - in user mode, or in system mode, but without the CAP_SYS_ADMIN capability (e.g. services - for which User= is set), NoNewPrivileges=yes is implied. Note that this - option does not prevent indirect changes to kernel tunables effected by IPC calls to other processes. However, - InaccessiblePaths= may be used to make relevant IPC file system objects inaccessible. If - ProtectKernelTunables= is set, MountAPIVFS=yes is - implied. + ReadOnlyPaths= and related calls, see above. Defaults to off. If this + setting is on, but the unit doesn't have the CAP_SYS_ADMIN capability + (e.g. services for which User= is set), + NoNewPrivileges=yes is implied. Note that this option does not prevent + indirect changes to kernel tunables effected by IPC calls to other processes. However, + InaccessiblePaths= may be used to make relevant IPC file system objects + inaccessible. If ProtectKernelTunables= is set, + MountAPIVFS=yes is implied. @@ -1628,9 +1732,9 @@ BindReadOnlyPaths=/var/lib/systemd both privileged and unprivileged. To disable module auto-load feature please see sysctl.d5 kernel.modules_disabled mechanism and - /proc/sys/kernel/modules_disabled documentation. If turned on and if running in user - mode, or in system mode, but without the CAP_SYS_ADMIN capability (e.g. setting - User=), NoNewPrivileges=yes is implied. + /proc/sys/kernel/modules_disabled documentation. If this setting is on, + but the unit doesn't have the CAP_SYS_ADMIN capability (e.g. services for + which User= is set), NoNewPrivileges=yes is implied. @@ -1646,7 +1750,10 @@ BindReadOnlyPaths=/var/lib/systemd system call (not to be confused with the libc API syslog3 for userspace logging). The kernel exposes its log buffer to userspace via /dev/kmsg and - /proc/kmsg. If enabled, these are made inaccessible to all the processes in the unit. + /proc/kmsg. If enabled, these are made inaccessible to all the processes in the unit. + If this setting is on, but the unit doesn't have the CAP_SYS_ADMIN + capability (e.g. services for which User= is set), + NoNewPrivileges=yes is implied. @@ -1686,7 +1793,7 @@ BindReadOnlyPaths=/var/lib/systemd restrictions of this option. Specifically, it is recommended to combine this option with SystemCallArchitectures=native or similar. If running in user mode, or in system mode, but without the CAP_SYS_ADMIN capability (e.g. setting - User=nobody), NoNewPrivileges=yes is implied. By default, no + User=), NoNewPrivileges=yes is implied. By default, no restrictions apply, all address families are accessible to processes. If assigned the empty string, any previous address family restriction changes are undone. This setting does not affect commands prefixed with +. @@ -1916,7 +2023,7 @@ RestrictNamespaces=~cgroup net explicitly specify killing. This value takes precedence over the one given in SystemCallErrorNumber=, see below. If running in user mode, or in system mode, but without the CAP_SYS_ADMIN capability (e.g. setting - User=nobody), NoNewPrivileges=yes is implied. This feature + User=), NoNewPrivileges=yes is implied. This feature makes use of the Secure Computing Mode 2 interfaces of the kernel ('seccomp filtering') and is useful for enforcing a minimal sandboxing environment. Note that the execve(), exit(), exit_group(), getrlimit(), @@ -2138,7 +2245,7 @@ SystemCallErrorNumber=EPERM the special identifier native. The special identifier native implicitly maps to the native architecture of the system (or more precisely: to the architecture the system manager is compiled for). If running in user mode, or in system mode, but without the - CAP_SYS_ADMIN capability (e.g. setting User=nobody), + CAP_SYS_ADMIN capability (e.g. setting User=), NoNewPrivileges=yes is implied. By default, this option is set to the empty list, i.e. no filtering is applied. @@ -2167,7 +2274,7 @@ SystemCallErrorNumber=EPERM system calls executed by the unit processes for the listed ones will be logged. If the first character of the list is ~, the effect is inverted: all system calls except the listed system calls will be logged. If running in user mode, or in system mode, but without the - CAP_SYS_ADMIN capability (e.g. setting User=nobody), + CAP_SYS_ADMIN capability (e.g. setting User=), NoNewPrivileges=yes is implied. This feature makes use of the Secure Computing Mode 2 interfaces of the kernel ('seccomp filtering') and is useful for auditing or setting up a minimal sandboxing environment. This option may be specified more than once, in which case the filter @@ -2186,18 +2293,24 @@ SystemCallErrorNumber=EPERM Environment= - Sets environment variables for executed processes. Takes a space-separated list of - variable assignments. This option may be specified more than once, in which case all listed variables - will be set. If the same variable is set twice, the later setting will override the earlier - setting. If the empty string is assigned to this option, the list of environment variables is reset, - all prior assignments have no effect. Variable expansion is not performed inside the strings, - however, specifier expansion is possible. The $ character has no special - meaning. If you need to assign a value containing spaces or the equals sign to a variable, use double - quotes (") for the assignment. + Sets environment variables for executed processes. Each line is unquoted using the + rules described in "Quoting" section in + systemd.syntax5 + and becomes a list of variable assignments. If you need to assign a value containing spaces or the + equals sign to a variable, put quotes around the whole assignment. Variable expansion is not + performed inside the strings and the $ character has no special meaning. Specifier + expansion is performed, see the "Specifiers" section in + systemd.unit5. + - The names of the variables can contain ASCII letters, digits, and the underscore - character. Variable names cannot be empty or start with a digit. In variable values, most characters - are allowed, but non-printable characters are currently rejected. + This option may be specified more than once, in which case all listed variables will be set. If + the same variable is listed twice, the later setting will override the earlier setting. If the empty + string is assigned to this option, the list of environment variables is reset, all prior assignments + have no effect. + + The names of the variables can contain ASCII letters, digits, and the underscore character. + Variable names cannot be empty or start with a digit. In variable values, most characters are + allowed, but non-printable characters are currently rejected. Example: Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6" @@ -2207,10 +2320,9 @@ SystemCallErrorNumber=EPERM word3, $word 5 6. - - See environ7 for details - about environment variables. + See environ7 for + details about environment variables. Note that environment variables are not suitable for passing secrets (such as passwords, key material, …) to service processes. Environment variables set for a unit are exposed to unprivileged @@ -2373,7 +2485,9 @@ SystemCallErrorNumber=EPERM systemd.socket5 for more details about named file descriptors and their ordering. - This setting defaults to . + This setting defaults to , unless + StandardInputText=/StandardInputData= are set, in which case it + defaults to . @@ -2383,8 +2497,8 @@ SystemCallErrorNumber=EPERM to. Takes one of , , , , , , , , - , or - . + , , + or . duplicates the file descriptor of standard input for standard output. @@ -2424,6 +2538,21 @@ SystemCallErrorNumber=EPERM above, but it opens the file in append mode. + is similar to + above, but it truncates the file when opening + it. For units with multiple command lines, e.g. Type=oneshot services with + multiple ExecStart=, or services with ExecCondition=, + ExecStartPre= or ExecStartPost=, the output file is reopened + and therefore re-truncated for each command line. If the output file is truncated while another + process still has the file open, e.g. by an ExecReload= running concurrently with + an ExecStart=, and the other process continues writing to the file without + adjusting its offset, then the space between the file pointers of the two processes may be filled + with NUL bytes, producing a sparse file. Thus, + is typically only useful for units where + only one process runs at a time, such as services with a single ExecStart= and no + ExecStartPost=, ExecReload=, ExecStop= or + similar. + connects standard output to a socket acquired via socket activation. The semantics are similar to the same option of StandardInput=, see above. @@ -2472,9 +2601,11 @@ SystemCallErrorNumber=EPERM StandardInputText= StandardInputData= - Configures arbitrary textual or binary data to pass via file descriptor 0 (STDIN) to the - executed processes. These settings have no effect unless StandardInput= is set to - . Use this option to embed process input data directly in the unit file. + Configures arbitrary textual or binary data to pass via file descriptor 0 (STDIN) to + the executed processes. These settings have no effect unless StandardInput= is set + to (which is the default if StandardInput= is not set + otherwise, but StandardInputText=/StandardInputData= is). Use + this option to embed process input data directly in the unit file. StandardInputText= accepts arbitrary textual data. C-style escapes for special characters as well as the usual %-specifiers are resolved. Each time this setting is used @@ -2728,8 +2859,7 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy ExecStart= command line use ${CREDENTIALS_DIRECTORY}/mycred, e.g. ExecStart=cat ${CREDENTIALS_DIRECTORY}/mycred. - Currently, an accumulated credential size limit of 1M bytes per unit is - enforced. + Currently, an accumulated credential size limit of 1 MB per unit is enforced. If referencing an AF_UNIX stream socket to connect to, the connection will originate from an abstract namespace socket, that includes information about the unit and the @@ -2854,7 +2984,8 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy configuration, with just a few environment variables. The user manager inherits environment variables as any other system service, but in addition may receive additional environment variables from PAM, and, typically, additional imported variables when the user starts a graphical session. It is recommended to - keep the environment blocks in both the system and user managers managers lean. + keep the environment blocks in both the system and user managers managers lean. Importing all variables + inherited by the graphical session or by one of the user shells is strongly discouraged. Hint: systemd-run -P env and systemd-run --user -P env print the effective system and user service environment blocks. @@ -2993,6 +3124,17 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy + + $SYSTEMD_EXEC_PID + + The PID of the unit process (e.g. process invoked by + ExecStart=). The child process can use this information to determine + whether the process is directly invoked by the service manager or indirectly as a child of + another process by comparing this value with the current PID (as similar to the scheme used in + sd_listen_fds3 + with $LISTEN_PID and $LISTEN_FDS). + + $TERM @@ -3473,7 +3615,7 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy 226 EXIT_NAMESPACE - Failed to set up mount namespacing. See ReadOnlyPaths= and related settings above. + Failed to set up mount, UTS, or IPC namespacing. See ReadOnlyPaths=, ProtectHostname=, PrivateIPC=, and related settings above. 227 diff --git a/man/systemd.generator.xml b/man/systemd.generator.xml index b1936bed4..9c622ed44 100644 --- a/man/systemd.generator.xml +++ b/man/systemd.generator.xml @@ -47,12 +47,13 @@ Description - Generators are small executables that live in - &systemgeneratordir;/ and other directories listed above. - systemd1 - will execute those binaries very early at bootup and at configuration reload time - — before unit files are loaded. Their main purpose is to convert configuration - that is not native into dynamically generated unit files. + Generators are small executables placed in &systemgeneratordir;/ and other + directories listed above. + systemd1 will execute + these binaries very early at bootup and at configuration reload time — before unit files are + loaded. Their main purpose is to convert configuration that is not native to the service manager into + dynamically generated unit files, symlinks or unit file drop-ins, so that they can extend the unit file + hierarchy the service manager subsequently loads and operates on. Each generator is called with three directory paths that are to be used for generator output. In these three directories, generators may dynamically generate @@ -155,17 +156,15 @@ - Generators are run very early at boot and cannot rely on any external - services. They may not talk to any other process. That includes simple things - such as logging to - syslog3, - or systemd itself (this means: no + Generators are run very early at boot and cannot rely on any external services. They may not + talk to any other process. That includes simple things such as logging to syslog3, or + systemd itself (this means: no systemctl1)! - Non-essential file systems like /var/ and - /home/ are mounted after generators have run. Generators - can however rely on the most basic kernel functionality to be available, - including a mounted /sys/, /proc/, - /dev/, /usr/. + Non-essential file systems like /var/ and /home/ are + mounted after generators have run. Generators can however rely on the most basic kernel functionality + to be available, as well as mounted /sys/, /proc/, + /dev/, /usr/ and /run/ file systems. @@ -176,12 +175,18 @@ - Generators should only be used to generate unit files and symlinks to - them, not any other kind of configuration. Due to the lifecycle logic - mentioned above, generators are not a good fit to generate dynamic - configuration for other services. If you need to generate dynamic - configuration for other services, do so in normal services you order before - the service in question. + Generators should only be used to generate unit files, .d/*.conf drop-ins + for them and symlinks to them, not any other kind of non-unit related configuration. Due to the + lifecycle logic mentioned above, generators are not a good fit to generate dynamic configuration for + other services. If you need to generate dynamic configuration for other services, do so in normal + services you order before the service in question. + + Note that using the StandardInputData=/StandardInputText= + settings of service unit files (see + systemd.exec5), it + is possible to make arbitrary input data (including daemon-specific configuration) part of the unit + definitions, which often might be sufficient to embed data or configuration for other programs into + unit files in a native fashion. diff --git a/man/systemd.link.xml b/man/systemd.link.xml index 24271ea65..5918a3218 100644 --- a/man/systemd.link.xml +++ b/man/systemd.link.xml @@ -32,23 +32,31 @@ systemd.syntax7 for a general description of the syntax. - The link files are read from the files located in the system - network directory /usr/lib/systemd/network, - the volatile runtime network directory - /run/systemd/network, and the local - administration network directory - /etc/systemd/network. Link files must have - the extension .link; other extensions are - ignored. All link files are collectively sorted and processed in - lexical order, regardless of the directories in which they live. - However, files with identical filenames replace each other. Files - in /etc/ have the highest priority, files in - /run/ take precedence over files with the same - name in /usr/lib/. This can be used to - override a system-supplied link file with a local file if needed. - As a special case, an empty file (file size 0) or symlink with the - same name pointing to /dev/null disables the - configuration file entirely (it is "masked"). + The link files are read from the files located in the system network directory + /usr/lib/systemd/network, the volatile runtime network directory + /run/systemd/network, and the local administration network directory + /etc/systemd/network. Link files must have the extension + .link; other extensions are ignored. All link files are collectively sorted + and processed in lexical order, regardless of the directories in which they live. However, files + with identical filenames replace each other. Files in /etc/ have the highest + priority, files in /run/ take precedence over files with the same name in + /usr/lib/. This can be used to override a system-supplied link file with a + local file if needed. As a special case, an empty file (file size 0) or symlink with the same name + pointing to /dev/null disables the configuration file entirely (it is + "masked"). + + Along with the link file foo.link, a "drop-in" directory + foo.link.d/ may exist. All files with the suffix .conf + from this directory will be parsed after the file itself is parsed. This is useful to alter or add + configuration settings, without having to modify the main configuration file. Each drop-in file + must have appropriate section headers. + + In addition to /etc/systemd/network, drop-in .d + directories can be placed in /usr/lib/systemd/network or + /run/systemd/network directories. Drop-in files in /etc/ + take precedence over those in /run/ which in turn take precedence over those + in /usr/lib/. Drop-in files under any of these directories take precedence + over the main link file wherever located. The link file contains a [Match] section, which determines if a given link file may be applied to a given device, as well as a [Link] section specifying how the device should be configured. The first (in @@ -409,6 +417,27 @@ be ignored. + + TransmitQueues= + + Specifies the device's number of transmit queues. An integer in the range 1…4096. + When unset, the kernel's default will be used. + + + + ReceiveQueues= + + Specifies the device's number of receive queues. An integer in the range 1…4096. + When unset, the kernel's default will be used. + + + + TransmitQueueLength= + + Specifies the transmit queue length of the device in number of packets. An unsigned integer + in the range 0…4294967294. When unset, the kernel's default will be used. + + MTUBytes= @@ -743,6 +772,22 @@ PAUSE configuration. When unset, the kernel's default will be used. + + GenericSegmentOffloadMaxBytes= + + Specifies the maximum size of a Generic Segment Offload (GSO) packet the + device should accept. The usual suffixes K, M, G, are supported and are + understood to the base of 1024. An unsigned integer in the range 1…65536. + Defaults to unset. + + + + GenericSegmentOffloadMaxSegments= + + Specifies the maximum number of a Generic Segment Offload (GSO) segments the device should + accept. An unsigned integer in the range 1…65535. Defaults to unset. + + diff --git a/man/systemd.net-naming-scheme.xml b/man/systemd.net-naming-scheme.xml index 054de92c0..646dd3e56 100644 --- a/man/systemd.net-naming-scheme.xml +++ b/man/systemd.net-naming-scheme.xml @@ -271,7 +271,7 @@ History The following "naming schemes" have been defined (which may be chosen at system boot-up time via - the net.naming-scheme= kernel command line switch, see above: + the net.naming-scheme= kernel command line switch, see above): @@ -362,11 +362,11 @@ v247 - If the PCI slot is associated with PCI bridge and that has multiple child network - controllers then all of them might derive the same value of ID_NET_NAME_SLOT - property. That could cause naming conflict if the property is selected as a device name. Now, we detect the - situation, slot - bridge relation, and we don't produce the ID_NET_NAME_SLOT property to - avoid possible naming conflict. + When a PCI slot is associated with a PCI bridge that has multiple child network + controllers, the same value of the ID_NET_NAME_SLOT property might be derived + for those controllers. This would cause a naming conflict if the property is selected as the device + name. Now, we detect this situation and don't produce the ID_NET_NAME_SLOT + property. diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index ddda14d27..c1b1980ba 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -181,10 +181,13 @@ A virtual tunnel interface like vti/vti6 but with several advantages. ifb - The Intermediate Functional Block (ifb) pseudo network interface acts as a QoS concentrator for multiple different sources of traffic. + The Intermediate Functional Block (ifb) pseudo network interface acts as a QoS concentrator for multiple different sources of traffic. bareudp - Bare UDP tunnels provide a generic L3 encapsulation support for tunnelling different L3 protocols like MPLS, IP etc. inside of an UDP tunnel. + Bare UDP tunnels provide a generic L3 encapsulation support for tunnelling different L3 protocols like MPLS, IP etc. inside of an UDP tunnel. + + batadv + B.A.T.M.A.N. Advanced is a routing protocol for multi-hop mobile ad-hoc networks which operates on layer 2. @@ -450,6 +453,13 @@ This setting is compulsory. + + Protocol= + + Allows setting the protocol used for the VLAN interface. Takes 802.1q or, + 802.1ad, and defaults to unset and kernel's default is used. + + GVRP= @@ -484,6 +494,28 @@ like physical interfaces. When unset, the kernel's default will be used. + + EgressQOSMaps= + + Defines a mapping of Linux internal packet priority (SO_PRIORITY) to VLAN header + PCP field for outgoing frames. Takes a whitespace-separated list of unsigned integer pairs in the format + from-to, e.g., 21-7 45-5 ranges 1–4294967294. + Note that from must be greater than or equal to to. When unset, + the kernel's default will be used. + + + + + IngressQOSMaps= + + Defines a mapping of Linux internal packet priority (SO_PRIORITY) to VLAN header + PCP field for incoming frames. Takes a whitespace-separated list of unsigned integer pairs in the format + from-to, e.g., 21-7 45-5 ranges 1–4294967294. + Note that from must be greater than or equal to to. When unset, + the kernel's default will be used. + + +
@@ -517,6 +549,13 @@ to this is reset. Defaults to unset. + + BroadcastMulticastQueueLength= + + Specifies the length of the receive queue for broadcast/multicast packets. An unsigned + integer in the range 0…4294967294. Defaults to unset. + + @@ -572,7 +611,7 @@ VNI= - The VXLAN Network Identifier (or VXLAN Segment ID). Takes a number in the range 1-16777215. + The VXLAN Network Identifier (or VXLAN Segment ID). Takes a number in the range 1…16777215. @@ -871,7 +910,7 @@ PeerTunnelId= - Specifies the peer tunnel id. Takes a number in the range 1—4294967295. The value used must + Specifies the peer tunnel id. Takes a number in the range 1…4294967295. The value used must match the TunnelId= value being used at the peer. This setting is compulsory. @@ -1354,7 +1393,7 @@ ERSPANIndex= - Specifies the ERSPAN index field for the interface, an integer in the range 1-1048575 associated with + Specifies the ERSPAN index field for the interface, an integer in the range 1…1048575 associated with the ERSPAN traffic's source port and direction. This field is mandatory. @@ -1406,7 +1445,7 @@ The Protocol= specifies the protocol number of the packets arriving at the UDP port. When Encapsulation=FooOverUDP, this field is mandatory and is not set by default. Takes an IP protocol name such as gre or - ipip, or an integer within the range 1-255. When + ipip, or an integer within the range 1…255. When Encapsulation=GenericUDPEncapsulation, this must not be specified. @@ -1765,7 +1804,7 @@ AdActorSystemPriority= - Specifies the 802.3ad actor system priority. Takes a number in the range 1—65535. + Specifies the 802.3ad actor system priority. Takes a number in the range 1…65535. @@ -1984,6 +2023,107 @@ + + [BatmanAdvanced] Section Options + The [BatmanAdvanced] section only applies for + netdevs of kind batadv and accepts the + following keys: + + + + GatewayMode= + + Takes one of off, server, or client. + A batman-adv node can either run in server mode (sharing its internet + connection with the mesh) or in client mode (searching for the most suitable internet connection + in the mesh) or having the gateway support turned off entirely (which is the default setting). + + + + + Aggregation= + + Takes a boolean value. Enables or disables aggregation of originator messages. Defaults to + true. + + + + + BridgeLoopAvoidance= + + Takes a boolean value. Enables or disables avoidance of loops on bridges. Defaults to true. + + + + + DistributedArpTable= + + Takes a boolean value. Enables or disables the distributed ARP table. Defaults to true. + + + + Fragmentation= + + Takes a boolean value. Enables or disables fragmentation. Defaults to true. + + + + HopPenalty= + + The hop penalty setting allows to modify + batctl8 + preference for multihop routes vs. short routes. This integer value is applied to the + TQ (Transmit Quality) of each forwarded OGM (Originator Message), thereby propagating the + cost of an extra hop (the packet has to be received and retransmitted which costs airtime). + A higher hop penalty will make it more unlikely that other nodes will choose this node as + intermediate hop towards any given destination. The default hop penalty of '15' is a reasonable + value for most setups and probably does not need to be changed. However, mobile nodes could + choose a value of 255 (maximum value) to avoid being chosen as a router by other nodes. + The minimum value is 0. + + + + + OriginatorIntervalSec= + + The value specifies the interval in seconds, unless another time unit is specified in which + batman-adv floods the network with its protocol information. + See systemd.time7 + for more information. + + + + GatewayBandwidthDown= + + If the node is a server, this + parameter is used to inform other nodes in the network about + this node's internet connection download bandwidth in bits per second. Just enter any number + suffixed with K, M, G or T (base 1000) and the batman-adv + module will propagate the entered value in the mesh. + + + + GatewayBandwidthUp= + + If the node is a server, this + parameter is used to inform other nodes in the network about + this node's internet connection upload bandwidth in bits per second. Just enter any number + suffixed with K, M, G or T (base 1000) and the batman-adv + module will propagate the entered value in the mesh. + + + + RoutingAlgorithm= + + This can be either batman-v or batman-iv and describes which routing_algo + of batctl8 to use. The algorithm + cannot be changed after interface creation. Defaults to batman-v. + + + + + + Examples diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 6314a8252..cec2f96f2 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -61,12 +61,6 @@ /etc/ take precedence over those in /run/ which in turn take precedence over those in /usr/lib/. Drop-in files under any of these directories take precedence over the main network file wherever located. - - Note that an interface without any static IPv6 addresses configured, and neither DHCPv6 - nor IPv6LL enabled, shall be considered to have no IPv6 support. IPv6 will be automatically - disabled for that interface by writing "1" to - /proc/sys/net/ipv6/conf/ifname/disable_ipv6. - @@ -171,20 +165,27 @@ For example, disabling ARP is useful when creating multiple MACVLAN or VLAN virtual interfaces atop a single lower-level physical interface, which will then only serve as a link/"bridge" device aggregating traffic to the same physical link and not participate in - the network otherwise. + the network otherwise. Defaults to unset. Multicast= - Takes a boolean. If set to true, the multicast flag on the device is enabled. + Takes a boolean. If set to true, the multicast flag on the device is enabled. Defaults to unset. AllMulticast= Takes a boolean. If set to true, the driver retrieves all multicast packets from the network. - This happens when multicast routing is enabled. + This happens when multicast routing is enabled. Defaults to unset. + + + + Promiscuous= + + Takes a boolean. If set to true, promiscuous mode of the interface is enabled. + Defaults to unset. @@ -205,7 +206,7 @@ Link groups are similar to port ranges found in managed switches. When network interfaces are added to a numbered group, operations on all the interfaces from that group can be performed at once. An unsigned - integer in the range 0—4294967294. Defaults to unset. + integer in the range 0…4294967294. Defaults to unset. @@ -228,6 +229,36 @@ if RequiredForOnline=no. + + ActivationPolicy= + + Specifies the policy for systemd-networkd managing the link + administrative state. Specifically, this controls how systemd-networkd + changes the network device's IFF_UP flag, which is sometimes + controlled by system administrators by running e.g., ip set dev eth0 up + or ip set dev eth0 down, and can also be changed with + networkctl up eth0 or networkctl down eth0. + + Takes one of up, always-up, + manual, always-down, down, + or bound. When manual, systemd-networkd + will not change the link's admin state automatically; the system administrator must bring the + interface up or down manually, as desired. When up (the default) or + always-up, or down or always-down, + systemd-networkd will set the link up or down, respectively, + when the interface is (re)configured. When always-up or + always-down, systemd-networkd will set the link up + or down, respectively, any time systemd-networkd detects a change in + the administrative state. When BindCarrier= is also set, this is + automatically set to bound and any other value is ignored. + + The administrative state is not the same as the carrier state, so using + always-up does not mean the link will never lose carrier. The link + carrier depends on both the administrative state as well as the network device's physical + connection. However, to avoid reconfiguration failures, when using always-up, + IgnoreCarrierLoss= is forced to true. + + @@ -244,21 +275,21 @@ VirtualFunction= Specifies a Virtual Function (VF), lightweight PCIe function designed solely to move data - in and out. Takes an unsigned integer in the range 0..2147483646. This option is compulsory. + in and out. Takes an unsigned integer in the range 0…2147483646. This option is compulsory. VLANId= - Specifies VLAN ID of the virtual function. Takes an unsigned integer in the range 1..4095. + Specifies VLAN ID of the virtual function. Takes an unsigned integer in the range 1…4095. QualityOfService= - Specifies quality of service of the virtual function. Takes an unsigned integer in the range 1..4294967294. + Specifies quality of service of the virtual function. Takes an unsigned integer in the range 1…4294967294. @@ -364,17 +395,15 @@ LinkLocalAddressing= - Enables link-local address autoconfiguration. Accepts yes, - no, ipv4, ipv6, - fallback, or ipv4-fallback. If - fallback or ipv4-fallback is specified, then an IPv4 - link-local address is configured only when DHCPv4 fails. If fallback, - an IPv6 link-local address is always configured, and if ipv4-fallback, - the address is not configured. Note that, the fallback mechanism works only when DHCPv4 - client is enabled, that is, it requires DHCP=yes or - DHCP=ipv4. If Bridge= is set, defaults to - no, and if not, defaults to ipv6. - + Enables link-local address autoconfiguration. Accepts , + , , and . An IPv6 link-local address + is configured when or . An IPv4 link-local address is + configured when or and when DHCPv4 autoconfiguration + has been unsuccessful for some time. (IPv4 link-local address autoconfiguration will usually + happen in parallel with repeated attempts to acquire a DHCPv4 lease). + + Defaults to when Bridge=yes is set, and + otherwise. @@ -573,8 +602,9 @@ IPv6Token=prefixstable:2002:da8:1:: A link name or a list of link names. When set, controls the behavior of the current link. When all links in the list are in an operational down state, the current link is brought - down. When at least one link has carrier, the current interface is brought up. - + down. When at least one link has carrier, the current interface is brought up. + + This forces ActivationPolicy= to be set to bound. @@ -615,8 +645,7 @@ IPv6Token=prefixstable:2002:da8:1:: DNS= - A DNS server address, which must be in the format - described in + A DNS server address, which must be in the format described in inet_pton3. This option may be specified more than once. Each address can optionally take a port number separated with :, a network interface name or index separated with @@ -624,9 +653,8 @@ IPv6Token=prefixstable:2002:da8:1:: When IPv6 address is specified with a port number, then the address must be in the square brackets. That is, the acceptable full formats are 111.222.333.444:9953%ifname#example.com for IPv4 and - [1111:2222::3333]:9953%ifname#example.com for IPv6. This setting can be - specified multiple times. If an empty string is assigned, then the all previous assignments - are cleared. This setting is read by + [1111:2222::3333]:9953%ifname#example.com for IPv6. If an empty string is + assigned, then the all previous assignments are cleared. This setting is read by systemd-resolved.service8. @@ -707,12 +735,15 @@ IPv6Token=prefixstable:2002:da8:1:: IPMasquerade= - Configures IP masquerading for the network - interface. If enabled, packets forwarded from the network - interface will be appear as coming from the local host. - Takes a boolean argument. Implies - IPForward=ipv4. Defaults to - no. + Configures IP masquerading for the network interface. If enabled, packets + forwarded from the network interface will be appear as coming from the local host. Takes one + of ipv4, ipv6, both, or + no. Defaults to no. If enabled, this automatically sets + IPForward= to one of ipv4, ipv6 or + yes. + Note. Any positive boolean values such as yes or + true are now deprecated. Please use one of the values in the above. + IPv6PrivacyExtensions= @@ -776,6 +807,12 @@ IPv6Token=prefixstable:2002:da8:1:: the wire and have them accepted properly. When unset, the kernel's default will be used. + + IPv4RouteLocalnet= + Takes a boolean. When true, the kernel does not consider loopback addresses as martian source or destination + while routing. This enables the use of 127.0.0.0/8 for local routing purposes. When unset, the kernel's default will be used. + + IPv4ProxyARP= Takes a boolean. Configures proxy ARP for IPv4. Proxy ARP is the technique in which one host, @@ -947,6 +984,10 @@ IPv6Token=prefixstable:2002:da8:1:: of the interface even if its carrier is lost. When unset, the value specified with is used. + + When ActivationPolicy= is set to always-up, this + is forced to true. + @@ -973,7 +1014,14 @@ IPv6Token=prefixstable:2002:da8:1:: - + + BatmanAdvanced= + + The name of the B.A.T.M.A.N. Advanced interface to add the link to. See + systemd.netdev5. + + + @@ -1003,12 +1051,12 @@ IPv6Token=prefixstable:2002:da8:1:: Broadcast= - The broadcast address, which must be in the format - described in + Takes an IPv4 address or boolean value. The address must be in the format described in inet_pton3. - This key only applies to IPv4 addresses. If it is not - given, it is derived from the Address= - key. + If set to true, then the IPv4 broadcast address will be derived from the + Address= setting. If set to false, then the broadcast address will not + be set. Defaults to true, except for wireguard interfaces, where it default to false. + @@ -1020,13 +1068,12 @@ IPv6Token=prefixstable:2002:da8:1:: PreferredLifetime= - Allows the default "preferred lifetime" of the address to be overridden. - Only three settings are accepted: forever or infinity - which is the default and means that the address never expires, and 0 which means - that the address is considered immediately "expired" and will not be used, - unless explicitly requested. A setting of PreferredLifetime=0 is useful for - addresses which are added to be used only by a specific application, - which is then configured to use them explicitly. + Allows the default "preferred lifetime" of the address to be overridden. Only three + settings are accepted: forever, infinity, which is the + default and means that the address never expires, and 0, which means that the + address is considered immediately "expired" and will not be used, unless explicitly requested. A + setting of is useful for addresses which are added to be + used only by a specific application, which is then configured to use them explicitly. @@ -1036,7 +1083,7 @@ IPv6Token=prefixstable:2002:da8:1:: global (valid everywhere on the network, even through a gateway), link (only valid on this device, will not traverse a gateway) or host (only valid within the device itself, e.g. 127.0.0.1) - or an unsigned integer in the range 0—255. + or an unsigned integer in the range 0…255. Defaults to global. @@ -1065,11 +1112,11 @@ IPv6Token=prefixstable:2002:da8:1:: Takes a boolean. If true the kernel manage temporary addresses created from this one as template on behalf of Privacy Extensions - RFC 3041. For this to become + RFC 3041. For this to become active, the use_tempaddr sysctl setting has to be set to a value greater than zero. The given address needs to have a prefix length of 64. This flag allows using privacy extensions in a manually configured network, just like if stateless auto-configuration - was active. Defaults to false. + was active. Defaults to false. @@ -1181,8 +1228,9 @@ IPv6Token=prefixstable:2002:da8:1:: Table= - Specifies the routing table identifier to lookup if the rule selector matches. Takes - one of default, main, and local, + Specifies the routing table identifier to lookup if the rule selector matches. Takes one of predefined names + default, main, and local, and names defined in RouteTable= + in networkd.conf5, or a number between 1 and 4294967295. Defaults to main. @@ -1254,11 +1302,19 @@ IPv6Token=prefixstable:2002:da8:1:: SuppressPrefixLength= - Takes a number N in the range 0-128 and rejects routing + Takes a number N in the range 0…128 and rejects routing decisions that have a prefix length of N or less. Defaults to unset. + + Type= + + Specifies Routing Policy Database (RPDB) rule type. Takes one of blackhole, + unreachable or prohibit. + + + @@ -1270,15 +1326,42 @@ IPv6Token=prefixstable:2002:da8:1:: - Gateway= + Id= - As in the [Network] section. This is mandatory. + The id of the next hop. Takes an unsigned integer in the range 1…4294967295. If left + unspecified, then automatically chosen by kernel. - Id= + Gateway= - The id of the nexthop (an unsigned integer). If unspecified or '0' then automatically chosen by kernel. + As in the [Network] section. + + + + Family= + + Takes one of the special values ipv4 or ipv6. + By default, the family is determined by the address specified in + Gateway=. If Gateway= is not specified, then defaults + to ipv4. + + + + OnLink= + + Takes a boolean. If set to true, the kernel does not have to check if the gateway is + reachable directly by the current machine (i.e., attached to the local network), so that we + can insert the nexthop in the kernel table without it being complained about. Defaults to + no. + + + + Blackhole= + + Takes a boolean. If enabled, packets to the corresponding routes are discarded + silently, and Gateway= cannot be specified. Defaults to + no. @@ -1298,16 +1381,15 @@ IPv6Token=prefixstable:2002:da8:1:: set, then the gateway address provided by DHCPv4 or IPv6 RA is used. - - GatewayOnLink= - - Takes a boolean. If set to true, the kernel does not have - to check if the gateway is reachable directly by the current machine (i.e., the kernel does - not need to check if the gateway is attached to the local network), so that we can insert the - route in the kernel table without it being complained about. Defaults to no. - - - + + GatewayOnLink= + + Takes a boolean. If set to true, the kernel does not have to check if the gateway is + reachable directly by the current machine (i.e., attached to the local network), so that we + can insert the route in the kernel table without it being complained about. Defaults to + no. + + Destination= @@ -1382,11 +1464,11 @@ IPv6Token=prefixstable:2002:da8:1:: Table= - The table identifier for the route. Takes default, - main, local or a number between 1 and 4294967295. - The table can be retrieved using ip route show table num. - If unset and Type= is local, broadcast, - anycast, or nat, then local is used. + The table identifier for the route. Takes one of predefined names default, main, + and local, and names defined in RouteTable= in networkd.conf + 5, or a number between 1 and 4294967295. The table can be retrieved using + ip route show table num. If unset and Type= is local, + broadcast, anycast, or nat, then local is used. In other cases, defaults to main. @@ -1478,6 +1560,14 @@ IPv6Token=prefixstable:2002:da8:1:: service type to CS6 (network control) or CS4 (Realtime). Defaults to CS6. + + TCPAdvertisedMaximumSegmentSize= + + Specifies the Path MSS (in bytes) hints given on TCP layer. The usual suffixes K, M, G, are + supported and are understood to the base of 1024. An unsigned integer in the range 1–4294967294. + When unset, the kernel's default will be used. + + MultiPathRoute=address[@name] [weight] @@ -1488,6 +1578,13 @@ IPv6Token=prefixstable:2002:da8:1:: times. If an empty string is assigned, then the all previous assignments are cleared. + + NextHop= + + Specifies the nexthop id. Takes an unsigned integer in the range 1…4294967295. + If set, the corresponding [NextHop] section must be configured. Defaults to unset. + + @@ -1500,9 +1597,7 @@ IPv6Token=prefixstable:2002:da8:1:: UseDNS= - When true (the default), the DNS servers received - from the DHCP server will be used and take precedence over - any statically configured ones. + When true (the default), the DNS servers received from the DHCP server will be used. This corresponds to the option in UseNTP= When true (the default), the NTP servers received from the DHCP server will be used by - systemd-timesyncd.service and take precedence over any statically configured - ones. + systemd-timesyncd.service. @@ -1642,13 +1736,12 @@ IPv6Token=prefixstable:2002:da8:1:: UseGateway= When true, the gateway will be requested from the DHCP server and added to the routing table with a - metric of 1024, and a scope of "link". When unset, the value specified with + metric of 1024, and a scope of "link". When unset, the value specified with is used. UseTimezone= - When true, the timezone received from the DHCP server will be set as timezone of the local system. Defaults to no. @@ -1687,9 +1780,10 @@ IPv6Token=prefixstable:2002:da8:1:: MaxAttempts= Specifies how many times the DHCPv4 client configuration should be attempted. Takes a - number or infinity. Defaults to infinity. - Note that the time between retries is increased exponentially, so the network will not be - overloaded even if this number is high. + number or infinity. Defaults to infinity. Note that the + time between retries is increased exponentially, up to approximately one per minute, so the + network will not be overloaded even if this number is high. The default is suitable in most + circumstances. @@ -1810,8 +1904,8 @@ IPv6Token=prefixstable:2002:da8:1:: RequestOptions= - When configured, allows to set arbitrary request options in the DHCPv4 request options list and will be - sent to the DHCPV4 server. A whitespace-separated list of integers in the range 1..254. Defaults to unset. + Sets request options to be sent to the server in the DHCPv4 request options list. A + whitespace-separated list of integers in the range 1…254. Defaults to unset. @@ -1821,10 +1915,11 @@ IPv6Token=prefixstable:2002:da8:1:: Send an arbitrary raw option in the DHCPv4 request. Takes a DHCP option number, data type and data separated with a colon (option:type:value). - The option number must be an integer in the range 1..254. The type takes one of uint8, - uint16, uint32, ipv4address, or - string. Special characters in the data string may be escaped using - C-style + The option number must be an integer in the range 1…254. The type takes one of + uint8, uint16, uint32, + ipv4address, or string. Special characters in the data + string may be escaped using C-style escapes. This setting can be specified multiple times. If an empty string is specified, then all options specified earlier are cleared. Defaults to unset. @@ -1833,13 +1928,14 @@ IPv6Token=prefixstable:2002:da8:1:: SendVendorOption= - Send an arbitrary vendor option in the DHCPv4 request. Takes a DHCP option number, data type - and data separated with a colon + Send an arbitrary vendor option in the DHCPv4 request. Takes a DHCP option number, data + type and data separated with a colon (option:type:value). - The option number must be an integer in the range 1..254. The type takes one of uint8, - uint16, uint32, ipv4address, or - string. Special characters in the data string may be escaped using - C-style + The option number must be an integer in the range 1…254. The type takes one of + uint8, uint16, uint32, + ipv4address, or string. Special characters in the data + string may be escaped using C-style escapes. This setting can be specified multiple times. If an empty string is specified, then all options specified earlier are cleared. Defaults to unset. @@ -1853,9 +1949,18 @@ IPv6Token=prefixstable:2002:da8:1:: DHCP= setting described above, or invoked by the IPv6 Router Advertisement: + + UseAddress= + + When true (the default), the IP addresses provided by the DHCPv6 server will be + assigned. + + + UseDNS= UseNTP= + UseHostname= As in the [DHCPv4] section. @@ -1885,7 +1990,7 @@ IPv6Token=prefixstable:2002:da8:1:: MUDURL= When configured, the specified Manufacturer Usage Description (MUD) URL will be sent to - the DHCPV6 server. The syntax and semantics are the same as for MUDURL= in the + the DHCPv6 server. The syntax and semantics are the same as for MUDURL= in the [DHCPv4] section described above. @@ -1894,8 +1999,8 @@ IPv6Token=prefixstable:2002:da8:1:: RequestOptions= When configured, allows to set arbitrary request options in the DHCPv6 request options list - that will be sent to the DHCPV6 server. A whitespace-separated list of integers in the range - 1..254. Defaults to unset. + that will be sent to the DHCPv6 server. A whitespace-separated list of integers in the range + 1…254. Defaults to unset. @@ -1955,7 +2060,7 @@ IPv6Token=prefixstable:2002:da8:1:: SendOption= As in the [DHCPv4] section, however because DHCPv6 uses 16-bit fields to store - option numbers, the option number is an integer in the range 1..65536. + option numbers, the option number is an integer in the range 1…65536. @@ -2035,6 +2140,13 @@ IPv6Token=prefixstable:2002:da8:1:: addresses. Defaults to unset. + + + ManageTemporaryAddress= + + As in the [Address] section, but defaults to true. + + @@ -2047,8 +2159,7 @@ IPv6Token=prefixstable:2002:da8:1:: UseDNS= - When true (the default), the DNS servers received in the Router Advertisement will be used and take - precedence over any statically configured ones. + When true (the default), the DNS servers received in the Router Advertisement will be used. This corresponds to the option in resolv.conf5. @@ -2102,9 +2213,53 @@ IPv6Token=prefixstable:2002:da8:1:: - DenyList= + RouterDenyList= - A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router advertisements in the list are ignored. + A whitespace-separated list of IPv6 router addresses. Any information advertised by + the listed router is ignored. + + + + + RouterAllowList= + + A whitespace-separated list of IPv6 router addresses. Only information advertised by + the listed router is accepted. Note that if RouterAllowList= is + configured then RouterDenyList= is ignored. + + + + + PrefixDenyList= + + A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router + advertisements in the list are ignored. + + + + + PrefixAllowList= + + A whitespace-separated list of IPv6 prefixes. IPv6 prefixes supplied via router + advertisements in the list are allowed. Note that if PrefixAllowList= is + configured then PrefixDenyList= is ignored. + + + + + RouteDenyList= + + A whitespace-separated list of IPv6 route prefixes. IPv6 route prefixes supplied via + router advertisements in the list are ignored. + + + + + RouteAllowList= + + A whitespace-separated list of IPv6 route prefixes. IPv6 route prefixes supplied via + router advertisements in the list are allowed. Note that if RouteAllowList= is + configured then RouteDenyList= is ignored. @@ -2175,7 +2330,7 @@ IPv6Token=prefixstable:2002:da8:1:: servers set. The "uplink" interface is determined by the default route of the system with the highest priority. Note that this information is acquired at the time the lease is handed out, and does not take uplink interfaces into account that acquire DNS server information at a later point. If no - suitable uplinkg interface is found the DNS server data from /etc/resolv.conf is + suitable uplink interface is found the DNS server data from /etc/resolv.conf is used. Also, note that the leases are not refreshed if the uplink network configuration changes. To ensure clients regularly acquire the most current uplink DNS server information, it is thus advisable to shorten the DHCP lease time via MaxLeaseTimeSec= described @@ -2229,7 +2384,7 @@ IPv6Token=prefixstable:2002:da8:1:: Send a raw option with value via DHCPv4 server. Takes a DHCP option number, data type and data (option:type:value). - The option number is an integer in the range 1..254. The type takes one of uint8, + The option number is an integer in the range 1…254. The type takes one of uint8, uint16, uint32, ipv4address, ipv6address, or string. Special characters in the data string may be escaped using C-style @@ -2243,7 +2398,7 @@ IPv6Token=prefixstable:2002:da8:1:: Send a vendor option with value via DHCPv4 server. Takes a DHCP option number, data type and data (option:type:value). - The option number is an integer in the range 1..254. The type takes one of uint8, + The option number is an integer in the range 1…254. The type takes one of uint8, uint16, uint32, ipv4address, or string. Special characters in the data string may be escaped using C-style @@ -2568,7 +2723,7 @@ IPv6Token=prefixstable:2002:da8:1:: VNI= The VXLAN Network Identifier (or VXLAN Segment ID) to use to connect to - the remote VXLAN tunnel endpoint. Takes a number in the range 1-16777215. + the remote VXLAN tunnel endpoint. Takes a number in the range 1…16777215. Defaults to unset. @@ -2636,7 +2791,7 @@ IPv6Token=prefixstable:2002:da8:1:: BitRate= The bitrate of CAN device in bits per second. The usual SI prefixes (K, M) with the base of 1000 can - be used here. Takes a number in the range 1..4294967295. + be used here. Takes a number in the range 1…4294967295. @@ -2693,6 +2848,16 @@ IPv6Token=prefixstable:2002:da8:1:: the value of a received bit by majority rule. When unset, the kernel's default will be used. + + BusErrorReporting= + + Takes a boolean. When yes, reporting of CAN bus errors is activated + (those include single bit, frame format, and bit stuffing errors, unable to send dominant bit, + unable to send recessive bit, bus overload, active error announcement, error occurred on + transmission). When unset, the kernel's default will be used. Note: in case of a CAN bus with a + single CAN device, sending a CAN frame may result in a huge number of CAN bus errors. + + ListenOnly= @@ -2862,8 +3027,9 @@ IPv6Token=prefixstable:2002:da8:1:: PacketLimit= - Specifies the hard limit on the queue size in number of packets. When this limit is reached, incoming packets are - dropped. An unsigned integer in the range 1–4294967294. Defaults to unset and kernel's default is used. + Specifies the hard limit on the queue size in number of packets. When this limit is reached, + incoming packets are dropped. An unsigned integer in the range 1…4294967294. Defaults to unset and + kernel's default is used. @@ -2881,8 +3047,9 @@ IPv6Token=prefixstable:2002:da8:1:: PacketLimit= - Specifies the hard limit on the queue size in number of packets. When this limit is reached, incoming packets are - dropped. An unsigned integer ranges 1 to 4294967294. Defaults to unset and kernel's default is used. + Specifies the hard limit on the queue size in number of packets. When this limit is reached, + incoming packets are dropped. An unsigned integer ranges 1 to 4294967294. Defaults to unset and + kernel's default is used. @@ -2960,10 +3127,10 @@ IPv6Token=prefixstable:2002:da8:1:: PacketLimit= - Specifies the hard limit on the FIFO size in number of packets. The size limit (a buffer - size) to prevent it from overflowing in case it is unable to dequeue packets as quickly as it - receives them. When this limit is reached, incoming packets are dropped. An unsigned integer in the - range 0–4294967294. Defaults to unset and kernel's default is used. + Specifies the hard limit on the number of packets in the FIFO queue. The size limit prevents + overflow in case the kernel is unable to dequeue packets as quickly as it receives them. When this + limit is reached, incoming packets are dropped. An unsigned integer in the range + 0–4294967294. Defaults to unset and kernel's default is used. @@ -3153,7 +3320,7 @@ IPv6Token=prefixstable:2002:da8:1:: separated list of numbers. The first number indicates which band the packets with priority 0 should be put to, the second is for priority 1, and so on. There can be up to 16 numbers in the list. If there are fewer, the default band that traffic with one of the unmentioned priorities goes to is - the last one. Each band number must be in the range 0..255. This setting can be specified multiple + the last one. Each band number must be in the range 0…255. This setting can be specified multiple times. If an empty string is assigned, then the all previous assignments are cleared. @@ -3172,7 +3339,8 @@ IPv6Token=prefixstable:2002:da8:1:: VirtualQueues= - Specifies the number of virtual queues. Takes a integer in the range 1-16. Defaults to unset and kernel's default is used. + Specifies the number of virtual queues. Takes a integer in the range 1…16. Defaults to unset + and kernel's default is used. @@ -3533,7 +3701,7 @@ IPv6Token=prefixstable:2002:da8:1:: Weight= - Specifies the weight of the class. Takes an integer in the range 1..1023. Defaults to + Specifies the weight of the class. Takes an integer in the range 1…1023. Defaults to unset in which case the kernel default is used. @@ -3541,9 +3709,9 @@ IPv6Token=prefixstable:2002:da8:1:: MaxPacketBytes= - Specifies the maximum packet size in bytes for the class. When suffixed with K, M, or G, the specified - size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of 1024. When unset, - the kernel default is used. + Specifies the maximum packet size in bytes for the class. When suffixed with K, M, or G, the + specified size is parsed as Kilobytes, Megabytes, or Gigabytes, respectively, to the base of + 1024. When unset, the kernel default is used. diff --git a/man/systemd.nspawn.xml b/man/systemd.nspawn.xml index 0125b71e3..6ad0e1a10 100644 --- a/man/systemd.nspawn.xml +++ b/man/systemd.nspawn.xml @@ -190,7 +190,34 @@ /run/system/nspawn/ (see above). On the other hand, DropCapability= takes effect in all cases. If the special value all is passed, all - capabilities are retained (or dropped). + capabilities are retained (or dropped). + These settings change the bounding set of capabilities which + also limits the ambient capabilities as given with the + AmbientCapability=. + + + + AmbientCapability= + Takes a space-separated list of Linux process + capabilities (see + capabilities7 + for details). The AmbientCapability= setting + specifies capability which will be passed to to started program + in the inheritable and ambient capability sets. This will grant + these capabilities to this process. This setting correspond to + the command line switch. + + + The value all is not supported for this + setting. + + The setting of AmbientCapability= must + be covered by the bounding set settings which were established by + Capability= and DropCapability=. + + + Note that AmbientCapability= is a privileged + setting (see above). diff --git a/man/systemd.preset.xml b/man/systemd.preset.xml index 5697e50be..64333a321 100644 --- a/man/systemd.preset.xml +++ b/man/systemd.preset.xml @@ -32,28 +32,20 @@ Description - Preset files may be used to encode policy which units shall - be enabled by default and which ones shall be disabled. They are - read by systemctl preset (for more information - see - systemctl1) - which uses this information to enable or disable a unit according - to preset policy. systemctl preset is used by - the post install scriptlets of RPM packages (or other OS package - formats), to enable/disable specific units by default on package - installation, enforcing distribution, spin or administrator preset - policy. This allows choosing a certain set of units to be - enabled/disabled even before installing the actual package. + Preset files may be used to encode policy which units shall be enabled by default and which ones + shall be disabled. They are read by systemctl preset which uses this information to + enable or disable a unit. Depending on that policy, systemctl preset is identical to + systemctl enable or systemctl disable. - For more information on the preset logic please have a look - at the Presets - document. + systemctl preset is used by the post install scriptlets of rpm packages (or other OS + package formats), to enable/disable specific units by default on package installation, enforcing + distribution, spin or administrator preset policy. This allows choosing a certain set of units to be + enabled/disabled even before installing the actual package. For more information, see + systemctl1. - It is not recommended to ship preset files within the - respective software packages implementing the units, but rather - centralize them in a distribution or spin default policy, which - can be amended by administrator policy. + It is not recommended to ship preset files within the respective software packages implementing the + units, but rather centralize them in a distribution or spin default policy, which can be amended by + administrator policy, see below. If no preset files exist, systemctl preset will enable all units that are installed by @@ -175,6 +167,38 @@ disable * override all other preset policy files. + + Motivation for the preset logic + + Different distributions have different policies on which services shall be enabled by default when + the package they are shipped in is installed. On Fedora all services stay off by default, so that + installing a package will not cause a service to be enabled (with some exceptions). On Debian all + services are immediately enabled by default, so that installing a package will cause its services to be + enabled right-away. + + Even within a single distribution, different spins (flavours, remixes, whatever you might want to + call them) of a distribution also have different policies on what services to enable, and what services + to leave off. For example, Fedora Workstation will enable gdm as display manager by + default, while the Fedora KDE spin will enable sddm instead. + + Different sites might also have different policies what to turn on by default and what to turn + off. For example, one administrator would prefer to enforce the policy of "sshd should + be always on, but everything else off", while another one might say "snmpd always on, + and for everything else use the distribution policy defaults". + + Traditionally, policy about which services shall be enabled were implemented in each package + individually. This made it cumbersome to implement different policies per spin or per site, or to create + software packages that do the right thing on more than one distribution. The enablement mechanism was + also encoding the enablement policy. + + The preset mechanism allows clean separation of the enablement mechanism (inside the package + scriptlets, by invoking systemctl preset) and enablement policy (centralized in the + preset files), and lifts the configuration out of individual packages. Preset files may be written for + specific distributions, for specific spins or for specific sites, in order to enforce different policies + as needed. It is recommended to apply the policy encoded in preset files in package installation + scriptlets. + + See Also @@ -182,6 +206,13 @@ disable * systemctl1, systemd-delta1 + + daemon8 + has a discussion of packaging scriptlets. + + Fedora page introducing the use of presets: + Features/PackagePresets. + diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml index 26dedda3f..1bc45a9f0 100644 --- a/man/systemd.resource-control.xml +++ b/man/systemd.resource-control.xml @@ -63,6 +63,25 @@ url="https://www.freedesktop.org/wiki/Software/systemd/ControlGroupInterface/">New Control Group Interfaces for an introduction on how to make use of resource control APIs from programs. + + + Setting resource controls for a group of related units + + As described in + systemd.unit5, the + settings listed here may be set through the main file of a unit and drop-in snippets in + *.d/ directories. The list of directories searched for drop-ins + includes names formed by repeatedly truncating the unit name after all dashes. This is particularly + convenient to set resource limits for a group of units with similar names. + + For example, every user gets their own slice + user-nnn.slice. Drop-ins with local configuration that + affect user 1000 may be placed in + /etc/systemd/system/user-1000.slice, + /etc/systemd/system/user-1000.slice.d/*.conf, but also + /etc/systemd/system/user-.slice.d/*.conf. This last directory + applies to all user slices. + @@ -901,14 +920,46 @@ DeviceAllow=/dev/loop-control - ManagedOOMMemoryPressureLimitPercent= + ManagedOOMMemoryPressureLimit= Overrides the default memory pressure limit set by - oomd.conf5 for this unit - (cgroup). Takes a percentage value between 0% and 100%, inclusive. This property is ignored unless - ManagedOOMMemoryPressure=. Defaults to 0%, which means use the - default set by oomd.conf5. + oomd.conf5 for + this unit (cgroup). Takes a percentage value between 0% and 100%, inclusive. This property is + ignored unless ManagedOOMMemoryPressure=. Defaults to 0%, + which means to use the default set by + oomd.conf5. + + + + + + ManagedOOMPreference=none|avoid|omit + + + Allows deprioritizing or omitting this unit's cgroup as a candidate when + systemd-oomd needs to act. Requires support for extended attributes (see + xattr7) + in order to use or . Additionally, + systemd-oomd will ignore these extended attributes if the unit's cgroup is not + owned by the root user. + + If this property is set to , the service manager will convey this to + systemd-oomd, which will only select this cgroup if there are no other viable + candidates. + + If this property is set to , the service manager will convey this to + systemd-oomd, which will ignore this cgroup as a candidate and will not perform + any actions on it. + + It is recommended to use and sparingly, as it + can adversely affect systemd-oomd's kill behavior. Also note that these extended + attributes are not applied recursively to cgroups under this unit's cgroup. + + Defaults to which means systemd-oomd will rank this + unit's cgroup as defined in + systemd-oomd.service8 + and oomd.conf5. diff --git a/man/systemd.service.xml b/man/systemd.service.xml index 5da6d132e..350bc5f8e 100644 --- a/man/systemd.service.xml +++ b/man/systemd.service.xml @@ -292,7 +292,11 @@ will remove the file after the service has shut down if it still exists. The PID file does not need to be owned by a privileged user, but if it is owned by an unprivileged user additional safety restrictions are enforced: the file may not be a symlink to a file owned by a different user (neither directly nor indirectly), and the - PID file must refer to a process already belonging to the service. + PID file must refer to a process already belonging to the service. + + Note that PID files should be avoided in modern projects. Use or + where possible, which does not require use of PID files to determine the + main process of a service and avoids needless forking. @@ -752,14 +756,19 @@ If set to (the default), the service will not be restarted. If set to , it will be restarted only when the service process exits cleanly. - In this context, a clean exit means an exit code of 0, or one - of the signals - SIGHUP, - SIGINT, - SIGTERM or - SIGPIPE, and - additionally, exit statuses and signals specified in - SuccessExitStatus=. If set to + In this context, a clean exit means any of the following: + + exit code of 0; + for types other than + Type=oneshot, one of the signals + SIGHUP, + SIGINT, + SIGTERM, or + SIGPIPE; + exit statuses and signals specified in + SuccessExitStatus=. + + If set to , the service will be restarted when the process exits with a non-zero exit code, is terminated by a signal (including on core dump, but excluding @@ -780,7 +789,7 @@ abnormally by a signal, or hit a timeout. - Exit causes and the effect of the <varname>Restart=</varname> settings on them + Exit causes and the effect of the <varname>Restart=</varname> settings @@ -881,7 +890,7 @@ Takes a list of exit status definitions that, when returned by the main service process, will be considered successful termination, in addition to the normal successful exit status - 0 and the signals SIGHUP, SIGINT, + 0 and, except for Type=oneshot, the signals SIGHUP, SIGINT, SIGTERM, and SIGPIPE. Exit status definitions can be numeric termination statuses, termination status names, or termination signal names, separated by spaces. See the Process Exit Codes section in @@ -1103,11 +1112,9 @@ Check - systemd.exec5 - and - systemd.kill5 - for more settings. - + systemd.exec5 and + systemd.kill5 for more + settings. @@ -1122,21 +1129,13 @@ ExecStop=, and ExecStopPost= options. - Multiple command lines may be concatenated in a single - directive by separating them with semicolons (these semicolons - must be passed as separate words). Lone semicolons may be escaped - as \;. + Multiple command lines may be concatenated in a single directive by separating them with semicolons + (these semicolons must be passed as separate words). Lone semicolons may be escaped as + \;. - Each command line is split on whitespace, with the first item being the command to - execute, and the subsequent items being the arguments. Double quotes ("…") and single quotes - ('…') may be used to wrap a whole item (the opening quote may appear only at the beginning or - after whitespace that is not quoted, and the closing quote must be followed by whitespace or the - end of line), in which case everything until the next matching quote becomes part of the same - argument. Quotes themselves are removed. C-style escapes are also supported. The table below - contains the list of known escape patterns. Only escape patterns which match the syntax in the - table are allowed; other patterns may be added in the future and unknown patterns will result in - a warning. In particular, any backslashes should be doubled. Finally, a trailing backslash - (\) may be used to merge lines. + Each command line is unquoted using the rules described in "Quoting" section in + systemd.syntax5. The + first item becomes the command to execute, and the subsequent items the arguments. This syntax is inspired by shell syntax, but only the meta-characters and expansions described in the following paragraphs are understood, and the expansion of variables is @@ -1236,74 +1235,6 @@ ls >/dev/null, &, ;, and ls. - -
- C escapes supported in command lines and environment variables - - - - - - Literal - Actual value - - - - - \a - bell - - - \b - backspace - - - \f - form feed - - - \n - newline - - - \r - carriage return - - - \t - tab - - - \v - vertical tab - - - \\ - backslash - - - \" - double quotation mark - - - \' - single quotation mark - - - \s - space - - - \xxx - character number xx in hexadecimal encoding - - - \nnn - character number nnn in octal encoding - - - -
diff --git a/man/systemd.special.xml b/man/systemd.special.xml index a70e9ee0c..c9f320935 100644 --- a/man/systemd.special.xml +++ b/man/systemd.special.xml @@ -25,6 +25,8 @@ bluetooth.target, cryptsetup-pre.target, cryptsetup.target, + veritysetup-pre.target, + veritysetup.target, ctrl-alt-del.target, blockdev@.target, boot-complete.target, @@ -60,6 +62,7 @@ printer.target, reboot.target, remote-cryptsetup.target, + remote-veritysetup.target, remote-fs-pre.target, remote-fs.target, rescue.target, @@ -186,6 +189,13 @@ encrypted block devices.
+ + veritysetup.target + + A target that pulls in setup services for all + verity integrity protected block devices. + + dbus.service @@ -479,11 +489,10 @@ Services After the Network is up for more information. - All mount units for remote network file systems - automatically pull in this unit, and order themselves after - it. Note that networking daemons that simply provide - functionality to other hosts generally do not need to pull - this in. + All mount units for remote network file systems automatically pull in this unit, and order + themselves after it. Note that networking daemons that simply provide + functionality to other hosts (as opposed to consume functionality of other + hosts) generally do not need to pull this in. systemd automatically adds dependencies of type Wants= and After= for this target unit to all SysV init script service units @@ -552,6 +561,15 @@ entries marked with . + + remote-veritysetup.target + + Similar to veritysetup.target, but for verity + integrity protected devices which are accessed over the network. It is used for + veritytab8 + entries marked with . + + remote-fs.target @@ -855,7 +873,8 @@ This template unit is used to order mount units and other consumers of block devices after services that synthesize these block devices. In particular, this is intended to be used with storage services (such as - systemd-cryptsetup@.service5) + systemd-cryptsetup@.service5/ + systemd-veritysetup@.service5) that allocate and manage a virtual block device. Storage services are ordered before an instance of blockdev@.target, and the consumer units after it. The ordering is particularly relevant during shutdown, as it ensures that the mount is deactivated first and the @@ -879,6 +898,19 @@ stopped. + + veritysetup-pre.target + + This passive target unit may be pulled in by services + that want to run before any verity integrity protected block + device is set up. All verity integrity protected block + devices are set up after this target has been reached. Since + the shutdown order is implicitly the reverse start-up order + between units, this target is particularly useful to ensure + that a service is shut down only after all verity integrity + protected block devices are fully stopped. + + first-boot-complete.target @@ -916,20 +948,29 @@ network.target - This unit is supposed to indicate when network - functionality is available, but it is only very weakly - defined what that is supposed to mean, with one exception: - at shutdown, a unit that is ordered after - network.target will be stopped before - the network — to whatever level it might be set up then — - is shut down. It is hence useful when writing service files - that require network access on shutdown, which should order - themselves after this target, but not pull it in. Also see - Running - Services After the Network is up for more - information. Also see - network-online.target described - above. + This unit is supposed to indicate when network functionality is available, but it is only + very weakly defined what that is supposed to mean. However, the following should apply at + minimum: + + + At start-up, any configured synthetic network devices (i.e. not physical ones + that require hardware to show up and be probed, but virtual ones like bridge devices and + similar which are created programmatically) that do not depend on any underlying hardware + should be allocated by the time this target is reached. It is not necessary for these + interfaces to also have completed IP level configuration by the time + network.target is reached. + + At shutdown, a unit that is ordered after network.target + will be stopped before the network — to whatever level it might be set up by then — is shut + down. It is hence useful when writing service files that require network access on shutdown, + which should order themselves after this target, but not pull it in. Also see Running Services After + the Network is up for more information. + + + It must emphasized that at start-up there's no guarantee that hardware-based devices have + shown up by the time this target is reached, or even acquired complete IP configuration. For that + purpose use network-online.target as described above. @@ -972,7 +1013,7 @@ remote-fs-pre.target This target unit is automatically ordered before all - mount point units (see above) and cryptsetup devices + mount point units (see above) and cryptsetup/veritysetup devices marked with the . It can be used to run certain units before remote encrypted devices and mounts are established. Note that this unit is generally not part of the initial @@ -998,27 +1039,103 @@ time-set.target - Services responsible for setting the system clock from - a local source (such as a maintained timestamp file or - imprecise real-time clock) should pull in this target and - order themselves before it. Services where approximate time - is desired should be ordered after this unit, but not pull - it in. This target does not provide the accuracy guarantees - of time-sync.target. + Services responsible for setting the system clock (CLOCK_REALTIME) + from a local source (such as a maintained timestamp file or imprecise real-time clock) should + pull in this target and order themselves before it. Services where approximate, roughly monotonic + time is desired should be ordered after this unit, but not pull it in. + + This target does not provide the accuracy guarantees of + time-sync.target (see below), however does not depend on remote clock + sources to be reachable, i.e. the target is typically not delayed by network problems and + similar. Use of this target is recommended for services where approximate clock accuracy and + rough monotonicity is desired but activation shall not be delayed for possibly unreliable network + communication. + + The service manager automatically adds dependencies of type After= for + this target unit to all timer units with at least one OnCalendar= + directive. + + The + systemd-timesyncd.service8 + service is a simple daemon that pulls in this target and orders itself before it. Besides + implementing the SNTP network protocol it maintains a timestamp file on disk whose modification + time is regularlary updated. At service start-up the local system clock is set from that modification time, + ensuring it increases roughly monotonically. + + Note that ordering a unit after time-set.target only has effect if + there's actually a service ordered before it that delays it until the clock is adjusted for rough + monotonicity. Otherwise, this target might get reached before the clock is adjusted to be roughly + monotonic. Enable + systemd-timesyncd.service8, + or an alternative NTP implementation to delay the target. time-sync.target - Services responsible for synchronizing the system - clock from a remote source (such as NTP client - implementations) should pull in this target and order - themselves before it. All services where correct time is - essential should be ordered after this unit, but not pull it - in. systemd automatically adds dependencies of type - After= for this target unit to all SysV - init script service units with an LSB header referring to - the $time facility. + Services indicating completed synchronization of the system clock + (CLOCK_REALTIME) to a remote source should pull in this target and order + themselves before it. Services where accurate time is essential should be ordered after this + unit, but not pull it in. + + The service manager automatically adds dependencies of type After= for + this target unit to all SysV init script service units with an LSB header referring to the + $time facility, as well to all timer units with at least one + OnCalendar= directive. + + This target provides stricter clock accuracy guarantees than + time-set.target (see above), but likely requires + network communication and thus introduces unpredictable delays. + Services that require clock accuracy and where network + communication delays are acceptable should use this target. Services that require a less accurate + clock, and only approximate and roughly monotonic clock behaviour should use + time-set.target instead. + + Note that ordering a unit after time-sync.target only has effect if + there's actually a service ordered before it that delays it until clock synchronization is + reached. Otherwise, this target might get reached before the clock is synchronized to any remote + accurate reference clock. When using + systemd-timesyncd.service8, + enable + systemd-time-wait-sync.service8 + to delay the target; or use an equivalent service for other NTP implementations. + + + Comparison + + + + + + time-set.target + time-sync.target + + + + + "quick" to reach + "slow" to reach + + + typically uses local clock sources, boot process not affected by availability of external resources + typically uses remote clock sources, inserts dependencies on remote resources into boot process + + + reliable, because local + unreliable, because typically network involved + + + typically guarantees an approximate and roughly monotonic clock only + typically guarantees an accurate clock + + + implemented by systemd-timesyncd.service + implemented by systemd-time-wait-sync.service + + + +
+
@@ -1138,18 +1255,18 @@ gnome-session.target pulls in Nautilus as top-level service: [Unit] - Description=User systemd services for GNOME graphical session - Wants=nautilus.service - BindsTo=graphical-session.target +Description=User systemd services for GNOME graphical session +Wants=nautilus.service +BindsTo=graphical-session.target nautilus.service gets stopped when the session stops: [Unit] - Description=Render the desktop icons with Nautilus - PartOf=graphical-session.target +Description=Render the desktop icons with Nautilus +PartOf=graphical-session.target - [Service] - … +[Service] +…
@@ -1172,9 +1289,9 @@ The XDG specification defines a way to autostart applications using XDG desktop files. systemd ships systemd-xdg-autostart-generator8 - for the XDG desktop files in autostart directories. - Desktop Environments can opt-in to use this service by adding a Wants= - dependency on xdg-desktop-autostart.target. + for the XDG desktop files in autostart directories. Desktop Environments can opt-in to use this + service by adding a Wants= dependency on + xdg-desktop-autostart.target. diff --git a/man/systemd.syntax.xml b/man/systemd.syntax.xml index 7960adb65..e900747ae 100644 --- a/man/systemd.syntax.xml +++ b/man/systemd.syntax.xml @@ -74,10 +74,10 @@ .ini files. - Each file is a plain text file divided into sections, with configuration entries in the - style key=value. - Whitespace immediately before or after the = is ignored. Empty lines and lines starting with # or ; are - ignored, which may be used for commenting. + Each file is a plain text file divided into sections, with configuration entries in the style + key=value. Whitespace immediately before or after + the = is ignored. Empty lines and lines starting with # or + ; are ignored, which may be used for commenting. Lines ending in a backslash are concatenated with the following line while reading and the backslash is replaced by a space character. This may be used to wrap long lines. The limit on @@ -129,6 +129,96 @@ KeyThree=value 3\ file format. + + Quoting + + For settings where quoting is allowed, the following general rules apply: double quotes ("…") and + single quotes ('…') may be used to wrap a whole item (the opening quote may appear only at the beginning + or after whitespace that is not quoted, and the closing quote must be followed by whitespace or the end + of line), in which case everything until the next matching quote becomes part of the same item. Quotes + themselves are removed. C-style escapes are supported. The table below contains the list of known escape + patterns. Only escape patterns which match the syntax in the table are allowed; other patterns may be + added in the future and unknown patterns will result in a warning. In particular, any backslashes should + be doubled. Finally, a trailing backslash (\) may be used to merge lines, as described + above. UTF-8 is accepted, and hence typical unicode characters do not need to be escaped. + + + Supported escapes + + + + + + Literal + Actual value + + + + + \a + bell + + + \b + backspace + + + \f + form feed + + + \n + newline + + + \r + carriage return + + + \t + tab + + + \v + vertical tab + + + \\ + backslash + + + \" + double quotation mark + + + \' + single quotation mark + + + \s + space + + + \xxx + character number xx in hexadecimal encoding + + + \nnn + character number nnn in octal encoding + + + \unnnn + unicode code point nnnn in hexadecimal encoding + + + \Unnnnnnnn + unicode code point nnnnnnnn in hexadecimal encoding + + + +
+
+ See Also diff --git a/man/systemd.timer.xml b/man/systemd.timer.xml index 9fe7ff325..84c5bb564 100644 --- a/man/systemd.timer.xml +++ b/man/systemd.timer.xml @@ -81,10 +81,12 @@ units involved with early boot or late system shutdown should disable the DefaultDependencies= option. - Timer units - with at least one OnCalendar= directive will have an additional After= - dependency on time-sync.target to avoid being started before the system clock has been - correctly set. + Timer units with at least one OnCalendar= directive acquire a pair + of additional After= dependencies on time-set.target and + time-sync.target, in order to avoid being started before the system clock has + been correctly set. See + systemd.special7 + for details on these two targets. diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index 5364c4c97..42dcbac72 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -45,9 +45,9 @@ /run/systemd/transient/* /run/systemd/generator.early/* /etc/systemd/system/* -/etc/systemd/systemd.attached/* +/etc/systemd/system.attached/* /run/systemd/system/* -/run/systemd/systemd.attached/* +/run/systemd/system.attached/* /run/systemd/generator/* /usr/lib/systemd/system/* @@ -60,7 +60,7 @@ $XDG_RUNTIME_DIR/systemd/user.control/* $XDG_RUNTIME_DIR/systemd/transient/* $XDG_RUNTIME_DIR/systemd/generator.early/* -$XDG_CONFIG_HOME/systemd/user/* +~/.config/systemd/user/* $XDG_CONFIG_DIRS/systemd/user/* /etc/systemd/user/* $XDG_RUNTIME_DIR/systemd/user/* @@ -163,7 +163,7 @@ section. When the unit is enabled, symlinks will be created for those names, and removed when the unit is disabled. For example, reboot.target specifies Alias=ctrl-alt-del.target, so when enabled, the symlink - /etc/systemd/systemd/ctrl-alt-del.service pointing to the + /etc/systemd/system/ctrl-alt-del.service pointing to the reboot.target file will be created, and when CtrlAltDel is invoked, systemd will look for the ctrl-alt-del.service and execute @@ -190,8 +190,8 @@ headers. For instantiated units, this logic will first look for the instance .d/ subdirectory (e.g. foo@bar.service.d/) and read its .conf files, followed by the template .d/ subdirectory (e.g. foo@.service.d/) and the .conf - files there. Moreover for units names containing dashes (-), the set of directories generated by - truncating the unit name after all dashes is searched too. Specifically, for a unit name + files there. Moreover for unit names containing dashes (-), the set of directories generated by + repeatedly truncating the unit name after all dashes is searched too. Specifically, for a unit name foo-bar-baz.service not only the regular drop-in directory foo-bar-baz.service.d/ is searched but also both foo-bar-.service.d/ and foo-.service.d/. This is useful for defining common drop-ins for a set of related units, whose @@ -596,11 +596,11 @@ Wants= - Configures requirement dependencies on other units. This option may be specified more - than once or multiple space-separated units may be specified in one option in which case dependencies - for all listed names will be created. Dependencies of this type may also be configured outside of the - unit configuration file by adding a symlink to a .wants/ directory accompanying - the unit file. For details, see above. + Configures (weak) requirement dependencies on other units. This option may be + specified more than once or multiple space-separated units may be specified in one option in which + case dependencies for all listed names will be created. Dependencies of this type may also be + configured outside of the unit configuration file by adding a symlink to a + .wants/ directory accompanying the unit file. For details, see above. Units listed in this option will be started if the configuring unit is. However, if the listed units fail to start or cannot be added to the transaction, this has no impact on the validity of the @@ -619,7 +619,7 @@ Requires= - Similar to Wants=, but declares a stronger + Similar to Wants=, but declares a stronger requirement dependency. Dependencies of this type may also be configured by adding a symlink to a .requires/ directory accompanying the unit file. @@ -799,14 +799,16 @@ For units that start processes (such as service units), lists one or more other units whose network and/or temporary file namespace to join. This only applies to unit types which support - the PrivateNetwork=, NetworkNamespacePath= and + the PrivateNetwork=, NetworkNamespacePath=, + PrivateIPC=, IPCNamespacePath=, and PrivateTmp= directives (see systemd.exec5 for details). If a unit that has this setting set is started, its processes will see the same - /tmp/, /var/tmp/ and network namespace as one listed unit - that is started. If multiple listed units are already started, it is not defined which namespace is - joined. Note that this setting only has an effect if - PrivateNetwork=/NetworkNamespacePath= and/or + /tmp/, /var/tmp/, IPC namespace and network namespace as + one listed unit that is started. If multiple listed units are already started, it is not defined + which namespace is joined. Note that this setting only has an effect if + PrivateNetwork=/NetworkNamespacePath=, + PrivateIPC=/IPCNamespacePath= and/or PrivateTmp= is enabled for both the unit that joins the namespace and the unit whose namespace is joined. @@ -976,16 +978,24 @@ JobTimeoutSec= JobRunningTimeoutSec= - When a job for this unit is queued, a timeout JobTimeoutSec= may be - configured. Similarly, JobRunningTimeoutSec= starts counting when the queued job is actually - started. If either time limit is reached, the job will be cancelled, the unit however will not change state or - even enter the failed mode. This value defaults to infinity (job timeouts - disabled), except for device units (JobRunningTimeoutSec= defaults to - DefaultTimeoutStartSec=). NB: this timeout is independent from any unit-specific timeout - (for example, the timeout set with TimeoutStartSec= in service units) as the job timeout has - no effect on the unit itself, only on the job that might be pending for it. Or in other words: unit-specific - timeouts are useful to abort unit state changes, and revert them. The job timeout set with this option however - is useful to abort only the job waiting for the unit state to change. + JobTimeoutSec= specifies a timeout for the whole job that starts + running when the job is queued. JobRunningTimeoutSec= specifies a timeout that + starts running when the queued job is actually started. If either limit is reached, the job will be + cancelled, the unit however will not change state or even enter the failed mode. + + + Both settings take a time span with the default unit of seconds, but other units may be + specified, see + systemd.time5. + The default is infinity (job timeouts disabled), except for device units where + JobRunningTimeoutSec= defaults to DefaultTimeoutStartSec=. + + + Note: these timeouts are independent from any unit-specific timeouts (for example, the timeout + set with TimeoutStartSec= in service units). The job timeout has no effect on the + unit itself. Or in other words: unit-specific timeouts are useful to abort unit state changes, and + revert them. The job timeout set with this option however is useful to abort only the job waiting for + the unit state to change. @@ -993,13 +1003,14 @@ JobTimeoutAction= JobTimeoutRebootArgument= - JobTimeoutAction= optionally configures an additional action to take when - the timeout is hit, see description of JobTimeoutSec= and + JobTimeoutAction= optionally configures an additional action to + take when the timeout is hit, see description of JobTimeoutSec= and JobRunningTimeoutSec= above. It takes the same values as - StartLimitAction=. Defaults to . - JobTimeoutRebootArgument= configures an optional reboot string to pass to the - reboot2 system call. - + StartLimitAction=. Defaults to . + + JobTimeoutRebootArgument= configures an optional reboot string to pass to + the reboot2 system + call. @@ -1007,28 +1018,39 @@ StartLimitBurst=burst Configure unit start rate limiting. Units which are started more than - burst times within an interval time interval are not - permitted to start any more. Use StartLimitIntervalSec= to configure the checking interval - (defaults to DefaultStartLimitIntervalSec= in manager configuration file, set it to 0 to - disable any kind of rate limiting). Use StartLimitBurst= to configure how many starts per - interval are allowed (defaults to DefaultStartLimitBurst= in manager configuration - file). These configuration options are particularly useful in conjunction with the service setting - Restart= (see - systemd.service5); however, - they apply to all kinds of starts (including manual), not just those triggered by the - Restart= logic. Note that units which are configured for Restart= and - which reach the start limit are not attempted to be restarted anymore; however, they may still be restarted - manually at a later point, after the interval has passed. From this point on, the - restart logic is activated again. Note that systemctl reset-failed will cause the restart - rate counter for a service to be flushed, which is useful if the administrator wants to manually start a unit - and the start limit interferes with that. Note that this rate-limiting is enforced after any unit condition - checks are executed, and hence unit activations with failing conditions do not count towards this rate - limit. This setting does not apply to slice, target, device, and scope units, since they are unit types whose - activation may either never fail, or may succeed only a single time. + burst times within an interval time span are + not permitted to start any more. Use StartLimitIntervalSec= to configure the + checking interval and StartLimitBurst= to configure how many starts per interval + are allowed. - When a unit is unloaded due to the garbage collection logic (see above) its rate limit counters are - flushed out too. This means that configuring start rate limiting for a unit that is not referenced continuously - has no effect. + interval is a time span with the default unit of seconds, but other + units may be specified, see + systemd.time5. + Defaults to DefaultStartLimitIntervalSec= in manager configuration file, and may + be set to 0 to disable any kind of rate limiting. burst is a number and + defaults to DefaultStartLimitBurst= in manager configuration file. + + These configuration options are particularly useful in conjunction with the service setting + Restart= (see + systemd.service5); + however, they apply to all kinds of starts (including manual), not just those triggered by the + Restart= logic. + + Note that units which are configured for Restart=, and which reach the start + limit are not attempted to be restarted anymore; however, they may still be restarted manually or + from a timer or socket at a later point, after the interval has passed. + From that point on, the restart logic is activated again. systemctl reset-failed + will cause the restart rate counter for a service to be flushed, which is useful if the administrator + wants to manually start a unit and the start limit interferes with that. Rate-limiting is enforced + after any unit condition checks are executed, and hence unit activations with failing conditions do + not count towards the rate limit. + + When a unit is unloaded due to the garbage collection logic (see above) its rate limit counters + are flushed out too. This means that configuring start rate limiting for a unit that is not + referenced continuously has no effect. + + This setting does not apply to slice, target, device, and scope units, since they are unit + types whose activation may either never fail, or may succeed only a single time. @@ -1063,28 +1085,32 @@ Conditions and Asserts - Unit files may also include a number of Condition…= and - Assert…= settings. Before the unit is started, systemd will verify - that the specified conditions are true. If not, the starting of the unit will be (mostly silently) - skipped. Failing conditions will not result in the unit being moved into the failed - state. The conditions are checked at the time the queued start job is to be executed. The ordering - dependencies are still respected, so other units are still pulled in and ordered as if this unit was - successfully activated. Use condition expressions in order to skip units that do not apply to the local - system, for example because the kernel or runtime environment doesn't require their functionality. + Unit files may also include a number of Condition…= and Assert…= settings. Before the unit is started, systemd will verify that the + specified conditions and asserts are true. If not, the starting of the unit will be (mostly silently) + skipped (in case of conditions), or aborted with an error message (in case of asserts). Failing + conditions or asserts will not result in the unit being moved into the failed + state. The conditions and asserts are checked at the time the queued start job is to be executed. The + ordering dependencies are still respected, so other units are still pulled in and ordered as if this + unit was successfully activated, and the conditions and asserts are executed the precise moment the + unit would normally start and thus can validate system state after the units ordered before completed + initialization. Use condition expressions for skipping units that do not apply to the local system, for + example because the kernel or runtime environment doesn't require their functionality. If multiple conditions are specified, the unit will be executed if all of them apply (i.e. a logical AND is applied). Condition checks can use a pipe symbol (|) after the equals - sign (Condition…=|…), which causes the condition becomes a triggering condition. If - at least one triggering condition is defined for a unit, then the unit will be executed if at least one - of the triggering conditions apply and all of the non-triggering conditions. If you prefix an argument - with the pipe symbol and an exclamation mark, the pipe symbol must be passed first, the exclamation - second. If any of these options is assigned the empty string, the list of conditions is reset - completely, all previous condition settings (of any kind) will have no effect. + sign (Condition…=|…), which causes the condition to become a + triggering condition. If at least one triggering condition is defined for a unit, + then the unit will be started if at least one of the triggering conditions of the unit applies and all + of the regular (i.e. non-triggering) conditions apply. If you prefix an argument with the pipe symbol + and an exclamation mark, the pipe symbol must be passed first, the exclamation second. If any of these + options is assigned the empty string, the list of conditions is reset completely, all previous + condition settings (of any kind) will have no effect. The AssertArchitecture=, AssertVirtualization=, … options - provide a similar mechanism that causes the job to fail (instead of being skipped). The failed check is - logged. Units with failed conditions are considered to be in a clean state and will be garbage + are similar to conditions but cause the start job to fail (instead of being skipped). The failed check + is logged. Units with failed conditions are considered to be in a clean state and will be garbage collected if they are not referenced. This means that when queried, the condition failure may or may not show up in the state of the unit. @@ -1257,9 +1283,9 @@ ConditionSecurity= may be used to check whether the given security technology is enabled on the system. Currently, the recognized values are selinux, apparmor, tomoyo, - ima, smack, audit and - uefi-secureboot. The test may be negated by prepending an exclamation - mark. + ima, smack, audit, + uefi-secureboot and tpm2. The test may be negated by prepending + an exclamation mark. @@ -1452,14 +1478,25 @@ ConditionControlGroupController= - Verify that the given cgroup controller (eg. cpu) is available - for use on the system. For example, a particular controller may not be available if it was disabled - on the kernel command line with cgroup_disable=controller. Multiple controllers - may be passed with a space separating them; in this case the condition will only pass if all listed - controllers are available for use. Controllers unknown to systemd are ignored. Valid controllers - are cpu, cpuacct, io, - blkio, memory, devices, and - pids. + Check whether given cgroup controllers (eg. cpu) are available + for use on the system or whether the legacy v1 cgroup or the modern v2 cgroup hierarchy is used. + + + Multiple controllers may be passed with a space separating them; in this case the condition + will only pass if all listed controllers are available for use. Controllers unknown to systemd are + ignored. Valid controllers are cpu, cpuacct, + io, blkio, memory, + devices, and pids. Even if available in the kernel, a + particular controller may not be available if it was disabled on the kernel command line with + cgroup_disable=controller. + + Alternatively, two special strings v1 and v2 may be + specified (without any controller names). v2 will pass if the unified v2 cgroup + hierarchy is used, and v1 will pass if the legacy v1 hierarchy or the hybrid + hierarchy are used (see the discussion of systemd.unified_cgroup_hierarchy and + systemd.legacy_systemd_cgroup_controller in + systemd.service5 + for more information). @@ -1489,12 +1526,75 @@ to the container and not the physically available ones. + + ConditionCPUFeature= + + Verify that a given CPU feature is available via the CPUID + instruction. This condition only does something on i386 and x86-64 processors. On other + processors it is assumed that the CPU does not support the given feature. It checks the leaves + 1, 7, 0x80000001, and + 0x80000007. Valid values are: + fpu, + vme, + de, + pse, + tsc, + msr, + pae, + mce, + cx8, + apic, + sep, + mtrr, + pge, + mca, + cmov, + pat, + pse36, + clflush, + mmx, + fxsr, + sse, + sse2, + ht, + pni, + pclmul, + monitor, + ssse3, + fma3, + cx16, + sse4_1, + sse4_2, + movbe, + popcnt, + aes, + xsave, + osxsave, + avx, + f16c, + rdrand, + bmi1, + avx2, + bmi2, + rdseed, + adx, + sha_ni, + syscall, + rdtscp, + lm, + lahf_lm, + abm, + constant_tsc. + + + AssertArchitecture= AssertVirtualization= AssertHost= AssertKernelCommandLine= AssertKernelVersion= + AssertEnvironment= AssertSecurity= AssertCapability= AssertACPower= @@ -1506,12 +1606,15 @@ AssertPathIsSymbolicLink= AssertPathIsMountPoint= AssertPathIsReadWrite= + AssertPathIsEncrypted= AssertDirectoryNotEmpty= AssertFileNotEmpty= AssertFileIsExecutable= AssertUser= AssertGroup= AssertControlGroupController= + AssertMemory= + AssertCPUs= Similar to the ConditionArchitecture=, ConditionVirtualization=, …, condition settings described above, these settings diff --git a/man/systemd.xml b/man/systemd.xml index 882b5a6c7..c60f220f3 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -609,41 +609,63 @@ Environment + The environment block for the system manager is initially set by the kernel. (In particular, + key=value assignments on the kernel command line are returned into environment + variables for PID 1). For the user manager, the system manager sets the environment as described in the + "Environment Variables in Spawned Processes" section of + systemd.exec5. The + DefaultEnvironment= setting in the system manager applies to all services including + user@.service. Additional entries may be configured (as for any other service) + through the Environment= and EnvironmentFile= settings for + user@.service (see + systemd.exec5). Also, + additional environment variables may be set through the ManagerEnvironment= setting in + systemd-system.conf5 + and + systemd-user.conf5. + + + Some of the variables understood by systemd: + - - $SYSTEMD_LOG_COLOR - Controls whether systemd highlights important log messages. This can be overridden - with . - - $SYSTEMD_LOG_LEVEL - systemd reads the log level from this environment variable. This can be overridden - with . + + + This can be overridden with . - $SYSTEMD_LOG_LOCATION - Controls whether systemd prints the code location along with log messages. This can - be overridden with . - + $SYSTEMD_LOG_COLOR + - - $SYSTEMD_LOG_TARGET - systemd reads the log target from this environment variable. This can be overridden - with . + This can be overridden with . $SYSTEMD_LOG_TIME - Controls whether systemd prefixes log messages with the current time. This can be - overridden with . + + + This can be overridden with . + + + + $SYSTEMD_LOG_LOCATION + + + This can be overridden with . $SYSTEMD_LOG_TID - Controls whether systemd prefixes log messages with the current thread ID - (TID). + + + + + $SYSTEMD_LOG_TARGET + + + This can be overridden with . @@ -674,26 +696,12 @@ - - $SYSTEMD_SYSVINIT_PATH - - Controls where systemd looks for SysV init - scripts. - - - - $SYSTEMD_SYSVRCND_PATH - - Controls where systemd looks for SysV init - script runlevel link farms. - - - - - - - - + + + + + + $LISTEN_PID @@ -1090,12 +1098,11 @@ only the options described below are understood. Nevertheless, systemd is usually started in this mode through the user@.service5 - service, which is shared between all users, and it may be more convenient to use configuration files to + service, which is shared between all users. It may be more convenient to use configuration files to modify settings (see systemd-user.conf5), - or a drop-in that specifies one of the environment variables listed above in the Environment section - (see the discussion of Environment= and EnvironmentFile= in - systemd.exec5). + or environment variables. See the "Environment" section above for a discussion of how the environment + block is set. diff --git a/man/sysusers.d.xml b/man/sysusers.d.xml index a76dda954..e15c1b2ee 100644 --- a/man/sysusers.d.xml +++ b/man/sysusers.d.xml @@ -216,6 +216,11 @@ r - 500-900 Only applies to lines of type u and should otherwise be left unset (or -). It is recommended to omit this, unless software strictly requires a home directory to be set. + + systemd-sysusers only sets the home directory record in the + user database. To actually create the directory, consider adding a corresponding + tmpfiles.d5 + fragment. diff --git a/man/timedatectl.xml b/man/timedatectl.xml index e7db4870c..ce1415237 100644 --- a/man/timedatectl.xml +++ b/man/timedatectl.xml @@ -253,7 +253,7 @@ On success, 0 is returned, a non-zero failure code otherwise. - + Examples diff --git a/man/timesyncd.conf.xml b/man/timesyncd.conf.xml index 1cbea9eaa..3fd11cea0 100644 --- a/man/timesyncd.conf.xml +++ b/man/timesyncd.conf.xml @@ -47,48 +47,60 @@ NTP= - A space-separated list of NTP server host - names or IP addresses. During runtime this list is combined - with any per-interface NTP servers acquired from + A space-separated list of NTP server host names or IP addresses. During runtime this + list is combined with any per-interface NTP servers acquired from systemd-networkd.service8. - systemd-timesyncd will contact all configured system or - per-interface servers in turn until one is found that - responds. When the empty string is assigned, the list of - NTP servers is reset, and all assignments prior to this one - will have no effect. This setting defaults to an empty - list. + systemd-timesyncd will contact all configured system or per-interface servers in + turn, until one responds. When the empty string is assigned, the list of NTP servers is reset, and + all prior assignments will have no effect. This setting defaults to an empty list. FallbackNTP= - A space-separated list of NTP server host - names or IP addresses to be used as the fallback NTP servers. - Any per-interface NTP servers obtained from + A space-separated list of NTP server host names or IP addresses to be used as the + fallback NTP servers. Any per-interface NTP servers obtained from systemd-networkd.service8 - take precedence over this setting, as do any servers set via - NTP= above. This setting is hence only used - if no other NTP server information is known. When the empty - string is assigned, the list of NTP servers is reset, - and all assignments prior to this one will have no effect. - If this option is not given, a compiled-in list of NTP servers - is used instead. + take precedence over this setting, as do any servers set via NTP= above. This + setting is hence only relevant if no other NTP server information is known. When the empty string is + assigned, the list of NTP servers is reset, and all prior assignments will have no effect. If this + option is not given, a compiled-in list of NTP servers is used. RootDistanceMaxSec= - Maximum acceptable root distance. Takes a time value (in seconds). + Maximum acceptable root distance, i.e. the maximum estimated time required for a + packet to travel to the server we are connected to from the server with the reference clock. If + the current server does not satisfy this limit, systemd-timesyncd will switch + to a different server. + + Takes a time span value. The default unit is seconds, but other units may be specified, see + systemd.time5. Defaults to 5 seconds. PollIntervalMinSec= PollIntervalMaxSec= - The minimum and maximum poll intervals for NTP messages. - Each setting takes a time value (in seconds). - PollIntervalMinSec= must not be smaller than 16 seconds. - PollIntervalMaxSec= must be larger than PollIntervalMinSec=. - PollIntervalMinSec= defaults to 32 seconds, and - PollIntervalMaxSec= defaults to 2048 seconds. + The minimum and maximum poll intervals for NTP messages. Polling starts at the + minimum poll interval, and is adjusted within the specified limits in response to received packets. + + + Each setting takes a time span value. The default unit is seconds, but other units may be + specified, see + systemd.time5. + PollIntervalMinSec= defaults to 32 seconds and must not be smaller than + 16 seconds. PollIntervalMaxSec= defaults to 34 min 8 s (2048 seconds) and must be + larger than PollIntervalMinSec=. + + + + ConnectionRetrySec= + Specifies the minimum delay before subsequent attempts to contact a new NTP server + are made. + + Takes a time span value. The default unit is seconds, but other units may be specified, see + systemd.time5. + Defaults to 30 seconds and must not be smaller than 1 second. diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml index 49ce8375a..4adbf6bb0 100644 --- a/man/tmpfiles.d.xml +++ b/man/tmpfiles.d.xml @@ -145,14 +145,17 @@ A+ /path-or-glob/to/append/acls/recursively - - - - POSIX Configuration File Format - The configuration format is one line per path containing - type, path, mode, ownership, age, and argument fields: + The configuration format is one line per path, containing type, path, mode, ownership, age, and + argument fields. The lines are separated by newlines, the fields by whitespace: - #Type Path Mode User Group Age Argument + #Type Path Mode User Group Age Argument… d /run/user 0755 root root 10d - L /tmp/foobar - - - - /dev/null - Fields may be enclosed within quotes and contain C-style escapes. + Fields may contain C-style escapes. With the exception of the seventh field (the "argument") all + fields may be enclosed in quotes. Note that any whitespace found in the line after the beginning of the + argument field will be considered part of the argument field. To begin the argument field with a + whitespace character, use C-style escapes (e.g. \x20). Type diff --git a/man/tpm2-crypttab.sh b/man/tpm2-crypttab.sh new file mode 100644 index 000000000..41db2aedd --- /dev/null +++ b/man/tpm2-crypttab.sh @@ -0,0 +1,10 @@ +# Enroll the TPM2 security chip in the LUKS2 volume, and bind it to PCR 7 +# only. Replace /dev/sdXn by the partition to use (e.g. /dev/sda1). +sudo systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=7 /dev/sdXn + +# Test: Let's run systemd-cryptsetup to test if this worked. +sudo /usr/lib/systemd/systemd-cryptsetup attach mytest /dev/sdXn - tpm2-device=auto + +# If that worked, let's now add the same line persistently to /etc/crypttab, +# for the future. +sudo bash -c 'echo "mytest /dev/sdXn - tpm2-device=auto" >> /etc/crypttab' diff --git a/man/udev.xml b/man/udev.xml index 14e4c21aa..8782bb15c 100644 --- a/man/udev.xml +++ b/man/udev.xml @@ -79,14 +79,16 @@ == - Compare for equality. + Compare for equality. (The specified key has the specified value.) != - Compare for inequality. + Compare for inequality. (The specified key doesn't have the specified value, or the + specified key is not present at all.) + @@ -125,7 +127,7 @@ Values Values are written as double quoted strings, such as ("string"). To include a quotation mark (") in the value, precede it by a backslash (\"). - Any other occurrences of a character followed by a backslash are not further unescaped. + Any other occurrences of a backslash followed by a character are not unescaped. That is, "\t\n" is treated as four characters: backslash, lowercase t, backslash, lowercase n. @@ -166,6 +168,13 @@ + + KERNELS + + Search the devpath upwards for a matching device name. + + + NAME @@ -190,36 +199,6 @@ Match the subsystem of the event device. - - DRIVER - - Match the driver name of the event device. Only set this key for devices - which are bound to a driver at the time the event is generated. - - - - ATTR{filename} - - Match sysfs attribute values of the event device. Trailing - whitespace in the attribute values is ignored unless the specified match - value itself contains trailing whitespace. - - - - - SYSCTL{kernel parameter} - - Match a kernel parameter value. - - - - - - KERNELS - - Search the devpath upwards for a matching device name. - - SUBSYSTEMS @@ -228,6 +207,14 @@ + + DRIVER + + Match the driver name of the event device. Only set this key for devices + which are bound to a driver at the time the event is generated. + + + DRIVERS @@ -236,19 +223,31 @@ - ATTRS{filename} + ATTR{filename} - Search the devpath upwards for a device with matching sysfs attribute values. - If multiple ATTRS matches are specified, all of them - must match on the same device. Trailing whitespace in the attribute values is ignored - unless the specified match value itself contains trailing whitespace. + Match sysfs attribute value of the event device. + + Trailing whitespace in the attribute values is ignored unless the specified match value + itself contains trailing whitespace. - TAGS + ATTRS{filename} - Search the devpath upwards for a device with matching tag. + Search the devpath upwards for a device with matching sysfs attribute values. If + multiple ATTRS matches are specified, all of them must match on the same + device. + + Trailing whitespace in the attribute values is ignored unless the specified match value + itself contains trailing whitespace. + + + + + SYSCTL{kernel parameter} + + Match a kernel parameter value. @@ -292,6 +291,13 @@ + + TAGS + + Search the devpath upwards for a device with matching tag. + + + TEST{octal mode mask} @@ -459,7 +465,7 @@ Specify a program to be executed after processing of all the rules for the event. With +=, this invocation is added to the list, and with = or :=, it replaces any previous contents of the list. Please note that both - program and builtin types described below use a single + program and builtin types described below share a common list, so clearing the list with := and = affects both types. @@ -647,6 +653,24 @@ on the transition from initramfs. + + + + Takes a log level name like debug or + info, or a special value reset. When a log + level name is specified, the maximum log level is changed to that level. When + reset is set, then the previously specified log level is + revoked. Defaults to the log level of the main process of + systemd-udevd. + This may be useful when debugging events for certain devices. Note that the + log level is applied when the line including this rule is processed. So, for + debugging, it is recommended that this is specified at earlier place, e.g., the + first line of 00-debug.rules. + Example for debugging uevent processing for network interfaces. + # /etc/udev/rules.d/00-debug-net.rules +SUBSYSTEM=="net", OPTIONS="log_level=debug" + + diff --git a/man/udevadm.xml b/man/udevadm.xml index ec26cc3c0..b731f808b 100644 --- a/man/udevadm.xml +++ b/man/udevadm.xml @@ -212,6 +212,13 @@ Do not actually trigger the event. + + + + + Suppress error logging in triggering events. + + diff --git a/man/user-system-options.xml b/man/user-system-options.xml index 728118e60..f3bafaea3 100644 --- a/man/user-system-options.xml +++ b/man/user-system-options.xml @@ -45,8 +45,14 @@ - Execute operation on a local container. Specify a - container name to connect to. + Execute operation on a local container. Specify a container name to connect to, optionally + prefixed by a user name to connect as and a separating @ character. If the special + string .host is used in place of the container name, a connection to the local + system is made (which is useful to connect to a specific user's user bus: --user + --machine=lennart@.host). If the @ syntax is not used, the connection is + made as root user. If the @ syntax is used either the left hand side or the right hand + side may be omitted (but not both) in which case the local user name and .host are + implied. diff --git a/man/userdbctl.xml b/man/userdbctl.xml index 0c2dd73bb..896ad2225 100644 --- a/man/userdbctl.xml +++ b/man/userdbctl.xml @@ -36,8 +36,8 @@ userdbctl may be used to inspect user and groups (as well as group memberships) of the system. This client utility inquires user/group information provided by various system services, both operating on JSON user/group records (as defined by the JSON User Record and JSON Group Record definitions), and classic UNIX NSS/glibc + url="https://systemd.io/USER_RECORD">JSON User Records and JSON Group Records definitions), and classic UNIX NSS/glibc user and group records. This tool is primarily a client to the User/Group Record Lookup API via Varlink. @@ -215,7 +215,7 @@ - io.systemd.NameSeviceSwitch + io.systemd.NameServiceSwitch This service is (also) provided by systemd-userdbd.service8 @@ -232,7 +232,7 @@ Note that userdbctl has internal support for NSS-based lookups too. This means that if neither io.systemd.Multiplexer nor - io.systemd.NameSeviceSwitch are running look-ups into the basic user/group + io.systemd.NameServiceSwitch are running look-ups into the basic user/group databases will still work. @@ -256,7 +256,7 @@ AuthorizedKeysCommandUser root On success, 0 is returned, a non-zero failure code otherwise. - + See Also diff --git a/man/veritytab.xml b/man/veritytab.xml new file mode 100644 index 000000000..d29e9f5f2 --- /dev/null +++ b/man/veritytab.xml @@ -0,0 +1,198 @@ + + + + + + + + veritytab + systemd + + + + veritytab + 5 + + + + veritytab + Configuration for verity block devices + + + + /etc/veritytab + + + + Description + + The /etc/veritytab file describes + verity integrity protected block devices that are set up during + system boot. + + Empty lines and lines starting with the # + character are ignored. Each of the remaining lines describes one + verity integrity protected block device. Fields are delimited by + white space. + + Each line is in the formvolume-name data-device hash-device roothash options + The first four fields are mandatory, the remaining one is optional. + + The first field contains the name of the resulting verity volume; its block device is set up + below /dev/mapper/. + + The second field contains a path to the underlying block data device, or a specification of a block device via + UUID= followed by the UUID. + + The third field contains a path to the underlying block hash device, or a specification of a block device via + UUID= followed by the UUID. + + The fourth field is the roothash in hexadecimal. + + The fifth field, if present, is a comma-delimited list of options. The following options are + recognized: + + + + + + + + + Defines what to do if data integrity problem is detected (data corruption). Without these + options kernel fails the IO operation with I/O error. With --ignore-corruption option the + corruption is only logged. With --restart-on-corruption or + --panic-on-corruption the kernel is restarted (panicked) immediately. + + (You have to provide way how to avoid restart loops.) + + + + + + Instruct kernel to not verify blocks that are expected to contain zeroes and always directly + return zeroes instead. + + WARNING: Use this option only in very specific cases. This option is available since Linux kernel version 4.5. + + + + + + + Instruct kernel to verify blocks only the first time they are read from the data device, rather + than every time. + + WARNING: It provides a reduced level of security because only offline tampering of the data device's content + will be detected, not online tampering. This option is available since Linux kernel version 4.17. + + + + + + + A base64 string encoding the root hash signature prefixed by base64: or a + path to roothash signature file used to verify the root hash (in kernel). This feature requires Linux kernel + version 5.4 or more recent. + + + + + + Marks this veritysetup device as requiring network. It will be + started after the network is available, similarly to + systemd.mount5 + units marked with . The service unit to set up this device + will be ordered between remote-fs-pre.target and + remote-veritysetup.target, instead of + veritysetup-pre.target and + veritysetup.target. + + Hint: if this device is used for a mount point that is specified in + fstab5, + the option should also be used for the mount + point. Otherwise, a dependency loop might be created where the mount point + will be pulled in by local-fs.target, while the + service to configure the network is usually only started after + the local file system has been mounted. + + + + + + + This device will not be added to veritysetup.target. + This means that it will not be automatically enabled on boot, unless something else pulls + it in. In particular, if the device is used for a mount point, it'll be enabled + automatically during boot, unless the mount point itself is also disabled with + . + + + + + + This device will not be a hard dependency of + veritysetup.target. It'll still be pulled in and started, but the system + will not wait for the device to show up and be enabled, and boot will not fail if this is + unsuccessful. Note that other units that depend on the enabled device may still fail. In + particular, if the device is used for a mount point, the mount point itself also needs to + have the option, or the boot will fail if the device is not enabled + successfully. + + + + + + Setup this verity integrity protected block device in the initramfs, similarly to + systemd.mount5 + units marked with . + + Although it's not necessary to mark the mount entry for the root file system with + , is still recommended with + the verity integrity protected block device containing the root file system as otherwise systemd + will attempt to detach the device during the regular system shutdown while it's still in + use. With this option the device will still be detached but later after the root file + system is unmounted. + + All other verity integrity protected block devices that contain file systems mounted in the + initramfs should use this option. + + + + + + At early boot and when the system manager configuration is + reloaded, this file is translated into native systemd units by + systemd-veritysetup-generator8. + + + + Examples + + /etc/veritytab example + Set up two verity integrity protected block devices. One using device blocks, another using files. + + usr PARTUUID=783e45ae-7aa3-484a-beef-a80ff9c19cbb PARTUUID=21dc1dfe-4c33-8b48-98a9-918a22eb3e37 36e3f740ad502e2c25e2a23d9c7c17bf0fdad2300b7580842d4b7ec1fb0fa263 auto +data /etc/data /etc/hash a5ee4b42f70ae1f46a08a7c92c2e0a20672ad2f514792730f5d49d7606ab8fdf auto + + + + + + See Also + + systemd1, + systemd-veritysetup@.service8, + systemd-veritysetup-generator8, + fstab5, + veritysetup8, + + + + diff --git a/man/yubikey-crypttab.sh b/man/yubikey-crypttab.sh index 651246d6a..05e581b32 100644 --- a/man/yubikey-crypttab.sh +++ b/man/yubikey-crypttab.sh @@ -1,50 +1,26 @@ -# Make sure no one can read the files we generate but us -umask 077 - # Destroy any old key on the Yubikey (careful!) ykman piv reset -# Generate a new private/public key pair on the device, store the public key in 'pubkey.pem'. +# Generate a new private/public key pair on the device, store the public key in +# 'pubkey.pem'. ykman piv generate-key -a RSA2048 9d pubkey.pem # Create a self-signed certificate from this public key, and store it on the -# device. The "subject" should be an arbitrary string to identify the token in -# the p11tool output below. +# device. The "subject" should be an arbitrary user-chosen string to identify +# the token with. ykman piv generate-certificate --subject "Knobelei" 9d pubkey.pem -# Check if the newly create key on the Yubikey shows up as token in PKCS#11. Have a look at the output, and -# copy the resulting token URI to the clipboard. -p11tool --list-tokens - -# Generate a (secret) random key to use as LUKS decryption key. -dd if=/dev/urandom of=plaintext.bin bs=128 count=1 - -# Encode the secret key also as base64 text (with all whitespace removed) -base64 < plaintext.bin | tr -d '\n\r\t ' > plaintext.base64 - -# Encrypt this newly generated (binary) LUKS decryption key using the public key whose private key is on the -# Yubikey, store the result in /etc/cryptsetup-keys.d/mytest.key, where we'll look for it during boot. -mkdir -p /etc/cryptsetup-keys.d -sudo openssl rsautl -encrypt -pubin -inkey pubkey.pem -in plaintext.bin -out /etc/cryptsetup-keys.d/mytest.key - -# Configure the LUKS decryption key on the LUKS device. We use very low pbkdf settings since the key already -# has quite a high quality (it comes directly from /dev/urandom after all), and thus we don't need to do much -# key derivation. Replace /dev/sdXn by the partition to use (e.g. sda1) -sudo cryptsetup luksAddKey /dev/sdXn plaintext.base64 --pbkdf=pbkdf2 --pbkdf-force-iterations=1000 - -# Now securely delete the plain text LUKS key, we don't need it anymore, and since it contains secret key -# material it should be removed from disk thoroughly. -shred -u plaintext.bin plaintext.base64 - -# We don't need the public key anymore either, let's remove it too. Since this one is not security -# sensitive we just do a regular "rm" here. +# We don't need the public key anymore, let's remove it. Since it is not +# security sensitive we just do a regular "rm" here. rm pubkey.pem -# Test: Let's run systemd-cryptsetup to test if this all worked. The option string should contain the full -# PKCS#11 URI we have in the clipboard; it tells the tool how to decipher the encrypted LUKS key. Note that -# systemd-cryptsetup automatically searches for the encrypted key in /etc/cryptsetup-keys.d/, hence we do -# not need to specify the key file path explicitly here. -sudo systemd-cryptsetup attach mytest /dev/sdXn - 'pkcs11-uri=pkcs11:…' +# Enroll the freshly initialized security token in the LUKS2 volume. Replace +# /dev/sdXn by the partition to use (e.g. /dev/sda1). +sudo systemd-cryptenroll --pkcs11-token-uri=auto /dev/sdXn -# If that worked, let's now add the same line persistently to /etc/crypttab, for the future. -sudo bash -c 'echo "mytest /dev/sdXn - \'pkcs11-uri=pkcs11:…\'" >> /etc/crypttab' +# Test: Let's run systemd-cryptsetup to test if this all worked. +sudo /usr/lib/systemd/systemd-cryptsetup attach mytest /dev/sdXn - pkcs11-uri=auto + +# If that worked, let's now add the same line persistently to /etc/crypttab, +# for the future. +sudo bash -c 'echo "mytest /dev/sdXn - pkcs11-uri=auto" >> /etc/crypttab' diff --git a/meson.build b/meson.build index 580964c3f..6a474afda 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later project('systemd', 'c', - version : '247', + version : '248', license : 'LGPLv2+', default_options: [ 'c_std=gnu99', @@ -13,8 +13,8 @@ project('systemd', 'c', meson_version : '>= 0.46', ) -libsystemd_version = '0.30.0' -libudev_version = '1.7.0' +libsystemd_version = '0.31.0' +libudev_version = '1.7.1' # We need the same data in two different formats, ugh! # Also, for hysterical reasons, we use different variable @@ -68,6 +68,11 @@ if get_option('split-usr') == 'auto' else split_usr = get_option('split-usr') == 'true' endif +if split_usr + warning('\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n' + + ' split-usr mode is going to be removed\n' + + '\n\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!') +endif conf.set10('HAVE_SPLIT_USR', split_usr, description : '/usr/bin and /bin directories are separate') @@ -110,6 +115,11 @@ prefixdir = get_option('prefix') if not prefixdir.startswith('/') error('Prefix is not absolute: "@0@"'.format(prefixdir)) endif +if prefixdir != rootprefixdir and not prefixdir.startswith(rootprefixdir.strip('/') + '/') + error('Prefix is not below root prefix (now rootprefix=@0@ prefix=@1@)'.format( + rootprefixdir, prefixdir)) +endif + bindir = join_paths(prefixdir, get_option('bindir')) libdir = join_paths(prefixdir, get_option('libdir')) sysconfdir = join_paths(prefixdir, get_option('sysconfdir')) @@ -126,14 +136,15 @@ if rootlibdir == '' rootlibdir = join_paths(rootprefixdir, libdir.split('/')[-1]) endif -install_sysconfdir = get_option('install-sysconfdir') +install_sysconfdir = get_option('install-sysconfdir') != 'false' +install_sysconfdir_samples = get_option('install-sysconfdir') == 'true' # Dirs of external packages pkgconfigdatadir = get_option('pkgconfigdatadir') == '' ? join_paths(datadir, 'pkgconfig') : get_option('pkgconfigdatadir') pkgconfiglibdir = get_option('pkgconfiglibdir') == '' ? join_paths(libdir, 'pkgconfig') : get_option('pkgconfiglibdir') polkitpolicydir = join_paths(datadir, 'polkit-1/actions') polkitrulesdir = join_paths(datadir, 'polkit-1/rules.d') polkitpkladir = join_paths(localstatedir, 'lib/polkit-1/localauthority/10-vendor.d') -xinitrcdir = join_paths(sysconfdir, 'X11/xinit/xinitrc.d') +xinitrcdir = get_option('xinitrcdir') == '' ? join_paths(sysconfdir, 'X11/xinit/xinitrc.d') : get_option('xinitrcdir') rpmmacrosdir = get_option('rpmmacrosdir') if rpmmacrosdir != 'no' rpmmacrosdir = join_paths(prefixdir, rpmmacrosdir) @@ -216,16 +227,17 @@ conf.set_quoted('SYSTEM_SYSVRCND_PATH', sysvrcnd_path) conf.set_quoted('RC_LOCAL_PATH', get_option('rc-local')) conf.set('ANSI_OK_COLOR', 'ANSI_' + get_option('ok-color').underscorify().to_upper()) +conf.set10('ENABLE_FEXECVE', get_option('fexecve')) conf.set_quoted('USER_CONFIG_UNIT_DIR', join_paths(pkgsysconfdir, 'user')) conf.set_quoted('USER_DATA_UNIT_DIR', userunitdir) conf.set_quoted('CERTIFICATE_ROOT', get_option('certificate-root')) conf.set_quoted('CATALOG_DATABASE', join_paths(catalogstatedir, 'database')) -conf.set_quoted('SYSTEMD_CGROUP_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent')) conf.set_quoted('SYSTEMD_BINARY_PATH', join_paths(rootlibexecdir, 'systemd')) +conf.set_quoted('SYSTEMD_CGROUPS_AGENT_PATH', join_paths(rootlibexecdir, 'systemd-cgroups-agent')) conf.set_quoted('SYSTEMD_FSCK_PATH', join_paths(rootlibexecdir, 'systemd-fsck')) -conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs')) conf.set_quoted('SYSTEMD_GROWFS_PATH', join_paths(rootlibexecdir, 'systemd-growfs')) +conf.set_quoted('SYSTEMD_MAKEFS_PATH', join_paths(rootlibexecdir, 'systemd-makefs')) conf.set_quoted('SYSTEMD_SHUTDOWN_BINARY_PATH', join_paths(rootlibexecdir, 'systemd-shutdown')) conf.set_quoted('SYSTEMCTL_BINARY_PATH', join_paths(rootbindir, 'systemctl')) conf.set_quoted('SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH', join_paths(rootbindir, 'systemd-tty-ask-password-agent')) @@ -235,6 +247,7 @@ conf.set_quoted('ROOTPREFIX_NOSLASH', rootprefixdir_nosl conf.set_quoted('RANDOM_SEED_DIR', randomseeddir) conf.set_quoted('RANDOM_SEED', join_paths(randomseeddir, 'random-seed')) conf.set_quoted('SYSTEMD_CRYPTSETUP_PATH', join_paths(rootlibexecdir, 'systemd-cryptsetup')) +conf.set_quoted('SYSTEMD_VERITYSETUP_PATH', join_paths(rootlibexecdir, 'systemd-veritysetup')) conf.set_quoted('SYSTEM_GENERATOR_DIR', systemgeneratordir) conf.set_quoted('USER_GENERATOR_DIR', usergeneratordir) conf.set_quoted('SYSTEM_ENV_GENERATOR_DIR', systemenvgeneratordir) @@ -534,7 +547,9 @@ foreach ident : [ #include #include '''], ['mallinfo', '''#include '''], + ['execveat', '''#include '''], ['close_range', '''#include '''], + ['epoll_pwait2', '''#include '''], ] have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE') @@ -552,15 +567,24 @@ endif ##################################################################### -vcs_tagger = [project_source_root + '/tools/meson-vcs-tag.sh', - project_source_root, - get_option('version-tag'), - meson.project_version()] +version_tag = get_option('version-tag') +if version_tag != '' + vcs_data = configuration_data() + vcs_data.set('VCS_TAG', version_tag) + version_h = configure_file(configuration : vcs_data, + input : 'src/version/version.h.in', + output : 'version.h') +else + vcs_tagger = [ + project_source_root + '/tools/meson-vcs-tag.sh', + project_source_root, + meson.project_version()] -version_h = vcs_tag( - input : 'src/version/version.h.in', - output : 'version.h', - command: vcs_tagger) + version_h = vcs_tag( + input : 'src/version/version.h.in', + output : 'version.h', + command: vcs_tagger) +endif versiondep = declare_dependency(sources: version_h) @@ -649,6 +673,7 @@ foreach header : ['crypt.h', 'sys/auxv.h', 'valgrind/memcheck.h', 'valgrind/valgrind.h', + 'linux/time_types.h', ] conf.set10('HAVE_' + header.underscorify().to_upper(), @@ -665,9 +690,6 @@ if fallback_hostname == '' or fallback_hostname[0] == '.' or fallback_hostname[0 endif conf.set_quoted('FALLBACK_HOSTNAME', fallback_hostname) -conf.set10('ENABLE_COMPAT_GATEWAY_HOSTNAME', get_option('compat-gateway-hostname')) -gateway_hostnames = ['_gateway'] + (conf.get('ENABLE_COMPAT_GATEWAY_HOSTNAME') == 1 ? ['gateway'] : []) - default_hierarchy = get_option('default-hierarchy') conf.set_quoted('DEFAULT_HIERARCHY_NAME', default_hierarchy, description : 'default cgroup hierarchy as string') @@ -833,6 +855,17 @@ if default_locale == '' endif conf.set_quoted('SYSTEMD_DEFAULT_LOCALE', default_locale) +localegen_path = get_option('localegen-path') +have = false +writable = '' +if localegen_path != '' + conf.set_quoted('LOCALEGEN_PATH', localegen_path) + have = true + writable = ' /usr/lib/locale' +endif +substs.set('SERVICE_LOCALEGEN_WRITABLE', writable) +conf.set10('HAVE_LOCALEGEN', have) + conf.set_quoted('GETTEXT_PACKAGE', meson.project_name()) service_watchdog = get_option('service-watchdog') @@ -1004,6 +1037,9 @@ want_blkid = get_option('blkid') if want_blkid != 'false' and not skip_deps libblkid = dependency('blkid', required : want_blkid == 'true') have = libblkid.found() + + conf.set10('HAVE_BLKID_PROBE_SET_HINT', + have and cc.has_function('blkid_probe_set_hint', dependencies : libblkid)) else have = false libblkid = [] @@ -1057,6 +1093,8 @@ if want_libcryptsetup != 'false' and not skip_deps have and cc.has_function('crypt_set_metadata_size', dependencies : libcryptsetup)) conf.set10('HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY', have and cc.has_function('crypt_activate_by_signed_key', dependencies : libcryptsetup)) + conf.set10('HAVE_CRYPT_TOKEN_MAX', + have and cc.has_function('crypt_token_max', dependencies : libcryptsetup)) else have = false libcryptsetup = [] @@ -1186,6 +1224,17 @@ else endif conf.set10('HAVE_LIBFIDO2', have) +want_tpm2 = get_option('tpm2') +if want_tpm2 != 'false' and not skip_deps + tpm2 = dependency('tss2-esys tss2-rc tss2-mu', + required : want_tpm2 == 'true') + have = tpm2.found() +else + have = false + tpm2 = [] +endif +conf.set10('HAVE_TPM2', have) + want_elfutils = get_option('elfutils') if want_elfutils != 'false' and not skip_deps libdw = dependency('libdw', @@ -1416,14 +1465,6 @@ have = have and conf.get('HAVE_PAM') == 1 conf.set10('ENABLE_PAM_HOME', have) have = get_option('oomd') -if have == 'auto' - have = get_option('mode') == 'developer' -else - have = have == 'true' - if have and get_option('mode') != 'developer' - warning('oomd is not ready for release mode (yet)') - endif -endif conf.set10('ENABLE_OOMD', have) substs.set10('ENABLE_OOMD', have) @@ -1459,6 +1500,7 @@ foreach term : ['analyze', 'ima', 'initrd', 'compat-mutable-uid-boundaries', + 'nscd', 'ldconfig', 'localed', 'logind', @@ -1467,6 +1509,7 @@ foreach term : ['analyze', 'nss-myhostname', 'nss-systemd', 'portabled', + 'sysext', 'pstore', 'quotacheck', 'randomseed', @@ -1518,9 +1561,6 @@ conf.set10('ENABLE_NSS', enable_nss) conf.set10('ENABLE_TIMEDATECTL', get_option('timedated') or get_option('timesyncd')) -tests = [] -fuzzers = [] - conf.set10('SYSTEMD_SLOW_TESTS_DEFAULT', slow_tests) ##################################################################### @@ -1554,75 +1594,74 @@ else endif conf.set10('ENABLE_EFI', have) +############################################################ + +generate_gperfs = find_program('tools/generate-gperfs.py') +make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py') +make_directive_index_py = find_program('tools/make-directive-index.py') +make_man_index_py = find_program('tools/make-man-index.py') +meson_apply_m4 = find_program('tools/meson-apply-m4.sh') +update_dbus_docs_py = find_program('tools/update-dbus-docs.py') +update_hwdb_sh = find_program('tools/update-hwdb.sh') +update_hwdb_autosuspend_sh = find_program('tools/update-hwdb-autosuspend.sh') +update_syscall_tables_sh = find_program('tools/update-syscall-tables.sh') +xml_helper_py = find_program('tools/xml_helper.py') + ##################################################################### config_h = configure_file( output : 'config.h', configuration : conf) -meson_apply_m4 = find_program('tools/meson-apply-m4.sh') - -includes = include_directories('src/basic', - 'src/boot', - 'src/core', - 'src/home', - 'src/journal', - 'src/journal-remote', - 'src/libsystemd-network', - 'src/libsystemd/sd-bus', - 'src/libsystemd/sd-device', - 'src/libsystemd/sd-event', - 'src/libsystemd/sd-hwdb', - 'src/libsystemd/sd-id128', - 'src/libsystemd/sd-netlink', - 'src/libsystemd/sd-network', - 'src/libsystemd/sd-resolve', - 'src/libudev', - 'src/login', - 'src/nspawn', - 'src/resolve', - 'src/shared', - 'src/shutdown', - 'src/systemd', - 'src/time-wait-sync', - 'src/timesync', - 'src/udev', - 'src/xdg-autostart-generator', - '.') - add_project_arguments('-include', 'config.h', language : 'c') -generate_gperfs = find_program('tools/generate-gperfs.py') +############################################################ + +# binaries that have --help and are intended for use by humans, +# usually, but not always, installed in /bin. +public_programs = [] + +tests = [] +fuzzers = [] + +basic_includes = include_directories( + 'src/basic', + 'src/fundamental', + 'src/systemd', + '.') + +libsystemd_includes = [basic_includes, include_directories( + 'src/libsystemd/sd-bus', + 'src/libsystemd/sd-device', + 'src/libsystemd/sd-event', + 'src/libsystemd/sd-hwdb', + 'src/libsystemd/sd-id128', + 'src/libsystemd/sd-journal', + 'src/libsystemd/sd-netlink', + 'src/libsystemd/sd-network', + 'src/libsystemd/sd-resolve')] + +includes = [libsystemd_includes, include_directories('src/shared')] subdir('po') subdir('catalog') -subdir('src/libudev') -subdir('src/systemd') +subdir('src/fundamental') subdir('src/basic') subdir('src/libsystemd') -subdir('src/libsystemd-network') -subdir('src/journal') -subdir('src/login') +subdir('src/shared') +subdir('src/udev') +subdir('src/libudev') -libjournal_core = static_library( - 'journal-core', - libjournal_core_sources, - journald_gperf_c, - include_directories : includes, - install : false) - -libsystemd_sym_path = '@0@/@1@'.format(project_source_root, libsystemd_sym) libsystemd = shared_library( 'systemd', disable_mempool_c, version : libsystemd_version, - include_directories : includes, + include_directories : libsystemd_includes, link_args : ['-shared', '-Wl,--version-script=' + libsystemd_sym_path], link_with : [libbasic, libbasic_gcrypt], - link_whole : [libsystemd_static, - libjournal_client], + link_whole : [libsystemd_static], dependencies : [threads, librt, libxz, @@ -1632,21 +1671,18 @@ libsystemd = shared_library( install : true, install_dir : rootlibdir) -static_libsystemd = get_option('static-libsystemd') -static_libsystemd_pic = static_libsystemd == 'true' or static_libsystemd == 'pic' - install_libsystemd_static = static_library( 'systemd', libsystemd_sources, - journal_client_sources, basic_sources, basic_gcrypt_sources, + fundamental_sources, disable_mempool_c, - include_directories : includes, + include_directories : libsystemd_includes, build_by_default : static_libsystemd != 'false', install : static_libsystemd != 'false', install_dir : rootlibdir, - pic : static_libsystemd == 'true' or static_libsystemd == 'pic', + pic : static_libsystemd_pic, dependencies : [threads, librt, libxz, @@ -1659,50 +1695,79 @@ install_libsystemd_static = static_library( libgcrypt], c_args : libsystemd_c_args + (static_libsystemd_pic ? [] : ['-fno-PIC'])) -############################################################ +libudev = shared_library( + 'udev', + disable_mempool_c, + version : libudev_version, + include_directories : includes, + link_args : ['-shared', + '-Wl,--version-script=' + libudev_sym_path], + link_with : [libsystemd_static, libshared_static], + link_whole : libudev_basic, + dependencies : [threads], + link_depends : libudev_sym, + install : true, + install_dir : rootlibdir) -autosuspend_update_sh = find_program('tools/autosuspend-update.sh') -hwdb_update_sh = find_program('tools/hwdb-update.sh') -make_autosuspend_rules_py = find_program('tools/make-autosuspend-rules.py') -make_directive_index_py = find_program('tools/make-directive-index.py') -make_man_index_py = find_program('tools/make-man-index.py') -syscall_names_update_sh = find_program('tools/syscall-names-update.sh') -xml_helper_py = find_program('tools/xml_helper.py') -update_dbus_docs_py = find_program('tools/update-dbus-docs.py') +install_libudev_static = static_library( + 'udev', + basic_sources, + fundamental_sources, + shared_sources, + libsystemd_sources, + libudev_sources, + disable_mempool_c, + include_directories : includes, + build_by_default : static_libudev != 'false', + install : static_libudev != 'false', + install_dir : rootlibdir, + link_depends : libudev_sym, + dependencies : libshared_deps + [libmount], + c_args : static_libudev_pic ? [] : ['-fno-PIC'], + pic : static_libudev_pic) ############################################################ -# binaries that have --help and are intended for use by humans, -# usually, but not always, installed in /bin. -public_programs = [] - -subdir('src/shared') +# systemd-analyze requires 'libcore' subdir('src/core') -subdir('src/shutdown') -subdir('src/udev') -subdir('src/network') +# systemd-journal-remote requires 'libjournal_core' +subdir('src/journal') +# systemd-networkd requires 'libsystemd_network' +subdir('src/libsystemd-network') subdir('src/analyze') -subdir('src/journal-remote') +subdir('src/boot/efi') +subdir('src/busctl') subdir('src/coredump') -subdir('src/pstore') -subdir('src/oom') +subdir('src/cryptenroll') +subdir('src/cryptsetup') +subdir('src/home') subdir('src/hostname') subdir('src/import') -subdir('src/partition') +subdir('src/journal-remote') subdir('src/kernel-install') subdir('src/locale') +subdir('src/login') subdir('src/machine') -subdir('src/portable') -subdir('src/userdb') -subdir('src/home') +subdir('src/network') subdir('src/nspawn') +subdir('src/oom') +subdir('src/partition') +subdir('src/portable') +subdir('src/pstore') subdir('src/resolve') +subdir('src/rpm') +subdir('src/shutdown') +subdir('src/sysext') +subdir('src/systemctl') subdir('src/timedate') subdir('src/timesync') subdir('src/tmpfiles') +subdir('src/userdb') subdir('src/vconsole') -subdir('src/boot/efi') +subdir('src/xdg-autostart-generator') + +subdir('src/systemd') subdir('src/test') subdir('src/fuzz') @@ -1723,9 +1788,9 @@ 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 src/nss-systemd/nss-systemd.h'], + ['systemd', 'ENABLE_NSS_SYSTEMD', ['nss-systemd.h', 'userdb-glue.c', 'userdb-glue.h']], ['mymachines', 'ENABLE_NSS_MYMACHINES'], - ['resolve', 'ENABLE_NSS_RESOLVE']] + ['resolve', 'ENABLE_NSS_RESOLVE', [], resolve_includes]] condition = tuple[1] == '' or conf.get(tuple[1]) == 1 if condition @@ -1736,15 +1801,19 @@ foreach tuple : [['myhostname', 'ENABLE_NSS_MYHOSTNAME'], sources = ['src/nss-@0@/nss-@0@.c'.format(module)] if tuple.length() > 2 - sources += tuple[2].split() + foreach s : tuple[2] + sources += ['src/nss-@0@/@1@'.format(module, s)] + endforeach endif + incs = tuple.length() > 3 ? tuple[3] : includes + nss = shared_library( 'nss_' + module, sources, disable_mempool_c, version : '2', - include_directories : includes, + include_directories : incs, # Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned link_args : ['-Wl,-z,nodelete', '-shared', @@ -1799,7 +1868,7 @@ meson.add_install_script(meson_make_symlink, public_programs += executable( 'systemd-analyze', systemd_analyze_sources, - include_directories : includes, + include_directories : core_includes, link_with : [libcore, libshared], dependencies : [versiondep, @@ -1883,8 +1952,7 @@ executable( 'systemd-fstab-generator', 'src/fstab-generator/fstab-generator.c', include_directories : includes, - link_with : [libcore_shared, - libshared], + link_with : [libshared], install_rpath : rootlibexecdir, install : true, install_dir : systemgeneratordir) @@ -1928,7 +1996,6 @@ if conf.get('HAVE_BLKID') == 1 executable( 'systemd-gpt-auto-generator', 'src/gpt-auto-generator/gpt-auto-generator.c', - 'src/shared/blkid-util.h', include_directories : includes, link_with : [libshared], dependencies : libblkid, @@ -1949,7 +2016,7 @@ if conf.get('ENABLE_RESOLVE') == 1 executable( 'systemd-resolved', systemd_resolved_sources, - include_directories : includes, + include_directories : resolve_includes, link_with : [libshared, libbasic_gcrypt, libsystemd_resolve_core], @@ -2112,88 +2179,9 @@ public_programs += executable( install_rpath : rootlibexecdir, install : true) -if get_option('link-systemctl-shared') - systemctl_link_with = [libshared] -else - systemctl_link_with = [libsystemd_static, - libshared_static, - libjournal_client, - libbasic_gcrypt] -endif - public_programs += executable( 'systemctl', - 'src/systemctl/systemctl-add-dependency.c', - 'src/systemctl/systemctl-add-dependency.h', - 'src/systemctl/systemctl-cancel-job.c', - 'src/systemctl/systemctl-cancel-job.h', - 'src/systemctl/systemctl-clean-or-freeze.c', - 'src/systemctl/systemctl-clean-or-freeze.h', - 'src/systemctl/systemctl-compat-halt.c', - 'src/systemctl/systemctl-compat-halt.h', - 'src/systemctl/systemctl-compat-runlevel.c', - 'src/systemctl/systemctl-compat-runlevel.h', - 'src/systemctl/systemctl-compat-shutdown.c', - 'src/systemctl/systemctl-compat-shutdown.h', - 'src/systemctl/systemctl-compat-telinit.c', - 'src/systemctl/systemctl-compat-telinit.h', - 'src/systemctl/systemctl-daemon-reload.c', - 'src/systemctl/systemctl-daemon-reload.h', - 'src/systemctl/systemctl-edit.c', - 'src/systemctl/systemctl-edit.h', - 'src/systemctl/systemctl-enable.c', - 'src/systemctl/systemctl-enable.h', - 'src/systemctl/systemctl-is-active.c', - 'src/systemctl/systemctl-is-active.h', - 'src/systemctl/systemctl-is-enabled.c', - 'src/systemctl/systemctl-is-enabled.h', - 'src/systemctl/systemctl-is-system-running.c', - 'src/systemctl/systemctl-is-system-running.h', - 'src/systemctl/systemctl-kill.c', - 'src/systemctl/systemctl-kill.h', - 'src/systemctl/systemctl-list-dependencies.c', - 'src/systemctl/systemctl-list-dependencies.h', - 'src/systemctl/systemctl-list-jobs.c', - 'src/systemctl/systemctl-list-jobs.h', - 'src/systemctl/systemctl-list-machines.c', - 'src/systemctl/systemctl-list-machines.h', - 'src/systemctl/systemctl-list-unit-files.c', - 'src/systemctl/systemctl-list-unit-files.h', - 'src/systemctl/systemctl-list-units.c', - 'src/systemctl/systemctl-list-units.h', - 'src/systemctl/systemctl-log-setting.c', - 'src/systemctl/systemctl-log-setting.h', - 'src/systemctl/systemctl-logind.c', - 'src/systemctl/systemctl-logind.h', - 'src/systemctl/systemctl-preset-all.c', - 'src/systemctl/systemctl-preset-all.h', - 'src/systemctl/systemctl-reset-failed.c', - 'src/systemctl/systemctl-reset-failed.h', - 'src/systemctl/systemctl-service-watchdogs.c', - 'src/systemctl/systemctl-service-watchdogs.h', - 'src/systemctl/systemctl-set-default.c', - 'src/systemctl/systemctl-set-default.h', - 'src/systemctl/systemctl-set-environment.c', - 'src/systemctl/systemctl-set-environment.h', - 'src/systemctl/systemctl-set-property.c', - 'src/systemctl/systemctl-set-property.h', - 'src/systemctl/systemctl-show.c', - 'src/systemctl/systemctl-show.h', - 'src/systemctl/systemctl-start-special.c', - 'src/systemctl/systemctl-start-special.h', - 'src/systemctl/systemctl-start-unit.c', - 'src/systemctl/systemctl-start-unit.h', - 'src/systemctl/systemctl-switch-root.c', - 'src/systemctl/systemctl-switch-root.h', - 'src/systemctl/systemctl-sysv-compat.c', - 'src/systemctl/systemctl-sysv-compat.h', - 'src/systemctl/systemctl-trivial-method.c', - 'src/systemctl/systemctl-trivial-method.h', - 'src/systemctl/systemctl-util.c', - 'src/systemctl/systemctl-util.c', - 'src/systemctl/systemctl-util.h', - 'src/systemctl/systemctl.c', - 'src/systemctl/systemctl.h', + systemctl_sources, include_directories : includes, link_with : systemctl_link_with, dependencies : [threads, @@ -2228,6 +2216,17 @@ if conf.get('ENABLE_PORTABLED') == 1 install_dir : rootbindir) endif +if conf.get('ENABLE_SYSEXT') == 1 + public_programs += executable( + 'systemd-sysext', + systemd_sysext_sources, + include_directories : includes, + link_with : [libshared], + install_rpath : rootlibexecdir, + install : true, + install_dir : rootbindir) +endif + if conf.get('ENABLE_USERDB') == 1 executable( 'systemd-userwork', @@ -2272,8 +2271,7 @@ if conf.get('ENABLE_HOMED') == 1 libcrypt, libopenssl, libfdisk, - libp11kit, - libfido2], + libp11kit], install_rpath : rootlibexecdir, install : true, install_dir : rootlibexecdir) @@ -2281,7 +2279,7 @@ if conf.get('ENABLE_HOMED') == 1 executable( 'systemd-homed', systemd_homed_sources, - include_directories : includes, + include_directories : home_includes, link_with : [libshared], dependencies : [threads, libcrypt, @@ -2299,7 +2297,6 @@ if conf.get('ENABLE_HOMED') == 1 libcrypt, libopenssl, libp11kit, - libfido2, libdl], install_rpath : rootlibexecdir, install : true, @@ -2369,17 +2366,6 @@ executable( install_dir : systemgeneratordir) if conf.get('HAVE_LIBCRYPTSETUP') == 1 - systemd_cryptsetup_sources = files(''' - src/cryptsetup/cryptsetup-pkcs11.h - src/cryptsetup/cryptsetup-keyfile.c - src/cryptsetup/cryptsetup-keyfile.h - src/cryptsetup/cryptsetup.c -'''.split()) - - if conf.get('HAVE_P11KIT') == 1 - systemd_cryptsetup_sources += files('src/cryptsetup/cryptsetup-pkcs11.c') - endif - executable( 'systemd-cryptsetup', systemd_cryptsetup_sources, @@ -2418,6 +2404,18 @@ if conf.get('HAVE_LIBCRYPTSETUP') == 1 install_rpath : rootlibexecdir, install : true, install_dir : systemgeneratordir) + + executable( + 'systemd-cryptenroll', + systemd_cryptenroll_sources, + include_directories : includes, + link_with : [libshared], + dependencies : [libcryptsetup, + libdl, + libopenssl, + libp11kit], + install_rpath : rootlibexecdir, + install : true) endif if conf.get('HAVE_SYSV_COMPAT') == 1 @@ -2443,8 +2441,7 @@ endif if conf.get('ENABLE_XDG_AUTOSTART') == 1 executable( 'systemd-xdg-autostart-generator', - 'src/xdg-autostart-generator/xdg-autostart-generator.c', - 'src/xdg-autostart-generator/xdg-autostart-service.c', + systemd_xdg_autostart_generator_sources, include_directories : includes, link_with : [libshared], install_rpath : rootlibexecdir, @@ -2530,20 +2527,11 @@ if conf.get('ENABLE_TIMEDATECTL') == 1 endif if conf.get('ENABLE_TIMESYNCD') == 1 - if get_option('link-timesyncd-shared') - timesyncd_link_with = [libshared] - else - timesyncd_link_with = [libsystemd_static, - libshared_static, - libjournal_client, - libbasic_gcrypt] - endif - executable( 'systemd-timesyncd', systemd_timesyncd_sources, include_directories : includes, - link_with : [timesyncd_link_with], + link_with : [libtimesyncd_core], dependencies : [threads, libm], install_rpath : rootlibexecdir, @@ -2552,9 +2540,9 @@ if conf.get('ENABLE_TIMESYNCD') == 1 executable( 'systemd-time-wait-sync', - 'src/time-wait-sync/time-wait-sync.c', + 'src/timesync/wait-sync.c', include_directories : includes, - link_with : [timesyncd_link_with], + link_with : [libtimesyncd_core], install_rpath : rootlibexecdir, install : true, install_dir : rootlibexecdir) @@ -2845,8 +2833,7 @@ executable( 'systemd-remount-fs', 'src/remount-fs/remount-fs.c', include_directories : includes, - link_with : [libcore_shared, - libshared], + link_with : [libshared], install_rpath : rootlibexecdir, install : true, install_dir : rootlibexecdir) @@ -2855,8 +2842,7 @@ executable( 'systemd-machine-id-setup', 'src/machine-id-setup/machine-id-setup-main.c', include_directories : includes, - link_with : [libcore_shared, - libshared], + link_with : [libshared], install_rpath : rootlibexecdir, install : true, install_dir : rootbindir) @@ -2896,7 +2882,7 @@ executable( install : true, install_dir : rootlibexecdir) -if install_sysconfdir +if install_sysconfdir_samples install_data('src/sleep/sleep.conf', install_dir : pkgsysconfdir) endif @@ -3070,9 +3056,7 @@ public_programs += executable( public_programs += executable( 'busctl', - 'src/busctl/busctl.c', - 'src/busctl/busctl-introspect.c', - 'src/busctl/busctl-introspect.h', + busctl_sources, include_directories : includes, link_with : [libshared], install_rpath : rootlibexecdir, @@ -3105,8 +3089,7 @@ if enable_sysusers link_with : [libshared_static, libbasic, libbasic_gcrypt, - libsystemd_static, - libjournal_client], + libsystemd_static], install : true, install_dir : rootbindir) public_programs += exe @@ -3148,8 +3131,7 @@ if conf.get('ENABLE_TMPFILES') == 1 link_with : [libshared_static, libbasic, libbasic_gcrypt, - libsystemd_static, - libjournal_client], + libsystemd_static], dependencies : [libacl], install : true, install_dir : rootbindir) @@ -3160,9 +3142,8 @@ if conf.get('ENABLE_HWDB') == 1 public_programs += executable( 'systemd-hwdb', 'src/hwdb/hwdb.c', - 'src/libsystemd/sd-hwdb/hwdb-internal.h', include_directories : includes, - link_with : [libudev_static], + link_with : udev_link_with, install_rpath : udev_rpath, install : true, install_dir : rootbindir) @@ -3192,11 +3173,8 @@ public_programs += executable( public_programs += executable( 'udevadm', udevadm_sources, - c_args : '-DLOG_REALM=LOG_REALM_UDEV', include_directories : includes, - link_with : [libudev_core, - libsystemd_network, - libudev_static], + link_with : [libudevd_core], dependencies : [versiondep, threads, libkmod, @@ -3211,8 +3189,7 @@ executable( 'systemd-shutdown', systemd_shutdown_sources, include_directories : includes, - link_with : [libcore_shared, - libshared], + link_with : [libshared], dependencies : [libmount], install_rpath : rootlibexecdir, install : true, @@ -3260,8 +3237,7 @@ public_programs += executable( 'systemd-nspawn', systemd_nspawn_sources, include_directories : includes, - link_with : [libcore_shared, - libnspawn_core, + link_with : [libnspawn_core, libshared], dependencies : [libblkid, libseccomp], @@ -3272,10 +3248,9 @@ if conf.get('ENABLE_NETWORKD') == 1 executable( 'systemd-networkd', systemd_networkd_sources, - include_directories : network_include_dir, + include_directories : network_includes, link_with : [libnetworkd_core, libsystemd_network, - libudev_static, networkd_link_with], dependencies : [threads], install_rpath : rootlibexecdir, @@ -3286,8 +3261,7 @@ if conf.get('ENABLE_NETWORKD') == 1 'systemd-networkd-wait-online', systemd_networkd_wait_online_sources, include_directories : includes, - link_with : [libnetworkd_core, - networkd_link_with], + link_with : [networkd_link_with], install_rpath : rootlibexecdir, install : true, install_dir : rootlibexecdir) @@ -3295,7 +3269,7 @@ if conf.get('ENABLE_NETWORKD') == 1 public_programs += executable( 'networkctl', networkctl_sources, - include_directories : includes, + include_directories : libsystemd_network_includes, link_with : [libsystemd_network, networkd_link_with], install_rpath : rootlibexecdir, @@ -3321,7 +3295,7 @@ endif executable( 'systemd-sulogin-shell', - ['src/sulogin-shell/sulogin-shell.c'], + 'src/sulogin-shell/sulogin-shell.c', include_directories : includes, link_with : [libshared], install_rpath : rootlibexecdir, @@ -3341,13 +3315,13 @@ custom_target( foreach tuple : tests sources = tuple[0] - link_with = tuple[1].length() > 0 ? tuple[1] : [libshared] - dependencies = tuple[2] - condition = tuple.length() >= 4 ? tuple[3] : '' - type = tuple.length() >= 5 ? tuple[4] : '' - defs = tuple.length() >= 6 ? tuple[5] : [] - incs = tuple.length() >= 7 ? tuple[6] : includes - parallel = tuple.length() >= 8 ? tuple[7] : true + link_with = tuple.length() > 1 and tuple[1].length() > 0 ? tuple[1] : [libshared] + dependencies = tuple.length() > 2 ? tuple[2] : [] + incs = tuple.length() > 3 and tuple[3].length() > 0 ? tuple[3] : includes + condition = tuple.length() > 4 ? tuple[4] : '' + type = tuple.length() > 5 ? tuple[5] : '' + defs = tuple.length() > 6 ? tuple[6] : [] + parallel = tuple.length() > 7 ? tuple[7] : true timeout = 30 name = sources[0].split('/')[-1].split('.')[0] @@ -3413,7 +3387,7 @@ endif exe = executable( 'test-libudev-sym', test_libudev_sym_c, - include_directories : includes, + include_directories : libudev_includes, c_args : '-Wno-deprecated-declarations', link_with : [libudev], build_by_default : want_tests != 'false', @@ -3426,7 +3400,7 @@ endif exe = executable( 'test-libudev-static-sym', test_libudev_sym_c, - include_directories : includes, + include_directories : libudev_includes, c_args : '-Wno-deprecated-declarations', link_with : [install_libudev_static], build_by_default : want_tests != 'false' and static_libudev_pic, @@ -3440,40 +3414,39 @@ endif fuzzer_exes = [] -if fuzz_tests or fuzzer_build - foreach tuple : fuzzers - sources = tuple[0] - link_with = tuple[1].length() > 0 ? tuple[1] : [libshared] - dependencies = tuple[2] - defs = tuple.length() >= 4 ? tuple[3] : [] - incs = tuple.length() >= 5 ? tuple[4] : includes - link_args = [] +foreach tuple : fuzzers + sources = tuple[0] + link_with = tuple.length() > 1 and tuple[1].length() > 0 ? tuple[1] : [libshared] + dependencies = tuple.length() > 2 ? tuple[2] : [] + incs = tuple.length() > 3 and tuple[3].length() > 0 ? tuple[3] : includes + defs = tuple.length() > 4 ? tuple[4] : [] + link_args = [] - if want_ossfuzz + if want_ossfuzz + dependencies += fuzzing_engine + elif want_libfuzzer + if fuzzing_engine.found() dependencies += fuzzing_engine - elif want_libfuzzer - if fuzzing_engine.found() - dependencies += fuzzing_engine - else - link_args += ['-fsanitize=fuzzer'] - endif else - sources += 'src/fuzz/fuzz-main.c' + link_args += ['-fsanitize=fuzzer'] endif + else + sources += 'src/fuzz/fuzz-main.c' + endif - name = sources[0].split('/')[-1].split('.')[0] + name = sources[0].split('/')[-1].split('.')[0] - fuzzer_exes += executable( - name, - sources, - include_directories : [incs, include_directories('src/fuzz')], - link_with : link_with, - dependencies : dependencies, - c_args : defs, - link_args: link_args, - install : false) - endforeach -endif + fuzzer_exes += executable( + name, + sources, + include_directories : [incs, include_directories('src/fuzz')], + link_with : link_with, + dependencies : dependencies, + c_args : defs, + link_args: link_args, + install : false, + build_by_default : fuzz_tests or fuzzer_build) +endforeach run_target( 'fuzzers', @@ -3502,7 +3475,8 @@ if install_sysconfdir install_data('xorg/50-systemd-user.sh', install_dir : xinitrcdir) endif -install_data('modprobe.d/systemd.conf', +install_data('README', + 'modprobe.d/systemd.conf', install_dir : modprobedir) install_data('LICENSE.GPL2', 'LICENSE.LGPL2.1', @@ -3515,7 +3489,7 @@ install_data('LICENSE.GPL2', 'docs/TRANSIENT-SETTINGS.md', 'docs/TRANSLATORS.md', 'docs/UIDS-GIDS.md', - 'src/libsystemd/sd-bus/GVARIANT-SERIALIZATION', + 'docs/GVARIANT-SERIALIZATION.md', install_dir : docdir) meson.add_install_script('sh', '-c', mkdir_p.format(systemdstatedir)) @@ -3594,10 +3568,11 @@ endforeach if git.found() all_files = run_command( + 'env', '-u', 'GIT_WORK_TREE', git, - ['--git-dir=@0@/.git'.format(project_source_root), - 'ls-files', - ':/*.[ch]']) + '--git-dir=@0@/.git'.format(project_source_root), + 'ls-files', ':/*.[ch]') + all_files = files(all_files.stdout().split()) custom_target( @@ -3643,6 +3618,34 @@ run_target( depends : [man, libsystemd, libudev], command : [check_api_docs_sh, libsystemd.full_path(), libudev.full_path()]) +############################################################ + +if dbus_docs.length() > 0 + custom_target( + 'update-dbus-docs', + output : 'update-dbus-docs', + command : [update_dbus_docs_py, + '--build-dir=@0@'.format(project_build_root), + '@INPUT@'], + input : dbus_docs) + + if conf.get('BUILD_MODE') == 'BUILD_MODE_DEVELOPER' + test('dbus-docs-fresh', + update_dbus_docs_py, + args : ['--build-dir=@0@'.format(project_build_root), + '--test'] + dbus_docs) + endif +endif + +custom_target( + 'update-man-rules', + output : 'update-man-rules', + command : ['sh', '-c', + 'cd @0@ && '.format(meson.build_root()) + + 'python3 @0@/tools/update-man-rules.py $(find @0@ -wholename "*/man/*.xml") >t && '.format(project_source_root) + + 'mv t @0@/man/rules/meson.build'.format(meson.current_source_dir())], + depend_files : custom_entities_ent) + ############################################################ watchdog_opt = service_watchdog == '' ? 'disabled' : service_watchdog @@ -3678,8 +3681,8 @@ status = [ conf.get('SYSTEM_ALLOC_UID_MIN')), 'system GIDs: <=@0@ (alloc >=@1@)'.format(conf.get('SYSTEM_GID_MAX'), conf.get('SYSTEM_ALLOC_GID_MIN')), - 'dynamic UIDs: @0@–@1@'.format(dynamic_uid_min, dynamic_uid_max), - 'container UID bases: @0@–@1@'.format(container_uid_base_min, container_uid_base_max), + 'dynamic UIDs: @0@…@1@'.format(dynamic_uid_min, dynamic_uid_max), + 'container UID bases: @0@…@1@'.format(container_uid_base_min, container_uid_base_max), '/dev/kvm access mode: @0@'.format(get_option('dev-kvm-mode')), 'render group access mode: @0@'.format(get_option('group-render-mode')), 'certificate root directory: @0@'.format(get_option('certificate-root')), @@ -3687,7 +3690,6 @@ status = [ 'nobody user name: @0@'.format(nobody_user), 'nobody group name: @0@'.format(nobody_group), 'fallback hostname: @0@'.format(get_option('fallback-hostname')), - 'symbolic gateway hostnames: @0@'.format(', '.join(gateway_hostnames)), 'default DNSSEC mode: @0@'.format(default_dnssec), 'default DNS-over-TLS mode: @0@'.format(default_dns_over_tls), @@ -3743,6 +3745,7 @@ foreach tuple : [ ['libfdisk'], ['p11kit'], ['libfido2'], + ['tpm2'], ['AUDIT'], ['IMA'], ['AppArmor'], @@ -3764,6 +3767,7 @@ foreach tuple : [ ['idn'], ['initrd'], ['compat-mutable-uid-boundaries'], + ['nscd'], ['libidn2'], ['libidn'], ['libiptc'], @@ -3783,6 +3787,7 @@ foreach tuple : [ ['logind'], ['machined'], ['portabled'], + ['sysext'], ['userdb'], ['homed'], ['importd'], @@ -3835,6 +3840,8 @@ foreach tuple : [ ['link-timesyncd-shared', get_option('link-timesyncd-shared')], ['kernel-install', get_option('kernel-install')], ['systemd-analyze', conf.get('ENABLE_ANALYZE') == 1], + ['fexecve'], + ['standalone-binaries', get_option('standalone-binaries')], ] if tuple.length() >= 2 diff --git a/meson_options.txt b/meson_options.txt index 2435ccebd..d96d4e3f0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -44,6 +44,8 @@ option('initrd', type : 'boolean', description : 'install services for use when running systemd in initrd') option('compat-mutable-uid-boundaries', type : 'boolean', value : 'false', description : 'look at uid boundaries in /etc/login.defs for compatibility') +option('nscd', type : 'boolean', + description : 'build support for flushing of the nscd caches') option('quotaon-path', type : 'string', description : 'path to quotaon') option('quotacheck-path', type : 'string', description : 'path to quotacheck') @@ -97,7 +99,7 @@ option('coredump', type : 'boolean', description : 'install the coredump handler') option('pstore', type : 'boolean', description : 'install the pstore archival tool') -option('oomd', type : 'combo', choices : ['auto', 'true', 'false'], +option('oomd', type : 'boolean', description : 'install the userspace oom killer') option('logind', type : 'boolean', description : 'install the systemd-logind stack') @@ -109,6 +111,8 @@ option('machined', type : 'boolean', description : 'install the systemd-machined stack') option('portabled', type : 'boolean', description : 'install the systemd-portabled stack') +option('sysext', type : 'boolean', + description : 'install the systemd-sysext stack') option('userdb', type : 'boolean', description : 'install the systemd-userdbd stack') option('homed', type : 'combo', choices : ['auto', 'true', 'false'], @@ -159,6 +163,8 @@ option('man', type : 'combo', choices : ['auto', 'true', 'false'], option('html', type : 'combo', choices : ['auto', 'true', 'false'], value : 'false', description : 'build and install html pages') +option('translations', type : 'boolean', value : true, + description : 'build and install translations') option('certificate-root', type : 'string', value : '/etc/ssl', description : 'the prefix for TLS certificates') @@ -172,6 +178,8 @@ option('pkgconfigdatadir', type : 'string', value : '', description : 'directory for arch-independent pkg-config files') option('pkgconfiglibdir', type : 'string', value : '', description : 'directory for standard pkg-config files') +option('xinitrcdir', type : 'string', value : '', + description : 'directory for xinitrc files') option('rpmmacrosdir', type : 'string', value : 'lib/rpm/macros.d', description : 'directory for rpm macros ["no" disables]') option('pamlibdir', type : 'string', @@ -180,13 +188,11 @@ option('pamconfdir', type : 'string', description : 'directory for PAM configuration ["no" disables]') option('docdir', type : 'string', description : 'documentation directory') -option('install-sysconfdir', type : 'boolean', value : true, - description : 'install configuration files to $sysconfdir') +option('install-sysconfdir', type : 'combo', choices : ['true', 'no-samples', 'false'], value : 'true', + description : 'install configuration files and directories to $sysconfdir') option('fallback-hostname', type : 'string', value : 'localhost', description : 'the hostname used if none configured') -option('compat-gateway-hostname', type : 'boolean', value : 'false', - description : 'allow "gateway" as the symbolic name for default gateway') option('default-hierarchy', type : 'combo', choices : ['legacy', 'hybrid', 'unified'], value : 'unified', description : 'default cgroup hierarchy') @@ -238,6 +244,8 @@ option('gshadow', type : 'boolean', description : 'support for shadow group') option('default-locale', type : 'string', value : '', description : 'default locale used when /etc/locale.conf does not exist') +option('localegen-path', type : 'string', value : '', + description : 'absolute path to the locale-gen binary in case the system is using locale-gen') option('service-watchdog', type : 'string', value : '3min', description : 'default watchdog setting for systemd services') @@ -327,6 +335,8 @@ option('p11kit', type : 'combo', choices : ['auto', 'true', 'false'], description : 'p11kit support') option('libfido2', type : 'combo', choices : ['auto', 'true', 'false'], description : 'FIDO2 support') +option('tpm2', type : 'combo', choices : ['auto', 'true', 'false'], + description : 'TPM2 support') option('elfutils', type : 'combo', choices : ['auto', 'true', 'false'], description : 'elfutils support') option('zlib', type : 'combo', choices : ['auto', 'true', 'false'], @@ -352,7 +362,7 @@ option('gnu-efi', type : 'combo', choices : ['auto', 'true', 'false'], description : 'gnu-efi support for sd-boot') option('efi-cc', type : 'array', description : 'the compiler to use for EFI modules') -option('efi-ld', type : 'string', +option('efi-ld', type : 'string', value : 'ld', description : 'the linker to use for EFI modules') option('efi-libdir', type : 'string', description : 'path to the EFI lib directory') @@ -375,13 +385,15 @@ option('fuzz-tests', type : 'boolean', value : 'false', option('install-tests', type : 'boolean', value : 'false', description : 'install test executables') -option('ok-color', type: 'combo', +option('ok-color', type : 'combo', choices : ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'highlight-black', 'highlight-red', 'highlight-green', 'highlight-yellow', 'highlight-blue', 'highlight-magenta', 'highlight-cyan', 'highlight-white'], value : 'green', description: 'color of the "OK" status message') +option('fexecve', type : 'boolean', value : 'false', + description : 'use fexecve() to spawn children') option('oss-fuzz', type : 'boolean', value : 'false', description : 'build against oss-fuzz') diff --git a/mkosi.build b/mkosi.build index 4a13f1075..a74fc196b 100755 --- a/mkosi.build +++ b/mkosi.build @@ -1,5 +1,5 @@ #!/bin/sh -set -ex +set -e # This is a build script for OS image generation using mkosi (https://github.com/systemd/mkosi). # Simply invoke "mkosi" in the project directory to build an OS image. @@ -9,8 +9,10 @@ set -ex # so the files keep those permissions, otherwise details of what umask # was set at the time the git tree was cloned will leak all the way # through. Also set umask explicitly during the build. -chmod -R u+w,go-w,a+rX . -umask 022 +if ! mountpoint -q "$SRCDIR"; then + chmod -R u+w,go-w,a+rX . + umask 022 +fi # If mkosi.builddir/ exists mkosi will set $BUILDDIR to it, let's then use it # as out-of-tree build dir. Otherwise, let's make up our own builddir. @@ -21,21 +23,21 @@ umask 022 # So let's ensure we're running under UTF-8. # # If our current locale already is UTF-8, then we don't need to do anything: -if [ "$(locale charmap)" != "UTF-8" ] ; then +if [ "$(locale charmap 2> /dev/null)" != "UTF-8" ] ; then # Try using C.UTF-8 locale, if available. This locale is not shipped # by upstream glibc, so it's not available in all distros. # (In particular, it's not available in Arch Linux.) - export LC_CTYPE=C.UTF-8 - if [ "$(locale charmap)" != "UTF-8" ] ; then - # Finally, try something like en_US.UTF-8, which should be - # available in Arch Linux, but is not present in Debian's - # minimal image in our mkosi config. + if locale -a | grep -q -E "C.UTF-8|C.utf8"; then + export LC_CTYPE=C.UTF-8 + # Finally, try something like en_US.UTF-8, which should be + # available in Arch Linux, but is not present in Debian's + # minimal image in our mkosi config. + elif locale -a | grep -q en_US.utf8; then export LC_CTYPE=en_US.UTF-8 - if [ "$(locale charmap)" != "UTF-8" ] ; then - # If nothing works, fail early. - echo "*** Could not find a valid locale that supports UTF-8. ***" >&2 - exit 1 - fi + else + # If nothing works, fail early. + echo "*** Could not find a valid locale that supports UTF-8. ***" >&2 + exit 1 fi fi @@ -84,18 +86,33 @@ if [ ! -f "$BUILDDIR"/build.ninja ] ; then fi fi - meson "$BUILDDIR" -D "sysvinit-path=$sysvinit_path" -D "rootprefix=$rootprefix" -D default-hierarchy=unified -D man=false -D "nobody-user=$nobody_user" -D "nobody-group=$nobody_group" + meson "$BUILDDIR" \ + -D "sysvinit-path=$sysvinit_path" \ + -D "rootprefix=$rootprefix" \ + -D man=false \ + -D "nobody-user=$nobody_user" \ + -D "nobody-group=$nobody_group" \ + -D translations=false \ + -D version-tag="${VERSION_TAG}" fi -ninja -C "$BUILDDIR" all +cd "$BUILDDIR" +ninja "$@" if [ "$WITH_TESTS" = 1 ] ; then for id in 1 2 3; do - groupadd -g $id testgroup$id || : + getent group $id > /dev/null || groupadd -g $id testgroup$id done - ninja -C "$BUILDDIR" test + ninja test +fi +cd "$SRCDIR" + +# Ubuntu Focal is stuck with meson 0.53.0. +if [ "$(meson -v | cut -d . -f 2)" -gt 53 ] ; then + meson install -C "$BUILDDIR" --quiet --no-rebuild --only-changed +else + meson install -C "$BUILDDIR" --no-rebuild --only-changed fi -ninja -C "$BUILDDIR" install mkdir -p "$DESTDIR"/etc diff --git a/mkosi.default.d/10-systemd.conf b/mkosi.default.d/10-systemd.conf new file mode 100644 index 000000000..08a03f489 --- /dev/null +++ b/mkosi.default.d/10-systemd.conf @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +# This is a settings file for OS image generation using mkosi (https://github.com/systemd/mkosi). + +[Output] +Format=gpt_btrfs +Bootable=yes +HostonlyInitrd=yes + +[Packages] +BuildDirectory=mkosi.builddir +Cache=mkosi.cache +InstallDirectory=mkosi.installdir +SourceFileTransferFinal=copy-git-others + +[Host] +QemuHeadless=yes +NetworkVeth=yes + +[Validation] +Password= +Autologin=yes diff --git a/modprobe.d/README b/modprobe.d/README new file mode 100644 index 000000000..4c11e46df --- /dev/null +++ b/modprobe.d/README @@ -0,0 +1,7 @@ +Files in this directory contain configuration for modprobe, a program to load +kernel modules. + +See man:modprobe.d(5) for explanation of the configuration file format, and +man:modprobe(8) for a description of the program itself. + +Use 'systemd-analyze cat-config modprobe.d' to display the effective config. diff --git a/network/80-container-ve.network b/network/80-container-ve.network index 7e8ff48d7..0c233bc8e 100644 --- a/network/80-container-ve.network +++ b/network/80-container-ve.network @@ -20,6 +20,7 @@ Driver=veth Address=0.0.0.0/28 LinkLocalAddressing=yes DHCPServer=yes -IPMasquerade=yes +IPMasquerade=both LLDP=yes EmitLLDP=customer-bridge +IPv6SendRA=yes diff --git a/network/80-container-vz.network b/network/80-container-vz.network index b0ea57a67..1c58f7d50 100644 --- a/network/80-container-vz.network +++ b/network/80-container-vz.network @@ -19,6 +19,7 @@ Driver=bridge Address=0.0.0.0/24 LinkLocalAddressing=yes DHCPServer=yes -IPMasquerade=yes +IPMasquerade=both LLDP=yes EmitLLDP=customer-bridge +IPv6SendRA=yes diff --git a/network/80-vm-vt.network b/network/80-vm-vt.network index 45c5ab173..e8365df31 100644 --- a/network/80-vm-vt.network +++ b/network/80-vm-vt.network @@ -19,6 +19,7 @@ Driver=tun Address=0.0.0.0/28 LinkLocalAddressing=yes DHCPServer=yes -IPMasquerade=yes +IPMasquerade=both LLDP=yes EmitLLDP=customer-bridge +IPv6SendRA=yes diff --git a/network/80-wifi-ap.network.example b/network/80-wifi-ap.network.example index 6644c7e76..2cbd59370 100644 --- a/network/80-wifi-ap.network.example +++ b/network/80-wifi-ap.network.example @@ -5,4 +5,4 @@ WLANInterfaceType=ap [Network] Address=0.0.0.0/24 DHCPServer=yes -IPMasquerade=yes +IPMasquerade=both diff --git a/po/LINGUAS b/po/LINGUAS index eeaafef2a..b5b60ef98 100644 --- a/po/LINGUAS +++ b/po/LINGUAS @@ -27,3 +27,7 @@ tr uk zh_CN zh_TW +pa +kab +si +nl diff --git a/po/be.po b/po/be.po index 77f3a3f2c..f34c0f8c5 100644 --- a/po/be.po +++ b/po/be.po @@ -4,13 +4,13 @@ # # # Viktar Vaŭčkievič , 2015, 2016. -# Zmicer Turok , 2020. +# Zmicer Turok , 2020, 2021. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-10-16 06:30+0000\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-01-10 18:36+0000\n" "Last-Translator: Zmicer Turok \n" "Language-Team: Belarusian \n" @@ -20,7 +20,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.2.2\n" +"X-Generator: Weblate 4.4\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -94,7 +94,8 @@ msgstr "Праверыць уліковыя даныя хатняй прасто #: src/home/org.freedesktop.home1.policy:34 msgid "" "Authentication is required to check credentials against a user's home area." -msgstr "Для праверкі ўліковых даных хатняй прасторы патрабуецца аўтэнтыфікацыя." +msgstr "" +"Для праверкі ўліковых даных хатняй прасторы патрабуецца аўтэнтыфікацыя." #: src/home/org.freedesktop.home1.policy:43 msgid "Update a home area" @@ -307,56 +308,69 @@ msgstr "" "ноўтбука, патрабуецца аўтэнтыфікацыя." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Дазволіць праграмам перашкаджаць сістэме апрацоўваць кнопку перазапуску" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Для таго, каб дазволіць праграмам перашкаджаць сістэме апрацоўваць кнопку " +"перазапуску, патрабуецца аўтэнтыфікацыя." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Дазволіць праграмам працаваць у фоне па-за сеансам карыстальніка" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Для таго, каб дазволіць праграмам працаваць па-за сеансам карыстальніка, " "патрабуецца відавочны запыт." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Дазволіць праграмам працаваць у фоне па-за сеансам карыстальніка" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Для таго, каб дазволіць праграмам працаваць па-за межамі сеанса " "карыстальніка, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Дазволіць далучаць прылады да працоўных месцаў" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Для таго, каб дазволіць далучаць прылады да працоўных месцаў, патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Адлучыць прылады ад працоўных месцаў" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "Для адлучэння прылад ад працоўных месцаў патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Выключыць сістэму" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Для выключэння сістэмы патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Выключыць сістэму з іншымі прысутнымі карыстальнікамі" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -364,11 +378,11 @@ msgstr "" "Для выключэння сістэмы з іншымі прысутнымі карыстальнікамі патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Выключыць сістэму, калі праграмы перашкаджаюць гэтаму" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -376,19 +390,19 @@ msgstr "" "Для выключэння сістэмы з актыўнымі праграмамі, якія перашкаджаюць " "выключэнню, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Перазагрузіць сістэму" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Для перазагрузкі сістэмы патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Перазагрузіць сістэму з іншымі прысутнымі карыстальнікамі" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -396,11 +410,11 @@ msgstr "" "Для перазагрузкі сістэмы з іншымі прысутнымі карыстальнікамі патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Перазагрузіць сістэму, калі праграмы перашкаджаюць гэтаму" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -408,19 +422,19 @@ msgstr "" "Для перазагрузкі сістэмы з актыўнымі праграмамі, якія перашкаджаюць " "выключэнню, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Спыніць сістэму" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Для спынення сістэмы патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Спыніць сістэму з іншымі прысутнымі карыстальнікамі" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -428,11 +442,11 @@ msgstr "" "Для спынення сістэмы з іншымі прысутнымі карыстальнікамі патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Спыніць сістэму, калі праграмы перашкаджаюць гэтаму" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." @@ -440,19 +454,19 @@ msgstr "" "Для спынення сістэмы з актыўнымі праграмамі, якія перашкаджаюць выключэнню, " "патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Прыпыніць сістэму" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Для прыпынення сістэмы патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Прыпыніць сістэму з іншымі прысутнымі карыстальнікамі" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -460,11 +474,11 @@ msgstr "" "Для прыпынення сістэмы з іншымі прысутнымі карыстальнікамі патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Прыпыніць сістэму, калі праграмы перашкаджаюць гэтаму" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -472,19 +486,19 @@ msgstr "" "Для прыпынення сістэмы з актыўнымі праграмамі, якія перашкаджаюць " "выключэнню, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Перавесці сістэму ў рэжым сну" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Для пераводу сістэмы ў рэжым сну патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Перавесці сістэму ў рэжым сну з іншымі прысутнымі карыстальнікамі" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -492,11 +506,11 @@ msgstr "" "Для пераводу сістэмы ў рэжым сну з іншымі прысутнымі карыстальнікамі " "патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Перавесці сістэму ў рэжым сну, калі праграмы перашкаджаюць гэтаму" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -504,50 +518,50 @@ msgstr "" "Для пераводу сістэмы ў рэжым сну з актыўнымі праграмамі, якія перашкаджаюць " "выключэнню, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Кіраванне актыўнымі сеансамі, карыстальнікамі і працоўнымі месцамі" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Для кіравання актыўнымі сеансамі, карыстальнікамі і працоўнымі месцамі " "патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Заблакаваць або разблакаваць актыўныя сеансы" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Для таго, каб заблакаваць ці разблакаваць актыўныя сеансы, патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Вызначыць \"прычыну\" перазапуску" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Для таго, каб вызначыць прычыну перазапуску, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Запусціць наладку прашыўкі падчас наступнага запуску" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "Для таго, каб запусціць наладку прашыўкі, патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Вывесці меню загрузчыка падчас наступнага запуску" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -555,11 +569,11 @@ msgstr "" "Для вываду меню загрузчыка падчас наступнага запуску патрабуецца " "аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "Абраць пэўны загрузачны запіс падчас наступнага запуску" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -567,19 +581,19 @@ msgstr "" "Для таго, каб абраць пэўны загрузачны запіс падчас наступнага запуску, " "патрабуецца аўтэнтыфікацыя." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Вызначыць усеагульнае паведамленне" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Для вызначэння ўсеагульнага паведамлення патрабуецца аўтэнтыфікацыя" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "Змяніць сеанс" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "Для змены віртуальнага сеанса патрабуецца аўтэнтыфікацыя." @@ -798,7 +812,8 @@ msgstr "Змяніць канфігурацыю сеткавага інтэрф #: src/network/org.freedesktop.network1.policy:177 msgid "Authentication is required to reconfigure network interface." -msgstr "Для змены канфігурацыі сеткавага інтэрфейсу патрабуецца аўтэнтыфікацыя." +msgstr "" +"Для змены канфігурацыі сеткавага інтэрфейсу патрабуецца аўтэнтыфікацыя." #: src/portable/org.freedesktop.portable1.policy:13 msgid "Inspect a portable service image" @@ -893,23 +908,23 @@ msgstr "" "Для ўключэння або выключэння сінхранізацыі часу па сетцы патрабуецца " "аўтэнтыфікацыя." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Для запуску \"$(unit)\" патрабуецца аўтэнтыфікацыя." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Для спынення \"$(unit)\" патрабуецца аўтэнтыфікацыя." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Для перачытання стану \"$(unit)\" патрабуецца аўтэнтыфікацыя." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Для перазапуску \"$(unit)\" патрабуецца аўтэнтыфікацыя." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." @@ -917,17 +932,17 @@ msgstr "" "Для адпраўкі сігналу UNIX працэсам адзінкі \"$(unit)\" патрабуецца " "аўтэнтыфікацыя." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Для таго, каб скінуць стан \"failed\" у \"$(unit)\", патрабуецца " "аўтэнтыфікацыя." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Для змены ўласцівасцей \"$(unit)\" патрабуецца аўтэнтыфікацыя." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -935,7 +950,7 @@ msgstr "" "Для выдалення файлаў і каталогаў, якія звязаныя з \"$(unit)\", патрабуецца " "аўтэнтыфікацыя." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" diff --git a/po/be@latin.po b/po/be@latin.po index 4e80e8ee7..28654885b 100644 --- a/po/be@latin.po +++ b/po/be@latin.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2016-06-09 19:50+0300\n" "Last-Translator: Viktar Vaŭčkievič \n" "Language-Team: \n" @@ -326,58 +326,77 @@ msgstr "" "apracoŭvać zakryccio kryški noŭtbuka." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Dazvolić prahramam pieraškadžać sistemie apracoŭvać klavišu vykliučennia" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Nieabchodna aŭtentyfikacyja dlia dazvolu prahramam pieraškadžać sistemie " +"apracoŭvać klavišu vykliučennia." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "" "Dazvolić karystaĺniku, jakija jašče nie ŭvajšoŭ u sistemu, vykonvać prahramy" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Nieabchodny vidavočny zapyt dlia vykanannia prahram karystaĺnika, jaki jašče " "nie ŭvajšoŭ u sistemu." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "" "Dazvolić karystaĺnikam, jakija jašče nie ŭvajšli ŭ sistemu, vykonvać prahramy" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Nieabchodna aŭtentyfikacyja dlia vykanannia prahram karystaĺnika, jaki jašče " "nie ŭvajšoŭ u sistemu." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Dazvolić dalučać prylady da pracoŭnych miescaŭ" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Nieabchodna aŭtentyfikacyja dlia dalučennia prylad da pracoŭnych miescaŭ." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Adkliučać prylady ad pracoŭnych miescaŭ" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Nieabchodna aŭtentyfikacyja dlia adkliučennia prylad ad pracoŭnych miescaŭ." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Vykliučyć sistemu" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Nieabchodna aŭtentyfikacyja dlia vykliučennia sistemy." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Vykliučyć sistemu pry prysutnasci inšych karystaĺnikaŭ" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -385,11 +404,11 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia vykliučennia sistemy pry prysutnasci inšych " "karystaĺnikaŭ." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Vykliučyć sistemu, kali prahramy pieraškadžajuć hetamu" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -397,19 +416,19 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia vykliučennia sistemy, kali prahramy " "pieraškadžajuć hetamu." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Pierazahruzić sistemu" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Nieabchodna aŭtentyfikacyja dlia pierazahruzki sistemy." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Pierazahruzić sistemu pry prysutnasci inšych karystaĺnikaŭ" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -417,11 +436,11 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia pierazahruzki sistemy pry prysutnasci " "inšych karystaĺnikaŭ." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Pierazahruzić sistemu, kali prahramy pieraškadžajuć hetamu" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -429,25 +448,25 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia pierazahruzki sistemy, kali prahramy " "pieraškadžajuć hetamu." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 #, fuzzy #| msgid "Hibernate the system" msgid "Halt the system" msgstr "Hibiernavać sistemu" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 #, fuzzy #| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to halt the system." msgstr "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 #, fuzzy #| msgid "Hibernate the system while other users are logged in" msgid "Halt the system while other users are logged in" msgstr "Hibiernavać sistemu pry prysutnasci inšych karystaĺnikaŭ" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while other users are " @@ -459,13 +478,13 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy pry prysutnasci inšych " "karystaĺnikaŭ." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 #, fuzzy #| msgid "Hibernate the system while an application is inhibiting this" msgid "Halt the system while an application is inhibiting this" msgstr "Hibiernavać sistemu, kali prahramy pieraškadžajuć hetamu" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -477,19 +496,19 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy, kali prahramy " "pieraškadžajuć hetamu." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Prypynić sistemu" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Nieabchodna aŭtentyfikacyja dlia prypyniennia sistemy." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Prypynić sistemu pry prysutnasci inšych karystaĺnikaŭ" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -497,11 +516,11 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia prypyniennia sistemy pry prysutnasci inšych " "karystaĺnikaŭ." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Prypynić sistemu, kali prahramy pieraškadžajuć hetamu" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -509,19 +528,19 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia prypyniennia sistemy, kali prahramy " "pieraškadžajuć hetamu." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Hibiernavać sistemu" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Hibiernavać sistemu pry prysutnasci inšych karystaĺnikaŭ" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -529,11 +548,11 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy pry prysutnasci inšych " "karystaĺnikaŭ." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Hibiernavać sistemu, kali prahramy pieraškadžajuć hetamu" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -541,44 +560,44 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia hibiernacyi sistemy, kali prahramy " "pieraškadžajuć hetamu." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Kiravać aktyŭnymi siesijami, karystaĺnikami i pracoŭnymi miescami" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Nieabchodna aŭtentyfikacyja dlia kiravannia aktyŭnymi siesijami, " "karystaĺnikami i miescami." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Blakavać abo razblakavać aktyŭnuju siesiju" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Nieabchodna aŭtentyfikacyja dlia blakiroŭki abo razblakiroŭki aktyŭnaj " "siesii." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia sistemnaha časavoha pojasu." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" msgstr "Dazvolić ukazannie prašyŭcy na zahruzku interfiejsu nalad" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -586,11 +605,11 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭkazannia prašyŭcy na zahruzku interfiejsu " "nalad." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -602,11 +621,11 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭkazannia prašyŭcy na zahruzku interfiejsu " "nalad." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -618,20 +637,20 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭkazannia prašyŭcy na zahruzku interfiejsu " "nalad." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Ustaliavać usieahuĺnaje paviedamliennie" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia ŭsieahuĺnaha paviedamliennia" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to change the virtual terminal." @@ -989,23 +1008,23 @@ msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭkliučennia abo vykliučennia sinchranizacyi " "času pa sietcy." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Nieabchodna aŭtentyfikacyja dlia zapusku '$(unit)'." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Nieabchodna aŭtentyfikacyja dlia spyniennia '$(unit)'." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Nieabchodna aŭtentyfikacyja dlia pieračytannia stanu '$(unit)'." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Nieabchodna aŭtentyfikacyja dlia pierazapusku '$(unit)'." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -1014,17 +1033,17 @@ msgid "" msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia ŭlascivasciej '$(unit)'." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Nieabchodna aŭtentyfikacyja dlia anuliavannia pamylkovaha stanu '$(unit)'." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" "Nieabchodna aŭtentyfikacyja dlia ŭstaliavannia ŭlascivasciej '$(unit)'." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -1034,7 +1053,7 @@ msgid "" msgstr "" "Nieabchodna aŭtentyfikacyja dlia anuliavannia pamylkovaha stanu '$(unit)'." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/bg.po b/po/bg.po index 0859b0973..3ab13ffa9 100644 --- a/po/bg.po +++ b/po/bg.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2016-05-14 13:28+0300\n" "Last-Translator: Alexander Shopov \n" "Language-Team: Bulgarian \n" @@ -334,62 +334,82 @@ msgstr "" "затваряне на екрана е необходима идентификация." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Позволяване на програмите да предотвратяват реакцията на системата при " +"натискане на клавиша за захранване" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"За позволяване на програмите да предотвратяват реакцията на системата при " +"натискане на клавиша за захранване е необходима идентификация." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "" "Позволяване на потребители, които не са се идентифицирали, да изпълняват " "програми" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "За позволяване на потребители, които не са се идентифицирали, да изпълняват " "програми е необходима изрична заявка." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "" "Позволяване на потребители, които не са се идентифицирали, да изпълняват " "програми" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "За позволяване на потребители, които не са се идентифицирали, да изпълняват " "програми е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Позволяване на закачане на устройства към работните места" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "За позволяване на закачане на устройства към работните места е необходима " "идентификация." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Изчистване на връзките между устройствата и работните места" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "За изчистване на връзките между устройствата и работните места е необходима " "идентификация." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Изключване на системата" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "За изключване на системата е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Изключване на системата, дори когато има други вписани потребители" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -397,11 +417,11 @@ msgstr "" "За изключване на системата, дори когато има други вписани потребители, е " "необходима идентификация." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Изключване на системата, дори когато програма иска да предотврати това" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -409,19 +429,19 @@ msgstr "" "За изключване на системата, дори когато програма иска да предотврати това, е " "необходима идентификация." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Рестартиране на системата" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "За рестартиране на системата е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Рестартиране на системата, дори когато има други вписани потребители" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -429,12 +449,12 @@ msgstr "" "За рестартиране на системата, дори когато има други вписани потребители, е " "необходима идентификация." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" "Рестартиране на системата, дори когато програма иска да предотврати това" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -442,26 +462,26 @@ msgstr "" "За рестартиране на системата, дори когато програма иска да предотврати това, " "е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 #, fuzzy #| msgid "Hibernate the system" msgid "Halt the system" msgstr "Дълбоко приспиване на системата" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 #, fuzzy #| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to halt the system." msgstr "За дълбоко приспиване на системата е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 #, fuzzy #| msgid "Hibernate the system while other users are logged in" msgid "Halt the system while other users are logged in" msgstr "" "Дълбоко приспиване на системата, дори когато има други вписани потребители" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while other users are " @@ -473,7 +493,7 @@ msgstr "" "За дълбоко приспиване на системата, дори когато има други вписани " "потребители, е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 #, fuzzy #| msgid "Hibernate the system while an application is inhibiting this" msgid "Halt the system while an application is inhibiting this" @@ -481,7 +501,7 @@ msgstr "" "Дълбоко приспиване на системата, дори когато програма иска да предотврати " "това" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -493,19 +513,19 @@ msgstr "" "За дълбоко приспиване на системата, дори когато програма иска да предотврати " "това, е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Приспиване на системата" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "За приспиване на системата е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Приспиване на системата, дори когато има други вписани потребители" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -513,11 +533,11 @@ msgstr "" "За приспиване на системата, дори когато има други вписани потребители, е " "необходима идентификация." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Приспиване на системата, дори когато програма иска да предотврати това" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -525,20 +545,20 @@ msgstr "" "За приспиване на системата, дори когато програма иска да предотврати това, е " "необходима идентификация." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Дълбоко приспиване на системата" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "За дълбоко приспиване на системата е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "" "Дълбоко приспиване на системата, дори когато има други вписани потребители" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -546,13 +566,13 @@ msgstr "" "За дълбоко приспиване на системата, дори когато има други вписани " "потребители, е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" "Дълбоко приспиване на системата, дори когато програма иска да предотврати " "това" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -560,43 +580,43 @@ msgstr "" "За дълбоко приспиване на системата, дори когато програма иска да предотврати " "това, е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Управление на работещите сесии, потребители и работни места" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "За управление на работещите сесии, потребители и работни места е необходима " "идентификация." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Заключване или отключване на работещите сесии" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "За заключване или отключване на работещите сесии е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "За задаване на часовия пояс на системата е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" msgstr "" "Позволяване на заявки към фърмуера да стартира с интерфейса за управление" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -604,11 +624,11 @@ msgstr "" "За позволяване на заявки към фърмуера да стартира с интерфейса за управление " "е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -620,11 +640,11 @@ msgstr "" "За позволяване на заявки към фърмуера да стартира с интерфейса за управление " "е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -636,19 +656,19 @@ msgstr "" "За позволяване на заявки към фърмуера да стартира с интерфейса за управление " "е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Задаване на системно съобщение „wall“" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "За задаване на системно съобщение „wall“ е необходима идентификация." -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to change the virtual terminal." @@ -1004,23 +1024,23 @@ msgstr "" "За превключване на синхронизацията на времето по мрежата е необходима " "идентификация." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "За стартиране на „$(unit)“ е необходима идентификация." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "За спиране на „$(unit)“ е необходима идентификация." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "За презареждане на „$(unit)“ е необходима идентификация." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "За рестартиране на „$(unit)“ е необходима идентификация." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -1028,17 +1048,17 @@ msgid "" "'$(unit)'." msgstr "За задаване на свойствата на „$(unit)“ е необходима идентификация." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "За премахване на състоянието за неуспех на „$(unit)“ е необходима " "идентификация." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "За задаване на свойствата на „$(unit)“ е необходима идентификация." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -1049,7 +1069,7 @@ msgstr "" "За премахване на състоянието за неуспех на „$(unit)“ е необходима " "идентификация." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/ca.po b/po/ca.po index fcbdb23ae..0cb2e497e 100644 --- a/po/ca.po +++ b/po/ca.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2018-02-27 04:18-0500\n" "Last-Translator: Robert Antoni Buj Gelonch \n" "Language-Team: Català \n" @@ -335,57 +335,77 @@ msgstr "" "tancament de la tapa per part del sistema." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Permet a les aplicacions inhibir la gestió de la tecla d'encesa per part del " +"sistema" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Es requereix autenticació perquè una aplicació inhibeixi la gestió de la " +"tecla d'encesa per part del sistema." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Permet a l'usuari sense inici de sessió executar programes" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Es requereix una sol·licitud explícita per executar programes com a usuari " "sense inici de sessió." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Permet als usuaris sense inici de sessió executar programes" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Es requereix una sol·licitud explícita per executar programes com a usuari " "sense inici de sessió." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Permet l'annexió de dispositius als llocs de treball" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Es requereix autenticació per annexar un dispositiu a un lloc de treball." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Allibera els dispositius a les annexions dels llocs de treball" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Es requereix autenticació per restablir com s'annexionen els dispositius als " "llocs de treball." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Apaga el sistema" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Es requereix autenticació per apagar el sistema." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Apaga el sistema mentre hi ha altres usuaris amb la sessió iniciada" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -393,11 +413,11 @@ msgstr "" "Es requereix autenticació per apagar el sistema mentre hi ha altres usuaris " "amb la sessió iniciada." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Apaga el sistema mentre hi ha una aplicació que ha demanat inhibir-ho" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -405,19 +425,19 @@ msgstr "" "Es requereix autenticació per apagar el sistema mentre hi ha una aplicació " "que ha demanat inhibir-ho." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Reinicia el sistema" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Es requereix autenticació per reiniciar el sistema." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Reinicia el sistema mentre hi ha usuaris amb la sessió iniciada" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -425,12 +445,12 @@ msgstr "" "Es requereix autenticació per reiniciar el sistema mentre hi ha usuaris amb " "la sessió iniciada." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" "Reinicia el sistema mentre hi ha una aplicació que ha demanat inhibir-ho" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -438,19 +458,19 @@ msgstr "" "Es requereix autenticació per reiniciar el sistema mentre hi ha una " "aplicació que ha demanat inhibir-ho." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Atura el sistema" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Es requereix autenticació per aturar el sistema." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Atura el sistema mentre hi ha altres usuaris amb la sessió iniciada" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -458,12 +478,12 @@ msgstr "" "Es requereix autenticació per aturar el sistema mentre hi ha altres usuaris " "amb la sessió iniciada." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "" "Atura el sistema mentre hi ha una aplicació que ha demanat d'inhibir-ho" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -475,19 +495,19 @@ msgstr "" "Es requereix autenticació per hibernar el sistema mentre hi ha una aplicació " "que ha demanat d'inhibir-ho." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Suspèn el sistema" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Es requereix autenticació per suspendre el sistema." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Suspèn el sistema mentre hi ha altres usuaris amb la sessió iniciada" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -495,12 +515,12 @@ msgstr "" "Es requereix autenticació per reiniciar el sistema mentre hi ha altres " "usuaris amb la sessió iniciada." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" "Suspèn el sistema mentre hi ha una aplicació que ha demanat d'inhibir-ho" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -508,19 +528,19 @@ msgstr "" "Es requereix autenticació per suspendre el sistema mentre hi ha una " "aplicació que ha demanat d'inhibir-ho." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Hiberna el sistema" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Es requereix autenticació per hibernar el sistema." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Hiberna el sistema mentre hi ha altres usuaris amb la sessió iniciada" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -528,12 +548,12 @@ msgstr "" "Es requereix autenticació per hibernar el sistema mentre hi ha altres " "usuaris amb la sessió iniciada." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" "Hiberna el sistema mentre hi ha una aplicació que ha demanat d'inhibir-ho" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -541,36 +561,36 @@ msgstr "" "Es requereix autenticació per hibernar el sistema mentre hi ha una aplicació " "que ha demanat d'inhibir-ho." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Gestiona les sessions, usuaris i llocs de treball actius" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Es requereix autenticació per gestionar les sessions, usuaris i llocs de " "treball actius." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Bloqueja o desbloqueja les sessions actives" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Es requereix autenticació per bloquejar o desbloquejar les sessions actives." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "Es requereix autenticació per establir la zona horària del sistema." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" @@ -578,7 +598,7 @@ msgstr "" "Permet la indicació al microprogramari en l'arrencada perquè prepari la " "interfície" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -586,11 +606,11 @@ msgstr "" "Es requereix autenticació per indicar al microprogramari en l'arrencada " "perquè prepari la interfície." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -602,11 +622,11 @@ msgstr "" "Es requereix autenticació per indicar al microprogramari en l'arrencada " "perquè prepari la interfície." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -618,19 +638,19 @@ msgstr "" "Es requereix autenticació per indicar al microprogramari en l'arrencada " "perquè prepari la interfície." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Estableix un missatge de mur" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Es requereix autenticació per establir un missatge de mur" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." @@ -984,23 +1004,23 @@ msgstr "" "Es requereix autenticació per controlar si s'ha d'activar la sincronització " "de l'hora de xarxa." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Es requereix autenticació per iniciar «$(unit)»." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Es requereix autenticació per aturar «$(unit)»." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Es requereix autenticació per tornar a carregar «$(unit)»." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Es requereix autenticació per reiniciar «$(unit)»." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -1008,15 +1028,15 @@ msgid "" "'$(unit)'." msgstr "Es requereix autenticació per establir les propietats a «$(unit)»." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "Es requereix autenticació per restablir l'estat «failed» de «$(unit)»." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Es requereix autenticació per establir les propietats a «$(unit)»." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -1025,7 +1045,7 @@ msgid "" "'$(unit)'." msgstr "Es requereix autenticació per restablir l'estat «failed» de «$(unit)»." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/cs.po b/po/cs.po index abc618857..f296766cc 100644 --- a/po/cs.po +++ b/po/cs.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" -"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" -"POT-Creation-Date: 2020-09-10 03:33+0000\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2020-10-26 22:48+0100\n" "Last-Translator: Daniel Rusek \n" "Language-Team: Czech\n" diff --git a/po/da.po b/po/da.po index 74ee78628..16a04889c 100644 --- a/po/da.po +++ b/po/da.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2020-09-19 12:22+0000\n" "Last-Translator: scootergrisen \n" "Language-Team: Danish , 2014, 2015. # Benjamin Steinwender , 2014. # Bernd Homuth , 2015. -# +# Fabian Affolter , 2020. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2015-09-19 20:02+0200\n" -"Last-Translator: Bernd Homuth \n" -"Language-Team: Deutsch \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2020-12-13 14:36+0000\n" +"Last-Translator: Fabian Affolter \n" +"Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Gtranslator 2.91.6\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -72,7 +73,7 @@ msgstr "Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig." #: src/home/org.freedesktop.home1.policy:13 msgid "Create a home area" -msgstr "" +msgstr "Zuhause-Bereich erzeugen" #: src/home/org.freedesktop.home1.policy:14 #, fuzzy @@ -82,7 +83,7 @@ msgstr "Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig." #: src/home/org.freedesktop.home1.policy:23 msgid "Remove a home area" -msgstr "" +msgstr "Zuhause-Bereich entfernen" #: src/home/org.freedesktop.home1.policy:24 #, fuzzy @@ -92,7 +93,7 @@ msgstr "Legitimierung ist zum erneuten Laden des systemd-Zustands notwendig." #: src/home/org.freedesktop.home1.policy:33 msgid "Check credentials of a home area" -msgstr "" +msgstr "Prüfen Sie die Zugangsdaten für den Zuhause-Bereich" # https://www.freedesktop.org/software/systemd/man/sd-login.html #: src/home/org.freedesktop.home1.policy:34 @@ -107,7 +108,7 @@ msgstr "" #: src/home/org.freedesktop.home1.policy:43 msgid "Update a home area" -msgstr "" +msgstr "Zuhause-Bereich aktualisieren" # https://www.freedesktop.org/software/systemd/man/sd-login.html #: src/home/org.freedesktop.home1.policy:44 @@ -342,11 +343,31 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:117 #, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Anwendungen dürfen das Auswerten des Ein-/Ausschaltknopfs des Systems " +"unterbinden" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Legitmierung ist erforderlich, um Anwendungen das Unterbinden der Auswertung " +"der Ein-/Ausschaltknopfs des Systems zu erlauben." + +#: src/login/org.freedesktop.login1.policy:128 +#, fuzzy #| msgid "Allow non-logged-in users to run programs" msgid "Allow non-logged-in user to run programs" msgstr "Nicht angemeldete Benutzer dürfen Programme ausführen" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 #, fuzzy #| msgid "Authentication is required to run programs as a non-logged-in user." msgid "Explicit request is required to run programs as a non-logged-in user." @@ -354,53 +375,53 @@ msgstr "" "Legitimierung ist erforderlich, damit nicht angemeldete Benutzer Programme " "ausführen dürfen." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Nicht angemeldete Benutzer dürfen Programme ausführen" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Legitimierung ist erforderlich, damit nicht angemeldete Benutzer Programme " "ausführen dürfen." # https://www.freedesktop.org/software/systemd/man/sd-login.html -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Das Anschließen von Geräten an Arbeitsstationen erlauben" # https://www.freedesktop.org/software/systemd/man/sd-login.html -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Legitimierung ist zum Anschließen eines Geräts an eine Arbeitsstation " "notwendig." # https://www.freedesktop.org/software/systemd/man/sd-login.html -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Zurücksetzen der an eine Arbeitsstation angeschlossenen Geräte" # https://www.freedesktop.org/software/systemd/man/sd-login.html -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Legitimierung ist zum Zurücksetzen notwendig, wie Geräte an eine " "Arbeitsstation angeschlossen werden." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Das System ausschalten" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Legitimierung ist zum Ausschalten des Systems notwendig." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Das System herunter fahren, während andere Benutzer angemeldet sind" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -408,12 +429,12 @@ msgstr "" "Legitimierung ist zum Herunterfahren des Systems notwendig, während andere " "Benutzer angemeldet sind." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "" "Das System ausschalten, während eine Anwendung anfordert es zu unterbinden" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -421,19 +442,19 @@ msgstr "" "Legitimierung ist zum Ausschalten des Systems notwendig, während eine " "Anwendung anfordert es zu unterbinden." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Das System neu starten" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Legitimierung ist zum Neustart des Systems notwendig." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Das Systems neu starten, während andere Benutzer angemeldet sind" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -441,12 +462,12 @@ msgstr "" "Legitimierung ist zum Neustart des Systems notwendig, während andere " "Benutzer angemeldet sind." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" "Das System neu starten, während eine Anwendung anfordert es zu unterbinden" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -454,20 +475,20 @@ msgstr "" "Legitimierung ist zum Neustart des Systems notwendig, während eine Anwendung " "anforderte es zu unterbinden." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 #, fuzzy #| msgid "Hibernate the system" msgid "Halt the system" msgstr "Den Ruhezustand des Systems aktivieren" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 #, fuzzy #| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to halt the system." msgstr "" "Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 #, fuzzy #| msgid "Hibernate the system while other users are logged in" msgid "Halt the system while other users are logged in" @@ -475,7 +496,7 @@ msgstr "" "Den Ruhezustand des Systems aktivieren, während andere Benutzer angemeldet " "sind" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while other users are " @@ -487,7 +508,7 @@ msgstr "" "Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig, " "während andere Benutzer angemeldet sind." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 #, fuzzy #| msgid "Hibernate the system while an application is inhibiting this" msgid "Halt the system while an application is inhibiting this" @@ -495,7 +516,7 @@ msgstr "" "Das System in den Ruhezustand versetzen, während eine Anwendung wünscht dies " "zu verhindern" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -507,21 +528,21 @@ msgstr "" "Legitimierung ist zum Versetzen des System in den Ruhezustand notwendig, " "während eine Anwendung wünscht dies zu verhindern." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Das System in Bereitschaft versetzen" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "" "Das System in Bereitschaft versetzen, während andere Benutzer angemeldet " "sind." -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -529,13 +550,13 @@ msgstr "" "Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig, " "während andere Benutzer angemeldet sind." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" "Das System in Bereitschaft versetzen, während eine Anwendung anfordert dies " "zu unterbinden" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -543,22 +564,22 @@ msgstr "" "Legitimierung ist zum Versetzen des Systems in Bereitschaft notwendig, " "während eine Anwendung anfordert dies zu unterbinden." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Den Ruhezustand des Systems aktivieren" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "" "Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "" "Den Ruhezustand des Systems aktivieren, während andere Benutzer angemeldet " "sind" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -566,13 +587,13 @@ msgstr "" "Legitimierung ist zum Aktivieren des Ruhezustands des Systems notwendig, " "während andere Benutzer angemeldet sind." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" "Das System in den Ruhezustand versetzen, während eine Anwendung wünscht dies " "zu verhindern" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -580,37 +601,37 @@ msgstr "" "Legitimierung ist zum Versetzen des System in den Ruhezustand notwendig, " "während eine Anwendung wünscht dies zu verhindern." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Aktive Sitzungen, Benutzer und Arbeitsstationen verwalten" # https://www.freedesktop.org/software/systemd/man/sd-login.html -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Legitimierung ist zur Verwaltung aktiver Sitzungen, Benutzern und " "Arbeitsstationen notwendig." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Aktive Sitzungen sperren und entsperren" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Legitimierung ist zum Sperren und Entsperren aktiver Sitzungen notwendig." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "Legitimierung ist zum Festlegen der Systemzeitzone notwendig." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" @@ -618,7 +639,7 @@ msgstr "" "Mitteilungen an die Firmware zum Starten in die Einrichtungsoberfläche " "zulassen" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -626,11 +647,11 @@ msgstr "" "Legitimierung ist zum Starten der Firmware in die Einrichtungsoberfläche " "notwendig." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -642,11 +663,11 @@ msgstr "" "Legitimierung ist zum Starten der Firmware in die Einrichtungsoberfläche " "notwendig." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -658,19 +679,19 @@ msgstr "" "Legitimierung ist zum Starten der Firmware in die Einrichtungsoberfläche " "notwendig." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Nachricht an alle einstellen" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Legitimierung ist zum Einstellen einer Nachricht an alle notwendig" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to change the virtual terminal." @@ -1036,23 +1057,23 @@ msgstr "" "Legitimierung ist zum Festlegen, ob Netzwerkzeitabgeich eingeschaltet sein " "soll, erforderlich." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Legitimierung ist zum Starten von »$(unit)« notwendig." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Legitimierung ist zum Stoppen von »$(unit)« notwendig." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Legitimierung ist zum erneuten Laden von »$(unit)« notwendig." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Legitimierung ist zum Neustarten von »$(unit)« notwendig." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -1061,18 +1082,18 @@ msgid "" msgstr "" "Legitimierung ist zum Festlegen der Eigenschaften von »$(unit)« notwendig." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Legitimierung ist zum Zurücksetzen des Status »fehlgeschlagen« von »$(unit)« " "notwendig" -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" "Legitimierung ist zum Festlegen der Eigenschaften von »$(unit)« notwendig." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -1083,7 +1104,7 @@ msgstr "" "Legitimierung ist zum Zurücksetzen des Status »fehlgeschlagen« von »$(unit)« " "notwendig" -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/el.po b/po/el.po index fa581d9a9..7d992885d 100644 --- a/po/el.po +++ b/po/el.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2014-04-29 09:17+0300\n" "Last-Translator: Dimitris Spingos (Δημήτρης Σπίγγος) \n" "Language-Team: team@lists.gnome.gr\n" @@ -333,11 +333,31 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:117 #, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Να επιτρέπεται στις εφαρμογές να αποτρέπουν τη διαχείριση του πλήκτρου " +"ενεργοποίησης του συστήματος" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Απαιτείται πιστοποίηση για να επιτρέπεται σε μια εφαρμογή να αποτρέψει την " +"διαχείριση του πλήκτρου ενεργοποίησης του συστήματος." + +#: src/login/org.freedesktop.login1.policy:128 +#, fuzzy #| msgid "Allow non-logged-in users to run programs" msgid "Allow non-logged-in user to run programs" msgstr "Να επιτρέπεται σε μη συνδεμένους χρήστες να εκτελούν προγράμματα" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 #, fuzzy #| msgid "Authentication is required to run programs as a non-logged-in user." msgid "Explicit request is required to run programs as a non-logged-in user." @@ -345,48 +365,48 @@ msgstr "" "Απαιτείται πιστοποίηση για να επιτρέπεται σε μη συνδεμένους χρήστες να " "εκτελούν προγράμματα." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Να επιτρέπεται σε μη συνδεμένους χρήστες να εκτελούν προγράμματα" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Απαιτείται πιστοποίηση για να επιτρέπεται σε μη συνδεμένους χρήστες να " "εκτελούν προγράμματα." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Να επιτρέπεται η προσάρτηση συσκευών στους σταθμούς εργασίας" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Απαιτείται πιστοποίηση για προσάρτηση μιας συσκευής σε έναν σταθμό εργασίας." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Αφαίρεση συσκευής από προσαρτήσεις σταθμού εργασίας" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Απαιτείται πιστοποίηση για επαναφορά του τρόπου που οι συσκευές προσαρτώνται " "στους σταθμούς εργασίας." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Σβήσιμο του συστήματος" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Απαιτείται πιστοποίηση για την σβήσιμο του συστήματος." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Σβήσιμο του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -394,11 +414,11 @@ msgstr "" "Απαιτείται πιστοποίηση για σβήσιμο του συστήματος ενώ άλλοι χρήστες είναι " "συνδεμένοι." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Απενεργοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί." -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -406,19 +426,19 @@ msgstr "" "Απαιτείται πιστοποίηση για απενεργοποίηση του συστήματος ενώ μια εφαρμογή " "ζήτησε να αποτραπεί." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Επανεκκίνηση του συστήματος" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Επανεκκίνηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -426,11 +446,11 @@ msgstr "" "Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος ενώ άλλοι χρήστες " "είναι συνδεμένοι." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Επανεκκίνηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -438,25 +458,25 @@ msgstr "" "Απαιτείται πιστοποίηση για επανεκκίνηση του συστήματος ενώ μια εφαρμογή " "ζήτησε να αποτραπεί." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 #, fuzzy #| msgid "Hibernate the system" msgid "Halt the system" msgstr "Αδρανοποίηση του συτήματος" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 #, fuzzy #| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to halt the system." msgstr "Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 #, fuzzy #| msgid "Hibernate the system while other users are logged in" msgid "Halt the system while other users are logged in" msgstr "Αδρανοποίηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while other users are " @@ -468,13 +488,13 @@ msgstr "" "Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ άλλοι χρήστες " "είναι συνδεμένοι." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 #, fuzzy #| msgid "Hibernate the system while an application is inhibiting this" msgid "Halt the system while an application is inhibiting this" msgstr "Αδρανοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -486,19 +506,19 @@ msgstr "" "Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ μια εφαρμογή " "ζήτησε να αποτραπεί." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Αναστολή του συστήματος" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Απαιτείται πιστοποίηση για την αναστολή του συστήματος." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Αναστολή του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -506,11 +526,11 @@ msgstr "" "Απαιτείται πιστοποίηση για αναστολή του συστήματος ενώ άλλοι χρήστες είναι " "συνδεμένοι." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Αναστολή του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -518,19 +538,19 @@ msgstr "" "Απαιτείται πιστοποίηση για αναστολή του συστήματος ενώ μια εφαρμογή ζήτησε " "να αποτραπεί." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Αδρανοποίηση του συτήματος" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Αδρανοποίηση του συστήματος ενώ άλλοι χρήστες είναι συνδεμένοι" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -538,11 +558,11 @@ msgstr "" "Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ άλλοι χρήστες " "είναι συνδεμένοι." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Αδρανοποίηση του συστήματος ενώ μια εφαρμογή ζήτησε να αποτραπεί" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -550,83 +570,83 @@ msgstr "" "Απαιτείται πιστοποίηση για αδρανοποίηση του συστήματος ενώ μια εφαρμογή " "ζήτησε να αποτραπεί." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 #, fuzzy msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Απαιτείται πιστοποίηση για προσάρτηση μιας συσκευής σε έναν σταθμό εργασίας." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 #, fuzzy msgid "Authentication is required to lock or unlock active sessions." msgstr "Απαιτείται πιστοποίηση για να ορίσετε πληροφορίες τοπικής μηχανής." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα ζώνης του συστήματος." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy msgid "Indicate to the firmware to boot to setup interface" msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 #, fuzzy msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 #, fuzzy msgid "Authentication is required to set a wall message" msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to change the virtual terminal." @@ -973,51 +993,51 @@ msgstr "" "Απαιτείται πιστοποίηση για να ελέγξετε αν ο συγχρονισμός ώρας δικτύου θα " "ενεργοποιηθεί." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 #, fuzzy msgid "Authentication is required to start '$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 #, fuzzy msgid "Authentication is required to stop '$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 #, fuzzy msgid "Authentication is required to reload '$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 #, fuzzy msgid "Authentication is required to restart '$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 #, fuzzy msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 #, fuzzy msgid "Authentication is required to set properties on '$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε την ώρα του συστήματος." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." msgstr "Απαιτείται πιστοποίηση για να ορίσετε τοπικά όνομα οικοδεσπότη." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." diff --git a/po/es.po b/po/es.po index 9d92545da..88e07131d 100644 --- a/po/es.po +++ b/po/es.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2020-08-24 07:29+0000\n" "Last-Translator: Adolfo Jayme Barrientos \n" "Language-Team: Spanish , 2020. +# Julien Humbert , 2020, 2021. +# Arnaud T. , 2021. msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-08-28 05:29+0000\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-01-14 06:37+0000\n" "Last-Translator: Julien Humbert \n" "Language-Team: French \n" @@ -18,7 +19,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n > 1;\n" -"X-Generator: Weblate 4.2.1\n" +"X-Generator: Weblate 4.4.1\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -59,8 +60,8 @@ msgid "" "Authentication is required to set or unset system and service manager " "environment variables." msgstr "" -"Authentification requise pour définir ou supprimer des variables d’" -"environnement du système ou du gestionnaire de services." +"Authentification requise pour définir ou supprimer des variables " +"d’environnement du système ou du gestionnaire de services." #: src/core/org.freedesktop.systemd1.policy.in:64 msgid "Reload the systemd state" @@ -192,8 +193,8 @@ msgstr "Télécharger une image de machine virtuelle (VM) ou de conteneur" #: src/import/org.freedesktop.import1.policy:43 msgid "Authentication is required to download a VM or container image" msgstr "" -"Authentification requise pour télécharger une image de machine virtuelle (VM)" -" ou de conteneur" +"Authentification requise pour télécharger une image de machine virtuelle " +"(VM) ou de conteneur" #: src/locale/org.freedesktop.locale1.policy:22 msgid "Set system locale" @@ -230,8 +231,8 @@ msgstr "Permet aux applications de retarder l’arrêt du système" #: src/login/org.freedesktop.login1.policy:34 msgid "Authentication is required for an application to delay system shutdown." msgstr "" -"Authentification requise pour permettre à une application de retarder l’" -"arrêt du système." +"Authentification requise pour permettre à une application de retarder " +"l’arrêt du système." #: src/login/org.freedesktop.login1.policy:44 msgid "Allow applications to inhibit system sleep" @@ -255,15 +256,16 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:65 msgid "Allow applications to inhibit automatic system suspend" -msgstr "Permet aux applications d’empêcher l’hibernation automatique du système" +msgstr "" +"Permet aux applications d’empêcher l’hibernation automatique du système" #: src/login/org.freedesktop.login1.policy:66 msgid "" "Authentication is required for an application to inhibit automatic system " "suspend." msgstr "" -"Authentification requise pour permettre à une application d’empêcher l’" -"hibernation automatique du système." +"Authentification requise pour permettre à une application d’empêcher " +"l’hibernation automatique du système." #: src/login/org.freedesktop.login1.policy:75 msgid "Allow applications to inhibit system handling of the power key" @@ -322,57 +324,71 @@ msgstr "" "gestion par le système du rabat de l’écran." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Permet aux applications d’empêcher la gestion du bouton de redémarrage du " +"système" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Authentification requise pour permettre à une application d’empêcher la " +"gestion du bouton de redémarrage du système." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Permet à un utilisateur non connecté d’exécuter des programmes" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" -"Requête explicite requise pour exécuter des programmes en tant qu’" -"utilisateur non connecté." +"Requête explicite requise pour exécuter des programmes en tant " +"qu’utilisateur non connecté." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Permet aux utilisateurs non connectés d’exécuter des programmes" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Authentification requise pour exécuter des programmes en tant qu’utilisateur " "non connecté." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Permet d’associer des périphériques à des postes (seats)" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Authentification requise pour associer un périphérique à un poste (seat)." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Révoquer les associations de périphériques aux postes (seats)" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Authentification requise pour révoquer les associations de périphériques aux " "postes (seats)." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Éteindre le système" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Authentification requise pour éteindre le système." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Éteindre le système alors que d’autres utilisateurs sont connectés" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -380,11 +396,11 @@ msgstr "" "Authentification requise pour éteindre le système alors que d’autres " "utilisateurs sont connectés." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Éteindre le système alors qu’une application a demandé de l’empêcher" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -392,19 +408,19 @@ msgstr "" "Authentification requise pour éteindre le système alors qu’une application a " "demandé de l’empêcher." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Redémarrer le système" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Authentification requise pour redémarrer le système." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Redémarrer le système alors que d’autres utilisateurs sont connectés" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -412,11 +428,11 @@ msgstr "" "Authentification requise pour redémarrer le système alors que d’autres " "utilisateurs sont connectés." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Redémarrer le système alors qu’une application a demandé de l’empêcher" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -424,19 +440,19 @@ msgstr "" "Authentification requise pour redémarrer le système alors qu’une application " "a demandé de l’empêcher." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Arrêter le système" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Authentification requise pour arrêter le système." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Arrêter le système alors que d’autres utilisateurs sont connectés" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -444,36 +460,32 @@ msgstr "" "Authentification requise pour arrêter le système alors que d’autres " "utilisateurs sont connectés." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Arrêter le système alors qu’une application a demandé de l’empêcher" -#: src/login/org.freedesktop.login1.policy:247 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while an application " -#| "is inhibiting this." +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." msgstr "" -"Authentification requise pour mettre le système en hibernation alors qu'une " -"application a demandé de l'empêcher." +"Authentification requise pour arrêter le système alors qu’une application a " +"demandé de l’empêcher." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Mettre le système en veille" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Authentification requise pour mettre le système en veille." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "" "Mettre le système en veille alors que d’autres utilisateurs sont connectés" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -481,12 +493,12 @@ msgstr "" "Authentification requise pour mettre le système en veille alors que d’autres " "utilisateurs sont connectés." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" "Mettre le système en veille alors qu’une application a demandé de l’empêcher" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -494,35 +506,35 @@ msgstr "" "Authentification requise pour mettre le système en veille alors qu’une " "application a demandé de l’empêcher." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Mettre le système en hibernation" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Authentification requise pour mettre le système en hibernation." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "" "Mettre le système en hibernation alors que d’autres utilisateurs sont " "connectés" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." msgstr "" -"Authentification requise pour mettre le système en hibernation alors que d’" -"autres utilisateurs sont connectés." +"Authentification requise pour mettre le système en hibernation alors que " +"d’autres utilisateurs sont connectés." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" "Mettre le système en hibernation alors qu’une application a demandé de " "l’empêcher" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -530,53 +542,53 @@ msgstr "" "Authentification requise pour mettre le système en hibernation alors qu’une " "application a demandé de l’empêcher." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Gérer les sessions actives, les utilisateurs et les postes (seats)" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Authentification requise pour gérer les sessions actives, les utilisateurs " "et les postes (seats)." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Verrouiller ou déverrouiller des sessions actives" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Authentification requise pour verrouiller ou déverrouiller des sessions " "actives." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Définir la « raison » du redémarrage dans le noyau" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Authentification requise pour définir la « raison » du redémarrage dans le " "noyau." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Indiquer au micrologiciel de démarrer sur l’interface de configuration" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "" -"Authentification requise pour indiquer au micrologiciel de démarrer sur l’" -"interface de configuration." +"Authentification requise pour indiquer au micrologiciel de démarrer sur " +"l’interface de configuration." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Indiquer au programme d’amorçage d’afficher le menu au démarrage" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -584,11 +596,11 @@ msgstr "" "Authentification requise pour indiquer au programme d’amorçage d’afficher le " "menu au démarrage." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "Indiquer au programme d’amorçage de démarrer une entrée spécifique" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -596,19 +608,19 @@ msgstr "" "Authentification requise pour indiquer au programme d’amorçage de démarrer " "une entrée spécifique." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Définir un message wall" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Authentification requise pour définir un message wall" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "Changer de Session" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "Authentification requise pour changer de terminal virtuel." @@ -799,13 +811,12 @@ msgstr "Authentification requise pour réinitialiser les paramètres DNS." #: src/network/org.freedesktop.network1.policy:143 msgid "DHCP server sends force renew message" -msgstr "" +msgstr "Le serveur DHCP envoie un message de renouvellement forcé" #: src/network/org.freedesktop.network1.policy:144 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to send force renew message." -msgstr "Authentification requise pour définir un message wall." +msgstr "" +"Authentification requise pour envoyer un message de renouvellement forcé." #: src/network/org.freedesktop.network1.policy:154 msgid "Renew dynamic addresses" @@ -926,44 +937,44 @@ msgid "" "Authentication is required to control whether network time synchronization " "shall be enabled." msgstr "" -"Authentification requise pour activer ou désactiver la synchronisation de l’" -"heure avec le réseau." +"Authentification requise pour activer ou désactiver la synchronisation de " +"l’heure avec le réseau." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Authentification requise pour démarrer « $(unit) »." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Authentification requise pour arrêter « $(unit) »." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Authentification requise pour recharger « $(unit) »." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Authentification requise pour redémarrer « $(unit) »." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "" -"Authentification requise pour envoyer un signal UNIX aux processus de « " -"$(unit) »." +"Authentification requise pour envoyer un signal UNIX aux processus de " +"« $(unit) »." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" -"Authentification requise pour réinitialiser l’état d’« échec » de « $(unit) " -"»." +"Authentification requise pour réinitialiser l’état d’« échec » de " +"« $(unit) »." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Authentification requise pour définir des propriétés de « $(unit) »." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -971,16 +982,12 @@ msgstr "" "Authentification requise pour supprimer les fichiers et les dossiers " "associés à « $(unit) »." -#: src/core/dbus-unit.c:760 -#, fuzzy -#| msgid "" -#| "Authentication is required to send a UNIX signal to the processes of " -#| "'$(unit)'." +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" -"Authentification requise pour envoyer un signal UNIX aux processus de " -"« $(unit) »." +"Authentification requise pour la suspension ou la reprise des processus de " +"l'unité « $(unit) »." #~ msgid "" #~ "Authentication is required to halt the system while an application asked " diff --git a/po/gl.po b/po/gl.po index 4843e21c4..babdfd25b 100644 --- a/po/gl.po +++ b/po/gl.po @@ -5,7 +5,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2019-12-29 22:30+0100\n" "Last-Translator: Fran Diéguez \n" "Language-Team: gnome-l10n-gl@gnome.org\n" @@ -324,56 +324,75 @@ msgstr "" "do sistema do interruptor da tapa." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Permitir ás aplicacións inhibir a xestión do sistema da tecla de acendido" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Requírese autenticación para permitirlle a unha aplicación inhibir a xestión " +"do sistema da tecla de acendido." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Permitirlle a usuarios sen unha sesión iniciada executar programas" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Requírese autenticación para poder executar programas como un usuario sen " "unha sesión iniciada." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Permitirlle a usuarios sen unha sesión iniciada executar programas" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Requírese autenticación para permitirlle executar programas a un usuario sen " "unha sesión iniciada." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Permitir conectar anexar a asentos" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "Requírese autenticación para anexar un dispositivo a un asento." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Reiniciar os anexos do dispositivo aos asentos" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Requírese autenticación para reiniciar como os dispositivos están anexados " "aos asentos." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Apagar o sistema" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Requírese autenticación para apagar o sistema." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Apagar o sistema mentres hai usuarios con unha sesión iniciada" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -381,11 +400,11 @@ msgstr "" "Requírese autenticación para apagar o sistema mentres hai usuarios con unha " "sesión iniciada." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Apagar o sistema cando unha aplicación solicitou a súa inhibición" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -393,19 +412,19 @@ msgstr "" "Requírese autenticación para apagar o sistema mentres unha aplicación " "solicitou a súa inhibición." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Reiniciar o sistema" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Requírese autenticación para reiniciar o sistema." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Reiniciar o sistema mentres outros usuarios teñen unha sesión iniciada" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -413,11 +432,11 @@ msgstr "" "Requírese autenticación para reiniciar o sistema mentres outros usuarios " "teñen unha sesión iniciada." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Reiniciar o sistema cando unha aplicación solicitou a súa inhibición" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -425,19 +444,19 @@ msgstr "" "Requírese autenticación para reiniciar o sistema mentres unha aplicación " "solicitou a súa inhibición." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Deter o sistema" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Requírese autenticación para deter o sistema." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Deter o sistema mentres outros usuarios teñen unha sesión iniciada" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -445,11 +464,11 @@ msgstr "" "Requírese autenticación para deter o sistema mentres outros usuarios teñen " "unha sesión iniciada." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Deter o sistema cando unha aplicación solicitou a súa inhibición" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -461,19 +480,19 @@ msgstr "" "Requírese autenticación para hibernar o sistema mentres unha aplicación " "solicitou a súa inhibición." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Suspender o sistema" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Requírese autenticación para suspender o sistema." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Suspender o sistema mentres outros usuarios teñen unha sesión iniciada" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -481,11 +500,11 @@ msgstr "" "Requírese autenticación para suspender o sistema mentres outros usuarios " "teñen unha sesión iniciada." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Suspender o sistema cando unha aplicación solicitou a súa inhibición" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -493,19 +512,19 @@ msgstr "" "Requírese autenticación para suspender o sistema mentres unha aplicación " "solicitou a súa inhibición." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Hibernar o sistema" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Requírese autenticación para hibernar o sistema." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Hibernar o sistema mentres outros usuarios teñen unha sesión iniciada" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -513,11 +532,11 @@ msgstr "" "Requírese autenticación para hibernar o sistema mentres outros usuarios " "teñen unha sesión iniciada." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Hibernar o sistema cando unha aplicación solicitou a súa inhibición" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -525,39 +544,39 @@ msgstr "" "Requírese autenticación para hibernar o sistema mentres unha aplicación " "solicitou a súa inhibición." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Xestionar as sesións, usuarios e asentos activos" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Requírese autenticación para xestionar as sesións, usuarios e asentos " "activos." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Bloquear ou desbloquear sesión activas" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Requírese autenticación para bloquear ou desbloquear as sesións activas." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Estabelecer a «razón» de reinicio no núcleo" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Requírese autenticación para estabelecer a «razón» de reinicio no núcleo." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Indícalle ao firmware arrincar para configurar unha interface" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -565,12 +584,12 @@ msgstr "" "Requírese autenticación para indicarlle ao firmware arrincar para configurar " "unha interface." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" "Indicarlle ao xestor de arranque para arrincar ao menú do xestor de arranque" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -578,12 +597,12 @@ msgstr "" "Requírese autenticación para indicarlle ao xestor de arranque arrincar ao " "menú do xestor de arranque." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" "Indícalle ao cargador de arranque que arranque nunha entrada específica" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -591,19 +610,19 @@ msgstr "" "Requírese autenticación para indicarlle ao xestor de arranque arrincar a " "unha entrada específica do xestor de arranque." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Estabelecer a mensaxe do muro" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Requírese autenticación para estabelecer unha mensaxe de muro" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." @@ -921,23 +940,23 @@ msgstr "" "Requírese autenticación para controlar se a sincronización de hora por rede " "debería activarse." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Requírese autenticación para inciar '$(unit)'." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Requírese autenticación para deter '$(unit)'." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Requírese autenticación para recargar '$(unit)'." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Requírese autenticación para reiniciar '$(unit)'." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." @@ -945,16 +964,16 @@ msgstr "" "Requírese autenticación para enviarlle un sinal UNIX aos procesos de " "'$(unit)'." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Requírese autenticación para reinicair o estado «fallido» de '$(unit)'." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Requírese autenticación para estabelecer as propiedades en '$(unit)'." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -962,7 +981,7 @@ msgstr "" "Requírese autenticación para eliminar ficheiros ou directorios asociados con " "'$(unit)'." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to send a UNIX signal to the processes of " diff --git a/po/hr.po b/po/hr.po index 23704ce95..c9e3d2361 100644 --- a/po/hr.po +++ b/po/hr.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2020-08-29 11:29+0000\n" "Last-Translator: Gogo Gogsi \n" "Language-Team: Croatian \n" "Language-Team: Hungarian \n" @@ -323,59 +323,78 @@ msgstr "" "kezelésének meggátlásához." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Alkalmazások meggátolhatják a bekapcsoló gomb rendszer általi kezelését" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Hitelesítés szükséges egy alkalmazás számára a bekapcsoló gomb rendszer " +"általi kezelésének meggátlásához." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Programfuttatás engedélyezése be nem jelentkezett felhasználó számára" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Határozott kérés szükséges a programfuttatáshoz be nem jelentkezett " "felhasználóként." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Programfuttatás engedélyezése be nem jelentkezett felhasználók számára" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Hitelesítés szükséges a programfuttatáshoz be nem jelentkezett " "felhasználóként." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Eszközök csatolásának engedélyezése munkaállomásokhoz" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Hitelesítés szükséges eszköz csatolásának engedélyezéséhez egy " "munkaállomáshoz" -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Eszközök és munkaállomások csatolásainak törlése" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Hitelesítés szükséges az eszközök munkaállomásokhoz csatolásainak " "alaphelyzetbe állításához." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "A rendszer kikapcsolása" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Hitelesítés szükséges a rendszer kikapcsolásához." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "" "A rendszer kikapcsolása miközben be vannak jelentkezve más felhasználók" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -383,12 +402,12 @@ msgstr "" "Hitelesítés szükséges a rendszer kikapcsolásához miközben be vannak " "jelentkezve más felhasználók." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "" "A rendszer kikapcsolása miközben egy alkalmazás ennek meggátlását kérte" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -396,19 +415,19 @@ msgstr "" "Hitelesítés szükséges a rendszer kikapcsolásához miközben egy alkalmazás " "ennek meggátlását kérte." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "A rendszer újraindítása" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Hitelesítés szükséges a rendszer újraindításához." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "A rendszer újraindítása mialatt be vannak jelentkezve más felhasználók" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -416,12 +435,12 @@ msgstr "" "Hitelesítés szükséges a rendszer újraindításához miközben be vannak " "jelentkezve más felhasználók." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" "A rendszer újraindítása miközben egy alkalmazás ennek meggátlását kérte" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -429,25 +448,25 @@ msgstr "" "Hitelesítés szükséges a rendszer újraindításához miközben egy alkalmazás " "ennek meggátlását kérte." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 #, fuzzy #| msgid "Hibernate the system" msgid "Halt the system" msgstr "A rendszer hibernálása" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 #, fuzzy #| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to halt the system." msgstr "Hitelesítés szükséges a rendszer hibernálásához." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 #, fuzzy #| msgid "Hibernate the system while other users are logged in" msgid "Halt the system while other users are logged in" msgstr "A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while other users are " @@ -459,13 +478,13 @@ msgstr "" "Hitelesítés szükséges a rendszer hibernálásához miközben be vannak " "jelentkezve más felhasználók." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 #, fuzzy #| msgid "Hibernate the system while an application is inhibiting this" msgid "Halt the system while an application is inhibiting this" msgstr "A rendszer hibernálása miközben egy alkalmazás ennek meggátlását kérte" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -477,20 +496,20 @@ msgstr "" "Hitelesítés szükséges a rendszer hibernálásához miközben egy alkalmazás " "ennek meggátlását kérte." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "A rendszer felfüggesztése" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Hitelesítés szükséges a rendszer felfüggesztéséhez." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "" "A rendszer felfüggesztése mialatt be vannak jelentkezve más felhasználók" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -498,12 +517,12 @@ msgstr "" "Hitelesítés szükséges a rendszer felfüggesztéséhez miközben be vannak " "jelentkezve más felhasználók." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" "A rendszer felfüggesztése miközben egy alkalmazás ennek meggátlását kérte" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -511,19 +530,19 @@ msgstr "" "Hitelesítés szükséges a rendszer felfüggesztéséhez miközben egy alkalmazás " "ennek meggátlását kérte." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "A rendszer hibernálása" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Hitelesítés szükséges a rendszer hibernálásához." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "A rendszer hibernálása mialatt be vannak jelentkezve más felhasználók" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -531,11 +550,11 @@ msgstr "" "Hitelesítés szükséges a rendszer hibernálásához miközben be vannak " "jelentkezve más felhasználók." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "A rendszer hibernálása miközben egy alkalmazás ennek meggátlását kérte" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -543,42 +562,42 @@ msgstr "" "Hitelesítés szükséges a rendszer hibernálásához miközben egy alkalmazás " "ennek meggátlását kérte." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Aktív munkamenetek, felhasználók és munkaállomások kezelése" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Hitelesítés szükséges az aktív munkamenetek, felhasználók és munkaállomások " "kezeléséhez." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Aktív munkamenetek zárolása vagy feloldása" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Hitelesítés szükséges az aktív munkamenetek zárolásához vagy feloldásához." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "Hitelesítés szükséges a rendszer időzónájának beállításához." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" msgstr "A firmware-nek jelezhető, hogy a beállítófelületet bootolja" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -586,11 +605,11 @@ msgstr "" "Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet " "bootolja" -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -602,11 +621,11 @@ msgstr "" "Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet " "bootolja" -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -618,19 +637,19 @@ msgstr "" "Hitelesítés szükséges a firmware-nek jelzéshez, hogy a beállítófelületet " "bootolja" -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Falüzenet beállítása" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Hitelesítés szükséges a falüzenet beállításához" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to change the virtual terminal." @@ -975,23 +994,23 @@ msgid "" "shall be enabled." msgstr "Hitelesítés szükséges a hálózati időszinkronizáció engedélyezéséhez." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Hitelesítés szükséges a következő elindításához: „$(unit)”." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Hitelesítés szükséges a következő leállításához: „$(unit)”." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Hitelesítés szükséges a következő újratöltéséhez: „$(unit)”." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Hitelesítés szükséges a következő újraindításához: „$(unit)”." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -1000,18 +1019,18 @@ msgid "" msgstr "" "Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: " "„$(unit)”." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" "Hitelesítés szükséges a következő tulajdonságainak beállításához: „$(unit)”." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -1022,7 +1041,7 @@ msgstr "" "Hitelesítés szükséges a következő „sikertelen” állapotának törléséhez: " "„$(unit)”." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/id.po b/po/id.po index 3e5fb7a51..eb9799218 100644 --- a/po/id.po +++ b/po/id.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2018-03-04 11:12+0700\n" "Last-Translator: Andika Triwidada \n" "Language-Team: Indonesian \n" @@ -302,55 +302,73 @@ msgstr "" "atas saklar lid." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "Ijinkan aplikasi mencegah penanganan sistem atas tombol daya" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Otentikasi diperlukan bagi suatu aplikasi untuk mencegah penanganan sistem " +"atas tombol daya." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Ijinkan pengguna yang tidak log masuk menjalankan program" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Permintaan eksplisit diperlukan untuk menjalankan program sebagai pengguna " "yang tidak log masuk." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Ijinkan pengguna yang tidak log masuk menjalankan program" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Otentikasi diperlukan untuk menjalankan program sebagai pengguna yang tidak " "log masuk." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Ijinkan mencantolkan perangkat ke seat" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "Otentikasi diperlukan untuk mencantol suatu perangkat ke sebuah seat." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Siram perangkat untuk mendudukkan lampiran" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Otentikasi diperlukan untuk me-reset bagaimana perangkat dicantolkan ke seat." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Matikan daya sistem" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Otentikasi diperlukan untuk mematikan daya sistem." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Matikan daya sistem ketika pengguna lain sedang log masuk" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -358,11 +376,11 @@ msgstr "" "Otentikasi diperlukan untuk mematikan daya sistem ketika pengguna lain " "sedang log masuk." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Matikan daya sistem ketika sebuah aplikasi meminta untuk mencegahnya" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -370,19 +388,19 @@ msgstr "" "Otentikasi diperlukan untuk mematikan daya sistem ketika sebuah aplikasi " "meminta untuk mencegahnya." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Boot ulang sistem" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Otentikasi diperlukan untuk mem-boot ulang sistem." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Boot ulang sistem ketika pengguna lain sedang log masuk" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -390,11 +408,11 @@ msgstr "" "Otentikasi diperlukan untuk mem-boot ulang sistem ketika pengguna lain " "sedang log masuk." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Boot ulang sistem ketika sebuah aplikasi meminta untuk mencegahnya" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -402,19 +420,19 @@ msgstr "" "Otentikasi diperlukan untuk mem-boot ulang sistem ketika sebuah aplikasi " "meminta untuk mencegahnya." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Halt sistem" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Otentikasi diperlukan untuk meng-halt sistem." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Halt sistem ketika pengguna lain sedang log masuk" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -422,11 +440,11 @@ msgstr "" "Otentikasi diperlukan untuk meng-halt sistem ketika pengguna lain sedang log " "masuk." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Halt sistem ketika sebuah aplikasi meminta untuk mencegahnya" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -438,19 +456,19 @@ msgstr "" "Otentikasi diperlukan untuk menghibernasi sistem ketika sebuah aplikasi " "meminta mencegahnya." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Suspensikan sistem" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Otentikasi diperlukan untuk mensuspensi sistem." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Suspensikan sistem ketika pengguna lain sedang log masuk" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -458,11 +476,11 @@ msgstr "" "Otentikasi diperlukan untuk mensuspensi sistem ketika pengguna lain sedang " "log masuk." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Suspensikan sistem ketika sebuah aplikasi meminta untuk mencegahnya" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -470,19 +488,19 @@ msgstr "" "Otentikasi diperlukan untuk mensuspensi sistem ketika suatu aplikasi meminta " "untuk mencegahnya." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Hibernasikan sistem" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Otentikasi diperlukan untuk menghibernasi sistem." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Hibernasikan sistem ketika pengguna lain sedang log masuk." -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -490,11 +508,11 @@ msgstr "" "Otentikasi diperlukan untuk menghibernasi sistem ketika pengguna lain sedang " "log masuk." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Hibernasikan sistem ketika sebuah aplikasi meminta untuk mencegahnya." -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -502,39 +520,39 @@ msgstr "" "Otentikasi diperlukan untuk menghibernasi sistem ketika sebuah aplikasi " "meminta mencegahnya." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Kelola seat, pengguna, dan sesi aktif" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "Otentikasi diperlukan untuk mengelola seat, pengguna, dan sesi aktif." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Kunci/buka kunci sesi aktif" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "Otentikasi diperlukan untuk mengunci atau membuka kunci sesi aktif." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "Otentikasi diperlukan untuk menyetel zona waktu sistem." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" msgstr "Ijinkan indikasi ke firmware untuk boot ke antar muka penyiapan" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -542,11 +560,11 @@ msgstr "" "Otentikasi diperlukan untuk mengindikasikan ke firmware agar boot ke " "antarmuka penyiapan." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -558,11 +576,11 @@ msgstr "" "Otentikasi diperlukan untuk mengindikasikan ke firmware agar boot ke " "antarmuka penyiapan." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -574,19 +592,19 @@ msgstr "" "Otentikasi diperlukan untuk mengindikasikan ke firmware agar boot ke " "antarmuka penyiapan." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Setel suatu pesan wall" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Otentikasi diperlukan untuk menyetel pesan wall" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." @@ -934,23 +952,23 @@ msgstr "" "Otentikasi diperlukan untuk mengendalikan apakah sinkronisasi waktu jaringan " "mesti difungsikan." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Otentikasi diperlukan untuk memulai '$(unit)'." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Otentikasi diperlukan untuk menghentikan '$(unit)'." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Otentikasi diperlukan untuk memuat ulang '$(unit)'." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Otentikasi diperlukan untuk memulai ulang '$(unit)'." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -958,16 +976,16 @@ msgid "" "'$(unit)'." msgstr "Otentikasi diperlukan untuk menata properti pada '$(unit)'." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Otentikasi diperlukan untuk me-reset keadaan \"failed\" dari '$(unit)'." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Otentikasi diperlukan untuk menata properti pada '$(unit)'." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -977,7 +995,7 @@ msgid "" msgstr "" "Otentikasi diperlukan untuk me-reset keadaan \"failed\" dari '$(unit)'." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/it.po b/po/it.po index 595e4868a..42156d5a1 100644 --- a/po/it.po +++ b/po/it.po @@ -2,21 +2,21 @@ # # Italian translation for systemd package # Traduzione in italiano per il pacchetto systemd -# Daniele Medri , 2013-2020. +# Daniele Medri , 2013-2021. msgid "" msgstr "" "Project-Id-Version: systemd\n" -"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-10-03 09:52+0200\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-01-08 17:51+0100\n" "Last-Translator: Daniele Medri \n" +"Language-Team: italian\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" "X-Generator: Poedit 2.2.1\n" -"Language-Team: \n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -26,7 +26,8 @@ msgstr "Invia la frase segreta (passphrase) al sistema" msgid "" "Authentication is required to send the entered passphrase back to the system." msgstr "" -"Autenticazione richiesta per inviare la frase segreta (passphrase) al sistema." +"Autenticazione richiesta per inviare la frase segreta (passphrase) al " +"sistema." #: src/core/org.freedesktop.systemd1.policy.in:33 msgid "Manage system services or other units" @@ -101,7 +102,7 @@ msgstr "Aggiorna un'area home" #: src/home/org.freedesktop.home1.policy:44 msgid "Authentication is required to update a user's home area." -msgstr "Autenticazione richiesta per aggiornare l'area home di un l'utente." +msgstr "Autenticazione richiesta per aggiornare l'area home di un utente." #: src/home/org.freedesktop.home1.policy:53 msgid "Resize a home area" @@ -109,14 +110,15 @@ msgstr "Ridimensiona un'area home" #: src/home/org.freedesktop.home1.policy:54 msgid "Authentication is required to resize a user's home area." -msgstr "Autenticazione richiesta per ridimensionare l'area home di un'utente." +msgstr "Autenticazione richiesta per ridimensionare l'area home di un utente." #: src/home/org.freedesktop.home1.policy:63 msgid "Change password of a home area" msgstr "Modifica password di un'area home" #: src/home/org.freedesktop.home1.policy:64 -msgid "Authentication is required to change the password of a user's home area." +msgid "" +"Authentication is required to change the password of a user's home area." msgstr "" "Autenticazione richiesta per modificare la password dell'area home di un " "utente." @@ -157,7 +159,7 @@ msgstr "Ottieni UUID del prodotto" #: src/hostname/org.freedesktop.hostname1.policy:52 msgid "Authentication is required to get product UUID." -msgstr "Autenticazione richiesta per ottenere lo UUID del prodotto." +msgstr "Autenticazione richiesta per ottenere il UUID prodotto." #: src/import/org.freedesktop.import1.policy:22 msgid "Import a VM or container image" @@ -190,7 +192,8 @@ msgstr "Configura le impostazioni regionali di sistema" #: src/locale/org.freedesktop.locale1.policy:23 msgid "Authentication is required to set the system locale." msgstr "" -"Autenticazione richiesta per configurare le impostazioni regionali di sistema." +"Autenticazione richiesta per configurare le impostazioni regionali di " +"sistema." #: src/locale/org.freedesktop.locale1.policy:33 msgid "Set system keyboard settings" @@ -299,7 +302,7 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:107 msgid "Allow applications to inhibit system handling of the lid switch" msgstr "" -"Consenti alle applicazioni di inibire la gestione di sistema alla apertura/" +"Consenti alle applicazioni di inibire la gestione di sistema all'apertura o " "chiusura del portatile" #: src/login/org.freedesktop.login1.policy:108 @@ -308,60 +311,74 @@ msgid "" "the lid switch." msgstr "" "Autenticazione richiesta per consentire a un'applicazione di inibire la " -"gestione di sistema alla apertura/chiusura del portatile." +"gestione di sistema all'apertura o chiusura del portatile." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Consenti alle applicazioni di inibire la gestione di sistema del tasto di " +"riavvio" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Autenticazione richiesta affinché un'applicazione possa inibire la gestione " +"di sistema del tasto di riavvio." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Consenti agli utenti non connessi di eseguire programmi" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "È necessaria una richiesta esplicita per eseguire programmi come utenti non " "connessi." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Consenti agli utenti non connessi di eseguire programmi" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Autenticazione richiesta per consentire agli utenti non connessi di eseguire " "programmi." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Consenti di collegare dispositivi alle postazioni" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Autenticazione richiesta per collegare un dispositivo ad una postazione." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Scollega i dispositivi dalla postazione" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Autenticazione richiesta per ripristinare come i dispositivi sono collegati " "alle postazioni." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Spegni il sistema" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Autenticazione richiesta per spegnere il sistema." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Spegni il sistema mentre altri utenti sono connessi" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -369,11 +386,11 @@ msgstr "" "Autenticazione richiesta per spegnere il sistema mentre altri utenti sono " "connessi." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Spegni il sistema mentre un'applicazione chiede di inibirne l'azione" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -381,19 +398,19 @@ msgstr "" "Autenticazione richiesta per spegnere il sistema mentre un'applicazione " "chiede di inibirne l'azione." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Riavvia il sistema" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Autenticazione richiesta per riavviare il sistema." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Riavvia il sistema mentre altri utenti sono connessi" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -401,11 +418,11 @@ msgstr "" "Autenticazione richiesta per riavviare il sistema mentre altri utenti sono " "connessi." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Riavvia il sistema mentre un'applicazione chiede di inibirne l'azione" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -413,30 +430,31 @@ msgstr "" "Autenticazione richiesta per riavviare il sistema mentre un'applicazione " "chiede di inibirne l'azione." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Ferma il sistema" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Autenticazione richiesta per fermare il sistema." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Ferma il sistema mentre altri utenti sono connessi" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" -"Authentication is required to halt the system while other users are logged in." +"Authentication is required to halt the system while other users are logged " +"in." msgstr "" "Autenticazione richiesta per fermare il sistema mentre altri utenti sono " "connessi." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Ferma il sistema mentre un'applicazione chiede di inibirne l'azione" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." @@ -444,31 +462,31 @@ msgstr "" "Autenticazione richiesta per ibernare il sistema mentre un'applicazione ne " "inibisce l'azione." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Sospendi il sistema" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Autenticazione richiesta per sospendere il sistema." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Sospendi il sistema mentre altri utenti sono connessi" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" -"Authentication is required to suspend the system while other users are logged " -"in." +"Authentication is required to suspend the system while other users are " +"logged in." msgstr "" "Autenticazione richiesta per sospendere il sistema mentre altri utenti sono " "connessi." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Sospendi il sistema mentre un'applicazione chiede di inibirne l'azione" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -476,19 +494,19 @@ msgstr "" "Autenticazione richiesta per sospendere il sistema mentre un'applicazione " "chiede di inibirne l'azione." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Iberna il sistema" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Autenticazione richiesta per ibernare il sistema." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Iberna il sistema mentre altri utenti sono connessi" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -496,11 +514,11 @@ msgstr "" "Autenticazione richiesta per ibernare il sistema mentre altri utenti sono " "connessi." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Iberna il sistema mentre un'applicazione chiede di inibirne l'azione" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -508,38 +526,39 @@ msgstr "" "Autenticazione richiesta per ibernare il sistema mentre un'applicazione " "chiede di inibirne l'azione." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Gestione delle sessioni attive, utenti e postazioni" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Autenticazione richiesta per gestire le sessioni attive, gli utenti e le " "postazioni." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Blocca/sblocca sessioni attive" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "Autenticazione richiesta per bloccare o sbloccare le sessioni attive." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Indica il \"motivo\" del riavvio nel kernel" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" -"Autenticazione richiesta per configurare il \"motivo\" del riavvio nel kernel." +"Autenticazione richiesta per configurare il \"motivo\" del riavvio nel " +"kernel." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Indicate al firmware di avviare un'interfaccia di configurazione" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -547,43 +566,43 @@ msgstr "" "Autenticazione richiesta per indicare al firmware l'avvio di un'interfaccia " "di configurazione." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Indicate al boot loader di avviare un menu" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" -"Authentication is required to indicate to the boot loader to boot to the boot " -"loader menu." +"Authentication is required to indicate to the boot loader to boot to the " +"boot loader menu." msgstr "" -"Autenticazione richiesta per indicate al boot loader l'avvio di uno specifico " -"menu." +"Autenticazione richiesta per indicate al boot loader l'avvio di uno " +"specifico menu." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "Indicare al boot loader di avviare una voce specifica" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "" -"Autenticazione richiesta per indicare al boot loader l'avvio di una specifica " -"voce in elenco." +"Autenticazione richiesta per indicare al boot loader l'avvio di una " +"specifica voce in elenco." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Configura un messaggio per gli utenti" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Autenticazione richiesta per configurare un messaggio per gli utenti" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "Cambia sessione" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "Autenticazione richiesta per cambiare il terminale virtuale." @@ -624,7 +643,8 @@ msgid "Acquire a pseudo TTY in a local container" msgstr "Apri un pseudo TTY in un container locale" #: src/machine/org.freedesktop.machine1.policy:65 -msgid "Authentication is required to acquire a pseudo TTY in a local container." +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." msgstr "" "Autenticazione richiesta per aprire un pseudo TTY in un container locale." @@ -746,7 +766,8 @@ msgstr "Configura DNSSEC Negative Trust Anchors" #: src/network/org.freedesktop.network1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:122 msgid "Authentication is required to set DNSSEC Negative Trust Anchors." -msgstr "Autenticazione richiesta per configurare DNSSEC Negative Trust Anchors." +msgstr "" +"Autenticazione richiesta per configurare DNSSEC Negative Trust Anchors." #: src/network/org.freedesktop.network1.policy:121 msgid "Revert NTP settings" @@ -810,7 +831,8 @@ msgid "Attach or detach a portable service image" msgstr "Collega o meno un'immagine di servizio portabile" #: src/portable/org.freedesktop.portable1.policy:24 -msgid "Authentication is required to attach or detach a portable service image." +msgid "" +"Authentication is required to attach or detach a portable service image." msgstr "" "Autenticazione richiesta per collegare o meno un'immagine di servizio " "portabile." @@ -820,7 +842,8 @@ msgid "Delete or modify portable service image" msgstr "Elimina o modifica un'immagine di servizio portabile" #: src/portable/org.freedesktop.portable1.policy:35 -msgid "Authentication is required to delete or modify a portable service image." +msgid "" +"Authentication is required to delete or modify a portable service image." msgstr "" "Autenticazione richiesta per eliminare o modificare un'immagine di servizio " "portabile." @@ -876,8 +899,8 @@ msgstr "" #: src/timedate/org.freedesktop.timedate1.policy:44 msgid "" -"Authentication is required to control whether the RTC stores the local or UTC " -"time." +"Authentication is required to control whether the RTC stores the local or " +"UTC time." msgstr "" "Autenticazione richiesta per verificare se l'orologio di sistema (RTC) è " "configurato all'orario locale o al tempo civile (UTC)." @@ -891,42 +914,43 @@ msgid "" "Authentication is required to control whether network time synchronization " "shall be enabled." msgstr "" -"Autenticazione richiesta per verificare se la sincronizzazione dell'orario in " -"rete deve essere attivata." +"Autenticazione richiesta per verificare se la sincronizzazione dell'orario " +"in rete deve essere attivata." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Autenticazione richiesta per avviare '${unit}'." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Autenticazione richiesta per fermare '${unit}'." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Autenticazione richiesta per ricaricare '${unit}'." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Autenticazione richiesta per riavviare '${unit}'." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "" -"Autenticazione richiesta per inviare un segnale UNIX ai processi di '${unit}'." +"Autenticazione richiesta per inviare un segnale UNIX ai processi di " +"'${unit}'." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Autenticazione richiesta per riconfigurare lo stato \"fallito\" di '${unit}'." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Autenticazione richiesta per configurare le proprietà di '${unit}'." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -934,7 +958,7 @@ msgstr "" "Autenticazione richiesta per eliminare i file e le directory associate a " "'${unit}'." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" diff --git a/po/its/polkit.its b/po/its/polkit.its index 1c37e6bee..d9799dc7f 100644 --- a/po/its/polkit.its +++ b/po/its/polkit.its @@ -1,4 +1,5 @@ + diff --git a/po/its/polkit.loc b/po/its/polkit.loc index c7427ec67..82bac6697 100644 --- a/po/its/polkit.loc +++ b/po/its/polkit.loc @@ -1,4 +1,5 @@ + diff --git a/po/ja.po b/po/ja.po index 7e55f1efc..46bcb432f 100644 --- a/po/ja.po +++ b/po/ja.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-17 20:41+0900\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2018-10-27 07:41+0900\n" "Last-Translator: Yu Watanabe \n" "Language-Team: \n" diff --git a/po/kab.po b/po/kab.po new file mode 100644 index 000000000..8f6626a8d --- /dev/null +++ b/po/kab.po @@ -0,0 +1,852 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the systemd package. +# Slimane Selyan Amiri , 2021. +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-02-26 19:40+0000\n" +"Last-Translator: Slimane Selyan Amiri \n" +"Language-Team: Kabyle \n" +"Language: kab\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.4.2\n" + +#: src/core/org.freedesktop.systemd1.policy.in:22 +msgid "Send passphrase back to system" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:23 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:33 +msgid "Manage system services or other units" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:34 +msgid "Authentication is required to manage system services or other units." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:43 +msgid "Manage system service or unit files" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:44 +msgid "Authentication is required to manage system service or unit files." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:54 +msgid "Set or unset system and service manager environment variables" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:55 +msgid "" +"Authentication is required to set or unset system and service manager " +"environment variables." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:64 +msgid "Reload the systemd state" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:65 +msgid "Authentication is required to reload the systemd state." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:13 +msgid "Create a home area" +msgstr "Rnu tmennaḍt agejdan" + +#: src/home/org.freedesktop.home1.policy:14 +msgid "Authentication is required to create a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:23 +msgid "Remove a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:24 +msgid "Authentication is required to remove a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:33 +msgid "Check credentials of a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:34 +msgid "" +"Authentication is required to check credentials against a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:43 +msgid "Update a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:44 +msgid "Authentication is required to update a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:53 +msgid "Resize a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:54 +msgid "Authentication is required to resize a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:63 +msgid "Change password of a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:64 +msgid "" +"Authentication is required to change the password of a user's home area." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:20 +msgid "Set hostname" +msgstr "Sbadu isem n usenneftaɣ" + +#: src/hostname/org.freedesktop.hostname1.policy:21 +msgid "Authentication is required to set the local hostname." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:30 +msgid "Set static hostname" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:31 +msgid "" +"Authentication is required to set the statically configured local hostname, " +"as well as the pretty hostname." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:41 +msgid "Set machine information" +msgstr "Sbadu talɣut n tmacint" + +#: src/hostname/org.freedesktop.hostname1.policy:42 +msgid "Authentication is required to set local machine information." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:51 +msgid "Get product UUID" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:52 +msgid "Authentication is required to get product UUID." +msgstr "" + +#: src/import/org.freedesktop.import1.policy:22 +msgid "Import a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:23 +msgid "Authentication is required to import a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:32 +msgid "Export a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:33 +msgid "Authentication is required to export a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:42 +msgid "Download a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:43 +msgid "Authentication is required to download a VM or container image" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:22 +msgid "Set system locale" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:23 +msgid "Authentication is required to set the system locale." +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:33 +msgid "Set system keyboard settings" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:34 +msgid "Authentication is required to set the system keyboard settings." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:22 +msgid "Allow applications to inhibit system shutdown" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:23 +msgid "" +"Authentication is required for an application to inhibit system shutdown." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:33 +msgid "Allow applications to delay system shutdown" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:34 +msgid "Authentication is required for an application to delay system shutdown." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:44 +msgid "Allow applications to inhibit system sleep" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:45 +msgid "Authentication is required for an application to inhibit system sleep." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:55 +msgid "Allow applications to delay system sleep" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:56 +msgid "Authentication is required for an application to delay system sleep." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:65 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:66 +msgid "" +"Authentication is required for an application to inhibit automatic system " +"suspend." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:75 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:76 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the power key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:86 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:87 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the suspend key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:97 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:98 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the hibernate key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:107 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:108 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the lid switch." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:128 +msgid "Allow non-logged-in user to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:129 +msgid "Explicit request is required to run programs as a non-logged-in user." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:138 +msgid "Allow non-logged-in users to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:139 +msgid "Authentication is required to run programs as a non-logged-in user." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:148 +msgid "Allow attaching devices to seats" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:149 +msgid "Authentication is required to attach a device to a seat." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:159 +msgid "Flush device to seat attachments" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:160 +msgid "Authentication is required to reset how devices are attached to seats." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:169 +msgid "Power off the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:170 +msgid "Authentication is required to power off the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:180 +msgid "Power off the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:181 +msgid "" +"Authentication is required to power off the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:191 +msgid "Power off the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:192 +msgid "" +"Authentication is required to power off the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:202 +msgid "Reboot the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:203 +msgid "Authentication is required to reboot the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:213 +msgid "Reboot the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:214 +msgid "" +"Authentication is required to reboot the system while other users are logged " +"in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:224 +msgid "Reboot the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:225 +msgid "" +"Authentication is required to reboot the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:235 +msgid "Halt the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:236 +msgid "Authentication is required to halt the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:246 +msgid "Halt the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:247 +msgid "" +"Authentication is required to halt the system while other users are logged " +"in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:257 +msgid "Halt the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:258 +msgid "" +"Authentication is required to halt the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:268 +msgid "Suspend the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:269 +msgid "Authentication is required to suspend the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:278 +msgid "Suspend the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:279 +msgid "" +"Authentication is required to suspend the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:289 +msgid "Suspend the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:290 +msgid "" +"Authentication is required to suspend the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:300 +msgid "Hibernate the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:301 +msgid "Authentication is required to hibernate the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:310 +msgid "Hibernate the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:311 +msgid "" +"Authentication is required to hibernate the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:321 +msgid "Hibernate the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:322 +msgid "" +"Authentication is required to hibernate the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:332 +msgid "Manage active sessions, users and seats" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:333 +msgid "Authentication is required to manage active sessions, users and seats." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:342 +msgid "Lock or unlock active sessions" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:343 +msgid "Authentication is required to lock or unlock active sessions." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:352 +msgid "Set the reboot \"reason\" in the kernel" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:364 +msgid "" +"Authentication is required to indicate to the firmware to boot to setup " +"interface." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:374 +msgid "Indicate to the boot loader to boot to the boot loader menu" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:375 +msgid "" +"Authentication is required to indicate to the boot loader to boot to the " +"boot loader menu." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:385 +msgid "Indicate to the boot loader to boot a specific entry" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:386 +msgid "" +"Authentication is required to indicate to the boot loader to boot into a " +"specific boot loader entry." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:396 +msgid "Set a wall message" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:397 +msgid "Authentication is required to set a wall message" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:406 +msgid "Change Session" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:407 +msgid "Authentication is required to change the virtual terminal." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:22 +msgid "Log into a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:23 +msgid "Authentication is required to log into a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:32 +msgid "Log into the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:33 +msgid "Authentication is required to log into the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:42 +msgid "Acquire a shell in a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:43 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:53 +msgid "Acquire a shell on the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:54 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:64 +msgid "Acquire a pseudo TTY in a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:65 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:74 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:75 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:84 +msgid "Manage local virtual machines and containers" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:85 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:95 +msgid "Manage local virtual machine and container images" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:96 +msgid "" +"Authentication is required to manage local virtual machine and container " +"images." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:22 +msgid "Set NTP servers" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:23 +msgid "Authentication is required to set NTP servers." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:33 +#: src/resolve/org.freedesktop.resolve1.policy:44 +msgid "Set DNS servers" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:34 +#: src/resolve/org.freedesktop.resolve1.policy:45 +msgid "Authentication is required to set DNS servers." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:44 +#: src/resolve/org.freedesktop.resolve1.policy:55 +msgid "Set domains" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:45 +#: src/resolve/org.freedesktop.resolve1.policy:56 +msgid "Authentication is required to set domains." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:55 +#: src/resolve/org.freedesktop.resolve1.policy:66 +msgid "Set default route" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:56 +#: src/resolve/org.freedesktop.resolve1.policy:67 +msgid "Authentication is required to set default route." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:66 +#: src/resolve/org.freedesktop.resolve1.policy:77 +msgid "Enable/disable LLMNR" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:67 +#: src/resolve/org.freedesktop.resolve1.policy:78 +msgid "Authentication is required to enable or disable LLMNR." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:77 +#: src/resolve/org.freedesktop.resolve1.policy:88 +msgid "Enable/disable multicast DNS" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:78 +#: src/resolve/org.freedesktop.resolve1.policy:89 +msgid "Authentication is required to enable or disable multicast DNS." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:88 +#: src/resolve/org.freedesktop.resolve1.policy:99 +msgid "Enable/disable DNS over TLS" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:89 +#: src/resolve/org.freedesktop.resolve1.policy:100 +msgid "Authentication is required to enable or disable DNS over TLS." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:99 +#: src/resolve/org.freedesktop.resolve1.policy:110 +msgid "Enable/disable DNSSEC" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:100 +#: src/resolve/org.freedesktop.resolve1.policy:111 +msgid "Authentication is required to enable or disable DNSSEC." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:110 +#: src/resolve/org.freedesktop.resolve1.policy:121 +msgid "Set DNSSEC Negative Trust Anchors" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:111 +#: src/resolve/org.freedesktop.resolve1.policy:122 +msgid "Authentication is required to set DNSSEC Negative Trust Anchors." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:121 +msgid "Revert NTP settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:122 +msgid "Authentication is required to reset NTP settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:132 +msgid "Revert DNS settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:133 +msgid "Authentication is required to reset DNS settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:143 +msgid "DHCP server sends force renew message" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:144 +msgid "Authentication is required to send force renew message." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:154 +msgid "Renew dynamic addresses" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:155 +msgid "Authentication is required to renew dynamic addresses." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:165 +msgid "Reload network settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:166 +msgid "Authentication is required to reload network settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:176 +msgid "Reconfigure network interface" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:177 +msgid "Authentication is required to reconfigure network interface." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:13 +msgid "Inspect a portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:14 +msgid "Authentication is required to inspect a portable service image." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:23 +msgid "Attach or detach a portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:24 +msgid "" +"Authentication is required to attach or detach a portable service image." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:34 +msgid "Delete or modify portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:35 +msgid "" +"Authentication is required to delete or modify a portable service image." +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:22 +msgid "Register a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:23 +msgid "Authentication is required to register a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:33 +msgid "Unregister a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:34 +msgid "Authentication is required to unregister a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:132 +msgid "Revert name resolution settings" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:133 +msgid "Authentication is required to reset name resolution settings." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:22 +msgid "Set system time" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:23 +msgid "Authentication is required to set the system time." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:33 +msgid "Set system timezone" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:34 +msgid "Authentication is required to set the system timezone." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:43 +msgid "Set RTC to local timezone or UTC" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:44 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:53 +msgid "Turn network time synchronization on or off" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:54 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" + +#: src/core/dbus-unit.c:359 +msgid "Authentication is required to start '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:360 +msgid "Authentication is required to stop '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:361 +msgid "Authentication is required to reload '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 +msgid "Authentication is required to restart '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:535 +msgid "" +"Authentication is required to send a UNIX signal to the processes of " +"'$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:566 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:599 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:708 +msgid "" +"Authentication is required to delete files and directories associated with " +"'$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:757 +msgid "" +"Authentication is required to freeze or thaw the processes of '$(unit)' unit." +msgstr "" diff --git a/po/ko.po b/po/ko.po index a5e3dbc38..3713b161e 100644 --- a/po/ko.po +++ b/po/ko.po @@ -3,21 +3,22 @@ # Korean translation for the systemd. # Seong-ho Cho , 2015. # Dongsu Park , 2015. -# +# simmon , 2021. msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2015-11-03 13:19+0100\n" -"Last-Translator: Dongsu Park \n" -"Language-Team: GNOME Korea \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-03-25 03:01+0000\n" +"Last-Translator: simmon \n" +"Language-Team: Korean \n" "Language: ko\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Gtranslator 2.91.7\n" "Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.5.1\n" "X-Poedit-SourceCharset: UTF-8\n" #: src/core/org.freedesktop.systemd1.policy.in:22 @@ -67,67 +68,53 @@ msgstr "systemd 상태를 다시 불러오려면 인증이 필요합니다." #: src/home/org.freedesktop.home1.policy:13 msgid "Create a home area" -msgstr "" +msgstr "홈 영역 생성" #: src/home/org.freedesktop.home1.policy:14 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to create a user's home area." -msgstr "systemd 상태를 다시 불러오려면 인증이 필요합니다." +msgstr "사용자 홈 영역을 생성하기 위해서는 인증이 필요합니다." #: src/home/org.freedesktop.home1.policy:23 msgid "Remove a home area" -msgstr "" +msgstr "홈 영역 제거" #: src/home/org.freedesktop.home1.policy:24 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to remove a user's home area." -msgstr "systemd 상태를 다시 불러오려면 인증이 필요합니다." +msgstr "사용자 홈 영역을 제거하기 위해서는 인증이 필요합니다." #: src/home/org.freedesktop.home1.policy:33 msgid "Check credentials of a home area" -msgstr "" +msgstr "홈영역 자격증명 확인" #: src/home/org.freedesktop.home1.policy:34 -#, fuzzy -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to check credentials against a user's home area." -msgstr "활성 세션, 사용자 시트를 관리하려면 인증이 필요합니다." +msgstr "사용자 홈 영역의 자격증명 확인하려면 인증이 필요합니다." #: src/home/org.freedesktop.home1.policy:43 msgid "Update a home area" -msgstr "" +msgstr "홈 영역을 최신화" #: src/home/org.freedesktop.home1.policy:44 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "Authentication is required to update a user's home area." -msgstr "시트에 장치 부착을 허용하려면 인증이 필요합니다." +msgstr "사용자 홈 영역을 최신화 하려면 인증이 필요합니다." #: src/home/org.freedesktop.home1.policy:53 msgid "Resize a home area" -msgstr "" +msgstr "홈 영역을 조절" #: src/home/org.freedesktop.home1.policy:54 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to resize a user's home area." -msgstr "wall 메시지를 설정하려면 인증이 필요합니다" +msgstr "사용자 홈 영역의 크기를 조절하려면 인증이 필요합니다." #: src/home/org.freedesktop.home1.policy:63 msgid "Change password of a home area" -msgstr "" +msgstr "홈 영역의 비밀번호를 변경" #: src/home/org.freedesktop.home1.policy:64 -#, fuzzy -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to change the password of a user's home area." -msgstr "활성 세션, 사용자 시트를 관리하려면 인증이 필요합니다." +msgstr "사용자 홈 영역의 비밀번호를 변경하려면 비밀번호가 필요합니다." #: src/hostname/org.freedesktop.hostname1.policy:20 msgid "Set hostname" @@ -145,9 +132,7 @@ msgstr "정적 호스트 이름 설정" msgid "" "Authentication is required to set the statically configured local hostname, " "as well as the pretty hostname." -msgstr "" -"로컬 호스트 이름을 모양새를 갖춘 호스트 이름 처럼 정적으로 설정하려면 인증" -"이 필요합니다." +msgstr "로컬호스트 이름을 모양새를 갖춘 호스트이름 처럼 정적으로 설정하려면 인증이 필요합니다." #: src/hostname/org.freedesktop.hostname1.policy:41 msgid "Set machine information" @@ -159,13 +144,11 @@ msgstr "로컬 머신 정보를 설정하려면 인증이 필요합니다." #: src/hostname/org.freedesktop.hostname1.policy:51 msgid "Get product UUID" -msgstr "" +msgstr "제품 UUID를 획득" #: src/hostname/org.freedesktop.hostname1.policy:52 -#, fuzzy -#| msgid "Authentication is required to reload '$(unit)'." msgid "Authentication is required to get product UUID." -msgstr "'$(unit)' 서비스 유닛을 다시 불러오려면 인증이 필요합니다." +msgstr "제품 UUID를 얻기 위해서는 인증이 필요합니다." #: src/import/org.freedesktop.import1.policy:22 msgid "Import a VM or container image" @@ -185,11 +168,11 @@ msgstr "가상 머신 또는 컨테이너의 이미지를 내보내려면 인증 #: src/import/org.freedesktop.import1.policy:42 msgid "Download a VM or container image" -msgstr "가상머신 또는 컨테이너 이미지 다운로드" +msgstr "가상머신 또는 컨테이너 이미지 내려받기" #: src/import/org.freedesktop.import1.policy:43 msgid "Authentication is required to download a VM or container image" -msgstr "가상머신 또는 컨테이너 이미지를 다운로드하려면 인증이 필요합니다" +msgstr "가상머신 또는 컨테이너 이미지를 내려받기하려면 인증이 필요합니다" #: src/locale/org.freedesktop.locale1.policy:22 msgid "Set system locale" @@ -300,64 +283,70 @@ msgstr "" "니다." #: src/login/org.freedesktop.login1.policy:117 -#, fuzzy -#| msgid "Allow non-logged-in users to run programs" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "응용프로그램이 리부트 키 처리하는 시스템 방지 허용" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "응용프로그램이 시스템 리부트 키 처리 방지 요청을 허용하려면 인증이 필요합니다." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "비 로그인 사용자 프로그램 실행 허용" -#: src/login/org.freedesktop.login1.policy:118 -#, fuzzy -#| msgid "Authentication is required to run programs as a non-logged-in user." +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." -msgstr "비 로그인 사용자에게 프로그램 실행을 허용하려면 인증이 필요합니다." +msgstr "비 로그인 사용자에게 프로그램 실행하려면 명시적 요청이 필요합니다." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "비 로그인 사용자 프로그램 실행 허용" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "비 로그인 사용자에게 프로그램 실행을 허용하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "시트에 장치 부착 허용" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "시트에 장치 부착을 허용하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "시트로부터 장치 해제 허용" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "시트에 붙인 장치 상태를 초기화하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "시스템 끄기" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "시스템을 끄려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "다른 사용자가 로그인 했을 때 시스템 끄기" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." msgstr "다른 사용자가 로그인 했을 때 시스템 전원을 끄려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "프로그램이 시스템을 끄지 못하게 요청할 때 시스템 전원 끄기" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -365,30 +354,30 @@ msgstr "" "프로그램이 시스템을 끄지 못하게 요청할 때 시스템 전원을 끄려면 인증이 필요합" "니다." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "시스템 다시 시작" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "시스템을 다시 시작하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "다른 사용자가 로그인 했을 때 시스템 다시 시작" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." msgstr "" "다른 사용자가 로그인 했을 때 시스템을 다시 시작하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "프로그램이 시스템을 다시 시작하지 못하게 요청할 때 시스템 다시 시작" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -396,79 +385,58 @@ msgstr "" "프로그램이 시스템을 다시 시작하지 못하게 요청할 때 시스템을 다시 시작하려면 " "인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:224 -#, fuzzy -#| msgid "Hibernate the system" -msgid "Halt the system" -msgstr "시스템 최대 절전 상태 진입" - -#: src/login/org.freedesktop.login1.policy:225 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." -msgid "Authentication is required to halt the system." -msgstr "시스템을 최대 절전 상태로 놓으려면 인증이 필요합니다." - #: src/login/org.freedesktop.login1.policy:235 -#, fuzzy -#| msgid "Hibernate the system while other users are logged in" -msgid "Halt the system while other users are logged in" -msgstr "다른 사용자가 로그인 했을 때 시스템 최대 절전 상태 진입" +msgid "Halt the system" +msgstr "시스템 정지 진입" #: src/login/org.freedesktop.login1.policy:236 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while other users are " -#| "logged in." +msgid "Authentication is required to halt the system." +msgstr "시스템을 정지 상태로 놓으려면 인증이 필요합니다." + +#: src/login/org.freedesktop.login1.policy:246 +msgid "Halt the system while other users are logged in" +msgstr "다른 사용자가 로그인 했을 때 시스템이 정지 상태진입" + +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." -msgstr "" -"다른 사용자가 로그인 했을 때 시스템을 최대 절전 상태로 놓으려면 인증이 필요합" -"니다." +msgstr "다른 사용자가 로그인 했을 때 시스템을 정지 상태로 놓으려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:246 -#, fuzzy -#| msgid "Hibernate the system while an application is inhibiting this" +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" -msgstr "" -"프로그램이 최대 절전 상태 진입을 못하게 요청할 때 시스템 최대 절전 상태 진입" +msgstr "응용프로그램이 이와 같이 금지 상태일 때에 시스템 정지 상태 진입" -#: src/login/org.freedesktop.login1.policy:247 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while an application " -#| "is inhibiting this." +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." -msgstr "" -"프로그램이 최대 절전 상태 진입을 못하게 요청할 때 시스템을 최대 절전 상태로 " -"놓으려면 인증이 필요합니다." +msgstr "응용프로그램이 이와 같이 금지 할 때에는 시스템을 정지 할 때에는인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "시스템 절전 상태 진입" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "시스템을 절전 상태로 놓으려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "다른 사용자가 로그인 했을 때 시스템 절전 상태 진입" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." msgstr "" "다른 사용자가 로그인 했을 때 시스템을 절전 상태로 놓으려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "프로그램이 절전 상태 진입을 못하게 요청할 때 시스템 절전 상태 진입" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -476,19 +444,19 @@ msgstr "" "프로그램이 절전 상태 진입을 못하게 요청할 때 시스템을 절전 상태로 놓으려면 인" "증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "시스템 최대 절전 상태 진입" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "시스템을 최대 절전 상태로 놓으려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "다른 사용자가 로그인 했을 때 시스템 최대 절전 상태 진입" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -496,12 +464,12 @@ msgstr "" "다른 사용자가 로그인 했을 때 시스템을 최대 절전 상태로 놓으려면 인증이 필요합" "니다." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" "프로그램이 최대 절전 상태 진입을 못하게 요청할 때 시스템 최대 절전 상태 진입" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -509,89 +477,75 @@ msgstr "" "프로그램이 최대 절전 상태 진입을 못하게 요청할 때 시스템을 최대 절전 상태로 " "놓으려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "활성 세션, 사용자, 시트 관리" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "활성 세션, 사용자 시트를 관리하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "활성 세션 잠금 또는 잠금 해제" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "활성화 세션을 잠금 또는 잠금 해제하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:341 -msgid "Set the reboot \"reason\" in the kernel" -msgstr "" - -#: src/login/org.freedesktop.login1.policy:342 -#, fuzzy -#| msgid "Authentication is required to set the system timezone." -msgid "Authentication is required to set the reboot \"reason\" in the kernel." -msgstr "시스템 시간대를 설정하려면 인증이 필요합니다." - #: src/login/org.freedesktop.login1.policy:352 -#, fuzzy -#| msgid "Allow indication to the firmware to boot to setup interface" -msgid "Indicate to the firmware to boot to setup interface" -msgstr "설정 화면으로 부팅하도록 펌웨어에게 지시 허용" +msgid "Set the reboot \"reason\" in the kernel" +msgstr "커널이 재시작 \"원인\"을 설정합니다" #: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "커널에서 \"reason\"으로 재동작 설정하려면 인증이 필요합니다." + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "설정 화면으로 부팅하도록 펌웨어에게 지시" + +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "설정 화면으로 부팅하도록 펌웨어에게 지시하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" -msgstr "" +msgstr "부트로더 메뉴에 부팅하기 위해 부트로더에 표시하기" -#: src/login/org.freedesktop.login1.policy:364 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." -msgstr "설정 화면으로 부팅하도록 펌웨어에게 지시하려면 인증이 필요합니다." +msgstr "부트로더에 부팅하려면 부트로더 메뉴에 표시하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" -msgstr "" +msgstr "특정 항목으로 재시작 하기 위해 부트로더 표시" -#: src/login/org.freedesktop.login1.policy:375 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." -msgstr "설정 화면으로 부팅하도록 펌웨어에게 지시하려면 인증이 필요합니다." +msgstr "부트로더에 지정한 부트로더 에서 부트하거나 지정한 부트로더 진입을 표시하려면 인증이 필요합니다." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "wall 메시지 설정" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "wall 메시지를 설정하려면 인증이 필요합니다" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" -msgstr "" +msgstr "세션 변경" -#: src/login/org.freedesktop.login1.policy:396 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." -msgstr "로컬 호스트 이름을 설정하려면 인증이 필요합니다." +msgstr "가상 터미널을 변경하려면 인증이 필요합니다." #: src/machine/org.freedesktop.machine1.policy:22 msgid "Log into a local container" @@ -663,231 +617,189 @@ msgstr "로컬 가상 머신 및 컨테이너 이미지를 관리하려면 인 #: src/network/org.freedesktop.network1.policy:22 msgid "Set NTP servers" -msgstr "" +msgstr "NTP 서버 설정" #: src/network/org.freedesktop.network1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set NTP servers." -msgstr "시스템 시간을 설정하려면 인증이 필요합니다." +msgstr "NTP 서버 설정에 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:33 #: src/resolve/org.freedesktop.resolve1.policy:44 msgid "Set DNS servers" -msgstr "" +msgstr "DNS 서버 설정" #: src/network/org.freedesktop.network1.policy:34 #: src/resolve/org.freedesktop.resolve1.policy:45 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set DNS servers." -msgstr "시스템 시간을 설정하려면 인증이 필요합니다." +msgstr "DNS 서버를 설정하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:44 #: src/resolve/org.freedesktop.resolve1.policy:55 msgid "Set domains" -msgstr "" +msgstr "도메인 설정" #: src/network/org.freedesktop.network1.policy:45 #: src/resolve/org.freedesktop.resolve1.policy:56 -#, fuzzy -#| msgid "Authentication is required to stop '$(unit)'." msgid "Authentication is required to set domains." -msgstr "'$(unit)' 서비스 유닛을 멈추려면 인증이 필요합니다." +msgstr "도메인을 설정하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:55 #: src/resolve/org.freedesktop.resolve1.policy:66 msgid "Set default route" -msgstr "" +msgstr "기본 라우트 설정" #: src/network/org.freedesktop.network1.policy:56 #: src/resolve/org.freedesktop.resolve1.policy:67 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to set default route." -msgstr "로컬 호스트 이름을 설정하려면 인증이 필요합니다." +msgstr "기본 라우트 설정하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:66 #: src/resolve/org.freedesktop.resolve1.policy:77 msgid "Enable/disable LLMNR" -msgstr "" +msgstr "LLMNR 활성화/비활성화" #: src/network/org.freedesktop.network1.policy:67 #: src/resolve/org.freedesktop.resolve1.policy:78 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable LLMNR." -msgstr "시스템을 최대 절전 상태로 놓으려면 인증이 필요합니다." +msgstr "LLMNR을 활성화 또는 비활성화 하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:77 #: src/resolve/org.freedesktop.resolve1.policy:88 msgid "Enable/disable multicast DNS" -msgstr "" +msgstr "멀티캐스트 DNS 활성화/비활성화" #: src/network/org.freedesktop.network1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:89 -#, fuzzy -#| msgid "Authentication is required to log into the local host." msgid "Authentication is required to enable or disable multicast DNS." -msgstr "로컬 호스트로 로그인하려면 인증이 필요합니다." +msgstr "멀티캐스트 DNS 활성화 또는 비활성화하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:99 msgid "Enable/disable DNS over TLS" -msgstr "" +msgstr "TLS를 통한 DNS 활성화/비활성화" #: src/network/org.freedesktop.network1.policy:89 #: src/resolve/org.freedesktop.resolve1.policy:100 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to enable or disable DNS over TLS." -msgstr "로컬 호스트 이름을 설정하려면 인증이 필요합니다." +msgstr "TLS를 통 DNS를 활성화 또는 비활성화하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:99 #: src/resolve/org.freedesktop.resolve1.policy:110 msgid "Enable/disable DNSSEC" -msgstr "" +msgstr "DNSSEC 활성화/비활성화" #: src/network/org.freedesktop.network1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:111 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable DNSSEC." -msgstr "시스템을 최대 절전 상태로 놓으려면 인증이 필요합니다." +msgstr "DNSSEC를 활성화 또는 비활성화 하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:121 msgid "Set DNSSEC Negative Trust Anchors" -msgstr "" +msgstr "DNSSEC 부정적인 신뢰 고정 설정" #: src/network/org.freedesktop.network1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system locale." msgid "Authentication is required to set DNSSEC Negative Trust Anchors." -msgstr "시스템 로캘을 설정하려면 인증이 필요합니다." +msgstr "DNSSEC 부정적인 신뢰 고정을 설정하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:121 msgid "Revert NTP settings" -msgstr "" +msgstr "NTP 설정 되돌리기" #: src/network/org.freedesktop.network1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset NTP settings." -msgstr "시스템 시간을 설정하려면 인증이 필요합니다." +msgstr "NTP 설정을 재시작하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:132 msgid "Revert DNS settings" -msgstr "" +msgstr "DNS 설정 되돌리기" #: src/network/org.freedesktop.network1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset DNS settings." -msgstr "시스템 시간을 설정하려면 인증이 필요합니다." +msgstr "DNS 설정을 재시작하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:143 msgid "DHCP server sends force renew message" -msgstr "" +msgstr "DHCP 서버는 새로운 메시지를 강제로 보냅니다" #: src/network/org.freedesktop.network1.policy:144 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to send force renew message." -msgstr "wall 메시지를 설정하려면 인증이 필요합니다" +msgstr "새로운 메시지를 보내려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:154 msgid "Renew dynamic addresses" -msgstr "" +msgstr "동적 주소 갱신" #: src/network/org.freedesktop.network1.policy:155 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to renew dynamic addresses." -msgstr "wall 메시지를 설정하려면 인증이 필요합니다" +msgstr "동적주소를 새로 변경하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:165 msgid "Reload network settings" -msgstr "" +msgstr "네트웍설정 다시 적재함" #: src/network/org.freedesktop.network1.policy:166 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to reload network settings." -msgstr "systemd 상태를 다시 불러오려면 인증이 필요합니다." +msgstr "네트웍 설정을 재적재하려면 인증이 필요합니다." #: src/network/org.freedesktop.network1.policy:176 msgid "Reconfigure network interface" -msgstr "" +msgstr "네트워크 인터페이스 재설정" #: src/network/org.freedesktop.network1.policy:177 -#, fuzzy -#| msgid "Authentication is required to reboot the system." msgid "Authentication is required to reconfigure network interface." -msgstr "시스템을 다시 시작하려면 인증이 필요합니다." +msgstr "네트웍 연결장치를 재설정하려면 인증이 필요합니다." #: src/portable/org.freedesktop.portable1.policy:13 msgid "Inspect a portable service image" -msgstr "" +msgstr "이동 서비스 이미지 검사" #: src/portable/org.freedesktop.portable1.policy:14 -#, fuzzy -#| msgid "Authentication is required to import a VM or container image" msgid "Authentication is required to inspect a portable service image." -msgstr "VM 또는 컨테이너의 이미지를 가져오려면 인증이 필요합니다" +msgstr "이동형 서비스 이미지를 검사하려면 인증이 필요합니다." #: src/portable/org.freedesktop.portable1.policy:23 msgid "Attach or detach a portable service image" -msgstr "" +msgstr "이동 서비스 첨부 또는 분리" #: src/portable/org.freedesktop.portable1.policy:24 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "" "Authentication is required to attach or detach a portable service image." -msgstr "시트에 장치 부착을 허용하려면 인증이 필요합니다." +msgstr "이동 서비스 장착 또는 분리에는 인증이 필요합니다." #: src/portable/org.freedesktop.portable1.policy:34 msgid "Delete or modify portable service image" -msgstr "" +msgstr "이동 서비스 이미지 삭제 또는 변경" #: src/portable/org.freedesktop.portable1.policy:35 -#, fuzzy -#| msgid "Authentication is required to download a VM or container image" msgid "" "Authentication is required to delete or modify a portable service image." -msgstr "가상머신 또는 컨테이너 이미지를 다운로드하려면 인증이 필요합니다" +msgstr "이동형 서비스 이미지를 지우거나 변경하려면 인증이 필요합니다." #: src/resolve/org.freedesktop.resolve1.policy:22 msgid "Register a DNS-SD service" -msgstr "" +msgstr "DNS-SD 서비스 등록" #: src/resolve/org.freedesktop.resolve1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to register a DNS-SD service" -msgstr "wall 메시지를 설정하려면 인증이 필요합니다" +msgstr "DNS-SD 서비스 등록에는 인증이 필요합니다" #: src/resolve/org.freedesktop.resolve1.policy:33 msgid "Unregister a DNS-SD service" -msgstr "" +msgstr "DNS-SD 서비스 해제" #: src/resolve/org.freedesktop.resolve1.policy:34 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to unregister a DNS-SD service" -msgstr "wall 메시지를 설정하려면 인증이 필요합니다" +msgstr "DNS-SD 서비스 등록해제에는 인증이 필요합니다" #: src/resolve/org.freedesktop.resolve1.policy:132 msgid "Revert name resolution settings" -msgstr "" +msgstr "이름 확인 설정 되돌리기" #: src/resolve/org.freedesktop.resolve1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system keyboard settings." msgid "Authentication is required to reset name resolution settings." -msgstr "시스템 키보드를 설정하려면 인증이 필요합니다." +msgstr "이름 해결 설정을 재시작하려면 인증이 필요합니다." #: src/timedate/org.freedesktop.timedate1.policy:22 msgid "Set system time" @@ -927,54 +839,46 @@ msgid "" "shall be enabled." msgstr "네트워크 시간 동기화의 활성화 여부를 제어하려면 인증이 필요합니다." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "'$(unit)' 서비스 유닛을 시작하려면 인증이 필요합니다." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "'$(unit)' 서비스 유닛을 멈추려면 인증이 필요합니다." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "'$(unit)' 서비스 유닛을 다시 불러오려면 인증이 필요합니다." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "'$(unit)' 서비스 유닛을 다시 시작하려면 인증이 필요합니다." -#: src/core/dbus-unit.c:538 -#, fuzzy -#| msgid "Authentication is required to set properties on '$(unit)'." +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." -msgstr "'$(unit)' 서비스 유닛 속성을 설정하려면 인증이 필요합니다." +msgstr "'$(unit)'의 처리에 유닉스 신호를 전송하려면 인증이 필요합니다." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "'$(unit)' 서비스 유닛의 \"실패\" 상태를 되돌리려면 인증이 필요합니다." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "'$(unit)' 서비스 유닛 속성을 설정하려면 인증이 필요합니다." -#: src/core/dbus-unit.c:711 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." -msgstr "'$(unit)' 서비스 유닛의 \"실패\" 상태를 되돌리려면 인증이 필요합니다." +msgstr "'$(unit)' 과 함께 지정된 파일 또는 디렉토리 삭제에는 인증이 필요합니다." -#: src/core/dbus-unit.c:760 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." -msgstr "'$(unit)' 서비스 유닛의 \"실패\" 상태를 되돌리려면 인증이 필요합니다." +msgstr "'$(unit)'단위의 처리를 동결 또는 해제하기 위해서는 인증이 필요합니다." #~ msgid "Authentication is required to kill '$(unit)'." #~ msgstr "'$(unit)' 서비스 유닛을 강제로 끝내려면 인증이 필요합니다." diff --git a/po/lt.po b/po/lt.po index af27e8940..c8eac8590 100644 --- a/po/lt.po +++ b/po/lt.po @@ -1,9 +1,11 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# # Moo, 2018. #zanata msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2019-04-08 22:01+0300\n" "Last-Translator: Moo\n" "Language-Team: Lithuanian\n" @@ -317,57 +319,75 @@ msgstr "" "reikia nustatyti tapatybę." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "Leisti programoms sulaikyti maitinimo rakto sisteminį apdorojimą" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Norint leisti programai sulaikyti maitinimo rakto sisteminį apdorojimą, " +"reikia nustatyti tapatybę." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Leisti neprisijungusiam naudotojui vykdyti programas" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Norint vykdyti programas kaip neprisijungusiam naudotojui, reikia aiškiai " "išreikštos užklausos." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Leisti neprisijungusiems naudotojams vykdyti programas" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Norint vykdyti programas kaip neprisijungusiems naudotojams, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Leisti prijungti įrenginius prie darbo vietų" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Norint prijungti įrenginį prie darbo vietos, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Išvalyti įrenginių prijungimus prie darbo vietų" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Norint atstatyti tai, kaip įrenginiai yra prijungti prie darbo vietų, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Išjungti sistemos maitinimą" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Norint išjungti sistemos maitinimą, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Išjungti sistemos maitinimą nepaisant kitų prisijungusių naudotojų" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -375,11 +395,11 @@ msgstr "" "Norint išjungti sistemos maitinimą nepaisant kitų prisijungusių naudotojų, " "reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Išjungti sistemos maitinimą, nors programa paprašė tai sulaikyti" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -387,19 +407,19 @@ msgstr "" "Norint išjungti sistemos maitinimą, nepaisant to, kad programa paprašė tai " "sulaikyti, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Paleisti sistemą iš naujo" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Norint paleisti sistemą iš naujo, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Paleisti sistemą iš naujo nepaisant kitų prisijungusių naudotojų" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -407,11 +427,11 @@ msgstr "" "Norint paleisti sistemą iš naujo nepaisant kitų prisijungusių naudotojų, " "reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Paleisti sistemą iš naujo, nors programa paprašė tai sulaikyti" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -419,19 +439,19 @@ msgstr "" "Norint paleisti sistemą iš naujo, nepaisant to, kad programa paprašė tai " "sulaikyti, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Stabdyti sistemą" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Norint stabdyti sistemą, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Stabdyti sistemą nepaisant kitų prisijungusių naudotojų" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -439,11 +459,11 @@ msgstr "" "Norint stabdyti sistemą nepaisant kitų prisijungusių naudotojų, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Stabdyti sistemą, nors programa paprašė tai sulaikyti" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -455,19 +475,19 @@ msgstr "" "Norint užmigdyti sistemą, nepaisant to, kad programa paprašė tai sulaikyti, " "reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Pristabdyti sistemą" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Norint pristabdyti sistemą, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Pristabdyti sistemą nepaisant kitų prisijungusių naudotojų" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -475,11 +495,11 @@ msgstr "" "Norint pristabdyti sistemą nepaisant kitų prisijungusių naudotojų, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Pristabdyti sistemą, nors programa paprašė tai sulaikyti" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -487,19 +507,19 @@ msgstr "" "Norint pristabdyti sistemą, nepaisant to, kad programa paprašė tai " "sulaikyti, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Užmigdyti sistemą" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Norint užmigdyti sistemą, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Užmigdyti sistemą nepaisant kitų prisijungusių naudotojų" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -507,11 +527,11 @@ msgstr "" "Norint užmigdyti sistemą nepaisant kitų prisijungusių naudotojų, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Užmigdyti sistemą, nors programa paprašė tai sulaikyti" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -519,40 +539,40 @@ msgstr "" "Norint užmigdyti sistemą, nepaisant to, kad programa paprašė tai sulaikyti, " "reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Tvarkyti aktyvius seansus, naudotojus ir darbo vietas" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Norint tvarkyti aktyvius seansus, naudotojus ir darbo vietas, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Užrakinti ar atrakinti aktyvius seansus" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Norint užrakinti ar atrakinti aktyvius seansus, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Nustatyti paleidimo iš naujo \"priežastį\" branduolyje" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Norint nustatyti paleidimo iš naujo \"priežastį\" branduolyje, reikia " "nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Nurodyti programinei aparatinei įrangai pasileisti į sąrankos sąsają" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -560,11 +580,11 @@ msgstr "" "Norint nurodyti programinei aparatinei įrangai pasileisti į sąrankos sąsają, " "reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Nurodyti pradiniam įkėlikliui paleisti pradinio įkėliklio meniu" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -572,11 +592,11 @@ msgstr "" "Norint nurodyti pradiniam įkėlikliui paleisti pradinio įkėliklio meniu, " "reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "Nurodyti pradiniam įkėlikliui paleisti tam tikrą įrašą" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -584,19 +604,19 @@ msgstr "" "Norint nurodyti pradiniam įkėlikliui paleisti tam tikrą pradinio įkėliklio " "įrašą, reikia nustatyti tapatybę." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Nustatyti sienos pranešimą" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Norint nustatyti sienos pranešimą, reikia nustatyti tapatybę" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." @@ -948,40 +968,40 @@ msgstr "" "Norint valdyti ar tinklo laiko sinchronizavimas turėtų būti įjungtas, reikia " "nustatyti tapatybę." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Norint paleisti \"$(unit)\", reikia nustatyti tapatybę." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Norint stabdyti \"$(unit)\", reikia nustatyti tapatybę." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Norint įkelti \"$(unit)\" iš naujo, reikia nustatyti tapatybę." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Norint paleisti \"$(unit)\" iš naujo, reikia nustatyti tapatybę." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "" "Norint siųsti UNIX signalą į \"$(unit)\" procesus, reikia nustatyti tapatybę." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Norint atstatyti \"$(unit)\" įtaiso \"failed\" būseną, reikia nustatyti " "tapatybę." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Norint nustatyti \"$(unit)\" savybes, reikia nustatyti tapatybę." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -992,7 +1012,7 @@ msgstr "" "Norint atstatyti \"$(unit)\" įtaiso \"failed\" būseną, reikia nustatyti " "tapatybę." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to send a UNIX signal to the processes of " diff --git a/po/meson.build b/po/meson.build index 193f614f4..139f393e3 100644 --- a/po/meson.build +++ b/po/meson.build @@ -1,6 +1,10 @@ # SPDX-License-Identifier: LGPL-2.1-or-later i18n = import('i18n') -i18n.gettext(meson.project_name(), - preset : 'glib', - data_dirs : '.') +want_translations = get_option('translations') + +if want_translations + i18n.gettext(meson.project_name(), + preset : 'glib', + data_dirs : '.') +endif diff --git a/po/nl.po b/po/nl.po new file mode 100644 index 000000000..efd7f244e --- /dev/null +++ b/po/nl.po @@ -0,0 +1,1015 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the systemd package. +# Pjotr Vertaalt , 2021. +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-03-24 09:16+0000\n" +"Last-Translator: Pjotr Vertaalt \n" +"Language-Team: Dutch \n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.5.1\n" + +#: src/core/org.freedesktop.systemd1.policy.in:22 +msgid "Send passphrase back to system" +msgstr "Stuur wachtwoordzin terug naar systeem" + +#: src/core/org.freedesktop.systemd1.policy.in:23 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" +"Authenticatie is vereist voor het terugsturen van de ingevulde wachtwoordzin " +"naar het systeem." + +#: src/core/org.freedesktop.systemd1.policy.in:33 +msgid "Manage system services or other units" +msgstr "Beheer systeemdiensten of andere eenheden" + +#: src/core/org.freedesktop.systemd1.policy.in:34 +msgid "Authentication is required to manage system services or other units." +msgstr "" +"Authenticatie is vereist voor het beheren van systeemdiensten of andere " +"eenheden." + +#: src/core/org.freedesktop.systemd1.policy.in:43 +msgid "Manage system service or unit files" +msgstr "Beheer systeemdienst of eenheidbestanden" + +#: src/core/org.freedesktop.systemd1.policy.in:44 +msgid "Authentication is required to manage system service or unit files." +msgstr "" +"Authenticatie is vereist voor het beheren van systeemdienst of " +"eenheidbestanden." + +#: src/core/org.freedesktop.systemd1.policy.in:54 +msgid "Set or unset system and service manager environment variables" +msgstr "Stel omgevingsvariabelen in voor systeem en dienstenbeheerder" + +#: src/core/org.freedesktop.systemd1.policy.in:55 +msgid "" +"Authentication is required to set or unset system and service manager " +"environment variables." +msgstr "" +"Authenticatie is vereist voor het instellen van omgevingsvariabelen voor " +"systeem en dienstenbeheerder." + +#: src/core/org.freedesktop.systemd1.policy.in:64 +msgid "Reload the systemd state" +msgstr "Herlaad de status van systemd" + +#: src/core/org.freedesktop.systemd1.policy.in:65 +msgid "Authentication is required to reload the systemd state." +msgstr "Authenticatie is vereist voor het herladen van de status van systemd." + +#: src/home/org.freedesktop.home1.policy:13 +msgid "Create a home area" +msgstr "Maak een persoonlijke gebruikersmap" + +#: src/home/org.freedesktop.home1.policy:14 +msgid "Authentication is required to create a user's home area." +msgstr "" +"Authenticatie is vereist voor het maken van een persoonlijke gebruikersmap." + +#: src/home/org.freedesktop.home1.policy:23 +msgid "Remove a home area" +msgstr "Verwijder een persoonlijke gebruikersmap" + +#: src/home/org.freedesktop.home1.policy:24 +msgid "Authentication is required to remove a user's home area." +msgstr "" +"Authenticatie is vereist voor het verwijderen van een persoonlijke " +"gebruikersmap." + +#: src/home/org.freedesktop.home1.policy:33 +msgid "Check credentials of a home area" +msgstr "Controleer de verificatiegegevens van een persoonlijke gebruikersmap" + +#: src/home/org.freedesktop.home1.policy:34 +msgid "" +"Authentication is required to check credentials against a user's home area." +msgstr "" +"Authenticatie is vereist voor het controleren van verificatiegegevens voor " +"een persoonlijke gebruikersmap." + +#: src/home/org.freedesktop.home1.policy:43 +msgid "Update a home area" +msgstr "Werk een persoonlijke gebruikersmap bij" + +#: src/home/org.freedesktop.home1.policy:44 +msgid "Authentication is required to update a user's home area." +msgstr "" +"Authenticatie is vereist voor het bijwerken van een persoonlijke " +"gebruikersmap." + +#: src/home/org.freedesktop.home1.policy:53 +msgid "Resize a home area" +msgstr "Verander de grootte van een persoonlijke gebruikersmap" + +#: src/home/org.freedesktop.home1.policy:54 +msgid "Authentication is required to resize a user's home area." +msgstr "" +"Authenticatie is vereist voor het veranderen van de grootte van een " +"persoonlijke gebruikersmap." + +#: src/home/org.freedesktop.home1.policy:63 +msgid "Change password of a home area" +msgstr "Verander het wachtwoord van een persoonlijke gebruikersmap" + +#: src/home/org.freedesktop.home1.policy:64 +msgid "" +"Authentication is required to change the password of a user's home area." +msgstr "" +"Authenticatie is vereist voor het wijzigen van het wachtwoord van een " +"persoonlijke gebruikersmap." + +#: src/hostname/org.freedesktop.hostname1.policy:20 +msgid "Set hostname" +msgstr "Stel computernaam in" + +#: src/hostname/org.freedesktop.hostname1.policy:21 +msgid "Authentication is required to set the local hostname." +msgstr "" +"Authenticatie is vereist voor het instellen van de plaatselijke computernaam." + +#: src/hostname/org.freedesktop.hostname1.policy:30 +msgid "Set static hostname" +msgstr "Stel statische computernaam in" + +#: src/hostname/org.freedesktop.hostname1.policy:31 +msgid "" +"Authentication is required to set the statically configured local hostname, " +"as well as the pretty hostname." +msgstr "" +"Authenticatie is vereist voor het instellen van de statische plaatselijke " +"computernaam en voor de 'mooie' computernaam." + +#: src/hostname/org.freedesktop.hostname1.policy:41 +msgid "Set machine information" +msgstr "Stel machine-informatie in" + +#: src/hostname/org.freedesktop.hostname1.policy:42 +msgid "Authentication is required to set local machine information." +msgstr "" +"Authenticatie is vereist voor het instellen van de plaatselijke machine-" +"informatie." + +#: src/hostname/org.freedesktop.hostname1.policy:51 +msgid "Get product UUID" +msgstr "Verkrijg de UUID van het product" + +#: src/hostname/org.freedesktop.hostname1.policy:52 +msgid "Authentication is required to get product UUID." +msgstr "" +"Authenticatie is vereist voor het verkrijgen van de UUID van het product." + +#: src/import/org.freedesktop.import1.policy:22 +msgid "Import a VM or container image" +msgstr "Importeer een VM of een container-schijfkopie" + +#: src/import/org.freedesktop.import1.policy:23 +msgid "Authentication is required to import a VM or container image" +msgstr "" +"Authenticatie is vereist voor het importeren van een VM of een container-" +"schijfkopie" + +#: src/import/org.freedesktop.import1.policy:32 +msgid "Export a VM or container image" +msgstr "Exporteer een VM of een container-schijfkopie" + +#: src/import/org.freedesktop.import1.policy:33 +msgid "Authentication is required to export a VM or container image" +msgstr "" +"Authenticatie is vereist voor het exporteren van een VM of container-" +"schijfkopie" + +#: src/import/org.freedesktop.import1.policy:42 +msgid "Download a VM or container image" +msgstr "Haal een VM of container-schijfkopie binnen" + +#: src/import/org.freedesktop.import1.policy:43 +msgid "Authentication is required to download a VM or container image" +msgstr "" +"Authenticatie is vereist voor het binnenhalen van een VM of container-" +"schijfkopie" + +#: src/locale/org.freedesktop.locale1.policy:22 +msgid "Set system locale" +msgstr "Stel de systeemtaal in" + +#: src/locale/org.freedesktop.locale1.policy:23 +msgid "Authentication is required to set the system locale." +msgstr "Authenticatie is vereist voor het instellen van de systeemtaal." + +#: src/locale/org.freedesktop.locale1.policy:33 +msgid "Set system keyboard settings" +msgstr "Stel de instellingen in van het systeemtoetsenbord" + +#: src/locale/org.freedesktop.locale1.policy:34 +msgid "Authentication is required to set the system keyboard settings." +msgstr "" +"Authenticatie is vereist voor het instellen van de configuratie van het " +"systeemtoetsenbord." + +#: src/login/org.freedesktop.login1.policy:22 +msgid "Allow applications to inhibit system shutdown" +msgstr "Sta toepassingen toe om afsluiten van het systeem te verhinderen" + +#: src/login/org.freedesktop.login1.policy:23 +msgid "" +"Authentication is required for an application to inhibit system shutdown." +msgstr "" +"Authenticatie is vereist alvorens een toepassing afsluiten van het systeem " +"kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:33 +msgid "Allow applications to delay system shutdown" +msgstr "Sta toepassingen toe om afsluiten van het systeem uit te stellen" + +#: src/login/org.freedesktop.login1.policy:34 +msgid "Authentication is required for an application to delay system shutdown." +msgstr "" +"Authenticatie is vereist alvorens een toepassing het afsluiten van het " +"systeem kan uitstellen." + +#: src/login/org.freedesktop.login1.policy:44 +msgid "Allow applications to inhibit system sleep" +msgstr "Sta toepassingen toe om slaapstand van het systeem te verhinderen" + +#: src/login/org.freedesktop.login1.policy:45 +msgid "Authentication is required for an application to inhibit system sleep." +msgstr "" +"Authenticatie is vereist alvorens een toepassing slaapstand van het systeem " +"kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:55 +msgid "Allow applications to delay system sleep" +msgstr "Sta toepassingen toe om slaapstand van het systeem uit te stellen" + +#: src/login/org.freedesktop.login1.policy:56 +msgid "Authentication is required for an application to delay system sleep." +msgstr "" +"Authenticatie is vereist alvorens een toepassing slaapstand van het systeem " +"kan uitstellen." + +#: src/login/org.freedesktop.login1.policy:65 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "" +"Sta toepassingen toe om automatische pauzestand van het systeem te " +"verhinderen" + +#: src/login/org.freedesktop.login1.policy:66 +msgid "" +"Authentication is required for an application to inhibit automatic system " +"suspend." +msgstr "" +"Authenticatie is vereist alvorens een toepassing automatische pauzestand van " +"het systeem kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:75 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "" +"Sta toepassingen toe om het bedienen van de aan/uit-toets door het systeem " +"te verhinderen" + +#: src/login/org.freedesktop.login1.policy:76 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the power key." +msgstr "" +"Authenticatie is vereist alvorens een toepassing het bedienen van de aan/uit-" +"toets door het systeem kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:86 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "" +"Sta toepassingen toe om bediening door het systeem van de pauzestandtoets te " +"verhinderen" + +#: src/login/org.freedesktop.login1.policy:87 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the suspend key." +msgstr "" +"Authenticatie is vereist alvorens een toepassing de bediening door het " +"systeem van de pauzestandtoets kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:97 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "" +"Sta toepassingen toe om behandeling door het systeem van de slaapstandtoets " +"te verhinderen" + +#: src/login/org.freedesktop.login1.policy:98 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the hibernate key." +msgstr "" +"Authenticatie is vereist alvorens een toepassing de behandeling door het " +"systeem van de slaapstandtoets kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:107 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" +"Sta toepassingen toe om de behandeling door het systeem van de " +"klepschakelaar te verhinderen" + +#: src/login/org.freedesktop.login1.policy:108 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the lid switch." +msgstr "" +"Authenticatie is vereist alvorens een toepassing de behandeling door het " +"systeem van de klepschakelaar kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Sta toepassingen toe om de behandeling door het systeem van de herstarttoets " +"te verhinderen" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Authenticatie is vereist alvorens een toepassing de behandeling door het " +"systeem van de herstarttoets kan verhinderen." + +#: src/login/org.freedesktop.login1.policy:128 +msgid "Allow non-logged-in user to run programs" +msgstr "Sta niet-aangemelde gebruiker toe om programma's te draaien" + +#: src/login/org.freedesktop.login1.policy:129 +msgid "Explicit request is required to run programs as a non-logged-in user." +msgstr "" +"Expliciet verzoek is vereist om programma's te draaien als een niet-" +"aangemelde gebruiker." + +#: src/login/org.freedesktop.login1.policy:138 +msgid "Allow non-logged-in users to run programs" +msgstr "Sta niet-aangemelde gebruikers toe om programma's te draaien" + +#: src/login/org.freedesktop.login1.policy:139 +msgid "Authentication is required to run programs as a non-logged-in user." +msgstr "" +"Authenticatie is vereist alvorens een niet-aangemelde gebruiker programma's " +"kan draaien." + +#: src/login/org.freedesktop.login1.policy:148 +msgid "Allow attaching devices to seats" +msgstr "Sta het verbinden van apparaten aan zittingen toe" + +#: src/login/org.freedesktop.login1.policy:149 +msgid "Authentication is required to attach a device to a seat." +msgstr "" +"Authenticatie is vereist voor het verbinden van een apparaat aan een zitting." + +#: src/login/org.freedesktop.login1.policy:159 +msgid "Flush device to seat attachments" +msgstr "Verwijder alle apparaat-zitting-koppelingen" + +#: src/login/org.freedesktop.login1.policy:160 +msgid "Authentication is required to reset how devices are attached to seats." +msgstr "" +"Authenticatie is vereist voor het terugzetten van de wijze waarop apparaten " +"zijn verbonden aan zittingen." + +#: src/login/org.freedesktop.login1.policy:169 +msgid "Power off the system" +msgstr "Sluit het systeem af" + +#: src/login/org.freedesktop.login1.policy:170 +msgid "Authentication is required to power off the system." +msgstr "Authenticatie is vereist voor het afsluiten van het systeem." + +#: src/login/org.freedesktop.login1.policy:180 +msgid "Power off the system while other users are logged in" +msgstr "Sluit het systeem af terwijl er nog andere gebruikers zijn aangemeld" + +#: src/login/org.freedesktop.login1.policy:181 +msgid "" +"Authentication is required to power off the system while other users are " +"logged in." +msgstr "" +"Authenticatie is vereist voor het afsluiten van het systeem terwijl er nog " +"andere gebruikers zijn aangemeld." + +#: src/login/org.freedesktop.login1.policy:191 +msgid "Power off the system while an application is inhibiting this" +msgstr "Sluit het systeem af terwijl er een toepassing is die dit verhindert" + +#: src/login/org.freedesktop.login1.policy:192 +msgid "" +"Authentication is required to power off the system while an application is " +"inhibiting this." +msgstr "" +"Authenticatie is vereist voor het afsluiten van het systeem terwijl er een " +"toepassing is die dit verhindert." + +#: src/login/org.freedesktop.login1.policy:202 +msgid "Reboot the system" +msgstr "Herstart het systeem" + +#: src/login/org.freedesktop.login1.policy:203 +msgid "Authentication is required to reboot the system." +msgstr "Authenticatie is vereist voor het herstarten van het systeem." + +#: src/login/org.freedesktop.login1.policy:213 +msgid "Reboot the system while other users are logged in" +msgstr "Herstart het systeem terwijl er nog andere gebruikers zijn aangemeld" + +#: src/login/org.freedesktop.login1.policy:214 +msgid "" +"Authentication is required to reboot the system while other users are logged " +"in." +msgstr "" +"Authenticatie is vereist voor het herstarten van het systeem terwijl er nog " +"andere gebruikers zijn aangemeld." + +#: src/login/org.freedesktop.login1.policy:224 +msgid "Reboot the system while an application is inhibiting this" +msgstr "Herstart het systeem terwijl er een toepassing is die dit verhindert" + +#: src/login/org.freedesktop.login1.policy:225 +msgid "" +"Authentication is required to reboot the system while an application is " +"inhibiting this." +msgstr "" +"Authenticatie is vereist voor het herstarten van het systeem terwijl er een " +"toepassing is die dit verhindert." + +#: src/login/org.freedesktop.login1.policy:235 +msgid "Halt the system" +msgstr "Zet het systeem stil" + +#: src/login/org.freedesktop.login1.policy:236 +msgid "Authentication is required to halt the system." +msgstr "Authenticatie is vereist voor het stilzetten van het systeem." + +#: src/login/org.freedesktop.login1.policy:246 +msgid "Halt the system while other users are logged in" +msgstr "Zet het systeem stil terwijl er nog andere gebruikers zijn aangemeld" + +#: src/login/org.freedesktop.login1.policy:247 +msgid "" +"Authentication is required to halt the system while other users are logged " +"in." +msgstr "" +"Authenticatie is vereist voor het stilzetten van het systeem terwijl er nog " +"andere gebruikers zijn aangemeld." + +#: src/login/org.freedesktop.login1.policy:257 +msgid "Halt the system while an application is inhibiting this" +msgstr "Zet het systeem stil terwijl er een toepassing is die dit verhindert" + +#: src/login/org.freedesktop.login1.policy:258 +msgid "" +"Authentication is required to halt the system while an application is " +"inhibiting this." +msgstr "" +"Authenticatie is vereist voor het stilzetten van het systeem terwijl er een " +"toepassing is die dit verhindert." + +#: src/login/org.freedesktop.login1.policy:268 +msgid "Suspend the system" +msgstr "Breng het systeem in pauzestand" + +#: src/login/org.freedesktop.login1.policy:269 +msgid "Authentication is required to suspend the system." +msgstr "" +"Authenticatie is vereist voor het in pauzestand brengen van het systeem." + +#: src/login/org.freedesktop.login1.policy:278 +msgid "Suspend the system while other users are logged in" +msgstr "" +"Breng het systeem in pauzestand terwijl er nog andere gebruikers zijn " +"aangemeld" + +#: src/login/org.freedesktop.login1.policy:279 +msgid "" +"Authentication is required to suspend the system while other users are " +"logged in." +msgstr "" +"Authenticatie is vereist voor het in pauzestand brengen van het systeem " +"terwijl er nog andere gebruikers zijn aangemeld." + +#: src/login/org.freedesktop.login1.policy:289 +msgid "Suspend the system while an application is inhibiting this" +msgstr "" +"Breng het systeem in pauzestand terwijl er een toepassing is die dit " +"verhindert" + +#: src/login/org.freedesktop.login1.policy:290 +msgid "" +"Authentication is required to suspend the system while an application is " +"inhibiting this." +msgstr "" +"Authenticatie is vereist voor het in pauzestand brengen van het systeem " +"terwijl er een toepassing is die dit verhindert." + +#: src/login/org.freedesktop.login1.policy:300 +msgid "Hibernate the system" +msgstr "Breng het systeem in slaapstand" + +#: src/login/org.freedesktop.login1.policy:301 +msgid "Authentication is required to hibernate the system." +msgstr "" +"Authenticatie is vereist voor het in slaapstand brengen van het systeem." + +#: src/login/org.freedesktop.login1.policy:310 +msgid "Hibernate the system while other users are logged in" +msgstr "" +"Breng het systeem in slaapstand terwijl er nog andere gebruikers zijn " +"aangemeld" + +#: src/login/org.freedesktop.login1.policy:311 +msgid "" +"Authentication is required to hibernate the system while other users are " +"logged in." +msgstr "" +"Authenticatie is vereist voor het in slaapstand brengen van het systeem " +"terwijl er nog andere gebruikers zijn aangemeld." + +#: src/login/org.freedesktop.login1.policy:321 +msgid "Hibernate the system while an application is inhibiting this" +msgstr "" +"Breng het systeem in slaapstand terwijl er een toepassing is die dit " +"verhindert" + +#: src/login/org.freedesktop.login1.policy:322 +msgid "" +"Authentication is required to hibernate the system while an application is " +"inhibiting this." +msgstr "" +"Authenticatie is vereist voor het in slaapstand brengen van het systeem " +"terwijl er een toepassing is die dit verhindert." + +#: src/login/org.freedesktop.login1.policy:332 +msgid "Manage active sessions, users and seats" +msgstr "Beheer actieve sessies, gebruikers en zittingen" + +#: src/login/org.freedesktop.login1.policy:333 +msgid "Authentication is required to manage active sessions, users and seats." +msgstr "" +"Authenticatie is vereist voor het beheren van actieve sessies, gebruikers en " +"zittingen." + +#: src/login/org.freedesktop.login1.policy:342 +msgid "Lock or unlock active sessions" +msgstr "Vergrendel of ontgrendel actieve sessies" + +#: src/login/org.freedesktop.login1.policy:343 +msgid "Authentication is required to lock or unlock active sessions." +msgstr "" +"Authenticatie is vereist voor het vergrendelen of ontgrendelen van actieve " +"sessies." + +#: src/login/org.freedesktop.login1.policy:352 +msgid "Set the reboot \"reason\" in the kernel" +msgstr "Stel de herstart-'reden' in de systeemkern in" + +#: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "" +"Authenticatie is vereist voor het instellen van de herstart-'reden' in de " +"systeemkern." + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "" +"Geef aan de firmware aan om op te starten ten einde een apparaat in te " +"stellen" + +#: src/login/org.freedesktop.login1.policy:364 +msgid "" +"Authentication is required to indicate to the firmware to boot to setup " +"interface." +msgstr "" +"Authenticatie is vereist voor het aangeven aan de firmware dat die moet " +"opstarten om een apparaat in te stellen." + +#: src/login/org.freedesktop.login1.policy:374 +msgid "Indicate to the boot loader to boot to the boot loader menu" +msgstr "" +"Geef aan de opstartlader aan dat die moet opstarten naar het opstartmenu" + +#: src/login/org.freedesktop.login1.policy:375 +msgid "" +"Authentication is required to indicate to the boot loader to boot to the " +"boot loader menu." +msgstr "" +"Authenticatie is vereist voor het aangeven aan de opstartlader dat die moet " +"opstarten naar het opstartmenu." + +#: src/login/org.freedesktop.login1.policy:385 +msgid "Indicate to the boot loader to boot a specific entry" +msgstr "" +"Geef aan de opstartlader aan dat die een bepaalde vermelding moet opstarten" + +#: src/login/org.freedesktop.login1.policy:386 +msgid "" +"Authentication is required to indicate to the boot loader to boot into a " +"specific boot loader entry." +msgstr "" +"Authenticatie is vereist voor het aangeven aan de opstartlader dat die een " +"bepaalde opstartvermelding moet opstarten." + +#: src/login/org.freedesktop.login1.policy:396 +msgid "Set a wall message" +msgstr "Stel een gebruikersmuurboodschap in" + +#: src/login/org.freedesktop.login1.policy:397 +msgid "Authentication is required to set a wall message" +msgstr "" +"Authenticatie is vereist voor het instellen van een gebruikersmuurboodschap" + +#: src/login/org.freedesktop.login1.policy:406 +msgid "Change Session" +msgstr "Verander van sessie" + +#: src/login/org.freedesktop.login1.policy:407 +msgid "Authentication is required to change the virtual terminal." +msgstr "Authenticatie is vereist voor het wijzigen van de virtuele terminal." + +#: src/machine/org.freedesktop.machine1.policy:22 +msgid "Log into a local container" +msgstr "Meld aan bij een plaatselijke container" + +#: src/machine/org.freedesktop.machine1.policy:23 +msgid "Authentication is required to log into a local container." +msgstr "" +"Authenticatie is vereist voor het aanmelden bij een plaatselijke container." + +#: src/machine/org.freedesktop.machine1.policy:32 +msgid "Log into the local host" +msgstr "Meld aan bij de plaatselijke computer" + +#: src/machine/org.freedesktop.machine1.policy:33 +msgid "Authentication is required to log into the local host." +msgstr "" +"Authenticatie is vereist voor het aanmelden bij de plaatselijke computer." + +#: src/machine/org.freedesktop.machine1.policy:42 +msgid "Acquire a shell in a local container" +msgstr "Verkrijg een bedieningsvenster in een plaatselijke container" + +#: src/machine/org.freedesktop.machine1.policy:43 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" +"Authenticatie is vereist voor het verkrijgen van een bedieningsvenster in " +"een plaatselijke container." + +#: src/machine/org.freedesktop.machine1.policy:53 +msgid "Acquire a shell on the local host" +msgstr "Verkrijg een bedieningsvenster op de plaatselijke computer" + +#: src/machine/org.freedesktop.machine1.policy:54 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" +"Authenticatie is vereist voor het verkrijgen van een bedieningsvenster op de " +"plaatselijke computer." + +#: src/machine/org.freedesktop.machine1.policy:64 +msgid "Acquire a pseudo TTY in a local container" +msgstr "Verkrijg een pseudo-TTY in een plaatselijke container" + +#: src/machine/org.freedesktop.machine1.policy:65 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" +"Authenticatie is vereist voor het verkrijgen van een pseudo-TTY in een " +"plaatselijke container." + +#: src/machine/org.freedesktop.machine1.policy:74 +msgid "Acquire a pseudo TTY on the local host" +msgstr "Verkrijg een pseudo-TTY op de plaatselijke computer" + +#: src/machine/org.freedesktop.machine1.policy:75 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" +"Authenticatie is vereist voor het verkrijgen van een pseudo-TTY op de " +"plaatselijke computer." + +#: src/machine/org.freedesktop.machine1.policy:84 +msgid "Manage local virtual machines and containers" +msgstr "Beheer lokale virtuele machines en containers" + +#: src/machine/org.freedesktop.machine1.policy:85 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "" +"Authenticatie is vereist voor het beheren van lokale virtuele machines en " +"containers." + +#: src/machine/org.freedesktop.machine1.policy:95 +msgid "Manage local virtual machine and container images" +msgstr "Beheer plaatselijke virtuele machine en container-schijfkopieën" + +#: src/machine/org.freedesktop.machine1.policy:96 +msgid "" +"Authentication is required to manage local virtual machine and container " +"images." +msgstr "" +"Authenticatie is vereist voor het beheren van plaatselijke virtuele machine " +"en container-schijfkopieën." + +#: src/network/org.freedesktop.network1.policy:22 +msgid "Set NTP servers" +msgstr "Stel NTP-servers in" + +#: src/network/org.freedesktop.network1.policy:23 +msgid "Authentication is required to set NTP servers." +msgstr "Authenticatie is vereist voor het instellen van NTP-servers." + +#: src/network/org.freedesktop.network1.policy:33 +#: src/resolve/org.freedesktop.resolve1.policy:44 +msgid "Set DNS servers" +msgstr "Stel DNS-servers in" + +#: src/network/org.freedesktop.network1.policy:34 +#: src/resolve/org.freedesktop.resolve1.policy:45 +msgid "Authentication is required to set DNS servers." +msgstr "Authenticatie is vereist voor het instellen van DNS-servers." + +#: src/network/org.freedesktop.network1.policy:44 +#: src/resolve/org.freedesktop.resolve1.policy:55 +msgid "Set domains" +msgstr "Stel domeinen in" + +#: src/network/org.freedesktop.network1.policy:45 +#: src/resolve/org.freedesktop.resolve1.policy:56 +msgid "Authentication is required to set domains." +msgstr "Authenticatie is vereist voor het instellen van domeinen." + +#: src/network/org.freedesktop.network1.policy:55 +#: src/resolve/org.freedesktop.resolve1.policy:66 +msgid "Set default route" +msgstr "Stel standaardroute in" + +#: src/network/org.freedesktop.network1.policy:56 +#: src/resolve/org.freedesktop.resolve1.policy:67 +msgid "Authentication is required to set default route." +msgstr "Authenticatie is vereist voor het instellen van een standaardroute." + +#: src/network/org.freedesktop.network1.policy:66 +#: src/resolve/org.freedesktop.resolve1.policy:77 +msgid "Enable/disable LLMNR" +msgstr "Schakel LLMNR in of uit" + +#: src/network/org.freedesktop.network1.policy:67 +#: src/resolve/org.freedesktop.resolve1.policy:78 +msgid "Authentication is required to enable or disable LLMNR." +msgstr "Authenticatie is vereist voor het in- of uitschakelen van LLMNR." + +#: src/network/org.freedesktop.network1.policy:77 +#: src/resolve/org.freedesktop.resolve1.policy:88 +msgid "Enable/disable multicast DNS" +msgstr "Schakel multicast-DNS in of uit" + +#: src/network/org.freedesktop.network1.policy:78 +#: src/resolve/org.freedesktop.resolve1.policy:89 +msgid "Authentication is required to enable or disable multicast DNS." +msgstr "" +"Authenticatie is vereist voor het in- of uitschakelen van multicast-DNS." + +#: src/network/org.freedesktop.network1.policy:88 +#: src/resolve/org.freedesktop.resolve1.policy:99 +msgid "Enable/disable DNS over TLS" +msgstr "Schakel DNS over TLS in of uit" + +#: src/network/org.freedesktop.network1.policy:89 +#: src/resolve/org.freedesktop.resolve1.policy:100 +msgid "Authentication is required to enable or disable DNS over TLS." +msgstr "" +"Authenticatie is vereist voor het inschakelen of uitschakelen van DNS over " +"TLS." + +#: src/network/org.freedesktop.network1.policy:99 +#: src/resolve/org.freedesktop.resolve1.policy:110 +msgid "Enable/disable DNSSEC" +msgstr "Schakel DNSSEC in of uit" + +#: src/network/org.freedesktop.network1.policy:100 +#: src/resolve/org.freedesktop.resolve1.policy:111 +msgid "Authentication is required to enable or disable DNSSEC." +msgstr "Authenticatie is vereist voor het in- of uitschakelen van DNSSEC." + +#: src/network/org.freedesktop.network1.policy:110 +#: src/resolve/org.freedesktop.resolve1.policy:121 +msgid "Set DNSSEC Negative Trust Anchors" +msgstr "Stel DNSSEC Negative Trust Anchors in" + +#: src/network/org.freedesktop.network1.policy:111 +#: src/resolve/org.freedesktop.resolve1.policy:122 +msgid "Authentication is required to set DNSSEC Negative Trust Anchors." +msgstr "" +"Authenticatie is vereist voor het instellen van DNSSEC Negative Trust " +"Anchors." + +#: src/network/org.freedesktop.network1.policy:121 +msgid "Revert NTP settings" +msgstr "Draai NTP-instellingen terug" + +#: src/network/org.freedesktop.network1.policy:122 +msgid "Authentication is required to reset NTP settings." +msgstr "Authenticatie is vereist voor het terugzetten van NTP-instellingen." + +#: src/network/org.freedesktop.network1.policy:132 +msgid "Revert DNS settings" +msgstr "Draai DNS-instellingen terug" + +#: src/network/org.freedesktop.network1.policy:133 +msgid "Authentication is required to reset DNS settings." +msgstr "Authenticatie is vereist voor het terugzetten van DNS-instellingen." + +#: src/network/org.freedesktop.network1.policy:143 +msgid "DHCP server sends force renew message" +msgstr "DHCP-server verstuurt 'gedwongen hernieuwing'-boodschap" + +#: src/network/org.freedesktop.network1.policy:144 +msgid "Authentication is required to send force renew message." +msgstr "" +"Authenticatie is vereist voor het verzenden van een 'gedwongen " +"hernieuwing'-boodschap." + +#: src/network/org.freedesktop.network1.policy:154 +msgid "Renew dynamic addresses" +msgstr "Hernieuw dynamische adressen" + +#: src/network/org.freedesktop.network1.policy:155 +msgid "Authentication is required to renew dynamic addresses." +msgstr "Authenticatie is vereist voor het hernieuwen van dynamische adressen." + +#: src/network/org.freedesktop.network1.policy:165 +msgid "Reload network settings" +msgstr "Herlaad netwerkinstellingen" + +#: src/network/org.freedesktop.network1.policy:166 +msgid "Authentication is required to reload network settings." +msgstr "Authenticatie is vereist voor het herladen van netwerkinstellingen." + +#: src/network/org.freedesktop.network1.policy:176 +msgid "Reconfigure network interface" +msgstr "Stel netwerkkaart opnieuw in" + +#: src/network/org.freedesktop.network1.policy:177 +msgid "Authentication is required to reconfigure network interface." +msgstr "" +"Authenticatie is vereist voor het opnieuw instellen van de netwerkkaart." + +#: src/portable/org.freedesktop.portable1.policy:13 +msgid "Inspect a portable service image" +msgstr "Inspecteer een portable service schijfkopie" + +#: src/portable/org.freedesktop.portable1.policy:14 +msgid "Authentication is required to inspect a portable service image." +msgstr "" +"Authenticatie is vereist voor het inspecteren van een portable service " +"schijfkopie." + +#: src/portable/org.freedesktop.portable1.policy:23 +msgid "Attach or detach a portable service image" +msgstr "Koppel een portable service schijfkopie aan of af" + +#: src/portable/org.freedesktop.portable1.policy:24 +msgid "" +"Authentication is required to attach or detach a portable service image." +msgstr "" +"Authenticatie is vereist voor het aan- of afkoppelen van een portable " +"service schijfkopie." + +#: src/portable/org.freedesktop.portable1.policy:34 +msgid "Delete or modify portable service image" +msgstr "Verwijder of wijzig een portable service schijfkopie" + +#: src/portable/org.freedesktop.portable1.policy:35 +msgid "" +"Authentication is required to delete or modify a portable service image." +msgstr "" +"Authenticatie is vereist voor het verwijderen of aanpassen van een portable " +"service schijfkopie." + +#: src/resolve/org.freedesktop.resolve1.policy:22 +msgid "Register a DNS-SD service" +msgstr "Registreer een DNS-SD-dienst" + +#: src/resolve/org.freedesktop.resolve1.policy:23 +msgid "Authentication is required to register a DNS-SD service" +msgstr "Authenticatie is vereist voor het registreren van een DNS-SD-dienst" + +#: src/resolve/org.freedesktop.resolve1.policy:33 +msgid "Unregister a DNS-SD service" +msgstr "Ontregistreer een DNS-SD-dienst" + +#: src/resolve/org.freedesktop.resolve1.policy:34 +msgid "Authentication is required to unregister a DNS-SD service" +msgstr "Authenticatie is vereist voor het ontregistreren van een DNS-SD-dienst" + +#: src/resolve/org.freedesktop.resolve1.policy:132 +msgid "Revert name resolution settings" +msgstr "Draai instellingen voor naamoplossing terug" + +#: src/resolve/org.freedesktop.resolve1.policy:133 +msgid "Authentication is required to reset name resolution settings." +msgstr "" +"Authenticatie is vereist voor het terugzetten van de instellingen voor " +"naamoplossing." + +#: src/timedate/org.freedesktop.timedate1.policy:22 +msgid "Set system time" +msgstr "Stel systeemtijd in" + +#: src/timedate/org.freedesktop.timedate1.policy:23 +msgid "Authentication is required to set the system time." +msgstr "Authenticatie is vereist voor het instellen van de systeemtijd." + +#: src/timedate/org.freedesktop.timedate1.policy:33 +msgid "Set system timezone" +msgstr "Stel de tijdzone van het systeem in" + +#: src/timedate/org.freedesktop.timedate1.policy:34 +msgid "Authentication is required to set the system timezone." +msgstr "" +"Authenticatie is vereist voor het instellen van de tijdzone van het systeem." + +#: src/timedate/org.freedesktop.timedate1.policy:43 +msgid "Set RTC to local timezone or UTC" +msgstr "Stel RTC in op plaatselijke tijdzone of UTC" + +#: src/timedate/org.freedesktop.timedate1.policy:44 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" +"Authenticatie is vereist voor het bepalen of RTC de plaatselijke tijd of de " +"UTC-tijd opslaat." + +#: src/timedate/org.freedesktop.timedate1.policy:53 +msgid "Turn network time synchronization on or off" +msgstr "Schakel netwerktijdsynchronisatie in of uit" + +#: src/timedate/org.freedesktop.timedate1.policy:54 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" +"Authenticatie is vereist voor het bepalen of netwerktijdsynchronisatie " +"ingeschakeld zal zijn." + +#: src/core/dbus-unit.c:359 +msgid "Authentication is required to start '$(unit)'." +msgstr "Authenticatie is vereist voor het starten van '$(unit)'." + +#: src/core/dbus-unit.c:360 +msgid "Authentication is required to stop '$(unit)'." +msgstr "Authenticatie is vereist voor het stilzetten van '$(unit)'." + +#: src/core/dbus-unit.c:361 +msgid "Authentication is required to reload '$(unit)'." +msgstr "Authenticatie is vereist voor het herladen van '$(unit)'." + +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 +msgid "Authentication is required to restart '$(unit)'." +msgstr "Authenticatie is vereist voor het herstarten van '$(unit)'." + +#: src/core/dbus-unit.c:535 +msgid "" +"Authentication is required to send a UNIX signal to the processes of " +"'$(unit)'." +msgstr "" +"Authenticatie is vereist voor het zenden van een UNIX-signaal naar de " +"processen van '$(unit)'." + +#: src/core/dbus-unit.c:566 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" +"Authenticatie is vereist voor het terugzetten van de 'mislukt'-status van " +"'$(unit)'." + +#: src/core/dbus-unit.c:599 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" +"Authenticatie is vereist voor het instellen van eigenschappen op '$(unit)'." + +#: src/core/dbus-unit.c:708 +msgid "" +"Authentication is required to delete files and directories associated with " +"'$(unit)'." +msgstr "" +"Authenticatie is vereist voor het verwijderen van bestanden en mappen die " +"verbonden zijn aan '$(unit)'." + +#: src/core/dbus-unit.c:757 +msgid "" +"Authentication is required to freeze or thaw the processes of '$(unit)' unit." +msgstr "" +"Authenticatie is vereist voor het bevriezen of ontdooien van de processen " +"van '$(unit)' unit." diff --git a/po/pa.po b/po/pa.po new file mode 100644 index 000000000..892a8e105 --- /dev/null +++ b/po/pa.po @@ -0,0 +1,853 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# A S Alam , 2020, 2021. +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-01-24 16:38+0000\n" +"Last-Translator: A S Alam \n" +"Language-Team: Punjabi \n" +"Language: pa\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.4.2\n" + +#: src/core/org.freedesktop.systemd1.policy.in:22 +msgid "Send passphrase back to system" +msgstr "ਵਾਕ ਵਾਪਸ ਸਿਸਟਮ ਨੂੰ ਭੇਜੋ" + +#: src/core/org.freedesktop.systemd1.policy.in:23 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "ਦਿੱਤਾ ਵਾਕ ਸਿਸਟਮ ਨੂੰ ਵਾਪਸ ਭੇਜਣ ਲਈ ਪਰਮਾਣਕਿਤਾ ਚਾਹੀਦੀ ਹੈ।" + +#: src/core/org.freedesktop.systemd1.policy.in:33 +msgid "Manage system services or other units" +msgstr "ਸਿਸਟਮ ਸੇਵਾਵਾਂ ਜਾਂ ਹੋਰ ਇਕਾਈਆਂ ਦਾ ਇੰਤਜ਼ਾਮ ਕਰੋ" + +#: src/core/org.freedesktop.systemd1.policy.in:34 +msgid "Authentication is required to manage system services or other units." +msgstr "ਸਿਸਟਮ ਸੇਵਾਵਾਂ ਜਾਂ ਹੋਰ ਇਕਾਈਆਂ ਦੇ ਇੰਤਜਾਮ ਲਈ ਪਰਮਾਣਕਿਤਾ ਚਾਹੀਦੀ ਹੈ।" + +#: src/core/org.freedesktop.systemd1.policy.in:43 +msgid "Manage system service or unit files" +msgstr "ਸਿਸਟਮ ਸੇਵਾਵਾਂ ਜਾਂ ਯੂਨਿਟ ਫ਼ਾਇਲਾਂ ਦਾ ਇੰਤਜ਼ਾਮ ਕਰੋ" + +#: src/core/org.freedesktop.systemd1.policy.in:44 +msgid "Authentication is required to manage system service or unit files." +msgstr "ਸਿਸਟਮ ਸੇਵਾਵਾਂ ਜਾਂ ਯੂਨਿਟ ਫ਼ਾਇਲਾਂ ਦਾ ਇੰਤਜ਼ਾਮ ਕਰਨ ਲਈ ਪਰਮਾਣਕਿਤਾ ਚਾਹੀਦੀ ਹੈ।" + +#: src/core/org.freedesktop.systemd1.policy.in:54 +msgid "Set or unset system and service manager environment variables" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:55 +msgid "" +"Authentication is required to set or unset system and service manager " +"environment variables." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:64 +msgid "Reload the systemd state" +msgstr "systemd ਹਾਲਤ ਮੁੜ ਲੋਡ ਕਰੋ" + +#: src/core/org.freedesktop.systemd1.policy.in:65 +msgid "Authentication is required to reload the systemd state." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:13 +msgid "Create a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:14 +msgid "Authentication is required to create a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:23 +msgid "Remove a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:24 +msgid "Authentication is required to remove a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:33 +msgid "Check credentials of a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:34 +msgid "" +"Authentication is required to check credentials against a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:43 +msgid "Update a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:44 +msgid "Authentication is required to update a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:53 +msgid "Resize a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:54 +msgid "Authentication is required to resize a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:63 +msgid "Change password of a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:64 +msgid "" +"Authentication is required to change the password of a user's home area." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:20 +msgid "Set hostname" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:21 +msgid "Authentication is required to set the local hostname." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:30 +msgid "Set static hostname" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:31 +msgid "" +"Authentication is required to set the statically configured local hostname, " +"as well as the pretty hostname." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:41 +msgid "Set machine information" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:42 +msgid "Authentication is required to set local machine information." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:51 +msgid "Get product UUID" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:52 +msgid "Authentication is required to get product UUID." +msgstr "" + +#: src/import/org.freedesktop.import1.policy:22 +msgid "Import a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:23 +msgid "Authentication is required to import a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:32 +msgid "Export a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:33 +msgid "Authentication is required to export a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:42 +msgid "Download a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:43 +msgid "Authentication is required to download a VM or container image" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:22 +msgid "Set system locale" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:23 +msgid "Authentication is required to set the system locale." +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:33 +msgid "Set system keyboard settings" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:34 +msgid "Authentication is required to set the system keyboard settings." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:22 +msgid "Allow applications to inhibit system shutdown" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:23 +msgid "" +"Authentication is required for an application to inhibit system shutdown." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:33 +msgid "Allow applications to delay system shutdown" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:34 +msgid "Authentication is required for an application to delay system shutdown." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:44 +msgid "Allow applications to inhibit system sleep" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:45 +msgid "Authentication is required for an application to inhibit system sleep." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:55 +msgid "Allow applications to delay system sleep" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:56 +msgid "Authentication is required for an application to delay system sleep." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:65 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:66 +msgid "" +"Authentication is required for an application to inhibit automatic system " +"suspend." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:75 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:76 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the power key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:86 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:87 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the suspend key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:97 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:98 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the hibernate key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:107 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:108 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the lid switch." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "Authentication is required to manage system services or other units." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "ਸਿਸਟਮ ਸੇਵਾਵਾਂ ਜਾਂ ਹੋਰ ਇਕਾਈਆਂ ਦੇ ਇੰਤਜਾਮ ਲਈ ਪਰਮਾਣਕਿਤਾ ਚਾਹੀਦੀ ਹੈ।" + +#: src/login/org.freedesktop.login1.policy:128 +msgid "Allow non-logged-in user to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:129 +msgid "Explicit request is required to run programs as a non-logged-in user." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:138 +msgid "Allow non-logged-in users to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:139 +msgid "Authentication is required to run programs as a non-logged-in user." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:148 +msgid "Allow attaching devices to seats" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:149 +msgid "Authentication is required to attach a device to a seat." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:159 +msgid "Flush device to seat attachments" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:160 +msgid "Authentication is required to reset how devices are attached to seats." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:169 +msgid "Power off the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:170 +msgid "Authentication is required to power off the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:180 +msgid "Power off the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:181 +msgid "" +"Authentication is required to power off the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:191 +msgid "Power off the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:192 +msgid "" +"Authentication is required to power off the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:202 +msgid "Reboot the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:203 +msgid "Authentication is required to reboot the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:213 +msgid "Reboot the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:214 +msgid "" +"Authentication is required to reboot the system while other users are logged " +"in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:224 +msgid "Reboot the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:225 +msgid "" +"Authentication is required to reboot the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:235 +msgid "Halt the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:236 +msgid "Authentication is required to halt the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:246 +msgid "Halt the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:247 +msgid "" +"Authentication is required to halt the system while other users are logged " +"in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:257 +msgid "Halt the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:258 +msgid "" +"Authentication is required to halt the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:268 +msgid "Suspend the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:269 +msgid "Authentication is required to suspend the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:278 +msgid "Suspend the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:279 +msgid "" +"Authentication is required to suspend the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:289 +msgid "Suspend the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:290 +msgid "" +"Authentication is required to suspend the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:300 +msgid "Hibernate the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:301 +msgid "Authentication is required to hibernate the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:310 +msgid "Hibernate the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:311 +msgid "" +"Authentication is required to hibernate the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:321 +msgid "Hibernate the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:322 +msgid "" +"Authentication is required to hibernate the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:332 +msgid "Manage active sessions, users and seats" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:333 +msgid "Authentication is required to manage active sessions, users and seats." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:342 +msgid "Lock or unlock active sessions" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:343 +msgid "Authentication is required to lock or unlock active sessions." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:352 +msgid "Set the reboot \"reason\" in the kernel" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:364 +msgid "" +"Authentication is required to indicate to the firmware to boot to setup " +"interface." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:374 +msgid "Indicate to the boot loader to boot to the boot loader menu" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:375 +msgid "" +"Authentication is required to indicate to the boot loader to boot to the " +"boot loader menu." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:385 +msgid "Indicate to the boot loader to boot a specific entry" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:386 +msgid "" +"Authentication is required to indicate to the boot loader to boot into a " +"specific boot loader entry." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:396 +msgid "Set a wall message" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:397 +msgid "Authentication is required to set a wall message" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:406 +msgid "Change Session" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:407 +msgid "Authentication is required to change the virtual terminal." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:22 +msgid "Log into a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:23 +msgid "Authentication is required to log into a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:32 +msgid "Log into the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:33 +msgid "Authentication is required to log into the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:42 +msgid "Acquire a shell in a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:43 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:53 +msgid "Acquire a shell on the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:54 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:64 +msgid "Acquire a pseudo TTY in a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:65 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:74 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:75 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:84 +msgid "Manage local virtual machines and containers" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:85 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:95 +msgid "Manage local virtual machine and container images" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:96 +msgid "" +"Authentication is required to manage local virtual machine and container " +"images." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:22 +msgid "Set NTP servers" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:23 +msgid "Authentication is required to set NTP servers." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:33 +#: src/resolve/org.freedesktop.resolve1.policy:44 +msgid "Set DNS servers" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:34 +#: src/resolve/org.freedesktop.resolve1.policy:45 +msgid "Authentication is required to set DNS servers." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:44 +#: src/resolve/org.freedesktop.resolve1.policy:55 +msgid "Set domains" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:45 +#: src/resolve/org.freedesktop.resolve1.policy:56 +msgid "Authentication is required to set domains." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:55 +#: src/resolve/org.freedesktop.resolve1.policy:66 +msgid "Set default route" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:56 +#: src/resolve/org.freedesktop.resolve1.policy:67 +msgid "Authentication is required to set default route." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:66 +#: src/resolve/org.freedesktop.resolve1.policy:77 +msgid "Enable/disable LLMNR" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:67 +#: src/resolve/org.freedesktop.resolve1.policy:78 +msgid "Authentication is required to enable or disable LLMNR." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:77 +#: src/resolve/org.freedesktop.resolve1.policy:88 +msgid "Enable/disable multicast DNS" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:78 +#: src/resolve/org.freedesktop.resolve1.policy:89 +msgid "Authentication is required to enable or disable multicast DNS." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:88 +#: src/resolve/org.freedesktop.resolve1.policy:99 +msgid "Enable/disable DNS over TLS" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:89 +#: src/resolve/org.freedesktop.resolve1.policy:100 +msgid "Authentication is required to enable or disable DNS over TLS." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:99 +#: src/resolve/org.freedesktop.resolve1.policy:110 +msgid "Enable/disable DNSSEC" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:100 +#: src/resolve/org.freedesktop.resolve1.policy:111 +msgid "Authentication is required to enable or disable DNSSEC." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:110 +#: src/resolve/org.freedesktop.resolve1.policy:121 +msgid "Set DNSSEC Negative Trust Anchors" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:111 +#: src/resolve/org.freedesktop.resolve1.policy:122 +msgid "Authentication is required to set DNSSEC Negative Trust Anchors." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:121 +msgid "Revert NTP settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:122 +msgid "Authentication is required to reset NTP settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:132 +msgid "Revert DNS settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:133 +msgid "Authentication is required to reset DNS settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:143 +msgid "DHCP server sends force renew message" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:144 +msgid "Authentication is required to send force renew message." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:154 +msgid "Renew dynamic addresses" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:155 +msgid "Authentication is required to renew dynamic addresses." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:165 +msgid "Reload network settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:166 +msgid "Authentication is required to reload network settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:176 +msgid "Reconfigure network interface" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:177 +msgid "Authentication is required to reconfigure network interface." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:13 +msgid "Inspect a portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:14 +msgid "Authentication is required to inspect a portable service image." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:23 +msgid "Attach or detach a portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:24 +msgid "" +"Authentication is required to attach or detach a portable service image." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:34 +msgid "Delete or modify portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:35 +msgid "" +"Authentication is required to delete or modify a portable service image." +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:22 +msgid "Register a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:23 +msgid "Authentication is required to register a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:33 +msgid "Unregister a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:34 +msgid "Authentication is required to unregister a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:132 +msgid "Revert name resolution settings" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:133 +msgid "Authentication is required to reset name resolution settings." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:22 +msgid "Set system time" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:23 +msgid "Authentication is required to set the system time." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:33 +msgid "Set system timezone" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:34 +msgid "Authentication is required to set the system timezone." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:43 +msgid "Set RTC to local timezone or UTC" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:44 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:53 +msgid "Turn network time synchronization on or off" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:54 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" + +#: src/core/dbus-unit.c:359 +msgid "Authentication is required to start '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:360 +msgid "Authentication is required to stop '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:361 +msgid "Authentication is required to reload '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 +msgid "Authentication is required to restart '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:535 +msgid "" +"Authentication is required to send a UNIX signal to the processes of " +"'$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:566 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:599 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:708 +msgid "" +"Authentication is required to delete files and directories associated with " +"'$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:757 +msgid "" +"Authentication is required to freeze or thaw the processes of '$(unit)' unit." +msgstr "" diff --git a/po/pl.po b/po/pl.po index b4b3912a5..a4251187f 100644 --- a/po/pl.po +++ b/po/pl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-09-10 03:33+0000\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2020-10-18 13:10+0200\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" diff --git a/po/pt_BR.po b/po/pt_BR.po index 188f8a9f9..8cdd49fe1 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -4,21 +4,22 @@ # Enrico Nicoletto , 2014. # Filipe Brandenburger , 2018. # Rafael Fontenelle , 2015-2020. -# +# Gustavo Costa , 2021. msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-05-30 09:10-0300\n" -"Last-Translator: Rafael Fontenelle \n" -"Language-Team: Brazilian Portuguese \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-02-25 18:41+0000\n" +"Last-Translator: Gustavo Costa \n" +"Language-Team: Portuguese (Brazil) \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1)\n" -"X-Generator: Gtranslator 3.36.0\n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.4.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -313,58 +314,72 @@ msgstr "" "sistema sobre o interruptor da tela." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Permitir que aplicativos inibam o sistema de gerenciar o botão de " +"reinicialização" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"É necessária autenticação para que um aplicativo iniba o sistema de " +"gerenciar o botão de reinicialização." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "" "Permitir que programas sejam executados por usuário que não possui sessão" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "É necessária requisição explícita para executar programas como usuário sem " "sessão aberta." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "" "Permitir que programas sejam executados por usuários que não possuem sessão" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "É necessária autenticação para executar programas como usuário sem sessão " "aberta." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Permitir conectar dispositivos em estações" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "É necessária autenticação para conectar um dispositivo em uma estação." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Liberar dispositivo para conexões da estação" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "É necessária autenticação para redefinir a quantidade de dispositivos " "conectados na estação." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Desligar o sistema" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "É necessária autenticação para desligar o sistema." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Desligar o sistema enquanto outros usuários estão conectados" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -372,11 +387,11 @@ msgstr "" "É necessária autenticação para desligar o sistema enquanto outros usuários " "estão conectados." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Desligar o sistema enquanto um aplicativo solicitou inibição" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -384,19 +399,19 @@ msgstr "" "É necessária autenticação para desligar o sistema enquanto um aplicativo " "solicitou inibição." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Reiniciar o sistema" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "É necessária autenticação para reiniciar o sistema." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Reiniciar o sistema enquanto outros usuários estiverem conectados" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -404,11 +419,11 @@ msgstr "" "É necessária autenticação para reiniciar o sistema enquanto outros usuários " "estiverem conectados." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Reiniciar o sistema enquanto um aplicativo solicitou inibição" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -416,19 +431,19 @@ msgstr "" "É necessária autenticação para reiniciar o sistema enquanto um aplicativo " "solicitou inibição." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Parar o sistema" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "É necessária autenticação para parar o sistema." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Parar o sistema enquanto outros usuários estão logados" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -436,11 +451,11 @@ msgstr "" "É necessária autenticação para parar o sistema enquanto outros usuários " "estejam logados." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Parar o sistema enquanto um aplicativo solicitou inibição" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." @@ -448,19 +463,19 @@ msgstr "" "É necessária autenticação para parar o sistema enquanto um aplicativo " "solicitou inibição." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Suspender o sistema" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "É necessária autenticação para suspender o sistema." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Suspender o sistema enquanto outros usuários estiverem conectados" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -468,11 +483,11 @@ msgstr "" "É necessária autenticação para suspender o sistema enquanto outros usuários " "estiverem conectados." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Suspender o sistema enquanto um aplicativo solicitou inibição" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -480,19 +495,19 @@ msgstr "" "É necessária autenticação para suspender o sistema enquanto um aplicativo " "solicitou inibição." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Hibernar o sistema" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "É necessária autenticação para hibernar o sistema." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Hibernar o sistema enquanto outros usuários estiverem conectados" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -500,11 +515,11 @@ msgstr "" "É necessária autenticação para hibernar o sistema enquanto outros usuários " "estiverem conectados." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Hibernar o sistema enquanto um aplicativo solicitou inibição" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -512,38 +527,38 @@ msgstr "" "É necessária autenticação para hibernar o sistema enquanto um aplicativo " "solicitou inibição." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Gerenciar estações, usuários e sessões ativas" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "É necessária autenticação para gerenciar estações, usuários e sessões ativas." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Travar ou destravar sessões ativas" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "É necessária autenticação para travar ou destravar sessões ativas." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Definir o “motivo” de reinicialização no kernel" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "É necessária autenticação para definir o “motivo” de reinicialização no " "kernel." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Indicar para o firmware inicializar para a interface de configuração" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -551,11 +566,11 @@ msgstr "" "É necessária autenticação para indicar para o firmware inicializar para a " "interface de configuração." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Indicar para o carregador de inicialização iniciar seu menu" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -563,12 +578,12 @@ msgstr "" "É necessária autenticação para indicar para o carregador de inicialização " "iniciar seu menu." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" "Indicar para o carregador de inicializar iniciar uma entrada específica" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -576,19 +591,19 @@ msgstr "" "É necessária autenticação para indicar para o carregador de inicializar " "iniciar uma entrada específica." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Definir uma mensagem de parede" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "É necessária autenticação para definir uma mensagem de parede" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "Alterar sessão" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "É necessária autenticação para alterar o terminal virtual." @@ -901,23 +916,23 @@ msgstr "" "É necessária autenticação para controlar se deve ser habilitada, ou não, a " "sincronização de horário através de rede." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "É necessária autenticação para iniciar “$(unit)”." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "É necessária autenticação para parar “$(unit)”." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "É necessária autenticação para recarregar “$(unit)”." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "É necessária autenticação para reiniciar “$(unit)”." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." @@ -925,16 +940,16 @@ msgstr "" "É necessária autenticação para enviar um sinal UNIX para os processos de " "“$(unit)”." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "É necessária autenticação para reiniciar o estado “failed” de “$(unit)”." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "É necessária autenticação para definir propriedades em “$(unit)”." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -942,7 +957,7 @@ msgstr "" "É necessária autenticação para excluir arquivos e diretórios associados com " "“$(unit)”." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" diff --git a/po/ro.po b/po/ro.po index 6c4690075..1dd04fc21 100644 --- a/po/ro.po +++ b/po/ro.po @@ -3,21 +3,23 @@ # Romanian translation for systemd. # va511e , 2015. # Daniel Șerbănescu , 2015, 2017. +# Vlad , 2020, 2021. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2017-08-13 19:48+0200\n" -"Last-Translator: Daniel Șerbănescu \n" -"Language-Team: Gnome Romanian Translation Team\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-01-12 17:36+0000\n" +"Last-Translator: Vlad \n" +"Language-Team: Romanian \n" "Language: ro\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " -"20)) ? 1 : 2);;\n" -"X-Generator: Virtaal 0.7.1\n" +"Plural-Forms: nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < " +"20)) ? 1 : 2;\n" +"X-Generator: Weblate 4.4\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -32,152 +34,146 @@ msgstr "" #: src/core/org.freedesktop.systemd1.policy.in:33 msgid "Manage system services or other units" -msgstr "Gestionează serviciile de sistem sau alte unități" +msgstr "Gestionează serviciile de sistem sau alte module" #: src/core/org.freedesktop.systemd1.policy.in:34 msgid "Authentication is required to manage system services or other units." msgstr "" "Autentificarea este necesară pentru a gestiona serviciile de sistem sau alte " -"unități." +"module." #: src/core/org.freedesktop.systemd1.policy.in:43 msgid "Manage system service or unit files" -msgstr "Gestionează serviciul de sistem sau fișiere unitate" +msgstr "Gestionează serviciul de sistem sau fișierele modulelor" #: src/core/org.freedesktop.systemd1.policy.in:44 msgid "Authentication is required to manage system service or unit files." msgstr "" "Autentificarea este necesară pentru a gestiona serviciul de sistem sau " -"fișierele unitate." +"fișierele modulelor." #: src/core/org.freedesktop.systemd1.policy.in:54 msgid "Set or unset system and service manager environment variables" msgstr "" -"Stabilește sau destabilește variabilele de mediu și managerul de servicii " -"ale sistemului" +"Setează sau resetează variabilele de mediu ale managerului de servicii si de " +"sistem" #: src/core/org.freedesktop.systemd1.policy.in:55 msgid "" "Authentication is required to set or unset system and service manager " "environment variables." msgstr "" -"Autentificarea este necesară pentru a stabili sau destabili variabile de " -"mediu și managerul de servicii ale sistemului." +"Autentificarea este necesară pentru setarea sau resetarea variabilelor de " +"mediu ale managerului de servicii si de sistem." #: src/core/org.freedesktop.systemd1.policy.in:64 msgid "Reload the systemd state" -msgstr "Reîncarcă starea systemd" +msgstr "Reîncarcă starea lui systemd" #: src/core/org.freedesktop.systemd1.policy.in:65 msgid "Authentication is required to reload the systemd state." -msgstr "Autentificarea este necesară pentru a reîncărca starea systemd." +msgstr "Autentificarea este necesară pentru a reîncărca starea lui systemd." #: src/home/org.freedesktop.home1.policy:13 msgid "Create a home area" -msgstr "" +msgstr "Crează un spațiu personal" #: src/home/org.freedesktop.home1.policy:14 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to create a user's home area." -msgstr "Autentificarea este necesară pentru a reîncărca starea systemd." +msgstr "" +"Autentificarea este necesară pentru a crea spațiul personal al unui " +"utilizator." #: src/home/org.freedesktop.home1.policy:23 msgid "Remove a home area" -msgstr "" +msgstr "Șterge spațiu personal" #: src/home/org.freedesktop.home1.policy:24 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to remove a user's home area." -msgstr "Autentificarea este necesară pentru a reîncărca starea systemd." +msgstr "" +"Autentificarea este necesară pentru a șterge spațiul personal al unui " +"utilizator." #: src/home/org.freedesktop.home1.policy:33 msgid "Check credentials of a home area" -msgstr "" +msgstr "Verifică datele de acreditare ale unui spațiu personal" #: src/home/org.freedesktop.home1.policy:34 -#, fuzzy -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to check credentials against a user's home area." msgstr "" -"Autentificarea este necesară pentru gestionarea sesiunilor active, " -"utilizatorilor și locurilor." +"Autentificarea este necesară pentru verificarea datelor de acreditare ale " +"unui spațiu personal al unui utilizator." #: src/home/org.freedesktop.home1.policy:43 msgid "Update a home area" -msgstr "" +msgstr "Actualizează un spațiu personal" #: src/home/org.freedesktop.home1.policy:44 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "Authentication is required to update a user's home area." -msgstr "Autentificarea este necesară pentru a atașa un dispozitiv la un loc." +msgstr "" +"Autentificarea este necesară pentru a actualiza spațiul personal al unui " +"utilizator." #: src/home/org.freedesktop.home1.policy:53 msgid "Resize a home area" -msgstr "" +msgstr "Redimensionează un spațiu personal" #: src/home/org.freedesktop.home1.policy:54 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to resize a user's home area." -msgstr "Autentificarea este necesară pentru a stabili un mesaj de perete" +msgstr "" +"Autentificarea este necesară pentru a redimensiona spațiul personal al unui " +"utilizator." #: src/home/org.freedesktop.home1.policy:63 msgid "Change password of a home area" -msgstr "" +msgstr "Schimbă parola pentru un spațiu personal" #: src/home/org.freedesktop.home1.policy:64 -#, fuzzy -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to change the password of a user's home area." msgstr "" -"Autentificarea este necesară pentru gestionarea sesiunilor active, " -"utilizatorilor și locurilor." +"Autentificarea este necesară pentru schimbarea parolei unui spațiu personal " +"al unui utilizator." #: src/hostname/org.freedesktop.hostname1.policy:20 msgid "Set hostname" -msgstr "Stabilește numele de server" +msgstr "Seteaza numele stației" #: src/hostname/org.freedesktop.hostname1.policy:21 msgid "Authentication is required to set the local hostname." -msgstr "Autentificarea este necesară pentru a stabili numele de server local." +msgstr "Autentificarea este necesară pentru a seta numele stației." #: src/hostname/org.freedesktop.hostname1.policy:30 msgid "Set static hostname" -msgstr "Stabilește numele de server static" +msgstr "Seteaza numele static al stației" #: src/hostname/org.freedesktop.hostname1.policy:31 msgid "" "Authentication is required to set the statically configured local hostname, " "as well as the pretty hostname." msgstr "" -"Autentificarea este necesara pentru a stabili numele de server static " -"configurat local, precum și numele lung de server." +"Autentificarea este necesară pentru a seta numele static de stație, precum " +"și numele descriptiv de stație." #: src/hostname/org.freedesktop.hostname1.policy:41 msgid "Set machine information" -msgstr "Stabilește informațiile despre mașină" +msgstr "Setează informațiile despre stație" #: src/hostname/org.freedesktop.hostname1.policy:42 msgid "Authentication is required to set local machine information." msgstr "" -"Autentificarea este necesară pentru stabili informațiile mașinii locale." +"Autentificarea este necesară pentru setarea informațiilor despre stație." #: src/hostname/org.freedesktop.hostname1.policy:51 msgid "Get product UUID" -msgstr "" +msgstr "Obține identificatorul unic universal (UUID) al produsului" #: src/hostname/org.freedesktop.hostname1.policy:52 -#, fuzzy -#| msgid "Authentication is required to reload '$(unit)'." msgid "Authentication is required to get product UUID." -msgstr "Autentificarea este necesară pentru a reîncărca „$ (unit)”." +msgstr "" +"Autentificarea este necesară pentru a obține identificatorul unic universal " +"(UUID) al produsului." #: src/import/org.freedesktop.import1.policy:22 msgid "Import a VM or container image" @@ -211,21 +207,21 @@ msgstr "" #: src/locale/org.freedesktop.locale1.policy:22 msgid "Set system locale" -msgstr "Stabilește localizarea sistemului" +msgstr "Configurează setările regionale ale sistemului" #: src/locale/org.freedesktop.locale1.policy:23 msgid "Authentication is required to set the system locale." -msgstr "Autentificarea este necesară pentru a stabili localizarea sistemului." +msgstr "" +"Autentificarea este necesară pentru a configura setările regionale ale " +"sistemului." #: src/locale/org.freedesktop.locale1.policy:33 msgid "Set system keyboard settings" -msgstr "Stabilește configurările tastaturii sistemului" +msgstr "Setează configurările tastaturii" #: src/locale/org.freedesktop.locale1.policy:34 msgid "Authentication is required to set the system keyboard settings." -msgstr "" -"Autentificarea este necesară pentru a stabili configurările tastaturii " -"sistemului." +msgstr "Autentificarea este necesară pentru a seta configurările tastaturii." #: src/login/org.freedesktop.login1.policy:22 msgid "Allow applications to inhibit system shutdown" @@ -250,23 +246,23 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:44 msgid "Allow applications to inhibit system sleep" -msgstr "Permite aplicațiilor să împiedice starea de veghe a sistemului" +msgstr "Permite aplicațiilor să împiedice adormirea sistemului" #: src/login/org.freedesktop.login1.policy:45 msgid "Authentication is required for an application to inhibit system sleep." msgstr "" -"Autentificarea este necesară pentru ca o aplicație să împiedice starea de " -"veghe a sistemului." +"Autentificarea este necesară pentru ca o aplicație să împiedice adormirea " +"sistemului." #: src/login/org.freedesktop.login1.policy:55 msgid "Allow applications to delay system sleep" -msgstr "Permite aplicațiilor să întârzie starea de veghe sistemului" +msgstr "Permite aplicațiilor să întârzie adormirea sistemului" #: src/login/org.freedesktop.login1.policy:56 msgid "Authentication is required for an application to delay system sleep." msgstr "" -"Autentificarea este necesară pentru ca o aplicație să întârzie starea de " -"veghe a sistemului." +"Autentificarea este necesară pentru ca o aplicație să întârzie adormirea " +"sistemului." #: src/login/org.freedesktop.login1.policy:65 msgid "Allow applications to inhibit automatic system suspend" @@ -291,8 +287,8 @@ msgid "" "Authentication is required for an application to inhibit system handling of " "the power key." msgstr "" -"Autentificarea este necesară pentru o aplicație să împiedice administrarea " -"butonului de pornire a sistemului." +"Autentificarea este necesară pentru ca o aplicație să împiedice " +"administrarea butonului de pornire a sistemului." #: src/login/org.freedesktop.login1.policy:86 msgid "Allow applications to inhibit system handling of the suspend key" @@ -305,8 +301,8 @@ msgid "" "Authentication is required for an application to inhibit system handling of " "the suspend key." msgstr "" -"Autentificarea este necesară pentru o aplicație pentru a împiedica " -"manipularea butonului de suspendare al sistemului." +"Autentificarea este necesară pentru ca o aplicație să împiedice manipularea " +"butonului de suspendare al sistemului." #: src/login/org.freedesktop.login1.policy:97 msgid "Allow applications to inhibit system handling of the hibernate key" @@ -319,14 +315,14 @@ msgid "" "Authentication is required for an application to inhibit system handling of " "the hibernate key." msgstr "" -"Autentificarea este necesară pentru o aplicație să împiedice administrarea " -"butonului de hibernare al sistemului." +"Autentificarea este necesară pentru ca o aplicație să împiedice " +"administrarea butonului de hibernare al sistemului." #: src/login/org.freedesktop.login1.policy:107 msgid "Allow applications to inhibit system handling of the lid switch" msgstr "" -"Permite aplicațiilor să împiedice administrarea comutatorului capacului al " -"sistemului" +"Permite aplicațiilor să împiedice administrarea comutatorului din capacul " +"statiei" #: src/login/org.freedesktop.login1.policy:108 msgid "" @@ -334,334 +330,317 @@ msgid "" "the lid switch." msgstr "" "Autentificarea este necesară pentru ca o aplicație să împiedice manipularea " -"comutatorului capacului al sistemului." +"comutatorului din capacul sistemului." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Permite aplicațiilor să împiedice administrarea butonului de repornire a " +"sistemului" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Autentificarea este necesară pentru ca o aplicație să împiedice " +"administrarea butonului de repornire a sistemului." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Permite utilizatorilor neautentificați să execute programe" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" -"Cererea explicită este necesară pentru a rula programe ca utilizator " -"neautentificat." +"Este necesară o cerere explicită pentru ca un utilizator neautentificat să " +"ruleze programe." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" -msgstr "Permite utilizatorilor neautentificați să execute programe" +msgstr "Permite utilizatorilor neautentificați să ruleze programe" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Autentificarea este necesară pentru a rula programe ca utilizator " "neautentificat." -#: src/login/org.freedesktop.login1.policy:137 -msgid "Allow attaching devices to seats" -msgstr "Permite atașarea dispozitivelor la locuri" - -#: src/login/org.freedesktop.login1.policy:138 -msgid "Authentication is required to attach a device to a seat." -msgstr "Autentificarea este necesară pentru a atașa un dispozitiv la un loc." - #: src/login/org.freedesktop.login1.policy:148 -msgid "Flush device to seat attachments" -msgstr "Purjează atașamentele dispozitiv-loc" +msgid "Allow attaching devices to seats" +msgstr "Permite atașarea dispozitivelor la stațiile de lucru" #: src/login/org.freedesktop.login1.policy:149 +msgid "Authentication is required to attach a device to a seat." +msgstr "Autentificarea este necesară pentru a atașa un dispozitiv la o stație." + +#: src/login/org.freedesktop.login1.policy:159 +msgid "Flush device to seat attachments" +msgstr "Înlăturare dispozitiv atașat la stație" + +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" -"Autentificarea este necesară pentru a restabili cum dispozitivele sunt " -"atașate la locuri." +"Autentificarea este necesară pentru a înlătura dispozitivele atașate la " +"stații." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Oprește sistemul" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Este necesară autentificarea pentru oprirea sistemului." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" -msgstr "Oprește sistemul în timp ce alți utilizatori sunt autentificați" +msgstr "Oprește sistemul în timp ce alți utilizatori sunt conectați" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." msgstr "" "Autentificarea este necesară pentru oprirea sistemului în timp ce alți " -"utilizatori sunt autentificați." +"utilizatori sunt conectați." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" -msgstr "Oprește sistemul în timp ce o aplicație a cerut să împiedice asta" +msgstr "Oprește sistemul în timp ce o aplicație împiedică oprirea" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." msgstr "" "Autentificarea este necesară pentru oprirea sistemului în timp ce o " -"aplicație a cerut să împiedice asta." +"aplicație împiedică oprirea." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Repornește sistemul" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Autentificarea este necesară pentru repornirea sistemului." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" -msgstr "Repornește sistemul în timp ce alți utilizatori sunt autentificați" +msgstr "Repornește sistemul în timp ce alți utilizatori sunt conectați" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." msgstr "" "Autentificarea este necesară pentru repornirea sistemului în timp ce alți " -"utilizatori autentificați." +"utilizatori sunt conectați." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" -msgstr "Repornește sistemul în timp ce o aplicație a cerut să împiedice asta" +msgstr "Repornește sistemul în timp ce o aplicație împiedică repornirea" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." msgstr "" "Autentificarea este necesară pentru repornirea sistemului în timp ce o " -"aplicație a cerut să împiedice asta." - -#: src/login/org.freedesktop.login1.policy:224 -#, fuzzy -#| msgid "Hibernate the system" -msgid "Halt the system" -msgstr "Hiberneaza sistemul" - -#: src/login/org.freedesktop.login1.policy:225 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." -msgid "Authentication is required to halt the system." -msgstr "Este necesară autentificarea pentru hibernarea sistemului." +"aplicație împiedică repornirea." #: src/login/org.freedesktop.login1.policy:235 -#, fuzzy -#| msgid "Hibernate the system while other users are logged in" -msgid "Halt the system while other users are logged in" -msgstr "Hiberneaza sistemul în timp ce alți utilizatori sunt autentificați" +msgid "Halt the system" +msgstr "Oprește sistemul" #: src/login/org.freedesktop.login1.policy:236 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while other users are " -#| "logged in." +msgid "Authentication is required to halt the system." +msgstr "Este necesară autentificarea pentru oprirea sistemului." + +#: src/login/org.freedesktop.login1.policy:246 +msgid "Halt the system while other users are logged in" +msgstr "Oprește sistemul în timp ce alți utilizatori sunt conectați" + +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." msgstr "" -"Autentificarea este necesară pentru hibernare a sistemului în timp ce alți " -"utilizatori sunt autentificați." +"Autentificarea este necesară pentru oprirea sistemului în timp ce alți " +"utilizatori sunt conectați." -#: src/login/org.freedesktop.login1.policy:246 -#, fuzzy -#| msgid "Hibernate the system while an application is inhibiting this" +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" -msgstr "Hibernează sistemul în timp ce o aplicație a cerut să împiedice asta" +msgstr "Oprește sistemul în timp ce o aplicație împiedică oprirea" -#: src/login/org.freedesktop.login1.policy:247 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while an application " -#| "is inhibiting this." +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." msgstr "" -"Autentificarea este necesară pentru hibernarea sistemului în timp ce o " -"aplicație a cerut să împiedice asta." +"Autentificarea este necesară pentru oprirea sistemului în timp ce o " +"aplicație împiedică oprirea." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Suspendă sistemul" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Este necesară autentificarea pentru suspendarea sistemului." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" -msgstr "Suspendă sistemul în timp ce alți utilizatori sunt autentificați" +msgstr "Suspendă sistemul în timp ce alți utilizatori sunt conectați" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." msgstr "" "Autentificarea este necesară pentru suspendarea sistemului timp ce alți " -"utilizatori autentificați." +"utilizatori sunt conectați." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" -msgstr "Suspendă sistemul în timp ce o aplicație a cerut să împiedice asta" +msgstr "Suspendă sistemul în timp ce o aplicație împiedică suspendarea" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." msgstr "" "Autentificarea este necesară pentru suspendarea sistemului în timp ce o " -"aplicație a cerut să împiedice asta." - -#: src/login/org.freedesktop.login1.policy:289 -msgid "Hibernate the system" -msgstr "Hiberneaza sistemul" - -#: src/login/org.freedesktop.login1.policy:290 -msgid "Authentication is required to hibernate the system." -msgstr "Este necesară autentificarea pentru hibernarea sistemului." - -#: src/login/org.freedesktop.login1.policy:299 -msgid "Hibernate the system while other users are logged in" -msgstr "Hiberneaza sistemul în timp ce alți utilizatori sunt autentificați" +"aplicație împiedică suspendarea." #: src/login/org.freedesktop.login1.policy:300 +msgid "Hibernate the system" +msgstr "Hibernează sistemul" + +#: src/login/org.freedesktop.login1.policy:301 +msgid "Authentication is required to hibernate the system." +msgstr "Autentificarea este necesară pentru hibernarea sistemului." + +#: src/login/org.freedesktop.login1.policy:310 +msgid "Hibernate the system while other users are logged in" +msgstr "Hiberneaza sistemul în timp ce alți utilizatori sunt conectați" + +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." msgstr "" -"Autentificarea este necesară pentru hibernare a sistemului în timp ce alți " -"utilizatori sunt autentificați." +"Autentificarea este necesară pentru hibernarea sistemului în timp ce alți " +"utilizatori sunt conectați." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" -msgstr "Hibernează sistemul în timp ce o aplicație a cerut să împiedice asta" +msgstr "Hibernează sistemul în timp ce o aplicație împiedică hibernarea" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." msgstr "" "Autentificarea este necesară pentru hibernarea sistemului în timp ce o " -"aplicație a cerut să împiedice asta." +"aplicație împiedică hibernarea." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" -msgstr "Gestionează sesiuni active, utilizatori și locuri" +msgstr "Gestionează sesiuni active, utilizatori și stații" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Autentificarea este necesară pentru gestionarea sesiunilor active, " -"utilizatorilor și locurilor." +"utilizatorilor și stațiilor." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Blochează sau deblochează sesiuni active" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Autentificarea este necesară pentru a bloca sau debloca sesiuni active." -#: src/login/org.freedesktop.login1.policy:341 -msgid "Set the reboot \"reason\" in the kernel" -msgstr "" - -#: src/login/org.freedesktop.login1.policy:342 -#, fuzzy -#| msgid "Authentication is required to set the system timezone." -msgid "Authentication is required to set the reboot \"reason\" in the kernel." -msgstr "" -"Autentificarea este necesară pentru a stabili fusul orar al sistemului." - #: src/login/org.freedesktop.login1.policy:352 -#, fuzzy -#| msgid "Allow indication to the firmware to boot to setup interface" -msgid "Indicate to the firmware to boot to setup interface" -msgstr "" -"Permite semnalizatrea către firmware pentru a porni în interfața de " -"configurare" +msgid "Set the reboot \"reason\" in the kernel" +msgstr "Setează în kernel \"cauza\" pentru repornire" #: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "" +"Autentificarea este necesară pentru a seta în kernel \"cauza\" pentru " +"repornire." + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "Indică firmware-ului să pornească în interfața de configurare" + +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "" -"Autentificarea este necesară pentru a semnaliza către firmware să pornească " -"în interfața de configurare." +"Autentificarea este necesară pentru a indica firmware-ului să pornească în " +"interfața de configurare." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" -msgstr "" +msgstr "Indică boot loader-ului să pornească cu afișarea propriului meniu" -#: src/login/org.freedesktop.login1.policy:364 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "" -"Autentificarea este necesară pentru a semnaliza către firmware să pornească " -"în interfața de configurare." +"Autentificarea este necesară pentru a indica boot loader-ului să pornească " +"cu afișarea propriului meniu." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" -msgstr "" +msgstr "Indică boot loader-ului să pornească cu o anumită opțiune" -#: src/login/org.freedesktop.login1.policy:375 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "" -"Autentificarea este necesară pentru a semnaliza către firmware să pornească " -"în interfața de configurare." - -#: src/login/org.freedesktop.login1.policy:385 -msgid "Set a wall message" -msgstr "Stabilește un mesaj de perete" - -#: src/login/org.freedesktop.login1.policy:386 -msgid "Authentication is required to set a wall message" -msgstr "Autentificarea este necesară pentru a stabili un mesaj de perete" - -#: src/login/org.freedesktop.login1.policy:395 -msgid "Change Session" -msgstr "" +"Autentificarea este necesară pentru a indica boot loader-ului să pornească " +"cu o anumită opțiune." #: src/login/org.freedesktop.login1.policy:396 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." +msgid "Set a wall message" +msgstr "Setează un mesaj pentru toată lumea" + +#: src/login/org.freedesktop.login1.policy:397 +msgid "Authentication is required to set a wall message" +msgstr "Autentificarea este necesară pentru a seta un mesaj pentru toată lumea" + +#: src/login/org.freedesktop.login1.policy:406 +msgid "Change Session" +msgstr "Schimbă sesiune" + +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." -msgstr "Autentificarea este necesară pentru a stabili numele de server local." +msgstr "Autentificarea este necesară pentru a schimba un terminal virtual." #: src/machine/org.freedesktop.machine1.policy:22 msgid "Log into a local container" -msgstr "Conectează la un container local" +msgstr "Conectare la un container local" #: src/machine/org.freedesktop.machine1.policy:23 msgid "Authentication is required to log into a local container." msgstr "" -"Autentificarea este necesară pentru a vă conecta într-un container local." +"Autentificarea este necesară pentru a vă conecta la un container local." #: src/machine/org.freedesktop.machine1.policy:32 msgid "Log into the local host" -msgstr "Conectează la serverul local" +msgstr "Conectare la o stație locală" #: src/machine/org.freedesktop.machine1.policy:33 msgid "Authentication is required to log into the local host." -msgstr "Autentificarea este necesară pentru a vă conecta la serverul local." +msgstr "Autentificarea este necesară pentru a vă conecta la o stație locală." #: src/machine/org.freedesktop.machine1.policy:42 msgid "Acquire a shell in a local container" @@ -675,12 +654,12 @@ msgstr "" #: src/machine/org.freedesktop.machine1.policy:53 msgid "Acquire a shell on the local host" -msgstr "Obține un shell pe serverul local" +msgstr "Obține un shell pe o stație locală" #: src/machine/org.freedesktop.machine1.policy:54 msgid "Authentication is required to acquire a shell on the local host." msgstr "" -"Autentificarea este necesară pentru a obține un shell pe serverul local." +"Autentificarea este necesară pentru a obține un shell pe o stație locală." #: src/machine/org.freedesktop.machine1.policy:64 msgid "Acquire a pseudo TTY in a local container" @@ -695,16 +674,17 @@ msgstr "" #: src/machine/org.freedesktop.machine1.policy:74 msgid "Acquire a pseudo TTY on the local host" -msgstr "Obține un pseudo-TTY pe serverul local" +msgstr "Obține un pseudo-TTY pe o stație locală" #: src/machine/org.freedesktop.machine1.policy:75 msgid "Authentication is required to acquire a pseudo TTY on the local host." msgstr "" -"Autentificarea este necesară pentru a obține un pseudo-TTY pe serverul local." +"Autentificarea este necesară pentru a obține un pseudo-TTY pe o stație " +"locală." #: src/machine/org.freedesktop.machine1.policy:84 msgid "Manage local virtual machines and containers" -msgstr "Gestioneaza mașini virtuale locale și containere" +msgstr "Gestionează mașini virtuale locale și containere" #: src/machine/org.freedesktop.machine1.policy:85 msgid "" @@ -715,270 +695,238 @@ msgstr "" #: src/machine/org.freedesktop.machine1.policy:95 msgid "Manage local virtual machine and container images" -msgstr "Gestionează imaginile locale de mașină virtuală și containere" +msgstr "" +"Gestionează imaginile pentru mașinile virtuale locale și pentru containere" #: src/machine/org.freedesktop.machine1.policy:96 msgid "" "Authentication is required to manage local virtual machine and container " "images." msgstr "" -"Autentificarea este necesară pentru a gestiona imagini locale de mașini " -"virtuale și de containere." +"Autentificarea este necesară pentru a gestiona imagini de mașini virtuale " +"locale și de containere." #: src/network/org.freedesktop.network1.policy:22 msgid "Set NTP servers" -msgstr "" +msgstr "Setare servere NTP" #: src/network/org.freedesktop.network1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set NTP servers." -msgstr "Autentificarea este necesară pentru a stabili ora sistemului." +msgstr "Autentificarea este necesară pentru a seta servere NTP." #: src/network/org.freedesktop.network1.policy:33 #: src/resolve/org.freedesktop.resolve1.policy:44 msgid "Set DNS servers" -msgstr "" +msgstr "Setare servere DNS" #: src/network/org.freedesktop.network1.policy:34 #: src/resolve/org.freedesktop.resolve1.policy:45 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set DNS servers." -msgstr "Autentificarea este necesară pentru a stabili ora sistemului." +msgstr "Autentificarea este necesară pentru a seta servere DNS." #: src/network/org.freedesktop.network1.policy:44 #: src/resolve/org.freedesktop.resolve1.policy:55 msgid "Set domains" -msgstr "" +msgstr "Setare domenii" #: src/network/org.freedesktop.network1.policy:45 #: src/resolve/org.freedesktop.resolve1.policy:56 -#, fuzzy -#| msgid "Authentication is required to stop '$(unit)'." msgid "Authentication is required to set domains." -msgstr "Autentificarea este necesară pentru a opri „$(unit)”." +msgstr "Autentificarea este necesară pentru a seta domenii." #: src/network/org.freedesktop.network1.policy:55 #: src/resolve/org.freedesktop.resolve1.policy:66 msgid "Set default route" -msgstr "" +msgstr "Setare rută implicită" #: src/network/org.freedesktop.network1.policy:56 #: src/resolve/org.freedesktop.resolve1.policy:67 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to set default route." -msgstr "Autentificarea este necesară pentru a stabili numele de server local." +msgstr "Autentificarea este necesară pentru a seta rută implicită." #: src/network/org.freedesktop.network1.policy:66 #: src/resolve/org.freedesktop.resolve1.policy:77 msgid "Enable/disable LLMNR" -msgstr "" +msgstr "Activare/dezactivare LLMNR" #: src/network/org.freedesktop.network1.policy:67 #: src/resolve/org.freedesktop.resolve1.policy:78 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable LLMNR." -msgstr "Este necesară autentificarea pentru hibernarea sistemului." +msgstr "Autentificarea este necesară pentru a activa sau dezactiva LLMNR." #: src/network/org.freedesktop.network1.policy:77 #: src/resolve/org.freedesktop.resolve1.policy:88 msgid "Enable/disable multicast DNS" -msgstr "" +msgstr "Activare/dezactivare distribuție multiplă DNS" #: src/network/org.freedesktop.network1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:89 -#, fuzzy -#| msgid "Authentication is required to log into the local host." msgid "Authentication is required to enable or disable multicast DNS." -msgstr "Autentificarea este necesară pentru a vă conecta la serverul local." +msgstr "" +"Autentificarea este necesară pentru a activa sau dezactiva distribuția " +"multiplă DNS." #: src/network/org.freedesktop.network1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:99 msgid "Enable/disable DNS over TLS" -msgstr "" +msgstr "Activare/dezactivare DNS prin TLS" #: src/network/org.freedesktop.network1.policy:89 #: src/resolve/org.freedesktop.resolve1.policy:100 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to enable or disable DNS over TLS." -msgstr "Autentificarea este necesară pentru a stabili numele de server local." +msgstr "" +"Autentificarea este necesară pentru a activa sau dezactiva DNS prin TLS." #: src/network/org.freedesktop.network1.policy:99 #: src/resolve/org.freedesktop.resolve1.policy:110 msgid "Enable/disable DNSSEC" -msgstr "" +msgstr "Activare/dezactivare DNSSEC" #: src/network/org.freedesktop.network1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:111 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable DNSSEC." -msgstr "Este necesară autentificarea pentru hibernarea sistemului." +msgstr "Autentificarea este necesară pentru a activa sau dezactiva DNSSEC." #: src/network/org.freedesktop.network1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:121 msgid "Set DNSSEC Negative Trust Anchors" -msgstr "" +msgstr "Setare ancore de încredere negative DNSSEC" #: src/network/org.freedesktop.network1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system locale." msgid "Authentication is required to set DNSSEC Negative Trust Anchors." -msgstr "Autentificarea este necesară pentru a stabili localizarea sistemului." +msgstr "" +"Autentificarea este necesară pentru a seta ancore de încredere negative " +"DNSSEC." #: src/network/org.freedesktop.network1.policy:121 msgid "Revert NTP settings" -msgstr "" +msgstr "Revenire setări NTP" #: src/network/org.freedesktop.network1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset NTP settings." -msgstr "Autentificarea este necesară pentru a stabili ora sistemului." +msgstr "Autentificarea este necesară pentru a reseta setările NTP." #: src/network/org.freedesktop.network1.policy:132 msgid "Revert DNS settings" -msgstr "" +msgstr "Revenire setări DNS" #: src/network/org.freedesktop.network1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset DNS settings." -msgstr "Autentificarea este necesară pentru a stabili ora sistemului." +msgstr "Autentificarea este necesară pentru a reseta setările DNS." #: src/network/org.freedesktop.network1.policy:143 msgid "DHCP server sends force renew message" -msgstr "" +msgstr "Serverul DHCP trimite mesaje de reînnoire forțată" #: src/network/org.freedesktop.network1.policy:144 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to send force renew message." -msgstr "Autentificarea este necesară pentru a stabili un mesaj de perete" +msgstr "" +"Autentificarea este necesară pentru a trimite mesaje de reînnoire forțată." #: src/network/org.freedesktop.network1.policy:154 msgid "Renew dynamic addresses" -msgstr "" +msgstr "Reînnoire adrese dinamice" #: src/network/org.freedesktop.network1.policy:155 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to renew dynamic addresses." -msgstr "Autentificarea este necesară pentru a stabili un mesaj de perete" +msgstr "Autentificarea este necesară pentru a reînnoi adresele dinamice." #: src/network/org.freedesktop.network1.policy:165 msgid "Reload network settings" -msgstr "" +msgstr "Reîncărcare setări de rețea" #: src/network/org.freedesktop.network1.policy:166 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to reload network settings." -msgstr "Autentificarea este necesară pentru a reîncărca starea systemd." +msgstr "Autentificarea este necesară pentru a reîncărca setările de rețea." #: src/network/org.freedesktop.network1.policy:176 msgid "Reconfigure network interface" -msgstr "" +msgstr "Reconfigurare interfață de rețea" #: src/network/org.freedesktop.network1.policy:177 -#, fuzzy -#| msgid "Authentication is required to reboot the system." msgid "Authentication is required to reconfigure network interface." -msgstr "Autentificarea este necesară pentru repornirea sistemului." +msgstr "Autentificarea este necesară pentru a reconfigura interfața de rețea." #: src/portable/org.freedesktop.portable1.policy:13 msgid "Inspect a portable service image" -msgstr "" +msgstr "Inspectare imagine a unui serviciu portabil" #: src/portable/org.freedesktop.portable1.policy:14 -#, fuzzy -#| msgid "Authentication is required to import a VM or container image" msgid "Authentication is required to inspect a portable service image." msgstr "" -"Autentificarea este necesară pentru a importa o VM (mașină virtuală) sau o " -"imagine container" +"Autentificarea este necesară pentru a inspecta imaginea unui serviciu " +"portabil." #: src/portable/org.freedesktop.portable1.policy:23 msgid "Attach or detach a portable service image" -msgstr "" +msgstr "Atașare sau detașare imagine a unui serviciu portabil" #: src/portable/org.freedesktop.portable1.policy:24 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "" "Authentication is required to attach or detach a portable service image." -msgstr "Autentificarea este necesară pentru a atașa un dispozitiv la un loc." +msgstr "" +"Autentificarea este necesară pentru a atașa sau detașa imaginea unui " +"serviciu portabil." #: src/portable/org.freedesktop.portable1.policy:34 msgid "Delete or modify portable service image" -msgstr "" +msgstr "Șterge sau modifică imagine a unui serviciu portabil" #: src/portable/org.freedesktop.portable1.policy:35 -#, fuzzy -#| msgid "Authentication is required to download a VM or container image" msgid "" "Authentication is required to delete or modify a portable service image." msgstr "" -"Autentificarea este necesară pentru a descărca o VM (mașină virtuală) sau o " -"imagine container" +"Autentificarea este necesară pentru a șterge sau modifica imaginea unui " +"serviciu portabil." #: src/resolve/org.freedesktop.resolve1.policy:22 msgid "Register a DNS-SD service" -msgstr "" +msgstr "Înregistrare serviciu DNS-SD" #: src/resolve/org.freedesktop.resolve1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to register a DNS-SD service" -msgstr "Autentificarea este necesară pentru a stabili un mesaj de perete" +msgstr "Autentificarea este necesară pentru a înregistra un serviciu DNS-SD" #: src/resolve/org.freedesktop.resolve1.policy:33 msgid "Unregister a DNS-SD service" -msgstr "" +msgstr "Anulare înregistrare serviciu DNS-SD" #: src/resolve/org.freedesktop.resolve1.policy:34 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to unregister a DNS-SD service" -msgstr "Autentificarea este necesară pentru a stabili un mesaj de perete" +msgstr "" +"Autentificarea este necesară pentru a anula înregistrarea unui serviciu DNS-" +"SD" #: src/resolve/org.freedesktop.resolve1.policy:132 msgid "Revert name resolution settings" -msgstr "" +msgstr "Revenire setări pentru rezoluția de nume" #: src/resolve/org.freedesktop.resolve1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system keyboard settings." msgid "Authentication is required to reset name resolution settings." msgstr "" -"Autentificarea este necesară pentru a stabili configurările tastaturii " -"sistemului." +"Autentificarea este necesară pentru a reseta setările pentru rezoluția de " +"nume." #: src/timedate/org.freedesktop.timedate1.policy:22 msgid "Set system time" -msgstr "Stabilește ora sistemului" +msgstr "Setare oră sistem" #: src/timedate/org.freedesktop.timedate1.policy:23 msgid "Authentication is required to set the system time." -msgstr "Autentificarea este necesară pentru a stabili ora sistemului." +msgstr "Autentificarea este necesară pentru a seta ora sistemului." #: src/timedate/org.freedesktop.timedate1.policy:33 msgid "Set system timezone" -msgstr "Stabilește fusul orar al sistemului" +msgstr "Setează fusul orar al sistemului" #: src/timedate/org.freedesktop.timedate1.policy:34 msgid "Authentication is required to set the system timezone." -msgstr "" -"Autentificarea este necesară pentru a stabili fusul orar al sistemului." +msgstr "Autentificarea este necesară pentru a seta fusul orar al sistemului." #: src/timedate/org.freedesktop.timedate1.policy:43 msgid "Set RTC to local timezone or UTC" -msgstr "Stabilește RTC la ora locală sau UTC" +msgstr "Setează RTC la ora locală sau UTC" #: src/timedate/org.freedesktop.timedate1.policy:44 msgid "" @@ -990,7 +938,7 @@ msgstr "" #: src/timedate/org.freedesktop.timedate1.policy:53 msgid "Turn network time synchronization on or off" -msgstr "Comută sincronizarea cu ora rețelei" +msgstr "Activează sau dezactivează sincronizarea cu ora rețelei" #: src/timedate/org.freedesktop.timedate1.policy:54 msgid "" @@ -1000,59 +948,54 @@ msgstr "" "Autentificarea este necesară pentru a controla dacă sincronizarea cu ora " "rețelei ar trebui activată." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Autentificarea este necesară pentru a porni „$(unit)”." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Autentificarea este necesară pentru a opri „$(unit)”." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." -msgstr "Autentificarea este necesară pentru a reîncărca „$ (unit)”." +msgstr "Autentificarea este necesară pentru a reîncărca „$(unit)”." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Autentificarea este necesară pentru a reporni „$(unit)”." -#: src/core/dbus-unit.c:538 -#, fuzzy -#| msgid "Authentication is required to set properties on '$(unit)'." +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "" -"Autentificarea este necesară pentru a stabili proprietățile pe „$(unit)”." +"Autentificarea este necesară pentru a trimite un semnal UNIX către procesele " +"unui „$(unit)”." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" -"Autentificarea este necesară pentru a restabili starea „eșuată” a „$(unit)”." +"Autentificarea este necesară pentru a reseta starea „eșuată” a „$(unit)”." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" -"Autentificarea este necesară pentru a stabili proprietățile pe „$(unit)”." +"Autentificarea este necesară pentru a seta proprietățile lui „$(unit)”." -#: src/core/dbus-unit.c:711 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." msgstr "" -"Autentificarea este necesară pentru a restabili starea „eșuată” a „$(unit)”." +"Autentificarea este necesară pentru a șterge fișierele și directoarele " +"asociate lui „$(unit)”." -#: src/core/dbus-unit.c:760 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" -"Autentificarea este necesară pentru a restabili starea „eșuată” a „$(unit)”." +"Autentificarea este necesară pentru a îngheța sau dezgheța procesele " +"corespunzătoare lui „$(unit)”." #~ msgid "Authentication is required to kill '$(unit)'." #~ msgstr "Autentificarea este necesară pentru a omorî „$(unit)”." diff --git a/po/ru.po b/po/ru.po index 2211d1163..596bad8b0 100644 --- a/po/ru.po +++ b/po/ru.po @@ -9,7 +9,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2020-03-03 16:05+1000\n" "Last-Translator: Vladimir Yerilov \n" "Language: ru\n" @@ -329,61 +329,81 @@ msgstr "" "крышки ноутбука, необходимо пройти аутентификацию." #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Разрешить приложениям устанавливать блокировку обработки нажатий на кнопку " +"выключения" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Чтобы разрешить приложениям устанавливать блокировку обработки нажатий на " +"кнопку выключения, необходимо пройти аутентификацию." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Разрешить работу программ в фоновом режиме после завершения сеанса" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Чтобы разрешить работу программ в фоновом режиме после завершения сеанса, " "необходимо явное подтверждение." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "" "Разрешить пользователям оставлять программы в фоновом режиме после " "завершения сеанса" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Чтобы разрешить пользователям оставлять программы в фоновом режиме после " "завершения сеанса, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Разрешить подключение устройств к рабочим местам" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Чтобы разрешить подключение устройств к рабочим местам, необходимо пройти " "аутентификацию." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Сбросить привязки устройств к рабочим местам" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Чтобы сбросить привязки устройств к рабочим местам, необходимо пройти " "аутентификацию." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Выключить систему" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Чтобы выключить систему, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "" "Выключить систему, несмотря на то, что в ней работают другие пользователи" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -391,13 +411,13 @@ msgstr "" "Чтобы выключить систему, несмотря на то, что в ней работают другие " "пользователи, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "" "Выключить систему, несмотря на то, что приложение запросило блокировку " "выключения" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -405,20 +425,20 @@ msgstr "" "Чтобы выключить систему, несмотря на то, что приложение запросило блокировку " "выключения, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Перезагрузить систему" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Чтобы перезагрузить систему, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "" "Перезагрузить систему, несмотря на то, что в ней работают другие пользователи" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -426,13 +446,13 @@ msgstr "" "Чтобы перезагрузить систему, несмотря на то, что в ней работают другие " "пользователи, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" "Перезагрузить систему, несмотря на то, что приложение запросило блокировку " "выключения" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -440,20 +460,20 @@ msgstr "" "Чтобы перезагрузить систему, несмотря на то, что приложение запросило " "блокировку выключения, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Остановить систему" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Чтобы остановить систему, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "" "Остановить систему, несмотря на то, что в ней работают другие пользователи" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -461,13 +481,13 @@ msgstr "" "Чтобы остановить систему, несмотря на то, что в ней работают другие " "пользователи, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "" "Остановить систему несмотря на то, что приложение запросило блокировку " "выключения" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." @@ -475,22 +495,22 @@ msgstr "" "Чтобы остановить систему несмотря на то, что приложение запросило блокировку " "выключения, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Перевести систему в ждущий режим" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "" "Чтобы перевести систему в ждущий режим, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "" "Перевести систему в ждущий режим, несмотря на то, что в ней работают другие " "пользователи" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -498,13 +518,13 @@ msgstr "" "Чтобы перевести систему в ждущий режим, несмотря на то, что в ней работают " "другие пользователи, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" "Перевести систему в ждущий режим, несмотря на то, что приложение запросило " "блокировку" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -512,22 +532,22 @@ msgstr "" "Чтобы перевести систему в ждущий режим, несмотря на то, что приложение " "запросило блокировку, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Перевести систему в спящий режим" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "" "Чтобы перевести систему в спящий режим, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "" "Перевести систему в спящий режим, несмотря на то, что в ней работают другие " "пользователи" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -535,13 +555,13 @@ msgstr "" "Чтобы перевести систему в спящий режим, несмотря на то, что в ней работают " "другие пользователи, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" "Перевести систему в спящий режим, несмотря на то, что приложение запросило " "блокировку" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -549,41 +569,41 @@ msgstr "" "Чтобы перевести систему в спящий режим, несмотря на то, что приложение " "запросило блокировку, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Управление текущими сеансами, пользователями и рабочими местами" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Для управления текущими сеансами, пользователями и рабочими местами, " "необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Заблокировать или разблокировать текущие сеансы" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Чтобы заблокировать или разблокировать текущие сеансы, необходимо пройти " "аутентификацию." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Установить \"причину\" перезагрузки" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Чтобы установить \"причину\" перезагрузки, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "" "Запустить режим настройки прошивки материнской платы при следующей загрузке" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -591,11 +611,11 @@ msgstr "" "Чтобы запустить режим настройки прошивки материнской платы, необходимо " "пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Отобразить меню загрузчика при следующей загрузке" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -603,11 +623,11 @@ msgstr "" "Чтобы отобразить меню загрузчика при следующей загрузке, необходимо пройти " "аутентификацию." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "Выбрать определённую загрузочную запись при следующем запуске" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -615,20 +635,20 @@ msgstr "" "Чтобы установить определённую загрузочную запись для загрузки, необходимо " "пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Отправить сообщение на все терминалы" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "" "Чтобы отправить сообщение на все терминалы, необходимо пройти аутентификацию." -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "Сменить сессию" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "Чтобы сменить виртуальный терминал, необходимо пройти аутентификацию." @@ -958,25 +978,25 @@ msgstr "" "Чтобы включить или выключить синхронизацию времени по сети, необходимо " "пройти аутентификацию." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Чтобы запустить «$(unit)», необходимо пройти аутентификацию." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Чтобы остановить «$(unit)», необходимо пройти аутентификацию." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "" "Чтобы заставить «$(unit)» перечитать конфигурацию, необходимо пройти " "аутентификацию." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Чтобы перезапустить «$(unit)», необходимо пройти аутентификацию." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." @@ -984,18 +1004,18 @@ msgstr "" "Чтобы отправить сигнал UNIX процессам юнита «$(unit)», необходимо пройти " "аутентификацию." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Чтобы сбросить состояние «failed» у юнита «$(unit)», необходимо пройти " "аутентификацию." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" "Чтобы изменить параметры юнита «$(unit)», необходимо пройти аутентификацию." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -1003,7 +1023,7 @@ msgstr "" "Чтобы удалить файлы и директории, относящиеся к юниту «$(unit)», необходимо " "пройти аутентификацию." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to send a UNIX signal to the processes of " diff --git a/po/si.po b/po/si.po new file mode 100644 index 000000000..1d6b64e66 --- /dev/null +++ b/po/si.po @@ -0,0 +1,849 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the systemd package. +# Hela Basa , 2021. +msgid "" +msgstr "" +"Project-Id-Version: systemd\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: si\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: src/core/org.freedesktop.systemd1.policy.in:22 +msgid "Send passphrase back to system" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:23 +msgid "" +"Authentication is required to send the entered passphrase back to the system." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:33 +msgid "Manage system services or other units" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:34 +msgid "Authentication is required to manage system services or other units." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:43 +msgid "Manage system service or unit files" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:44 +msgid "Authentication is required to manage system service or unit files." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:54 +msgid "Set or unset system and service manager environment variables" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:55 +msgid "" +"Authentication is required to set or unset system and service manager " +"environment variables." +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:64 +msgid "Reload the systemd state" +msgstr "" + +#: src/core/org.freedesktop.systemd1.policy.in:65 +msgid "Authentication is required to reload the systemd state." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:13 +msgid "Create a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:14 +msgid "Authentication is required to create a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:23 +msgid "Remove a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:24 +msgid "Authentication is required to remove a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:33 +msgid "Check credentials of a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:34 +msgid "" +"Authentication is required to check credentials against a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:43 +msgid "Update a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:44 +msgid "Authentication is required to update a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:53 +msgid "Resize a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:54 +msgid "Authentication is required to resize a user's home area." +msgstr "" + +#: src/home/org.freedesktop.home1.policy:63 +msgid "Change password of a home area" +msgstr "" + +#: src/home/org.freedesktop.home1.policy:64 +msgid "" +"Authentication is required to change the password of a user's home area." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:20 +msgid "Set hostname" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:21 +msgid "Authentication is required to set the local hostname." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:30 +msgid "Set static hostname" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:31 +msgid "" +"Authentication is required to set the statically configured local hostname, " +"as well as the pretty hostname." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:41 +msgid "Set machine information" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:42 +msgid "Authentication is required to set local machine information." +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:51 +msgid "Get product UUID" +msgstr "" + +#: src/hostname/org.freedesktop.hostname1.policy:52 +msgid "Authentication is required to get product UUID." +msgstr "" + +#: src/import/org.freedesktop.import1.policy:22 +msgid "Import a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:23 +msgid "Authentication is required to import a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:32 +msgid "Export a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:33 +msgid "Authentication is required to export a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:42 +msgid "Download a VM or container image" +msgstr "" + +#: src/import/org.freedesktop.import1.policy:43 +msgid "Authentication is required to download a VM or container image" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:22 +msgid "Set system locale" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:23 +msgid "Authentication is required to set the system locale." +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:33 +msgid "Set system keyboard settings" +msgstr "" + +#: src/locale/org.freedesktop.locale1.policy:34 +msgid "Authentication is required to set the system keyboard settings." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:22 +msgid "Allow applications to inhibit system shutdown" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:23 +msgid "" +"Authentication is required for an application to inhibit system shutdown." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:33 +msgid "Allow applications to delay system shutdown" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:34 +msgid "Authentication is required for an application to delay system shutdown." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:44 +msgid "Allow applications to inhibit system sleep" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:45 +msgid "Authentication is required for an application to inhibit system sleep." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:55 +msgid "Allow applications to delay system sleep" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:56 +msgid "Authentication is required for an application to delay system sleep." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:65 +msgid "Allow applications to inhibit automatic system suspend" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:66 +msgid "" +"Authentication is required for an application to inhibit automatic system " +"suspend." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:75 +msgid "Allow applications to inhibit system handling of the power key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:76 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the power key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:86 +msgid "Allow applications to inhibit system handling of the suspend key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:87 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the suspend key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:97 +msgid "Allow applications to inhibit system handling of the hibernate key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:98 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the hibernate key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:107 +msgid "Allow applications to inhibit system handling of the lid switch" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:108 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the lid switch." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:128 +msgid "Allow non-logged-in user to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:129 +msgid "Explicit request is required to run programs as a non-logged-in user." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:138 +msgid "Allow non-logged-in users to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:139 +msgid "Authentication is required to run programs as a non-logged-in user." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:148 +msgid "Allow attaching devices to seats" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:149 +msgid "Authentication is required to attach a device to a seat." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:159 +msgid "Flush device to seat attachments" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:160 +msgid "Authentication is required to reset how devices are attached to seats." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:169 +msgid "Power off the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:170 +msgid "Authentication is required to power off the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:180 +msgid "Power off the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:181 +msgid "" +"Authentication is required to power off the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:191 +msgid "Power off the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:192 +msgid "" +"Authentication is required to power off the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:202 +msgid "Reboot the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:203 +msgid "Authentication is required to reboot the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:213 +msgid "Reboot the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:214 +msgid "" +"Authentication is required to reboot the system while other users are logged " +"in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:224 +msgid "Reboot the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:225 +msgid "" +"Authentication is required to reboot the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:235 +msgid "Halt the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:236 +msgid "Authentication is required to halt the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:246 +msgid "Halt the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:247 +msgid "" +"Authentication is required to halt the system while other users are logged " +"in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:257 +msgid "Halt the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:258 +msgid "" +"Authentication is required to halt the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:268 +msgid "Suspend the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:269 +msgid "Authentication is required to suspend the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:278 +msgid "Suspend the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:279 +msgid "" +"Authentication is required to suspend the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:289 +msgid "Suspend the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:290 +msgid "" +"Authentication is required to suspend the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:300 +msgid "Hibernate the system" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:301 +msgid "Authentication is required to hibernate the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:310 +msgid "Hibernate the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:311 +msgid "" +"Authentication is required to hibernate the system while other users are " +"logged in." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:321 +msgid "Hibernate the system while an application is inhibiting this" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:322 +msgid "" +"Authentication is required to hibernate the system while an application is " +"inhibiting this." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:332 +msgid "Manage active sessions, users and seats" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:333 +msgid "Authentication is required to manage active sessions, users and seats." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:342 +msgid "Lock or unlock active sessions" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:343 +msgid "Authentication is required to lock or unlock active sessions." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:352 +msgid "Set the reboot \"reason\" in the kernel" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:364 +msgid "" +"Authentication is required to indicate to the firmware to boot to setup " +"interface." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:374 +msgid "Indicate to the boot loader to boot to the boot loader menu" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:375 +msgid "" +"Authentication is required to indicate to the boot loader to boot to the " +"boot loader menu." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:385 +msgid "Indicate to the boot loader to boot a specific entry" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:386 +msgid "" +"Authentication is required to indicate to the boot loader to boot into a " +"specific boot loader entry." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:396 +msgid "Set a wall message" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:397 +msgid "Authentication is required to set a wall message" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:406 +msgid "Change Session" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:407 +msgid "Authentication is required to change the virtual terminal." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:22 +msgid "Log into a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:23 +msgid "Authentication is required to log into a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:32 +msgid "Log into the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:33 +msgid "Authentication is required to log into the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:42 +msgid "Acquire a shell in a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:43 +msgid "Authentication is required to acquire a shell in a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:53 +msgid "Acquire a shell on the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:54 +msgid "Authentication is required to acquire a shell on the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:64 +msgid "Acquire a pseudo TTY in a local container" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:65 +msgid "" +"Authentication is required to acquire a pseudo TTY in a local container." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:74 +msgid "Acquire a pseudo TTY on the local host" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:75 +msgid "Authentication is required to acquire a pseudo TTY on the local host." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:84 +msgid "Manage local virtual machines and containers" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:85 +msgid "" +"Authentication is required to manage local virtual machines and containers." +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:95 +msgid "Manage local virtual machine and container images" +msgstr "" + +#: src/machine/org.freedesktop.machine1.policy:96 +msgid "" +"Authentication is required to manage local virtual machine and container " +"images." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:22 +msgid "Set NTP servers" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:23 +msgid "Authentication is required to set NTP servers." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:33 +#: src/resolve/org.freedesktop.resolve1.policy:44 +msgid "Set DNS servers" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:34 +#: src/resolve/org.freedesktop.resolve1.policy:45 +msgid "Authentication is required to set DNS servers." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:44 +#: src/resolve/org.freedesktop.resolve1.policy:55 +msgid "Set domains" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:45 +#: src/resolve/org.freedesktop.resolve1.policy:56 +msgid "Authentication is required to set domains." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:55 +#: src/resolve/org.freedesktop.resolve1.policy:66 +msgid "Set default route" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:56 +#: src/resolve/org.freedesktop.resolve1.policy:67 +msgid "Authentication is required to set default route." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:66 +#: src/resolve/org.freedesktop.resolve1.policy:77 +msgid "Enable/disable LLMNR" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:67 +#: src/resolve/org.freedesktop.resolve1.policy:78 +msgid "Authentication is required to enable or disable LLMNR." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:77 +#: src/resolve/org.freedesktop.resolve1.policy:88 +msgid "Enable/disable multicast DNS" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:78 +#: src/resolve/org.freedesktop.resolve1.policy:89 +msgid "Authentication is required to enable or disable multicast DNS." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:88 +#: src/resolve/org.freedesktop.resolve1.policy:99 +msgid "Enable/disable DNS over TLS" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:89 +#: src/resolve/org.freedesktop.resolve1.policy:100 +msgid "Authentication is required to enable or disable DNS over TLS." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:99 +#: src/resolve/org.freedesktop.resolve1.policy:110 +msgid "Enable/disable DNSSEC" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:100 +#: src/resolve/org.freedesktop.resolve1.policy:111 +msgid "Authentication is required to enable or disable DNSSEC." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:110 +#: src/resolve/org.freedesktop.resolve1.policy:121 +msgid "Set DNSSEC Negative Trust Anchors" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:111 +#: src/resolve/org.freedesktop.resolve1.policy:122 +msgid "Authentication is required to set DNSSEC Negative Trust Anchors." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:121 +msgid "Revert NTP settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:122 +msgid "Authentication is required to reset NTP settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:132 +msgid "Revert DNS settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:133 +msgid "Authentication is required to reset DNS settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:143 +msgid "DHCP server sends force renew message" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:144 +msgid "Authentication is required to send force renew message." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:154 +msgid "Renew dynamic addresses" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:155 +msgid "Authentication is required to renew dynamic addresses." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:165 +msgid "Reload network settings" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:166 +msgid "Authentication is required to reload network settings." +msgstr "" + +#: src/network/org.freedesktop.network1.policy:176 +msgid "Reconfigure network interface" +msgstr "" + +#: src/network/org.freedesktop.network1.policy:177 +msgid "Authentication is required to reconfigure network interface." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:13 +msgid "Inspect a portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:14 +msgid "Authentication is required to inspect a portable service image." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:23 +msgid "Attach or detach a portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:24 +msgid "" +"Authentication is required to attach or detach a portable service image." +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:34 +msgid "Delete or modify portable service image" +msgstr "" + +#: src/portable/org.freedesktop.portable1.policy:35 +msgid "" +"Authentication is required to delete or modify a portable service image." +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:22 +msgid "Register a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:23 +msgid "Authentication is required to register a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:33 +msgid "Unregister a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:34 +msgid "Authentication is required to unregister a DNS-SD service" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:132 +msgid "Revert name resolution settings" +msgstr "" + +#: src/resolve/org.freedesktop.resolve1.policy:133 +msgid "Authentication is required to reset name resolution settings." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:22 +msgid "Set system time" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:23 +msgid "Authentication is required to set the system time." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:33 +msgid "Set system timezone" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:34 +msgid "Authentication is required to set the system timezone." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:43 +msgid "Set RTC to local timezone or UTC" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:44 +msgid "" +"Authentication is required to control whether the RTC stores the local or " +"UTC time." +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:53 +msgid "Turn network time synchronization on or off" +msgstr "" + +#: src/timedate/org.freedesktop.timedate1.policy:54 +msgid "" +"Authentication is required to control whether network time synchronization " +"shall be enabled." +msgstr "" + +#: src/core/dbus-unit.c:359 +msgid "Authentication is required to start '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:360 +msgid "Authentication is required to stop '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:361 +msgid "Authentication is required to reload '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 +msgid "Authentication is required to restart '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:535 +msgid "" +"Authentication is required to send a UNIX signal to the processes of " +"'$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:566 +msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:599 +msgid "Authentication is required to set properties on '$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:708 +msgid "" +"Authentication is required to delete files and directories associated with " +"'$(unit)'." +msgstr "" + +#: src/core/dbus-unit.c:757 +msgid "" +"Authentication is required to freeze or thaw the processes of '$(unit)' unit." +msgstr "" diff --git a/po/sk.po b/po/sk.po index d3dec2ba1..da8b57ee4 100644 --- a/po/sk.po +++ b/po/sk.po @@ -2,21 +2,22 @@ # # Slovak translation for systemd. # Dušan Kazik , 2017. -# +# Frantisek Sumsal , 2021. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2017-06-25 11:03+0200\n" -"Last-Translator: Dušan Kazik \n" -"Language-Team: Slovak \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-02-22 20:21+0000\n" +"Last-Translator: Frantisek Sumsal \n" +"Language-Team: Slovak \n" "Language: sk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 1 : (n>=2 && n<=4) ? 2 : 0;\n" -"X-Generator: Poedit 2.0.2\n" +"X-Generator: Weblate 4.4.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -235,11 +236,11 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:44 msgid "Allow applications to inhibit system sleep" -msgstr "" +msgstr "Umožnenie aplikáciám odložiť spánok systému" #: src/login/org.freedesktop.login1.policy:45 msgid "Authentication is required for an application to inhibit system sleep." -msgstr "" +msgstr "Vyžaduje sa overenie totožnosti na odloženie spánku systému aplikáciou." #: src/login/org.freedesktop.login1.policy:55 msgid "Allow applications to delay system sleep" @@ -301,54 +302,69 @@ msgid "" msgstr "" #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to delay system sleep" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "Umožnenie aplikáciám odložiť spánok systému" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "Authentication is required for an application to delay system sleep." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Vyžaduje sa overenie totožnosti na odloženie spánku systému aplikáciou." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Umožnenie neprihlásenému používateľovi spúšťanie programov" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Vyžaduje sa explicitná požiadavka na spúšťanie programov ako neprihlásený " "používateľ." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Umožnenie neprihláseným používateľom spúšťanie programov" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Vyžaduje sa overenie totožnosti na spúšťanie programov ako neprihlásený " "používateľ." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Vypnutie systému" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Vyžaduje sa overenie totožnosti na vypnutie systému." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Vypnutie systému, pokiaľ sú prihlásení iní používatelia" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -356,29 +372,29 @@ msgstr "" "Vyžaduje sa overenie totožnosti na vypnutie systému, pokiaľ sú prihlásení " "iní používatelia." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Reštart systému" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Vyžaduje sa overenie totožnosti na reštartovanie systému." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Reštart systému, pokiaľ sú prihlásení iní používatelia" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -386,35 +402,35 @@ msgstr "" "Vyžaduje sa overenie totožnosti na reštartovanie systému, pokiaľ sú " "prihlásení iní používatelia." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 #, fuzzy #| msgid "Reboot the system" msgid "Halt the system" msgstr "Reštart systému" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 #, fuzzy #| msgid "Authentication is required to reboot the system." msgid "Authentication is required to halt the system." msgstr "Vyžaduje sa overenie totožnosti na reštartovanie systému." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 #, fuzzy #| msgid "Reboot the system while other users are logged in" msgid "Halt the system while other users are logged in" msgstr "Reštart systému, pokiaľ sú prihlásení iní používatelia" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 #, fuzzy #| msgid "" #| "Authentication is required to reboot the system while other users are " @@ -426,11 +442,11 @@ msgstr "" "Vyžaduje sa overenie totožnosti na reštartovanie systému, pokiaľ sú " "prihlásení iní používatelia." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "Authentication is required to set the system keyboard settings." msgid "" @@ -440,19 +456,19 @@ msgstr "" "Vyžaduje sa overenie totožnosti na nastavenie nastavení systémovej " "klávesnice." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Uspanie systému" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Vyžaduje sa overenie totožnosti na uspanie systému." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Uspanie systému, pokiaľ sú prihlásení iní používatelia" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -460,79 +476,79 @@ msgstr "" "Vyžaduje sa overenie totožnosti na uspanie systému, pokiaľ sú prihlásení iní " "používatelia." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "" -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." msgstr "" -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Zamknutie alebo odomknutie aktívnych relácií" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Vyžaduje sa overenie totožnosti na uzamknutie alebo odomknutie aktívnych " "relácií." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "Vyžaduje sa overenie totožnosti na nastavenie názvu hostiteľa." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" msgstr "Umožnenie indikácie spustenia inštalačného rozhrania pre firmvér" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -540,11 +556,11 @@ msgstr "" "Vyžaduje sa overenie totožnosti na indikáciu spustenia inštalačného " "rozhrania pre firmvér." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -556,11 +572,11 @@ msgstr "" "Vyžaduje sa overenie totožnosti na indikáciu spustenia inštalačného " "rozhrania pre firmvér." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -572,19 +588,19 @@ msgstr "" "Vyžaduje sa overenie totožnosti na indikáciu spustenia inštalačného " "rozhrania pre firmvér." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to change the virtual terminal." @@ -932,23 +948,23 @@ msgstr "" "Vyžaduje sa overenie totožnosti na ovládanie, či má byť povolená " "synchronizácia času cez sieť." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to suspend the system." msgid "" @@ -956,15 +972,15 @@ msgid "" "'$(unit)'." msgstr "Vyžaduje sa overenie totožnosti na uspanie systému." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "Authentication is required to reload the systemd state." msgid "" @@ -973,7 +989,7 @@ msgid "" msgstr "" "Vyžaduje sa overenie totožnosti na znovu načítanie stavu systému systemd." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "Authentication is required to reload the systemd state." msgid "" diff --git a/po/sr.po b/po/sr.po index 83920e80b..0f0094594 100644 --- a/po/sr.po +++ b/po/sr.po @@ -2,23 +2,23 @@ # # SOME DESCRIPTIVE TITLE. # This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# +# Frantisek Sumsal , 2021. msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2018-02-18 22:03+0100\n" -"Last-Translator: Марко М. Костић \n" -"Language-Team: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-02-23 22:40+0000\n" +"Last-Translator: Frantisek Sumsal \n" +"Language-Team: Serbian \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"X-Generator: Poedit 2.0.3\n" -"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 4.4.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -334,56 +334,69 @@ msgstr "" "систему да уради било шта приликом заклапања екрана." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Дозволи програмима да спрече систему управљање дугметом за поновно покретање" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Потребно је да се идентификујете да бисте дозволили програму да спречи " +"систему управљање дугметом за поновно покретање." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Дозволи непријављеним корисницима да покрећу програме" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Експлицитан захтев је потребан да бисте покретали програме као непријављен " "корисник." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Дозволи непријављеним корисницима да покрећу програме" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Потребно је да се идентификујете да бисте покретали програме као непријављен " "корисник." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Дозволи качење уређаја на седишта" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "Потребно је да се идентификујете да бисте закачили уређај на седиште." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Испери уређај да би уседиштио закачено" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Потребно је да се идентификујете да бисте поново подесили како се уређаји " "каче на седишта." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Искључи систем" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Потребно је да се идентификујете да бисте искључили систем." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Искључи систем док су други корисници пријављени" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -391,11 +404,11 @@ msgstr "" "Потребно је да се идентификујете да бисте искључили систем док су други " "корисници пријављени." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Искључи систем иако је програм затражио да се спречи гашење" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -403,19 +416,19 @@ msgstr "" "Потребно је да се идентификујете да бисте искључили систем иако је програм " "затражио да се спречи гашење система." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Поново покрени систем" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Потребно је да се идентификујете да бисте поново покренули систем." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Поново покрени систем док су други корисници пријављени" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -423,11 +436,11 @@ msgstr "" "Потребно је да се идентификујете да бисте поново покренули систем док су " "други корисници пријављени." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Поново покрени систем иако је програм затражио да се спречи гашење" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -435,19 +448,19 @@ msgstr "" "Потребно је да се идентификујете да бисте поново покренули систем иако је " "програм затражио да се спречи гашење система." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Заустави систем" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Потребно је да се идентификујете да бисте зауставили систем." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Заустави систем док су други корисници пријављени" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -455,35 +468,31 @@ msgstr "" "Потребно је да се идентификујете да бисте зауставили систем док су други " "корисници пријављени." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Заустави систем иако програм тражи да се спречи заустављање" -#: src/login/org.freedesktop.login1.policy:247 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while an application " -#| "is inhibiting this." +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." msgstr "" -"Потребно је да се идентификујете да бисте успавали систем иако је програм " -"затражио да се спречи успављивање система." +"Потребно је да се идентификујете да бисте обуставили систем иако је програм " +"затражио да се спречи обустављање система." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Обустави систем" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Потребно је да се идентификујете да бисте обуставили систем." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Обустави систем док су други корисници пријављени" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -491,11 +500,11 @@ msgstr "" "Потребно је да се идентификујете да бисте обуставили систем док су други " "корисници пријављени." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Обуставите систем иако програм тражи да се спречи обустава" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -503,19 +512,19 @@ msgstr "" "Потребно је да се идентификујете да бисте обуставили систем иако је програм " "затражио да се спречи обустава система." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Успавај систем" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Потребно је да се идентификујете да бисте успавали систем." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Успавај систем док су други корисници пријављени" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -523,11 +532,11 @@ msgstr "" "Потребно је да се идентификујете да бисте успавали систем док су други " "корисници пријављени." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Успавај систем иако је програм затражио да се спречи спавање" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -535,44 +544,43 @@ msgstr "" "Потребно је да се идентификујете да бисте успавали систем иако је програм " "затражио да се спречи успављивање система." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Управљај покренутим сесијама, корисницима и седиштима" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Потребно је да се идентификујете да бисте управљали покренутим сесијама, " "корисницима и седиштима." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Закључај или откључај покренуте сесије" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Потребно је да се идентификујете да бисте закључавали или откључавали " "покренуте сесије." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 -#, fuzzy -#| msgid "Authentication is required to set the system timezone." +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" -"Потребно је да се идентификујете да бисте поставили системску временску зону." +"Потребно је да се идентификујете да бисте поставили \"разлог\" за поновно " +"поретање унутар језгра." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 #, fuzzy #| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" msgstr "Напомени фирмверу да се подигне у режиму подешавања интерфејса" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -580,11 +588,11 @@ msgstr "" "Потребно је да се идентификујете да бисте напоменули фирмверу да се подигне " "у режиму подешавања интерфејса." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -596,11 +604,11 @@ msgstr "" "Потребно је да се идентификујете да бисте напоменули фирмверу да се подигне " "у режиму подешавања интерфејса." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 #, fuzzy #| msgid "" #| "Authentication is required to indicate to the firmware to boot to setup " @@ -612,19 +620,19 @@ msgstr "" "Потребно је да се идентификујете да бисте напоменули фирмверу да се подигне " "у режиму подешавања интерфејса." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Постави зидну поруку" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Потребно је да се идентификујете да бисте поставили зидну поруку" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." @@ -990,23 +998,23 @@ msgstr "" "Потребно је да се идентификујете да бисте подесили да ли се време усклађује " "са мреже." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Потребно је да се идентификујете да бисте покренули „$(unit)“." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Потребно је да се идентификујете да бисте зауставили „$(unit)“." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Потребно је да се идентификујете да бисте поново учитали „$(unit)“." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Потребно је да се идентификујете да бисте поново покренули „$(unit)“." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 #, fuzzy #| msgid "Authentication is required to set properties on '$(unit)'." msgid "" @@ -1015,18 +1023,18 @@ msgid "" msgstr "" "Потребно је да се идентификујете да бисте поставили својства за „$(unit)“." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Потребно је да се идентификујете да бисте поново поставили „неуспешно“ стање " "за „$(unit)“." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" "Потребно је да се идентификујете да бисте поставили својства за „$(unit)“." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." @@ -1037,7 +1045,7 @@ msgstr "" "Потребно је да се идентификујете да бисте поново поставили „неуспешно“ стање " "за „$(unit)“." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to reset the \"failed\" state of '$(unit)'." diff --git a/po/sv.po b/po/sv.po index 91108ad5f..4ded1962c 100644 --- a/po/sv.po +++ b/po/sv.po @@ -4,13 +4,14 @@ # Sebastian Rasmussen , 2015. # Andreas Henriksson , 2016. # Josef Andersson , 2015, 2017. -# Göran Uddeborg , 2020. +# Göran Uddeborg , 2020, 2021. +# Luna Jernberg , 2020. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-08-27 02:46+0000\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-02-10 15:40+0000\n" "Last-Translator: Göran Uddeborg \n" "Language-Team: Swedish \n" @@ -19,7 +20,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.2.1\n" +"X-Generator: Weblate 4.4.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -71,69 +72,54 @@ msgstr "Autentisering krävs för att läsa om tillståndet för systemd." #: src/home/org.freedesktop.home1.policy:13 msgid "Create a home area" -msgstr "" +msgstr "Skapa en hemarea" #: src/home/org.freedesktop.home1.policy:14 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to create a user's home area." -msgstr "Autentisering krävs för att läsa om tillståndet för systemd." +msgstr "Autentisering krävs för att skapa en användares hemarea." #: src/home/org.freedesktop.home1.policy:23 msgid "Remove a home area" -msgstr "" +msgstr "Ta bort en hemarea" #: src/home/org.freedesktop.home1.policy:24 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to remove a user's home area." -msgstr "Autentisering krävs för att läsa om tillståndet för systemd." +msgstr "Autentisering krävs för att ta bort en användares hemarea." #: src/home/org.freedesktop.home1.policy:33 msgid "Check credentials of a home area" -msgstr "" +msgstr "Kontrollera kreditiven för en hemarea" #: src/home/org.freedesktop.home1.policy:34 -#, fuzzy -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to check credentials against a user's home area." msgstr "" -"Autentisering krävs för att hantera aktiva sessioner, användare och platser." +"Autentisering krävs för att kontrollera kreditiven mot en användares hemarea." #: src/home/org.freedesktop.home1.policy:43 msgid "Update a home area" -msgstr "" +msgstr "Uppdatera en hemarea" #: src/home/org.freedesktop.home1.policy:44 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "Authentication is required to update a user's home area." -msgstr "Autentisering krävs för att binda en enhet till en plats." +msgstr "Autentisering krävs för att uppdatera en användares hemarea." #: src/home/org.freedesktop.home1.policy:53 msgid "Resize a home area" -msgstr "" +msgstr "Ändra storlek på en hemarea" #: src/home/org.freedesktop.home1.policy:54 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to resize a user's home area." -msgstr "Autentisering krävs för att ställa in ett väggmeddelande" +msgstr "Autentisering krävs för att ändra storlek på en hemarea." #: src/home/org.freedesktop.home1.policy:63 msgid "Change password of a home area" -msgstr "" +msgstr "Ändra lösenord för en hemarea" #: src/home/org.freedesktop.home1.policy:64 -#, fuzzy -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to change the password of a user's home area." -msgstr "" -"Autentisering krävs för att hantera aktiva sessioner, användare och platser." +msgstr "Autentisering krävs för att ändra lösenorded för en användares hemarea." #: src/hostname/org.freedesktop.hostname1.policy:20 msgid "Set hostname" @@ -165,13 +151,11 @@ msgstr "Autentisering krävs för att ställa in lokal datorinformation." #: src/hostname/org.freedesktop.hostname1.policy:51 msgid "Get product UUID" -msgstr "" +msgstr "Hämta produkt-UUID" #: src/hostname/org.freedesktop.hostname1.policy:52 -#, fuzzy -#| msgid "Authentication is required to reload '$(unit)'." msgid "Authentication is required to get product UUID." -msgstr "Autentisering krävs för att läsa om tillståndet för \"$(unit)\"." +msgstr "Autentisering krävs för att hämta produkt-UUID." #: src/import/org.freedesktop.import1.policy:22 msgid "Import a VM or container image" @@ -315,53 +299,65 @@ msgstr "" "av brytaren för datorhöljet." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "Tillåt program att hindra systemhantering av omstartsknappen" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Autentisering krävs för att tillåta ett program att hindra systemhantering " +"av omstartsknappen." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Tillåt ej inloggad användare att köra program" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Uttrycklig begäran krävs för att köra program som en icke inloggad användare." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Tillåt ej inloggade användare att köra program" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Autentisering krävs för att köra program som en icke inloggad användare." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Tillåt att binda enheter till platser" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "Autentisering krävs för att binda en enhet till en plats." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Töm bindningar för enhet-till-plats" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "" "Autentisering krävs för att återställa hur enheter är bundna till platser." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Stäng av systemet" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Autentisering krävs för att stänga av systemet." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Stäng av systemet medan andra användare är inloggade" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -369,11 +365,11 @@ msgstr "" "Autentisering krävs för att stänga av systemet medan andra användare är " "inloggade." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Stäng av systemet även då ett program hindrar det" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -381,19 +377,19 @@ msgstr "" "Autentisering krävs för att stänga av systemet även då ett program hindrar " "det." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Starta om systemet" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Autentisering krävs för att starta om systemet." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Starta om systemet medan andra användare är inloggade" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -401,11 +397,11 @@ msgstr "" "Autentisering krävs för att starta om systemet medan andra användare är " "inloggade." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Starta om systemet även då ett program hindrar det" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -413,19 +409,19 @@ msgstr "" "Autentisering krävs för att starta om systemet även då ett program hindrar " "det." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Stoppa systemet" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Autentisering krävs för att stoppa systemet." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Stoppa systemet medan andra användare är inloggade" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -433,35 +429,30 @@ msgstr "" "Autentisering krävs för att stoppa systemet medan andra användare är " "inloggade." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Stoppa systemet även då ett program hindrar det" -#: src/login/org.freedesktop.login1.policy:247 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while an application " -#| "is inhibiting this." +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." msgstr "" -"Autentisering krävs för att försätta ett program i viloläge även då ett " -"program hindrar det." +"Autentisering krävs för att stoppa systemet även då ett program hindrar det." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Försätt system i vänteläge" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Autentisering krävs för att försätta system i vänteläge." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Försätt systemet i vänteläge medan andra användare är inloggade" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -469,31 +460,31 @@ msgstr "" "Autentisering krävs för att försätta systemet i vänteläge medan andra " "användare är inloggade." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Försätt systemet i vänteläge även då ett program hindrar det" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." msgstr "" -"Autentisering krävs för att försätta ett program i vänteläge även då ett " -"program hindrar det." +"Autentisering krävs för att försätta systemet i sovläge även då ett program " +"hindrar det." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Försätt systemet i viloläge" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Autentisering krävs för att försätta systemet i viloläge." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Försätt systemet i viloläge medan andra användare är inloggade" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -501,109 +492,96 @@ msgstr "" "Autentisering krävs för att försätta systemet i viloläge medan andra " "användare är inloggade." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Försätt systemet i viloläge även då ett program hindrar det" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." msgstr "" -"Autentisering krävs för att försätta ett program i viloläge även då ett " -"program hindrar det." +"Autentisering krävs för att försätta systemet i viloläge även då ett program " +"hindrar det." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Hantera aktiva sessioner, användare och platser" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Autentisering krävs för att hantera aktiva sessioner, användare och platser." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Lås eller lås upp aktiva sessioner" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "Autentisering krävs för att låsa eller låsa upp aktiva sessioner." -#: src/login/org.freedesktop.login1.policy:341 -msgid "Set the reboot \"reason\" in the kernel" -msgstr "" - -#: src/login/org.freedesktop.login1.policy:342 -#, fuzzy -#| msgid "Authentication is required to set the system timezone." -msgid "Authentication is required to set the reboot \"reason\" in the kernel." -msgstr "Autentisering krävs för att ställa in systemets tidszon." - #: src/login/org.freedesktop.login1.policy:352 -#, fuzzy -#| msgid "Allow indication to the firmware to boot to setup interface" -msgid "Indicate to the firmware to boot to setup interface" -msgstr "" -"Tillåt indikering till firmware att starta upp i inställningsgränssnitt" +msgid "Set the reboot \"reason\" in the kernel" +msgstr "Sätt ”orsaken” för omstart i kärnan" #: src/login/org.freedesktop.login1.policy:353 +msgid "Authentication is required to set the reboot \"reason\" in the kernel." +msgstr "Autentisering krävs för att ställa in ”orsaken” för omstart i kärnan." + +#: src/login/org.freedesktop.login1.policy:363 +msgid "Indicate to the firmware to boot to setup interface" +msgstr "" +"Indikera till den fasta programvaran att starta upp till " +"inställningsgränssnittet" + +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "" -"Autentisering krävs för att indikera till firmware att starta upp till " -"inställningsgränssnitt." +"Autentisering krävs för att indikera till den fasta programvaran att starta " +"upp till inställningsgränssnitt." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" -msgstr "" +msgstr "Indikera till startprogrammet att starta upp i uppstartsladdmenyn" -#: src/login/org.freedesktop.login1.policy:364 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "" -"Autentisering krävs för att indikera till firmware att starta upp till " -"inställningsgränssnitt." +"Autentisering krävs för att indikera till uppstartsladdaren att starta upp " +"uppstartsladdmenyn." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" -msgstr "" +msgstr "Indikera till uppstartsladdaren att starta en specifik post" -#: src/login/org.freedesktop.login1.policy:375 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "" -"Autentisering krävs för att indikera till firmware att starta upp till " -"inställningsgränssnitt." +"Autentisering krävs för att indikera till uppstartsladdaren att starta upp " +"till en specifik uppstartsladdspost." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Ange ett väggmeddelande" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Autentisering krävs för att ställa in ett väggmeddelande" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" -msgstr "" +msgstr "Ändra session" -#: src/login/org.freedesktop.login1.policy:396 -#, fuzzy -#| msgid "Authentication is required to halt the system." +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." -msgstr "Autentisering krävs för att stoppa systemet." +msgstr "Autentisering krävs för att ändra den virtuella terminalen." #: src/machine/org.freedesktop.machine1.policy:22 msgid "Log into a local container" @@ -682,232 +660,192 @@ msgstr "" #: src/network/org.freedesktop.network1.policy:22 msgid "Set NTP servers" -msgstr "" +msgstr "Ange NTP-servrar" #: src/network/org.freedesktop.network1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set NTP servers." -msgstr "Autentisering krävs för ställa in systemtiden." +msgstr "Autentisering krävs för ställa in NTP-servrar." #: src/network/org.freedesktop.network1.policy:33 #: src/resolve/org.freedesktop.resolve1.policy:44 msgid "Set DNS servers" -msgstr "" +msgstr "Ange DNS-servrar" #: src/network/org.freedesktop.network1.policy:34 #: src/resolve/org.freedesktop.resolve1.policy:45 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set DNS servers." -msgstr "Autentisering krävs för ställa in systemtiden." +msgstr "Autentisering krävs för ställa in DNS-servrar." #: src/network/org.freedesktop.network1.policy:44 #: src/resolve/org.freedesktop.resolve1.policy:55 msgid "Set domains" -msgstr "" +msgstr "Ange domäner" #: src/network/org.freedesktop.network1.policy:45 #: src/resolve/org.freedesktop.resolve1.policy:56 -#, fuzzy -#| msgid "Authentication is required to stop '$(unit)'." msgid "Authentication is required to set domains." -msgstr "Autentisering krävs för att stoppa \"$(unit)\"." +msgstr "Autentisering krävs för att ange domäner." #: src/network/org.freedesktop.network1.policy:55 #: src/resolve/org.freedesktop.resolve1.policy:66 msgid "Set default route" -msgstr "" +msgstr "Ange standardrutt" #: src/network/org.freedesktop.network1.policy:56 #: src/resolve/org.freedesktop.resolve1.policy:67 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to set default route." -msgstr "Autentisering krävs för att ställa in lokalt värdnamn." +msgstr "Autentisering krävs för att ange standardrutten." #: src/network/org.freedesktop.network1.policy:66 #: src/resolve/org.freedesktop.resolve1.policy:77 msgid "Enable/disable LLMNR" -msgstr "" +msgstr "Aktivera/inaktivera LLMNR" #: src/network/org.freedesktop.network1.policy:67 #: src/resolve/org.freedesktop.resolve1.policy:78 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable LLMNR." -msgstr "Autentisering krävs för att försätta systemet i viloläge." +msgstr "Autentisering krävs för att aktivera eller avaktivera LLMNR." #: src/network/org.freedesktop.network1.policy:77 #: src/resolve/org.freedesktop.resolve1.policy:88 msgid "Enable/disable multicast DNS" -msgstr "" +msgstr "Aktivera/inaktivera multicast-DNS" #: src/network/org.freedesktop.network1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:89 -#, fuzzy -#| msgid "Authentication is required to log into the local host." msgid "Authentication is required to enable or disable multicast DNS." -msgstr "Autentisering krävs för att logga in på den lokala värden" +msgstr "Autentisering krävs för att aktivera eller avaktivera multicast-DNS." #: src/network/org.freedesktop.network1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:99 msgid "Enable/disable DNS over TLS" -msgstr "" +msgstr "Aktivera/inaktivera DNS över TLS" #: src/network/org.freedesktop.network1.policy:89 #: src/resolve/org.freedesktop.resolve1.policy:100 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to enable or disable DNS over TLS." -msgstr "Autentisering krävs för att ställa in lokalt värdnamn." +msgstr "Autentisering krävs för att aktivera eller avaktivera DNS över TLS." #: src/network/org.freedesktop.network1.policy:99 #: src/resolve/org.freedesktop.resolve1.policy:110 msgid "Enable/disable DNSSEC" -msgstr "" +msgstr "Aktivera/inaktivera DNSSEC" #: src/network/org.freedesktop.network1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:111 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable DNSSEC." -msgstr "Autentisering krävs för att försätta systemet i viloläge." +msgstr "Autentisering krävs för att aktivera eller avaktivera DNSSEC." #: src/network/org.freedesktop.network1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:121 msgid "Set DNSSEC Negative Trust Anchors" -msgstr "" +msgstr "Ange DNSSEC negativa förtroendeankare" #: src/network/org.freedesktop.network1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system locale." msgid "Authentication is required to set DNSSEC Negative Trust Anchors." -msgstr "Autentisering krävs för att ställa in systemlokal." +msgstr "Autentisering krävs för att ange DNSSEC negativa förtroendeankare." #: src/network/org.freedesktop.network1.policy:121 msgid "Revert NTP settings" -msgstr "" +msgstr "Återställ NTP-inställningar" #: src/network/org.freedesktop.network1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset NTP settings." -msgstr "Autentisering krävs för ställa in systemtiden." +msgstr "Autentisering krävs för återställa NTP-inställningar." #: src/network/org.freedesktop.network1.policy:132 msgid "Revert DNS settings" -msgstr "" +msgstr "Återställ DNS-inställningar" #: src/network/org.freedesktop.network1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset DNS settings." -msgstr "Autentisering krävs för ställa in systemtiden." +msgstr "Autentisering krävs för att återställa DNS-inställningar." #: src/network/org.freedesktop.network1.policy:143 msgid "DHCP server sends force renew message" -msgstr "" +msgstr "DHCP-servern skickar tvingande förnyelsemeddelande" #: src/network/org.freedesktop.network1.policy:144 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to send force renew message." -msgstr "Autentisering krävs för att ställa in ett väggmeddelande" +msgstr "Autentisering krävs för att skicka tvingande förnyelsemeddelande." #: src/network/org.freedesktop.network1.policy:154 msgid "Renew dynamic addresses" -msgstr "" +msgstr "Förnya dynamiska adresser" #: src/network/org.freedesktop.network1.policy:155 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to renew dynamic addresses." -msgstr "Autentisering krävs för att ställa in ett väggmeddelande" +msgstr "Autentisering krävs för att förnya dynamiska adresser." #: src/network/org.freedesktop.network1.policy:165 msgid "Reload network settings" -msgstr "" +msgstr "Läs om nätverksinställningarna" #: src/network/org.freedesktop.network1.policy:166 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to reload network settings." -msgstr "Autentisering krävs för att läsa om tillståndet för systemd." +msgstr "Autentisering krävs för läsa om nätverksinställningarna." #: src/network/org.freedesktop.network1.policy:176 msgid "Reconfigure network interface" -msgstr "" +msgstr "Konfigurera om nätverksgränssnitt" #: src/network/org.freedesktop.network1.policy:177 -#, fuzzy -#| msgid "Authentication is required to reboot the system." msgid "Authentication is required to reconfigure network interface." -msgstr "Autentisering krävs för att starta om systemet." +msgstr "Autentisering krävs för att konfigurera om nätverksgränssnitt." #: src/portable/org.freedesktop.portable1.policy:13 msgid "Inspect a portable service image" -msgstr "" +msgstr "Inspektera en portabel tjänsteavbild" #: src/portable/org.freedesktop.portable1.policy:14 -#, fuzzy -#| msgid "Authentication is required to import a VM or container image" msgid "Authentication is required to inspect a portable service image." -msgstr "Autentisering krävs för att importera en VM eller behållaravbildning" +msgstr "Autentisering krävs för att inspektera en portabel tjänsteavbild." #: src/portable/org.freedesktop.portable1.policy:23 msgid "Attach or detach a portable service image" -msgstr "" +msgstr "Koppla in eller koppla ifrån en portabel tjänsteavbild" #: src/portable/org.freedesktop.portable1.policy:24 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "" "Authentication is required to attach or detach a portable service image." -msgstr "Autentisering krävs för att binda en enhet till en plats." +msgstr "" +"Autentisering krävs för att koppla in eller koppla ifrån en portabel " +"tjänsteavbild." #: src/portable/org.freedesktop.portable1.policy:34 msgid "Delete or modify portable service image" -msgstr "" +msgstr "Radera eller modifiera en portabel tjänsteavbild" #: src/portable/org.freedesktop.portable1.policy:35 -#, fuzzy -#| msgid "Authentication is required to download a VM or container image" msgid "" "Authentication is required to delete or modify a portable service image." -msgstr "Autentisering krävs för att hämta ner en VM eller behållaravbildning" +msgstr "" +"Autentisering krävs för att radera eller modifiera en portabel tjänsteavbild." #: src/resolve/org.freedesktop.resolve1.policy:22 msgid "Register a DNS-SD service" -msgstr "" +msgstr "Registrera en DNS-SD-tjänst" #: src/resolve/org.freedesktop.resolve1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to register a DNS-SD service" -msgstr "Autentisering krävs för att ställa in ett väggmeddelande" +msgstr "Autentisering krävs för att registrera en DNS-SD-tjänst" #: src/resolve/org.freedesktop.resolve1.policy:33 msgid "Unregister a DNS-SD service" -msgstr "" +msgstr "Avregistrera en DNS-SD-tjänst" #: src/resolve/org.freedesktop.resolve1.policy:34 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to unregister a DNS-SD service" -msgstr "Autentisering krävs för att ställa in ett väggmeddelande" +msgstr "Autentisering krävs för att avregistrera en DNS-SD-tjänst" #: src/resolve/org.freedesktop.resolve1.policy:132 msgid "Revert name resolution settings" -msgstr "" +msgstr "Återställ namnuppslagningsinställningar" #: src/resolve/org.freedesktop.resolve1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system keyboard settings." msgid "Authentication is required to reset name resolution settings." -msgstr "" -"Autentisering krävs för att ställa in systeminställningar för tangentbord." +msgstr "Autentisering krävs för att återställa namnuppslagningsinställningar." #: src/timedate/org.freedesktop.timedate1.policy:22 msgid "Set system time" @@ -951,60 +889,53 @@ msgstr "" "Autentisering krävs för att kontrollera huruvida synkronisering av " "nätverkstid ska vara aktiverat." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Autentisering krävs för att starta \"$(unit)\"." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Autentisering krävs för att stoppa \"$(unit)\"." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." -msgstr "Autentisering krävs för att läsa om tillståndet för \"$(unit)\"." +msgstr "Autentisering krävs för att läsa om \"$(unit)\"." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Autentisering krävs för att starta om \"$(unit)\"." -#: src/core/dbus-unit.c:538 -#, fuzzy -#| msgid "Authentication is required to set properties on '$(unit)'." +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." -msgstr "Autentisering krävs för att ställa in egenskaper på \"$(unit)\"." +msgstr "" +"Autentisering krävs för att skicka en UNIX-signal till processerna i " +"”$(unit)”." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Autentisering krävs för att återställa det \"fallerade\" tillståndet för " "\"$(unit)\"." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Autentisering krävs för att ställa in egenskaper på \"$(unit)\"." -#: src/core/dbus-unit.c:711 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." msgstr "" -"Autentisering krävs för att återställa det \"fallerade\" tillståndet för " -"\"$(unit)\"." +"Autentisering krävs för att radera filer och kataloger associerade med " +"”$(unit)”." -#: src/core/dbus-unit.c:760 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" -"Autentisering krävs för att återställa det \"fallerade\" tillståndet för " -"\"$(unit)\"." +"Autentisering krävs för att frysa eller töa processerna i enheten ”$(unit)”." #~ msgid "" #~ "Authentication is required to halt the system while an application asked " diff --git a/po/systemd.pot b/po/systemd.pot index 76fa72ed1..1c5ed6f04 100644 --- a/po/systemd.pot +++ b/po/systemd.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -268,244 +268,254 @@ msgid "" msgstr "" #: src/login/org.freedesktop.login1.policy:117 -msgid "Allow non-logged-in user to run programs" +msgid "Allow applications to inhibit system handling of the reboot key" msgstr "" #: src/login/org.freedesktop.login1.policy:118 -msgid "Explicit request is required to run programs as a non-logged-in user." -msgstr "" - -#: src/login/org.freedesktop.login1.policy:127 -msgid "Allow non-logged-in users to run programs" +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." msgstr "" #: src/login/org.freedesktop.login1.policy:128 -msgid "Authentication is required to run programs as a non-logged-in user." +msgid "Allow non-logged-in user to run programs" msgstr "" -#: src/login/org.freedesktop.login1.policy:137 -msgid "Allow attaching devices to seats" +#: src/login/org.freedesktop.login1.policy:129 +msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" #: src/login/org.freedesktop.login1.policy:138 -msgid "Authentication is required to attach a device to a seat." +msgid "Allow non-logged-in users to run programs" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:139 +msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" #: src/login/org.freedesktop.login1.policy:148 -msgid "Flush device to seat attachments" +msgid "Allow attaching devices to seats" msgstr "" #: src/login/org.freedesktop.login1.policy:149 -msgid "Authentication is required to reset how devices are attached to seats." -msgstr "" - -#: src/login/org.freedesktop.login1.policy:158 -msgid "Power off the system" +msgid "Authentication is required to attach a device to a seat." msgstr "" #: src/login/org.freedesktop.login1.policy:159 -msgid "Authentication is required to power off the system." +msgid "Flush device to seat attachments" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:160 +msgid "Authentication is required to reset how devices are attached to seats." msgstr "" #: src/login/org.freedesktop.login1.policy:169 -msgid "Power off the system while other users are logged in" +msgid "Power off the system" msgstr "" #: src/login/org.freedesktop.login1.policy:170 +msgid "Authentication is required to power off the system." +msgstr "" + +#: src/login/org.freedesktop.login1.policy:180 +msgid "Power off the system while other users are logged in" +msgstr "" + +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." msgstr "" -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "" -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." msgstr "" -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "" -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." msgstr "" -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "" -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." msgstr "" -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "" -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." msgstr "" -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." msgstr "" -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "" -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "" -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "" -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "" @@ -799,43 +809,43 @@ msgid "" "shall be enabled." msgstr "" -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "" -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "" -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." msgstr "" -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" diff --git a/po/tr.po b/po/tr.po index 0e0473337..df901f16d 100644 --- a/po/tr.po +++ b/po/tr.po @@ -5,21 +5,21 @@ # Gökhan Gurbetoğlu , 2015. # Oğuz Ersen , 2020. # Muhammet Kara , 2015-2020. -# msgid "" msgstr "" "Project-Id-Version: systemd master\n" -"Report-Msgid-Bugs-To: https://github.com/systemd/systemd/issues\n" -"POT-Creation-Date: 2020-09-27 03:31+0000\n" -"PO-Revision-Date: 2020-11-01 15:10+0300\n" -"Last-Translator: Muhammet Kara \n" -"Language-Team: Turkish \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2020-11-28 13:35+0000\n" +"Last-Translator: Oğuz Ersen \n" +"Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=1; plural=0\n" -"X-Generator: Gtranslator 3.38.0\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.3.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -75,7 +75,6 @@ msgid "Create a home area" msgstr "Ev alanı oluştur" #: src/home/org.freedesktop.home1.policy:14 -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to create a user's home area." msgstr "Bir kullanıcının ev alanını oluşturmak kimlik doğrulaması gerektirir." @@ -84,7 +83,6 @@ msgid "Remove a home area" msgstr "Ev alanını kaldır" #: src/home/org.freedesktop.home1.policy:24 -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to remove a user's home area." msgstr "Bir kullanıcının ev alanını kaldırmak kimlik doğrulaması gerektirir." @@ -93,8 +91,6 @@ msgid "Check credentials of a home area" msgstr "Bir ev alanının kimlik bilgilerini denetle" #: src/home/org.freedesktop.home1.policy:34 -#| msgid "" -#| "Authentication is required to attach or detach a portable service image." msgid "" "Authentication is required to check credentials against a user's home area." msgstr "" @@ -106,7 +102,6 @@ msgid "Update a home area" msgstr "Ev alanını güncelle" #: src/home/org.freedesktop.home1.policy:44 -#| msgid "Authentication is required to attach a device to a seat." msgid "Authentication is required to update a user's home area." msgstr "Bir kullanıcının ev alanını güncellemek kimlik doğrulaması gerektirir." @@ -115,7 +110,6 @@ msgid "Resize a home area" msgstr "Ev alanını yeniden boyutlandır" #: src/home/org.freedesktop.home1.policy:54 -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to resize a user's home area." msgstr "" "Bir kullanıcının ev alanını yeniden boyutlandırmak kimlik doğrulaması " @@ -126,8 +120,6 @@ msgid "Change password of a home area" msgstr "Ev alanının parolasını değiştir" #: src/home/org.freedesktop.home1.policy:64 -#| msgid "" -#| "Authentication is required to manage active sessions, users and seats." msgid "" "Authentication is required to change the password of a user's home area." msgstr "" @@ -323,22 +315,18 @@ msgstr "" "kimlik doğrulaması gereklidir." #: src/login/org.freedesktop.login1.policy:117 -#, fuzzy -#| msgid "Allow applications to inhibit system handling of the power key" msgid "Allow applications to inhibit system handling of the reboot key" -msgstr "Uygulamaların sistemin güç tuşunun kullanımını engellemesine izin ver" +msgstr "" +"Uygulamaların sistemin yeniden başlatma tuşunun kullanımını engellemesine " +"izin ver" #: src/login/org.freedesktop.login1.policy:118 -#, fuzzy -#| msgid "" -#| "Authentication is required for an application to inhibit system handling " -#| "of the power key." msgid "" "Authentication is required for an application to inhibit system handling of " "the reboot key." msgstr "" -"Bir uygulamanın sistemin güç tuşunu idare etmesine engel olması için kimlik " -"doğrulaması gereklidir." +"Bir uygulamanın sistemin yeniden başlatma tuşunu idare etmesine engel olması " +"için kimlik doğrulaması gereklidir." #: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" @@ -385,7 +373,7 @@ msgstr "Sistemi kapat" #: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." -msgstr "Sistemi kapatmak için kimlik doğrulaması gerekiyor." +msgstr "Sistemi kapatmak için kimlik doğrulaması gereklidir." #: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" @@ -468,16 +456,12 @@ msgid "Halt the system while an application is inhibiting this" msgstr "Bir uygulama engellenmesini isterken sistemi durdur" #: src/login/org.freedesktop.login1.policy:258 -#, fuzzy -#| msgid "" -#| "Authentication is required to hibernate the system while an application " -#| "is inhibiting this." msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." msgstr "" -"Bir uygulama engellenmesini isterken sistemi hazırda bekletmek kimlik " -"doğrulaması gerektiriyor." +"Bir uygulama engellenmesini isterken sistemi durdurmak kimlik doğrulaması " +"gerektiriyor." #: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" @@ -565,20 +549,17 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" -msgstr "" +msgstr "Çekirdekte yeniden başlatma \"nedenini\" ayarla" #: src/login/org.freedesktop.login1.policy:353 -#, fuzzy -#| msgid "Authentication is required to set the system timezone." msgid "Authentication is required to set the reboot \"reason\" in the kernel." -msgstr "Sistem zaman dilimini ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "" +"Çekirdekte yeniden başlatma \"nedenini\" ayarlamak kimlik doğrulaması " +"gerektiriyor." #: src/login/org.freedesktop.login1.policy:363 -#, fuzzy -#| msgid "Allow indication to the firmware to boot to setup interface" msgid "Indicate to the firmware to boot to setup interface" -msgstr "" -"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesine izin ver" +msgstr "Ürün yazılımına kurulum arayüzüne önyükleme yapmasını belirt" #: src/login/org.freedesktop.login1.policy:364 msgid "" @@ -590,34 +571,26 @@ msgstr "" #: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" -msgstr "" +msgstr "Önyükleyiciye önyükleyici menüsünü başlatmasını belirt" #: src/login/org.freedesktop.login1.policy:375 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "" -"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesi için kimlik " +"Önyükleyiciye önyükleyici menüsünü başlatmasını belirtmek için kimlik " "doğrulaması gereklidir." #: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" -msgstr "" +msgstr "Önyükleyiciye belirli bir girdiye önyükleme yapmasını belirt" #: src/login/org.freedesktop.login1.policy:386 -#, fuzzy -#| msgid "" -#| "Authentication is required to indicate to the firmware to boot to setup " -#| "interface." msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "" -"Kurulum arayüzünü önyüklemek için ürün yazılımının belirtilmesi için kimlik " +"Önyükleyiciye belirli bir girdiye önyükleme yapmasını belirtmek için kimlik " "doğrulaması gereklidir." #: src/login/org.freedesktop.login1.policy:396 @@ -633,7 +606,6 @@ msgid "Change Session" msgstr "Oturumu Değiştir" #: src/login/org.freedesktop.login1.policy:407 -#| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." msgstr "Sanal uçbirimi değiştirmek kimlik doğrulaması gerektirir." @@ -720,23 +692,18 @@ msgid "Set NTP servers" msgstr "NTP sunucularını ayarla" #: src/network/org.freedesktop.network1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to set NTP servers." -msgstr "Sistem zamanını ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "NTP sunucularını ayarlamak için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:33 #: src/resolve/org.freedesktop.resolve1.policy:44 -#| msgid "Register a DNS-SD service" msgid "Set DNS servers" msgstr "DNS sunucularını ayarla" #: src/network/org.freedesktop.network1.policy:34 #: src/resolve/org.freedesktop.resolve1.policy:45 -#, fuzzy -#| msgid "Authentication is required to register a DNS-SD service" msgid "Authentication is required to set DNS servers." -msgstr "Bir DNS-SD hizmeti kaydetmek için kimlik doğrulaması gereklidir" +msgstr "DNS sunucularını ayarlamak için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:44 #: src/resolve/org.freedesktop.resolve1.policy:55 @@ -745,10 +712,8 @@ msgstr "Etki alanlarını ayarla" #: src/network/org.freedesktop.network1.policy:45 #: src/resolve/org.freedesktop.resolve1.policy:56 -#, fuzzy -#| msgid "Authentication is required to stop '$(unit)'." msgid "Authentication is required to set domains." -msgstr "'$(unit)' durdurmak için kimlik doğrulaması gereklidir." +msgstr "Etki alanlarını ayarlamak için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:55 #: src/resolve/org.freedesktop.resolve1.policy:66 @@ -757,10 +722,8 @@ msgstr "Öntanımlı rota belirle" #: src/network/org.freedesktop.network1.policy:56 #: src/resolve/org.freedesktop.resolve1.policy:67 -#, fuzzy -#| msgid "Authentication is required to set the local hostname." msgid "Authentication is required to set default route." -msgstr "Yerel makine adını ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "Öntanımlı rotayı ayarlamak için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:66 #: src/resolve/org.freedesktop.resolve1.policy:77 @@ -769,118 +732,106 @@ msgstr "LLMNR etkinleştir/devre dışı bırak" #: src/network/org.freedesktop.network1.policy:67 #: src/resolve/org.freedesktop.resolve1.policy:78 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable LLMNR." -msgstr "Sistemi hazırda bekletmek kimlik doğrulaması gerektiriyor." +msgstr "" +"LLMNR etkinleştirmek veya devre dışı bırakmak için kimlik doğrulaması " +"gereklidir." #: src/network/org.freedesktop.network1.policy:77 #: src/resolve/org.freedesktop.resolve1.policy:88 msgid "Enable/disable multicast DNS" -msgstr "" +msgstr "Çoklu yayın DNS'i etkinleştir/devre dışı bırak" #: src/network/org.freedesktop.network1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:89 -#, fuzzy -#| msgid "Authentication is required to get product UUID." msgid "Authentication is required to enable or disable multicast DNS." -msgstr "Ürün UUID'ini almak için kimlik doğrulaması gereklidir." +msgstr "" +"Çoklu yayın DNS'i etkinleştirmek veya devre dışı bırakmak için kimlik " +"doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:99 msgid "Enable/disable DNS over TLS" -msgstr "" +msgstr "TLS üzerinden DNS'i etkinleştir/devre dışı bırak" #: src/network/org.freedesktop.network1.policy:89 #: src/resolve/org.freedesktop.resolve1.policy:100 -#, fuzzy -#| msgid "Authentication is required to register a DNS-SD service" msgid "Authentication is required to enable or disable DNS over TLS." -msgstr "Bir DNS-SD hizmeti kaydetmek için kimlik doğrulaması gereklidir" +msgstr "" +"TLS üzerinden DNS'i etkinleştirmek veya devre dışı bırakmak için kimlik " +"doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:99 #: src/resolve/org.freedesktop.resolve1.policy:110 msgid "Enable/disable DNSSEC" -msgstr "" +msgstr "DNSSEC etkinleştir/devre dışı bırak" #: src/network/org.freedesktop.network1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:111 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable DNSSEC." -msgstr "Sistemi hazırda bekletmek kimlik doğrulaması gerektiriyor." +msgstr "" +"DNSSEC etkinleştirmek veya devre dışı bırakmak için kimlik doğrulaması " +"gereklidir." #: src/network/org.freedesktop.network1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:121 msgid "Set DNSSEC Negative Trust Anchors" -msgstr "" +msgstr "DNSSEC Negatif Güven Bağlantılarını Ayarla" #: src/network/org.freedesktop.network1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system locale." msgid "Authentication is required to set DNSSEC Negative Trust Anchors." -msgstr "Sistem yerelini ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "" +"DNSSEC Negatif Güven Bağlantılarını ayarlamak için kimlik doğrulaması " +"gereklidir." #: src/network/org.freedesktop.network1.policy:121 msgid "Revert NTP settings" -msgstr "" +msgstr "NTP ayarlarını geri al" #: src/network/org.freedesktop.network1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset NTP settings." -msgstr "Sistem zamanını ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "NTP ayarlarını sıfırlamak için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:132 msgid "Revert DNS settings" -msgstr "" +msgstr "DNS ayarlarını geri al" #: src/network/org.freedesktop.network1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset DNS settings." -msgstr "Sistem zamanını ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "DNS ayarlarını sıfırlamak için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:143 msgid "DHCP server sends force renew message" -msgstr "" +msgstr "DHCP sunucusu zorunlu yenileme mesajı gönderiyor" #: src/network/org.freedesktop.network1.policy:144 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to send force renew message." -msgstr "Duvar mesajı ayarlamak için kimlik doğrulaması gereklidir" +msgstr "Zorunlu yenileme mesajı göndermek için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:154 msgid "Renew dynamic addresses" msgstr "Dinamik adresleri yenile" #: src/network/org.freedesktop.network1.policy:155 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to renew dynamic addresses." -msgstr "Duvar mesajı ayarlamak için kimlik doğrulaması gereklidir" +msgstr "Dinamik adresleri yenilemek için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:165 msgid "Reload network settings" msgstr "Ağ ayarlarını yeniden yükle" #: src/network/org.freedesktop.network1.policy:166 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to reload network settings." -msgstr "systemd durumunu yeniden yüklemek kimlik doğrulaması gerektiriyor." +msgstr "Ağ ayarlarını yeniden yüklemek için kimlik doğrulaması gereklidir." #: src/network/org.freedesktop.network1.policy:176 msgid "Reconfigure network interface" msgstr "Ağ arabirimini yeniden yapılandır" #: src/network/org.freedesktop.network1.policy:177 -#, fuzzy -#| msgid "Authentication is required to reboot the system." msgid "Authentication is required to reconfigure network interface." -msgstr "Sistemi yeniden başlatmak kimlik doğrulaması gerektiriyor." +msgstr "Ağ arayüzünü yeniden yapılandırmak için kimlik doğrulaması gereklidir." #: src/portable/org.freedesktop.portable1.policy:13 msgid "Inspect a portable service image" @@ -932,13 +883,11 @@ msgstr "" #: src/resolve/org.freedesktop.resolve1.policy:132 msgid "Revert name resolution settings" -msgstr "" +msgstr "Ad çözümleme ayarlarını geri al" #: src/resolve/org.freedesktop.resolve1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system keyboard settings." msgid "Authentication is required to reset name resolution settings." -msgstr "Sistem klavye ayarlarını ayarlamak kimlik doğrulaması gerektiriyor." +msgstr "Ad çözümleme ayarlarını sıfırlamak için kimlik doğrulaması gereklidir." #: src/timedate/org.freedesktop.timedate1.policy:22 msgid "Set system time" @@ -1015,26 +964,19 @@ msgstr "" "gereklidir." #: src/core/dbus-unit.c:708 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." msgstr "" -"'$(unit)'in \"failed\" (başarısız) durumunu sıfırlamak için kimlik " -"doğrulaması gereklidir." +"'$(unit)' ile ilişkili dosyaları ve dizinleri silmek için kimlik doğrulaması " +"gereklidir." #: src/core/dbus-unit.c:757 -#, fuzzy -#| msgid "" -#| "Authentication is required to send a UNIX signal to the processes of " -#| "'$(unit)'." msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" -"'$(unit)' süreçlerine bir UNIX sinyali göndermek için kimlik doğrulaması " -"gereklidir." +"'$(unit)' biriminin işlemlerini dondurmak veya devam ettirmek için kimlik " +"doğrulaması gereklidir." #~ msgid "" #~ "Authentication is required to halt the system while an application asked " diff --git a/po/uk.po b/po/uk.po index 8e6f9dce8..b628f6c57 100644 --- a/po/uk.po +++ b/po/uk.po @@ -2,13 +2,13 @@ # Ukrainian translation for systemd. # Eugene Melnik , 2014. # Daniel Korostil , 2014, 2016, 2018. -# Yuri Chornoivan , 2019, 2020. +# Yuri Chornoivan , 2019, 2020, 2021. msgid "" msgstr "" "Project-Id-Version: systemd master\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-08-29 11:29+0000\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-01-09 10:51+0000\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" @@ -18,7 +18,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" -"X-Generator: Weblate 4.2.1\n" +"X-Generator: Weblate 4.4\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -152,7 +152,8 @@ msgstr "Встановлення даних щодо машини" #: src/hostname/org.freedesktop.hostname1.policy:42 msgid "Authentication is required to set local machine information." -msgstr "Для встановлення даних щодо локальної машини слід пройти розпізнавання." +msgstr "" +"Для встановлення даних щодо локальної машини слід пройти розпізнавання." #: src/hostname/org.freedesktop.hostname1.policy:51 msgid "Get product UUID" @@ -317,55 +318,69 @@ msgstr "" "перемикання кришки, слід пройти розпізнавання." #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "" +"Уможливлення перешкоджання обробці системою клавіші перезавантаження для " +"програм" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "" +"Для того, щоб дозволити програмам перешкоджати обробленню системою клавіші " +"перезавантаження, слід пройти розпізнавання." + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "Дозвіл для незареєстрованого користувача на запуск програм" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "" "Для того, щоб дозволити незареєстрованому користувачеві запускати програми, " "потрібен явний запит." -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "Дозвіл для незареєстрованих користувачів на запуск програм" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "" "Для того, щоб дозволити незареєстрованому користувачеві запускати програми, " "слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "Дозвіл на під'єднання пристроїв до місць" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "" "Для того, щоб під'єднувати пристрої до місць, слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "Вилучення прив'язки пристроїв для місць" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "Для скидання прив'язки пристроїв до місць слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "Вимикання системи" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "Для вимикання системи слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "Вимикання системи, коли інші користувачі ще у ній" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." @@ -373,11 +388,11 @@ msgstr "" "Для вимикання системи, коли у ній ще працюють інші користувачі, слід пройти " "розпізнавання." -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "Вимикання системи, коли програми намагаються перешкодити цьому" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." @@ -385,19 +400,19 @@ msgstr "" "Для того, щоб вимкнути систему, коли програми намагаються перешкодити цьому, " "слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "Перезавантаження системи" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "Для перезавантаження системи слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "Перезавантаження, якщо інші користувачі в системі" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." @@ -405,11 +420,11 @@ msgstr "" "Для перезавантаження системи, коли у ній ще працюють інші користувачі, слід " "пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "Перезапуск системи, коли програми намагаються перешкодити цьому" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." @@ -417,19 +432,19 @@ msgstr "" "Для того, щоб перезавантажити систему, коли програми намагаються перешкодити " "цьому, слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "Зупинення системи" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "Для зупинення системи слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "Зупинення системи, коли інші користувачі в ній" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." @@ -437,11 +452,11 @@ msgstr "" "Для зупинення системи, коли у ній ще працюють інші користувачі, слід пройти " "розпізнавання." -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "Зупинення системи, коли програми намагаються перешкодити цьому" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." @@ -449,19 +464,19 @@ msgstr "" "Для того, щоб зупинити систему, коли програми намагаються перешкодити цьому, " "слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "Призупинення системи" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "Для призупинення системи слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "Призупинення системи, коли інші користувачі в ній" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." @@ -469,11 +484,11 @@ msgstr "" "Для призупинення системи, коли у ній ще працюють інші користувачі, слід " "пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "Призупинення системи, коли програми намагаються перешкодити цьому" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." @@ -481,19 +496,19 @@ msgstr "" "Для того, щоб призупинити систему, коли програми намагаються перешкодити " "цьому, слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "Присипляння системи" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "Для присипляння системи слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "Присипляння системи, коли інші користувачі в ній" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." @@ -501,11 +516,11 @@ msgstr "" "Для присипляння системи, коли у ній ще працюють інші користувачі, слід " "пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "Присипляння системи, коли програми намагаються перешкодити цьому" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." @@ -513,41 +528,41 @@ msgstr "" "Для того, щоб приспати систему, коли програми намагаються перешкодити цьому, " "слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "Керування сеансами, користувачами і робочими місцями" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "" "Для того, щоб керувати сеансами, користувачами і робочими місцями, слід " "пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "Блокування і розблоковування сеансів" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "" "Для того, щоб заблокувати або розблокувати активні сеанси, слід пройти " "розпізнавання." -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "Встановлення «причини» перезавантаження у ядрі" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "" "Для того, щоб встановити «причину» перезавантаження у ядрі, слід пройти " "розпізнавання." -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "Визначення для мікрокоду завантаження інтерфейсу встановлення" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." @@ -555,11 +570,11 @@ msgstr "" "Для того, щоб дозволити мікрокоду визначати, чи завантажувати інтерфейс " "встановлення, слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "Визначення для завантажувача завантаження до меню завантажувача" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." @@ -567,11 +582,11 @@ msgstr "" "Для того, щоб вказати завантажувачу, що слід завантажитися до меню " "завантажувача, слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "Визначення для завантажувача певного пункту для завантаження" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." @@ -579,19 +594,19 @@ msgstr "" "Для того, щоб вказати завантажувачу, що слід завантажити певний пункт меню " "завантаження, слід пройти розпізнавання." -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "Встановлення повідомлення на стіні" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "Для встановлення повідомлення на стіні слід пройти розпізнавання" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "Зміна сеансу" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "Для зміни віртуального термінала слід пройти розпізнавання." @@ -648,7 +663,8 @@ msgstr "Отримання псевдо-TTY на локальному вузлі #: src/machine/org.freedesktop.machine1.policy:75 msgid "Authentication is required to acquire a pseudo TTY on the local host." -msgstr "Для отримання псевдо-TTY на локальному вузлі слід пройти розпізнавання." +msgstr "" +"Для отримання псевдо-TTY на локальному вузлі слід пройти розпізнавання." #: src/machine/org.freedesktop.machine1.policy:84 msgid "Manage local virtual machines and containers" @@ -729,7 +745,8 @@ msgstr "Вмикання або вимикання трансляційної DN #: src/network/org.freedesktop.network1.policy:78 #: src/resolve/org.freedesktop.resolve1.policy:89 msgid "Authentication is required to enable or disable multicast DNS." -msgstr "Для вмикання або вимикання трансляційної DNS слід пройти розпізнавання." +msgstr "" +"Для вмикання або вимикання трансляційної DNS слід пройти розпізнавання." #: src/network/org.freedesktop.network1.policy:88 #: src/resolve/org.freedesktop.resolve1.policy:99 @@ -909,39 +926,39 @@ msgstr "" "Для керування тим, чи слід вмикати синхронізацію часу за допомогою мережі, " "слід пройти розпізнавання." -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "Для запуску «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "Для зупинення «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "Для перезавантаження «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "Для перезапуску «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "" "Для надсилання сигналу UNIX до процесів «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "" "Для скидання «пошкодженого» стану з «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "Для визначення властивостей на «$(unit)» слід пройти розпізнавання." -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." @@ -949,7 +966,7 @@ msgstr "" "Для вилучення файлів і каталогів, які пов'язано із «$(unit)», слід пройти " "розпізнавання." -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." msgstr "" diff --git a/po/zh_CN.po b/po/zh_CN.po index 15a169167..f56869322 100644 --- a/po/zh_CN.po +++ b/po/zh_CN.po @@ -5,15 +5,15 @@ # Frank Hill , 2014. # Boyuan Yang <073plan@gmail.com>, 2015. # Jeff Bai , 2016. -# Charles Lee , 2020. +# Charles Lee , 2020, 2021. # Whired Planck , 2020. msgid "" msgstr "" "Project-Id-Version: systemd\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" -"PO-Revision-Date: 2020-11-26 11:35+0000\n" -"Last-Translator: Whired Planck \n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" +"PO-Revision-Date: 2021-03-01 09:40+0000\n" +"Last-Translator: Charles Lee \n" "Language-Team: Chinese (Simplified) \n" "Language: zh_CN\n" @@ -21,7 +21,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Weblate 4.3.2\n" +"X-Generator: Weblate 4.4.2\n" #: src/core/org.freedesktop.systemd1.policy.in:22 msgid "Send passphrase back to system" @@ -178,7 +178,7 @@ msgstr "下载虚拟机或容器镜像" #: src/import/org.freedesktop.import1.policy:43 msgid "Authentication is required to download a VM or container image" -msgstr "下载虚拟机或容器镜像需要认证。" +msgstr "下载虚拟机或容器镜像需要认证" #: src/locale/org.freedesktop.locale1.policy:22 msgid "Set system locale" @@ -280,247 +280,257 @@ msgid "" msgstr "允许应用程序阻止系统响应笔记本上盖开关事件需要认证。" #: src/login/org.freedesktop.login1.policy:117 +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "允许应用程序阻止系统响应重启键" + +#: src/login/org.freedesktop.login1.policy:118 +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "允许应用程序阻止系统响应重启键需要认证。" + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "允许未登录用户运行程序" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "要以未登录用户运行程序,需要明确请求。" -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "允许未登录用户运行程序" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "允许未登录用户运行程序需要认证。" -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "允许将设备附加至会话座位" # Pay attention to the concept of "seat". # # To fully understand the meaning, please refer to session management in old ConsoleKit and new systemd-logind. -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "允许将设备附加至某个会话座位需要认证。" -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "刷新设备至会话座位间的连接" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "重新设定设备的会话座位接入方式时需要认证。" -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "关闭系统" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "关闭系统需要认证。" -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "存在其他已登录用户时仍然关机" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." msgstr "存在其他已登录用户时关闭系统需要认证。" -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "有其它应用程序阻止时仍然关机" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." msgstr "在其它应用程序阻止关机时关闭系统需要认证。" -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "重启系统" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "重启系统需要认证。" -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "存在其他已登录用户时仍然重启" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." msgstr "存在其他已登录用户时重启系统需要认证。" -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "有其它应用程序阻止时仍然重启" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." msgstr "在其它应用程序阻止重启时重启系统需要认证。" -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "停止系统" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "停止系统需要认证。" -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "当存在其他已登录用户时仍然停止系统" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." msgstr "当存在其他已登录用户时停止系统需要认证。" -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "当存在应用程序阻止时仍然停止系统" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 msgid "" "Authentication is required to halt the system while an application is " "inhibiting this." -msgstr "当应用程序阻止时停止系统需要认证。" +msgstr "当应用程序阻止停止系统时需要认证。" -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "挂起系统" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "挂起系统需要认证。" -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "存在其他已登录用户时仍然挂起系统" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." msgstr "存在其他已登录用户时挂起系统需要认证。" -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "有其它应用程序阻止时仍然挂起系统" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." msgstr "在其它应用程序阻止挂起时挂起系统需要认证。" -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "休眠系统" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "休眠系统需要认证。" -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "存在其他已登录用户时仍然休眠" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." msgstr "存在其他已登录用户时进行休眠系统需要认证。" -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "有其它应用程序阻止时仍然休眠" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." msgstr "在其它应用程序阻止休眠时进行休眠需要认证。" -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "管理活动会话、用户与会话座位" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "管理活动会话、用户与会话座位需要认证。" -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "锁定或解锁活动会话" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "对活动会话进行锁定或解锁需要认证。" -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "在内核中设定重启“原因”" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "在内核中设定重启“原因”需要认证。" -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "指示固件以启动至设置界面" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "向固件发出启动时进入设置界面的指令需要认证。" -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "指示引导加载程序启动至引导加载程序菜单" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "指示引导加载程序启动至引导加载程序菜单需要认证。" -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "指示引导加载程序启动指定条目" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "指示引导加载程序启动入指定引导加载条目需要认证。" -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "设置 wall 消息" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" -msgstr "设置 wall 消息需要认证。" +msgstr "设置 wall 消息需要认证" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "更改会话" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 msgid "Authentication is required to change the virtual terminal." msgstr "更改虚拟终端需要认证。" @@ -667,147 +677,119 @@ msgstr "启用/禁用 DNSSEC" #: src/network/org.freedesktop.network1.policy:100 #: src/resolve/org.freedesktop.resolve1.policy:111 -#, fuzzy -#| msgid "Authentication is required to hibernate the system." msgid "Authentication is required to enable or disable DNSSEC." -msgstr "休眠系统需要认证。" +msgstr "启用或禁用 DNSSEC 需要认证。" #: src/network/org.freedesktop.network1.policy:110 #: src/resolve/org.freedesktop.resolve1.policy:121 msgid "Set DNSSEC Negative Trust Anchors" -msgstr "" +msgstr "设定 DNSSEC 负信任锚(Negative Trust Anchors)" #: src/network/org.freedesktop.network1.policy:111 #: src/resolve/org.freedesktop.resolve1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system locale." msgid "Authentication is required to set DNSSEC Negative Trust Anchors." -msgstr "设置系统区域和语言需要认证。" +msgstr "设定 DNSSEC 负信任锚需要认证。" #: src/network/org.freedesktop.network1.policy:121 msgid "Revert NTP settings" -msgstr "" +msgstr "重置 NTP 设置" #: src/network/org.freedesktop.network1.policy:122 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset NTP settings." -msgstr "设置系统时间需要认证。" +msgstr "重置 NTP 设置需要认证。" #: src/network/org.freedesktop.network1.policy:132 msgid "Revert DNS settings" -msgstr "" +msgstr "重置 DNS 设置" #: src/network/org.freedesktop.network1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system time." msgid "Authentication is required to reset DNS settings." -msgstr "设置系统时间需要认证。" +msgstr "重置 DNS 设置需要认证。" #: src/network/org.freedesktop.network1.policy:143 msgid "DHCP server sends force renew message" -msgstr "" +msgstr "DHCP 服务器发送强制更新消息" #: src/network/org.freedesktop.network1.policy:144 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to send force renew message." -msgstr "设置 wall 消息需要认证。" +msgstr "发送强制更新消息需要认证。" #: src/network/org.freedesktop.network1.policy:154 msgid "Renew dynamic addresses" -msgstr "" +msgstr "续订动态地址" #: src/network/org.freedesktop.network1.policy:155 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to renew dynamic addresses." -msgstr "设置 wall 消息需要认证。" +msgstr "续订动态地址需要认证。" #: src/network/org.freedesktop.network1.policy:165 msgid "Reload network settings" -msgstr "" +msgstr "重新加载网络设置" #: src/network/org.freedesktop.network1.policy:166 -#, fuzzy -#| msgid "Authentication is required to reload the systemd state." msgid "Authentication is required to reload network settings." -msgstr "重新载入 systemd 状态需要认证。" +msgstr "重新加载网络设置需要认证。" #: src/network/org.freedesktop.network1.policy:176 msgid "Reconfigure network interface" -msgstr "" +msgstr "重新配置网络接口" #: src/network/org.freedesktop.network1.policy:177 -#, fuzzy -#| msgid "Authentication is required to reboot the system." msgid "Authentication is required to reconfigure network interface." -msgstr "重启系统需要认证。" +msgstr "重新配置网络接口需要认证。" #: src/portable/org.freedesktop.portable1.policy:13 msgid "Inspect a portable service image" -msgstr "" +msgstr "检查便携式服务映像" #: src/portable/org.freedesktop.portable1.policy:14 -#, fuzzy -#| msgid "Authentication is required to import a VM or container image" msgid "Authentication is required to inspect a portable service image." -msgstr "导入虚拟机或容器镜像需要认证" +msgstr "检查便携式服务映像需要认证。" #: src/portable/org.freedesktop.portable1.policy:23 msgid "Attach or detach a portable service image" -msgstr "" +msgstr "添加或卸载便携式服务映像" # Pay attention to the concept of "seat". # # To fully understand the meaning, please refer to session management in old ConsoleKit and new systemd-logind. #: src/portable/org.freedesktop.portable1.policy:24 -#, fuzzy -#| msgid "Authentication is required to attach a device to a seat." msgid "" "Authentication is required to attach or detach a portable service image." -msgstr "允许将设备附加至某个会话座位需要认证。" +msgstr "添加或卸载便携式服务映像需要认证。" #: src/portable/org.freedesktop.portable1.policy:34 msgid "Delete or modify portable service image" -msgstr "" +msgstr "删除或修改便携式服务映像" #: src/portable/org.freedesktop.portable1.policy:35 -#, fuzzy -#| msgid "Authentication is required to download a VM or container image" msgid "" "Authentication is required to delete or modify a portable service image." -msgstr "下载虚拟机或容器镜像需要认证。" +msgstr "删除或修改便携式服务映像需要认证。" #: src/resolve/org.freedesktop.resolve1.policy:22 msgid "Register a DNS-SD service" -msgstr "" +msgstr "注册 DNS-SD 服务" #: src/resolve/org.freedesktop.resolve1.policy:23 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to register a DNS-SD service" -msgstr "设置 wall 消息需要认证。" +msgstr "注册 DNS-SD 服务需要认证" #: src/resolve/org.freedesktop.resolve1.policy:33 msgid "Unregister a DNS-SD service" -msgstr "" +msgstr "取消注册 DNS-SD 服务" #: src/resolve/org.freedesktop.resolve1.policy:34 -#, fuzzy -#| msgid "Authentication is required to set a wall message" msgid "Authentication is required to unregister a DNS-SD service" -msgstr "设置 wall 消息需要认证。" +msgstr "取消注册 DNS-SD 服务需要认证" #: src/resolve/org.freedesktop.resolve1.policy:132 msgid "Revert name resolution settings" -msgstr "" +msgstr "重置名称解析设置" #: src/resolve/org.freedesktop.resolve1.policy:133 -#, fuzzy -#| msgid "Authentication is required to set the system keyboard settings." msgid "Authentication is required to reset name resolution settings." -msgstr "设置系统键盘需要认证。" +msgstr "重置名称解析设置需要认证。" #: src/timedate/org.freedesktop.timedate1.policy:22 msgid "Set system time" @@ -845,54 +827,46 @@ msgid "" "shall be enabled." msgstr "打开或关闭网络时间同步需要认证。" -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "启动“$(unit)”需要认证。" -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "停止“$(unit)”需要认证。" -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "重新载入“$(unit)”需要认证。" -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "重新启动“$(unit)”需要认证。" -#: src/core/dbus-unit.c:538 -#, fuzzy -#| msgid "Authentication is required to set properties on '$(unit)'." +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." -msgstr "设置“$(unit)”的属性需要认证。" +msgstr "发送 UNIX 信号给 '$(unit)' 进程需要认证。" -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "重置“$(unit)”的失败(\"failed\")状态需要认证。" -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "设置“$(unit)”的属性需要认证。" -#: src/core/dbus-unit.c:711 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." -msgstr "重置“$(unit)”的失败(\"failed\")状态需要认证。" +msgstr "删除与 '$(unit)' 关联的文件和目录需要认证。" -#: src/core/dbus-unit.c:760 -#, fuzzy -#| msgid "" -#| "Authentication is required to reset the \"failed\" state of '$(unit)'." +#: src/core/dbus-unit.c:757 msgid "" "Authentication is required to freeze or thaw the processes of '$(unit)' unit." -msgstr "重置“$(unit)”的失败(\"failed\")状态需要认证。" +msgstr "冻结或解冻 '$(unit)' 单元进程需要认证。" #~ msgid "Authentication is required to kill '$(unit)'." #~ msgstr "杀死“$(unit)”需要认证。" diff --git a/po/zh_TW.po b/po/zh_TW.po index e706f70e1..f47d94913 100644 --- a/po/zh_TW.po +++ b/po/zh_TW.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-08-19 18:02+0200\n" +"POT-Creation-Date: 2021-01-08 17:48+0100\n" "PO-Revision-Date: 2019-10-23 19:19+0800\n" "Last-Translator: pan93412 \n" "Language-Team: Chinese \n" @@ -283,116 +283,132 @@ msgid "" msgstr "要讓應用程式阻止系統處理上蓋開關需要驗證。" #: src/login/org.freedesktop.login1.policy:117 +#, fuzzy +#| msgid "Allow applications to inhibit system handling of the power key" +msgid "Allow applications to inhibit system handling of the reboot key" +msgstr "允許應用程式阻止系統處理電源鍵" + +#: src/login/org.freedesktop.login1.policy:118 +#, fuzzy +#| msgid "" +#| "Authentication is required for an application to inhibit system handling " +#| "of the power key." +msgid "" +"Authentication is required for an application to inhibit system handling of " +"the reboot key." +msgstr "要讓應用程式阻止系統處理電源鍵需要驗證。" + +#: src/login/org.freedesktop.login1.policy:128 msgid "Allow non-logged-in user to run programs" msgstr "允許未登入的使用者執行程式" -#: src/login/org.freedesktop.login1.policy:118 +#: src/login/org.freedesktop.login1.policy:129 msgid "Explicit request is required to run programs as a non-logged-in user." msgstr "需要明確請求,才能以未登入使用者身份執行程式。" -#: src/login/org.freedesktop.login1.policy:127 +#: src/login/org.freedesktop.login1.policy:138 msgid "Allow non-logged-in users to run programs" msgstr "允許未登入的使用者執行程式" -#: src/login/org.freedesktop.login1.policy:128 +#: src/login/org.freedesktop.login1.policy:139 msgid "Authentication is required to run programs as a non-logged-in user." msgstr "要讓未登入的使用者執行程式需要驗證。" -#: src/login/org.freedesktop.login1.policy:137 +#: src/login/org.freedesktop.login1.policy:148 msgid "Allow attaching devices to seats" msgstr "允許將設備連接到座位" -#: src/login/org.freedesktop.login1.policy:138 +#: src/login/org.freedesktop.login1.policy:149 msgid "Authentication is required to attach a device to a seat." msgstr "將設備連接到座位需要驗證。" -#: src/login/org.freedesktop.login1.policy:148 +#: src/login/org.freedesktop.login1.policy:159 msgid "Flush device to seat attachments" msgstr "暴露裝置以安裝附件" -#: src/login/org.freedesktop.login1.policy:149 +#: src/login/org.freedesktop.login1.policy:160 msgid "Authentication is required to reset how devices are attached to seats." msgstr "要重置裝置如何連接到座位需要驗證。" -#: src/login/org.freedesktop.login1.policy:158 +#: src/login/org.freedesktop.login1.policy:169 msgid "Power off the system" msgstr "關閉系統電源" -#: src/login/org.freedesktop.login1.policy:159 +#: src/login/org.freedesktop.login1.policy:170 msgid "Authentication is required to power off the system." msgstr "關閉系統電源需要身份驗證。" -#: src/login/org.freedesktop.login1.policy:169 +#: src/login/org.freedesktop.login1.policy:180 msgid "Power off the system while other users are logged in" msgstr "在有其他使用者登入時關閉系統電源" -#: src/login/org.freedesktop.login1.policy:170 +#: src/login/org.freedesktop.login1.policy:181 msgid "" "Authentication is required to power off the system while other users are " "logged in." msgstr "在有其他使用者登入時關閉系統電源需要驗證。" -#: src/login/org.freedesktop.login1.policy:180 +#: src/login/org.freedesktop.login1.policy:191 msgid "Power off the system while an application is inhibiting this" msgstr "當應用程式阻止系統電源關閉時將其關閉" -#: src/login/org.freedesktop.login1.policy:181 +#: src/login/org.freedesktop.login1.policy:192 msgid "" "Authentication is required to power off the system while an application is " "inhibiting this." msgstr "當應用程式阻止系統電源關閉時將系統電源關閉需要驗證。" -#: src/login/org.freedesktop.login1.policy:191 +#: src/login/org.freedesktop.login1.policy:202 msgid "Reboot the system" msgstr "重新啟動系統" -#: src/login/org.freedesktop.login1.policy:192 +#: src/login/org.freedesktop.login1.policy:203 msgid "Authentication is required to reboot the system." msgstr "重新啟動系統需要驗證。" -#: src/login/org.freedesktop.login1.policy:202 +#: src/login/org.freedesktop.login1.policy:213 msgid "Reboot the system while other users are logged in" msgstr "在有其他使用者登入時重新啟動系統" -#: src/login/org.freedesktop.login1.policy:203 +#: src/login/org.freedesktop.login1.policy:214 msgid "" "Authentication is required to reboot the system while other users are logged " "in." msgstr "在有其他使用者登入時重新啟動系統需要驗證。" -#: src/login/org.freedesktop.login1.policy:213 +#: src/login/org.freedesktop.login1.policy:224 msgid "Reboot the system while an application is inhibiting this" msgstr "當應用程式阻止重新啟動系統時將系統重新啟動" -#: src/login/org.freedesktop.login1.policy:214 +#: src/login/org.freedesktop.login1.policy:225 msgid "" "Authentication is required to reboot the system while an application is " "inhibiting this." msgstr "當應用程式阻止系統重新啟動時將系統重新啟動需要驗證。" -#: src/login/org.freedesktop.login1.policy:224 +#: src/login/org.freedesktop.login1.policy:235 msgid "Halt the system" msgstr "停止系統" -#: src/login/org.freedesktop.login1.policy:225 +#: src/login/org.freedesktop.login1.policy:236 msgid "Authentication is required to halt the system." msgstr "停止系統需要身份驗證。" -#: src/login/org.freedesktop.login1.policy:235 +#: src/login/org.freedesktop.login1.policy:246 msgid "Halt the system while other users are logged in" msgstr "在其他使用者登入時停止系統" -#: src/login/org.freedesktop.login1.policy:236 +#: src/login/org.freedesktop.login1.policy:247 msgid "" "Authentication is required to halt the system while other users are logged " "in." msgstr "在其他使用者登入時停止系統需要身份驗證。" -#: src/login/org.freedesktop.login1.policy:246 +#: src/login/org.freedesktop.login1.policy:257 msgid "Halt the system while an application is inhibiting this" msgstr "在應用程式阻止時停止系統" -#: src/login/org.freedesktop.login1.policy:247 +#: src/login/org.freedesktop.login1.policy:258 #, fuzzy #| msgid "" #| "Authentication is required to hibernate the system while an application " @@ -402,129 +418,129 @@ msgid "" "inhibiting this." msgstr "當應用程式阻止系統冬眠時將系統冬眠需要驗證。" -#: src/login/org.freedesktop.login1.policy:257 +#: src/login/org.freedesktop.login1.policy:268 msgid "Suspend the system" msgstr "暫停系統" -#: src/login/org.freedesktop.login1.policy:258 +#: src/login/org.freedesktop.login1.policy:269 msgid "Authentication is required to suspend the system." msgstr "暫停系統需要驗證。" -#: src/login/org.freedesktop.login1.policy:267 +#: src/login/org.freedesktop.login1.policy:278 msgid "Suspend the system while other users are logged in" msgstr "在有其他使用者登入時暫停系統" -#: src/login/org.freedesktop.login1.policy:268 +#: src/login/org.freedesktop.login1.policy:279 msgid "" "Authentication is required to suspend the system while other users are " "logged in." msgstr "在有其他使用者登入時暫停系統需要驗證。" -#: src/login/org.freedesktop.login1.policy:278 +#: src/login/org.freedesktop.login1.policy:289 msgid "Suspend the system while an application is inhibiting this" msgstr "當應用程式阻止暫停系統時將系統暫停" -#: src/login/org.freedesktop.login1.policy:279 +#: src/login/org.freedesktop.login1.policy:290 msgid "" "Authentication is required to suspend the system while an application is " "inhibiting this." msgstr "當應用程式阻止系統暫停時將系統暫停需要驗證。" -#: src/login/org.freedesktop.login1.policy:289 +#: src/login/org.freedesktop.login1.policy:300 msgid "Hibernate the system" msgstr "系統冬眠" -#: src/login/org.freedesktop.login1.policy:290 +#: src/login/org.freedesktop.login1.policy:301 msgid "Authentication is required to hibernate the system." msgstr "系統冬眠需要驗證。" -#: src/login/org.freedesktop.login1.policy:299 +#: src/login/org.freedesktop.login1.policy:310 msgid "Hibernate the system while other users are logged in" msgstr "在有其他使用者登入時冬眠系統" -#: src/login/org.freedesktop.login1.policy:300 +#: src/login/org.freedesktop.login1.policy:311 msgid "" "Authentication is required to hibernate the system while other users are " "logged in." msgstr "在有其他使用者登入時冬眠系統需要驗證。" -#: src/login/org.freedesktop.login1.policy:310 +#: src/login/org.freedesktop.login1.policy:321 msgid "Hibernate the system while an application is inhibiting this" msgstr "當應用程式阻止冬眠系統時將系統冬眠" -#: src/login/org.freedesktop.login1.policy:311 +#: src/login/org.freedesktop.login1.policy:322 msgid "" "Authentication is required to hibernate the system while an application is " "inhibiting this." msgstr "當應用程式阻止系統冬眠時將系統冬眠需要驗證。" -#: src/login/org.freedesktop.login1.policy:321 +#: src/login/org.freedesktop.login1.policy:332 msgid "Manage active sessions, users and seats" msgstr "管理活躍的工作階段、使用者與座位" -#: src/login/org.freedesktop.login1.policy:322 +#: src/login/org.freedesktop.login1.policy:333 msgid "Authentication is required to manage active sessions, users and seats." msgstr "管理活躍的工作階段、使用者與座位需要驗證。" -#: src/login/org.freedesktop.login1.policy:331 +#: src/login/org.freedesktop.login1.policy:342 msgid "Lock or unlock active sessions" msgstr "鎖定或解鎖活躍的工作階段" -#: src/login/org.freedesktop.login1.policy:332 +#: src/login/org.freedesktop.login1.policy:343 msgid "Authentication is required to lock or unlock active sessions." msgstr "鎖定或解鎖活躍的工作階段需要驗證。" -#: src/login/org.freedesktop.login1.policy:341 +#: src/login/org.freedesktop.login1.policy:352 msgid "Set the reboot \"reason\" in the kernel" msgstr "設定內核中的重新啟動 \"reason (原因)\"" -#: src/login/org.freedesktop.login1.policy:342 +#: src/login/org.freedesktop.login1.policy:353 msgid "Authentication is required to set the reboot \"reason\" in the kernel." msgstr "設定內核中的重新啟動 \"reason (原因)\"需要身份驗證。" -#: src/login/org.freedesktop.login1.policy:352 +#: src/login/org.freedesktop.login1.policy:363 msgid "Indicate to the firmware to boot to setup interface" msgstr "引導韌體啟動設定畫面" -#: src/login/org.freedesktop.login1.policy:353 +#: src/login/org.freedesktop.login1.policy:364 msgid "" "Authentication is required to indicate to the firmware to boot to setup " "interface." msgstr "對韌體的指示以開始設定介面需要驗證。" -#: src/login/org.freedesktop.login1.policy:363 +#: src/login/org.freedesktop.login1.policy:374 msgid "Indicate to the boot loader to boot to the boot loader menu" msgstr "引導開機載入器啟動開機載入選單" -#: src/login/org.freedesktop.login1.policy:364 +#: src/login/org.freedesktop.login1.policy:375 msgid "" "Authentication is required to indicate to the boot loader to boot to the " "boot loader menu." msgstr "引導開機載入器啟動開機載入器選單需要身份驗證。" -#: src/login/org.freedesktop.login1.policy:374 +#: src/login/org.freedesktop.login1.policy:385 msgid "Indicate to the boot loader to boot a specific entry" msgstr "引導開機載入器啟動指定項目" -#: src/login/org.freedesktop.login1.policy:375 +#: src/login/org.freedesktop.login1.policy:386 msgid "" "Authentication is required to indicate to the boot loader to boot into a " "specific boot loader entry." msgstr "引導開機載入器啟動指定的開機載入器項目需要身份驗證。" -#: src/login/org.freedesktop.login1.policy:385 +#: src/login/org.freedesktop.login1.policy:396 msgid "Set a wall message" msgstr "設定 wall 訊息" -#: src/login/org.freedesktop.login1.policy:386 +#: src/login/org.freedesktop.login1.policy:397 msgid "Authentication is required to set a wall message" msgstr "設定 wall 訊息需要身份驗證" -#: src/login/org.freedesktop.login1.policy:395 +#: src/login/org.freedesktop.login1.policy:406 msgid "Change Session" msgstr "" -#: src/login/org.freedesktop.login1.policy:396 +#: src/login/org.freedesktop.login1.policy:407 #, fuzzy #| msgid "Authentication is required to halt the system." msgid "Authentication is required to change the virtual terminal." @@ -828,43 +844,43 @@ msgid "" "shall be enabled." msgstr "控制網路時間同步是否啟用需要驗證。" -#: src/core/dbus-unit.c:362 +#: src/core/dbus-unit.c:359 msgid "Authentication is required to start '$(unit)'." msgstr "啟動 '$(unit)' 需要驗證。" -#: src/core/dbus-unit.c:363 +#: src/core/dbus-unit.c:360 msgid "Authentication is required to stop '$(unit)'." msgstr "停止 '$(unit)' 需要驗證。" -#: src/core/dbus-unit.c:364 +#: src/core/dbus-unit.c:361 msgid "Authentication is required to reload '$(unit)'." msgstr "重新載入 '$(unit)' 需要驗證。" -#: src/core/dbus-unit.c:365 src/core/dbus-unit.c:366 +#: src/core/dbus-unit.c:362 src/core/dbus-unit.c:363 msgid "Authentication is required to restart '$(unit)'." msgstr "重新啟動 '$(unit)' 需要驗證。" -#: src/core/dbus-unit.c:538 +#: src/core/dbus-unit.c:535 msgid "" "Authentication is required to send a UNIX signal to the processes of " "'$(unit)'." msgstr "傳送 UNIX 信號至「$(unit)」的程序需要身份驗證。" -#: src/core/dbus-unit.c:569 +#: src/core/dbus-unit.c:566 msgid "Authentication is required to reset the \"failed\" state of '$(unit)'." msgstr "重置 '$(unit)' 的「失敗」狀態需要驗證。" -#: src/core/dbus-unit.c:602 +#: src/core/dbus-unit.c:599 msgid "Authentication is required to set properties on '$(unit)'." msgstr "在 '$(unit)' 上設定屬性需要驗證。" -#: src/core/dbus-unit.c:711 +#: src/core/dbus-unit.c:708 msgid "" "Authentication is required to delete files and directories associated with " "'$(unit)'." msgstr "刪除與 '$(unit)' 相關的檔案及目錄需要身份驗證。" -#: src/core/dbus-unit.c:760 +#: src/core/dbus-unit.c:757 #, fuzzy #| msgid "" #| "Authentication is required to send a UNIX signal to the processes of " diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in index cef78f9d6..edfa8bb10 100644 --- a/rules.d/50-udev-default.rules.in +++ b/rules.d/50-udev-default.rules.in @@ -10,9 +10,8 @@ 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", GOTO="default_hwdb_imported" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}" -LABEL="default_hwdb_imported" ACTION!="add", GOTO="default_end" @@ -40,6 +39,8 @@ SUBSYSTEM=="cec", GROUP="video" SUBSYSTEM=="drm", KERNEL=="renderD*", GROUP="render", MODE="@GROUP_RENDER_MODE@" SUBSYSTEM=="kfd", GROUP="render", MODE="@GROUP_RENDER_MODE@" +SUBSYSTEM=="misc", KERNEL=="sgx_enclave", GROUP="sgx", MODE="0660" + # When using static_node= with non-default permissions, also update # tmpfiles.d/static-nodes-permissions.conf.in to keep permissions synchronized. @@ -85,8 +86,18 @@ KERNEL=="fuse", MODE="0666", OPTIONS+="static_node=fuse" # The static_node is required on s390x and ppc (they are using MODULE_ALIAS) KERNEL=="kvm", GROUP="kvm", MODE="@DEV_KVM_MODE@", OPTIONS+="static_node=kvm" +KERNEL=="vsock", MODE="0666" +KERNEL=="vhost-vsock", GROUP="kvm", MODE="@DEV_KVM_MODE@", OPTIONS+="static_node=vhost-vsock" + +KERNEL=="vhost-net", GROUP="kvm", MODE="@DEV_KVM_MODE@", OPTIONS+="static_node=vhost-net" + KERNEL=="udmabuf", GROUP="kvm" SUBSYSTEM=="ptp", ATTR{clock_name}=="KVM virtual PTP", SYMLINK += "ptp_kvm" +SUBSYSTEM=="ptp", ATTR{clock_name}=="hyperv", SYMLINK += "ptp_hyperv" + +SUBSYSTEM=="dmi", ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="", ENV{ID_VENDOR}="$attr{sys_vendor}", ENV{ID_MODEL}="$attr{product_name}" +SUBSYSTEM=="dmi", ENV{ID_SYSFS_ATTRIBUTE_MODEL}=="product_version", ENV{ID_VENDOR}="$attr{sys_vendor}", ENV{ID_MODEL}="$attr{product_version}" + LABEL="default_end" diff --git a/rules.d/60-fido-id.rules b/rules.d/60-fido-id.rules index c7d5d2ff1..48c259ee0 100644 --- a/rules.d/60-fido-id.rules +++ b/rules.d/60-fido-id.rules @@ -7,7 +7,8 @@ SUBSYSTEM=="hidraw", IMPORT{program}="fido_id" # Tag any form of security token as such ENV{ID_SECURITY_TOKEN}=="1", TAG+="security-device" +SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0b????:*", ENV{ID_SMARTCARD_READER}="1" # Tag any CCID device (i.e. Smartcard Reader) as security token -SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="0b", TAG+="security-device" +ENV{ID_SMARTCARD_READER}=="1", TAG+="security-device" LABEL="fido_id_end" diff --git a/rules.d/60-persistent-input.rules b/rules.d/60-persistent-input.rules index 255547d90..52f4ddb7e 100644 --- a/rules.d/60-persistent-input.rules +++ b/rules.d/60-persistent-input.rules @@ -35,8 +35,8 @@ SUBSYSTEMS=="usb", ENV{ID_BUS}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", A SUBSYSTEMS=="pci|usb|platform|acpi", IMPORT{builtin}="path_id" ENV{ID_PATH}=="?*", KERNEL=="mouse*|js*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-$env{.INPUT_CLASS}" ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="?*", SYMLINK+="input/by-path/$env{ID_PATH}-event-$env{.INPUT_CLASS}" -# allow empty class for platform and usb devices; platform supports only a single interface that way -SUBSYSTEMS=="usb|platform", ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", \ +# allow empty class for platform, usb and i2c devices; platform supports only a single interface that way +SUBSYSTEMS=="usb|platform|i2c", ENV{ID_PATH}=="?*", KERNEL=="event*", ENV{.INPUT_CLASS}=="", \ SYMLINK+="input/by-path/$env{ID_PATH}-event" LABEL="persistent_input_end" diff --git a/rules.d/60-persistent-storage.rules b/rules.d/60-persistent-storage.rules index fc7f733e2..50b357f8d 100644 --- a/rules.d/60-persistent-storage.rules +++ b/rules.d/60-persistent-storage.rules @@ -104,13 +104,13 @@ KERNEL=="vd*[0-9]", ENV{ID_PATH}=="pci-*", SYMLINK+="disk/by-path/virtio-$env{ID # probe filesystem metadata of optical drives which have a media inserted KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \ - IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}" + IMPORT{builtin}="blkid --hint=session_offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}" # single-session CDs do not have ID_CDROM_MEDIA_SESSION_LAST_OFFSET KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="", \ IMPORT{builtin}="blkid --noraid" # probe filesystem metadata of disks -KERNEL!="sr*", IMPORT{builtin}="blkid" +KERNEL!="sr*|mmcblk[0-9]boot[0-9]", IMPORT{builtin}="blkid" # by-label/by-uuid links (filesystem metadata) ENV{ID_FS_USAGE}=="filesystem|other|crypto", ENV{ID_FS_UUID_ENC}=="?*", SYMLINK+="disk/by-uuid/$env{ID_FS_UUID_ENC}" diff --git a/rules.d/60-serial.rules b/rules.d/60-serial.rules index b1626650b..f303e27fd 100644 --- a/rules.d/60-serial.rules +++ b/rules.d/60-serial.rules @@ -4,9 +4,8 @@ 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}" -# 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" +SUBSYSTEMS=="pci", IMPORT{builtin}="hwdb --subsystem=pci" +SUBSYSTEMS=="usb", IMPORT{builtin}="usb_id", IMPORT{builtin}="hwdb --subsystem=usb" # /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/70-memory.rules b/rules.d/70-memory.rules new file mode 100644 index 000000000..f2610ff97 --- /dev/null +++ b/rules.d/70-memory.rules @@ -0,0 +1,8 @@ +# do not edit this file, it will be overwritten on update + +ACTION=="remove", GOTO="memory_end" +SUBSYSTEM!="dmi", GOTO="memory_end" + +IMPORT{program}="dmi_memory_id" + +LABEL="memory_end" diff --git a/rules.d/99-systemd.rules.in b/rules.d/99-systemd.rules.in index 7c22eefdb..be972f90f 100644 --- a/rules.d/99-systemd.rules.in +++ b/rules.d/99-systemd.rules.in @@ -42,14 +42,11 @@ SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTE # just an identification string for systemd, so whether the path actually is # accessible or not does not matter as long as it is unique and in the # filesystem namespace. -# -# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n955 SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name" SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k", \ ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0b????:*", ENV{ID_SMARTCARD_READER}="1" ENV{ID_SMARTCARD_READER}=="?*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target", ENV{SYSTEMD_USER_WANTS}+="smartcard.target" SUBSYSTEM=="sound", KERNEL=="controlC*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target", ENV{SYSTEMD_USER_WANTS}+="sound.target" diff --git a/rules.d/README b/rules.d/README new file mode 100644 index 000000000..294d6eeb5 --- /dev/null +++ b/rules.d/README @@ -0,0 +1,8 @@ +Files in this directory contain configuration for systemd-udev.service, a +daemon that manages symlinks to device nodes, permissions of devices nodes, +emits device events for userspace, and renames network interfaces. + +See man:udev(7) for an overview of the configuration file format, and +man:systemd-udevd.service(8) for a description of service itself. + +Use 'systemd-analyze cat-config udev/rules.d' to display the effective config. diff --git a/rules.d/meson.build b/rules.d/meson.build index 7e46abd55..42fa451c6 100644 --- a/rules.d/meson.build +++ b/rules.d/meson.build @@ -1,5 +1,9 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +install_data( + 'README', + install_dir : udevrulesdir) + rules = files(''' 60-autosuspend.rules 60-block.rules @@ -28,6 +32,10 @@ if conf.get('HAVE_KMOD') == 1 rules += files('80-drivers.rules') endif +if dmi_arches.contains(host_machine.cpu_family()) + rules += files('70-memory.rules') +endif + install_data(rules, install_dir : udevrulesdir) diff --git a/shell-completion/bash/coredumpctl b/shell-completion/bash/coredumpctl index 20886932e..5fc11fdbd 100644 --- a/shell-completion/bash/coredumpctl +++ b/shell-completion/bash/coredumpctl @@ -39,7 +39,8 @@ _coredumpctl() { local i verb comps local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} local OPTS='-h --help --version --no-pager --no-legend -o --output -F --field -1 - -r --reverse -S --since -U --until -D --directory -q --quiet --debugger' + -r --reverse -S --since -U --until -D --directory -q --quiet --debugger + -A --debugger-arguments --json -n' local -A VERBS=( [LIST]='list info' @@ -57,6 +58,8 @@ _coredumpctl() { compopt -o filenames elif __contains_word "$prev" '--field -F'; then comps=$( compgen -W '${__journal_fields[*]}' -- "$cur" ) + elif __contains_word "$prev" '--json'; then + comps=$( compgen -W 'pretty short off' -- "$cur" ) elif [[ $cur = -* ]]; then comps=${OPTS} elif __contains_word "$prev" ${VERBS[*]} && diff --git a/shell-completion/bash/loginctl b/shell-completion/bash/loginctl index ac85519c1..f94f191d8 100644 --- a/shell-completion/bash/loginctl +++ b/shell-completion/bash/loginctl @@ -43,7 +43,7 @@ _loginctl () { [STANDALONE]='--all -a --help -h --no-pager --version --no-legend --no-ask-password -l --full --value' [ARG]='--host -H --kill-who --property -p --signal -s -M --machine - -n --lines -o --output' + -n --lines -o --output -P' ) if __contains_word "$prev" ${OPTS[ARG]}; then @@ -61,7 +61,7 @@ _loginctl () { --machine|-M) comps=$( __get_machines ) ;; - --property|-p) + --property|-p|-P) comps='' ;; --output|-o) diff --git a/shell-completion/bash/portablectl b/shell-completion/bash/portablectl index fe3d925d7..e18d04c7e 100644 --- a/shell-completion/bash/portablectl +++ b/shell-completion/bash/portablectl @@ -40,7 +40,7 @@ _portablectl() { local -A VERBS=( [STANDALONE]='list' - [IMAGE]='attach detach inspect is-attached set-limit' + [IMAGE]='attach detach reattach inspect is-attached set-limit' [IMAGES]='remove' [IMAGE_WITH_BOOL]='read-only' ) diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in index b26381a32..c25a8d94c 100644 --- a/shell-completion/bash/systemctl.in +++ b/shell-completion/bash/systemctl.in @@ -7,7 +7,7 @@ __systemctl() { local mode=$1; shift 1 - systemctl $mode --full --no-legend --no-pager --plain "$@" 2>/dev/null + systemctl $mode --full --legend=no --no-pager --plain "$@" 2>/dev/null } __systemd_properties() { @@ -123,11 +123,11 @@ _systemctl () { local -A OPTS=( [STANDALONE]='--all -a --reverse --after --before --defaults --force -f --full -l --global - --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --now + --help -h --no-ask-password --no-block --legend=no --no-pager --no-reload --no-wall --now --quiet -q --system --user --version --runtime --recursive -r --firmware-setup - --show-types -i --ignore-inhibitors --plain --failed --value --fail --dry-run --wait' + --show-types --plain --failed --value --fail --dry-run --wait' [ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root - --preset-mode -n --lines -o --output -M --machine --message --timestamp' + --preset-mode -n --lines -o --output -M --machine --message --timestamp --check-inhibitors' ) if __contains_word "--user" ${COMP_WORDS[*]}; then @@ -179,6 +179,9 @@ _systemctl () { --timestamp) comps='pretty us µs utc us+utc µs+utc' ;; + --check-inhibitors) + comps='auto yes no' + ;; esac COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) return 0 @@ -211,7 +214,7 @@ _systemctl () { list-timers list-units list-unit-files poweroff reboot rescue show-environment suspend get-default is-system-running preset-all' - [FILE]='link switch-root' + [FILE]='link switch-root bind mount-image' [TARGETS]='set-default' [MACHINES]='list-machines' [LOG_LEVEL]='log-level' diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index 884065187..76b9700f7 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -31,20 +31,20 @@ __get_machines() { _systemd_run() { local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]} - local OPTS='-h --help --version --user --system --scope --unit --description --slice - -r --remain-after-exit --send-sighup -H --host -M --machine --service-type - --on-active --on-boot --on-startup --on-unit-active --on-unit-inactive - --on-calendar --timer-property --path-property --socket-property -t --pty - -q --quiet --no-block --uid --gid --nice -E --setenv -p --property - --no-ask-password --wait -P --pipe -G --collect --working-directory - -d --same-dir -S --shell' + local OPTS='--no-ask-password --scope -u --unit -p --property --description --slice --slice-inherit + -r --remain-after-exit --send-sighup --service-type --uid --gid --nice + --working-directory -d --same-dir -E --setenv -t --pty -P --pipe -S --shell -q --quiet + --on-active --on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar + --on-clock-change --on-timezone-change --path-property --socket-property + --timer-property --no-block --wait -G --collect --user --system -H --host -M --machine + -h --help --version' local mode=--system local i local opts_with_values=( - --unit --description --slice --service-type -H --host -M --machine -p --property --on-active - --on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar --timer-property - --path-property --socket-property --uid --gid --nice -E --setenv --working-directory + --unit -p --property --slice --description --service-type --uid --gid --nice --working-directory + -E --setenv --on-active --on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar + --path-property --socket-property --timer-property -H --host -M --machine ) for (( i=1; i <= COMP_CWORD; i++ )); do if [[ ${COMP_WORDS[i]} != -* ]]; then diff --git a/shell-completion/bash/udevadm b/shell-completion/bash/udevadm index 8b1b962f2..33d998395 100644 --- a/shell-completion/bash/udevadm +++ b/shell-completion/bash/udevadm @@ -51,7 +51,7 @@ _udevadm() { [INFO_STANDALONE]='-r --root -a --attribute-walk -x --export -e --export-db -c --cleanup-db -w --wait-for-initialization' [INFO_ARG]='-q --query -p --path -n --name -P --export-prefix -d --device-id-of-file' - [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -w --settle --wait-daemon' + [TRIGGER_STANDALONE]='-v --verbose -n --dry-run -q --quiet -w --settle --wait-daemon' [TRIGGER_ARG]='-t --type -c --action -s --subsystem-match -S --subsystem-nomatch -a --attr-match -A --attr-nomatch -p --property-match -g --tag-match -y --sysname-match --name-match -b --parent-match' diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in index 22c40898e..5e82ef7e1 100644 --- a/shell-completion/zsh/_systemctl.in +++ b/shell-completion/zsh/_systemctl.in @@ -31,6 +31,8 @@ "reset-failed:Reset failed state for all, one, or more units" "list-dependencies:Show unit dependency tree" "clean:Remove configuration, state, cache, logs or runtime data of units" + "bind:Bind mount a path from the host into a unit's namespace" + "mount-image:Mount an image from the host into a unit's namespace" ) local -a machine_commands=( @@ -145,7 +147,7 @@ # @todo _systemd-run has a helper with the same name, so we must redefine __systemctl() { - systemctl $_sys_service_mgr --full --no-legend --no-pager --plain "$@" 2>/dev/null + systemctl $_sys_service_mgr --full --legend=no --no-pager --plain "$@" 2>/dev/null } @@ -378,6 +380,14 @@ done _files } +(( $+functions[_systemctl_bind] )) || _systemctl_bind() { + _files + } + +(( $+functions[_systemctl_mount-image] )) || _systemctl_mount-image() { + _files + } + # no systemctl completion for: # [STANDALONE]='daemon-reexec daemon-reload default # emergency exit halt kexec list-jobs list-units @@ -443,6 +453,13 @@ done _values -s , "${_styles[@]}" } +(( $+functions[_systemctl_check_inhibitors] )) || + _systemctl_check_inhibitors() { + local -a _modes + _modes=(auto yes no) + _values -s , "${_modes[@]}" + } + # Build arguments for "systemctl" to be used in completion. local -a _modes; _modes=("--user" "--system") # Use the last mode (they are exclusive and the last one is used). @@ -460,10 +477,10 @@ _arguments -s \ '--before[Show units ordered before]' \ {-l,--full}"[Don't ellipsize unit names on output]" \ '--show-types[When showing sockets, show socket type]' \ - {-i,--ignore-inhibitors}'[When executing a job, ignore jobs dependencies]' \ + '--check-inhibitors[Specify if inhibitors should be checked]:mode:_systemctl_check_inhibitors' \ {-q,--quiet}'[Suppress output]' \ '--no-block[Do not wait until operation finished]' \ - '--no-legend[Do not print a legend, i.e. the column headers and the footer with hints]' \ + '--legend=no[Do not print a legend, i.e. the column headers and the footer with hints]' \ '--no-pager[Do not pipe output into a pager]' \ '--system[Connect to system manager]' \ '--user[Connect to user service manager]' \ diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index d9998e5df..bd70c13ba 100644 --- a/shell-completion/zsh/_systemd-run +++ b/shell-completion/zsh/_systemd-run @@ -23,13 +23,25 @@ __systemctl() { } _arguments \ + {-G,--collect}'[Unload the transient unit after it completed]' \ + '--description=[Description for unit]:description' \ + '--gid=[Run as system group]:group:_groups' \ {-h,--help}'[Show help message]' \ - '--version[Show package version]' \ - '--user[Run as user unit]' \ {-H+,--host=}'[Operate on remote host]:[user@]host:_sd_hosts_or_user_at_host' \ {-M+,--machine=}'[Operate on local container]:machines:_sd_machines' \ - '--scope[Run this as scope rather than service]' \ - '--unit=[Run under the specified unit name]:unit name' \ + '--nice=[Nice level]:nice level' \ + '--no-ask-password[Do not query the user for authentication]' \ + '--no-block[Do not synchronously wait for the unit start operation to finish]' \ + '--on-active=[Run after SEC seconds]:SEC' \ + '--on-boot=[Run SEC seconds after machine was booted up]:SEC' \ + '--on-calendar=[Realtime timer]:SPEC' \ + '--on-clock-change[Defines a trigger based on system clock jumps]' \ + '--on-startup=[Run SEC seconds after systemd was first started]:SEC' \ + '--on-timezone-change[Defines a trigger based on system timezone changes]' \ + '--on-unit-active=[Run SEC seconds after the last activation]:SEC' \ + '--on-unit-inactive=[Run SEC seconds after the last deactivation]:SEC' \ + '--path-property=[Set path unit property]:NAME=VALUE' \ + {-P,--pipe}'[Inherit standard input, output, and error]' \ {-p+,--property=}'[Set unit property]:NAME=VALUE:(( \ CPUAccounting= MemoryAccounting= BlockIOAccounting= SendSIGHUP= \ SendSIGKILL= MemoryLimit= CPUShares= BlockIOWeight= User= Group= \ @@ -45,21 +57,24 @@ _arguments \ ReadOnlyPaths= InaccessiblePaths= EnvironmentFile= \ ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment= \ ))' \ - '--description=[Description for unit]:description' \ - '--slice=[Run in the specified slice]:slices:__systemd-run_slices' \ + {-t,--pty}'[The service connects to the terminal]' \ + {-q,--quiet}'[Suppresses additional informational output]' \ {-r,--remain-after-exit}'[Leave service around until explicitly stopped]' \ + {-d,--same-dir}'[Run on the current working directory]' \ + '--scope[Run this as scope rather than service]' \ '--send-sighup[Send SIGHUP when terminating]' \ '--service-type=[Service type]:type:(simple forking oneshot dbus notify idle)' \ - '--uid=[Run as system user]:user:_users' \ - '--gid=[Run as system group]:group:_groups' \ - '--nice=[Nice level]:nice level' \ - '--setenv=[Set environment]:NAME=VALUE' \ - '--on-active=[Run after SEC seconds]:SEC' \ - '--on-boot=[Run SEC seconds after machine was booted up]:SEC' \ - '--on-startup=[Run SEC seconds after systemd was first started]:SEC' \ - '--on-unit-active=[Run SEC seconds after the last activation]:SEC' \ - '--on-unit-inactive=[Run SEC seconds after the last deactivation]:SEC' \ - '--on-calendar=[Realtime timer]:SPEC' \ + {-E+,--setenv=}'[Set environment]:NAME=VALUE' \ + {-S,--shell}'[requests an interactive shell in the current working directory]' \ + '--slice=[Run in the specified slice]:slices:__systemd-run_slices' \ + '--slice-inherit[Run in the inherited slice]' \ + '--socket-property=[Set socket unit property]:NAME=VALUE' \ + '--system[Run as system unit]' \ '--timer-property=[Set timer unit property]:NAME=VALUE' \ + '--uid=[Run as system user]:user:_users' \ + {-u+,--unit=}'[Run under the specified unit name]:unit name' \ + '--user[Run as user unit]' \ + '--version[Show package version]' \ '--wait=[Wait until service stopped again]' \ + '--working-directory=[Run with the specified working directory]' \ '*::command:_command' diff --git a/shell-completion/zsh/_udevadm b/shell-completion/zsh/_udevadm index ae82d8aa7..5e989b4a1 100644 --- a/shell-completion/zsh/_udevadm +++ b/shell-completion/zsh/_udevadm @@ -21,6 +21,7 @@ _udevadm_trigger(){ _arguments \ '--verbose[Print the list of devices which will be triggered.]' \ '--dry-run[Do not actually trigger the event.]' \ + '--quiet[Suppress error logging in triggering events.]' \ '--type=[Trigger a specific type of devices.]:types:(devices subsystems failed)' \ '--action=[Type of event to be triggered.]:actions:(add change remove)' \ '--subsystem-match=[Trigger events for devices which belong to a matching subsystem.]' \ diff --git a/src/ac-power/ac-power.c b/src/ac-power/ac-power.c index 9fabdb9e9..905da4ad8 100644 --- a/src/ac-power/ac-power.c +++ b/src/ac-power/ac-power.c @@ -12,8 +12,8 @@ static void help(void) { "Report whether we are connected to an external power source.\n\n" " -h --help Show this help\n" " --version Show package version\n" - " -v --verbose Show state as text\n" - , program_invocation_short_name); + " -v --verbose Show state as text\n", + program_invocation_short_name); } static int parse_argv(int argc, char *argv[]) { diff --git a/src/activate/activate.c b/src/activate/activate.c index 1f7a2490e..f298b1d49 100644 --- a/src/activate/activate.c +++ b/src/activate/activate.c @@ -342,11 +342,11 @@ static int help(void) { " --fdname=NAME[:NAME...] Specify names for file descriptors\n" " --inetd Enable inetd file descriptor passing protocol\n" "\nNote: file descriptors from sd_listen_fds() will be passed through.\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c index 8d94fbc5d..fc5af11f5 100644 --- a/src/analyze/analyze-security.c +++ b/src/analyze/analyze-security.c @@ -1528,11 +1528,11 @@ static int assess(const struct security_info *info, Table *overview_table, Analy if (!details_table) return log_oom(); - (void) table_set_sort(details_table, (size_t) 3, (size_t) 1, (size_t) -1); + (void) table_set_sort(details_table, (size_t) 3, (size_t) 1); (void) table_set_reverse(details_table, 3, true); if (getenv_bool("SYSTEMD_ANALYZE_DEBUG") <= 0) - (void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 6, (size_t) -1); + (void) table_set_display(details_table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 6); } for (i = 0; i < ELEMENTSOF(security_assessor_table); i++) { @@ -1545,7 +1545,7 @@ static int assess(const struct security_info *info, Table *overview_table, Analy if (a->default_dependencies_only && !info->default_dependencies) { badness = UINT64_MAX; - d = strdup("Service runs in special boot phase, option does not apply"); + d = strdup("Service runs in special boot phase, option is not appropriate"); if (!d) return log_oom(); } else { diff --git a/src/analyze/analyze-verify.c b/src/analyze/analyze-verify.c index a9c89173b..1b06e0701 100644 --- a/src/analyze/analyze-verify.c +++ b/src/analyze/analyze-verify.c @@ -13,6 +13,7 @@ #include "path-util.h" #include "strv.h" #include "unit-name.h" +#include "unit-serialize.h" static int prepare_filename(const char *filename, char **ret) { int r; @@ -115,14 +116,17 @@ static int verify_socket(Unit *u) { } int verify_executable(Unit *u, const ExecCommand *exec) { + int r; + if (!exec) return 0; if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE) return 0; - if (access(exec->path, X_OK) < 0) - return log_unit_error_errno(u, errno, "Command %s is not executable: %m", exec->path); + r = find_executable_full(exec->path, false, NULL, NULL); + if (r < 0) + return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path); return 0; } diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index 9920f2a85..1a38d878a 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -37,6 +37,7 @@ #include "main-func.h" #include "nulstr-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -92,7 +93,7 @@ static usec_t arg_base_time = USEC_INFINITY; STATIC_DESTRUCTOR_REGISTER(arg_dot_from_patterns, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_dot_to_patterns, strv_freep); -struct boot_times { +typedef struct BootTimes { usec_t firmware_time; usec_t loader_time; usec_t kernel_time; @@ -124,9 +125,9 @@ struct boot_times { * (so it is stored here for reference). */ usec_t reverse_offset; -}; +} BootTimes; -struct unit_times { +typedef struct UnitTimes { bool has_data; char *name; usec_t activating; @@ -134,9 +135,9 @@ struct unit_times { usec_t deactivated; usec_t deactivating; usec_t time; -}; +} UnitTimes; -struct host_info { +typedef struct HostInfo { char *hostname; char *kernel_name; char *kernel_release; @@ -144,7 +145,7 @@ struct host_info { char *os_pretty_name; char *virtualization; char *architecture; -}; +} HostInfo; static int acquire_bus(sd_bus **bus, bool *use_full_bus) { bool user = arg_scope != UNIT_FILE_SYSTEM; @@ -209,19 +210,16 @@ static int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char return 0; } -static int compare_unit_start(const struct unit_times *a, const struct unit_times *b) { +static int compare_unit_start(const UnitTimes *a, const UnitTimes *b) { return CMP(a->activating, b->activating); } -static void unit_times_free(struct unit_times *t) { - struct unit_times *p; - - for (p = t; p->has_data; p++) +static UnitTimes* unit_times_free_array(UnitTimes *t) { + for (UnitTimes *p = t; p && p->has_data; p++) free(p->name); - free(t); + return mfree(t); } - -DEFINE_TRIVIAL_CLEANUP_FUNC(struct unit_times *, unit_times_free); +DEFINE_TRIVIAL_CLEANUP_FUNC(UnitTimes*, unit_times_free_array); static void subtract_timestamp(usec_t *a, usec_t b) { assert(a); @@ -232,30 +230,30 @@ static void subtract_timestamp(usec_t *a, usec_t b) { } } -static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) { +static int acquire_boot_times(sd_bus *bus, BootTimes **bt) { static const struct bus_properties_map property_map[] = { - { "FirmwareTimestampMonotonic", "t", NULL, offsetof(struct boot_times, firmware_time) }, - { "LoaderTimestampMonotonic", "t", NULL, offsetof(struct boot_times, loader_time) }, - { "KernelTimestamp", "t", NULL, offsetof(struct boot_times, kernel_time) }, - { "InitRDTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_time) }, - { "UserspaceTimestampMonotonic", "t", NULL, offsetof(struct boot_times, userspace_time) }, - { "FinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, finish_time) }, - { "SecurityStartTimestampMonotonic", "t", NULL, offsetof(struct boot_times, security_start_time) }, - { "SecurityFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, security_finish_time) }, - { "GeneratorsStartTimestampMonotonic", "t", NULL, offsetof(struct boot_times, generators_start_time) }, - { "GeneratorsFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, generators_finish_time) }, - { "UnitsLoadStartTimestampMonotonic", "t", NULL, offsetof(struct boot_times, unitsload_start_time) }, - { "UnitsLoadFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, unitsload_finish_time) }, - { "InitRDSecurityStartTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_security_start_time) }, - { "InitRDSecurityFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_security_finish_time) }, - { "InitRDGeneratorsStartTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_generators_start_time) }, - { "InitRDGeneratorsFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_generators_finish_time) }, - { "InitRDUnitsLoadStartTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_unitsload_start_time) }, - { "InitRDUnitsLoadFinishTimestampMonotonic", "t", NULL, offsetof(struct boot_times, initrd_unitsload_finish_time) }, + { "FirmwareTimestampMonotonic", "t", NULL, offsetof(BootTimes, firmware_time) }, + { "LoaderTimestampMonotonic", "t", NULL, offsetof(BootTimes, loader_time) }, + { "KernelTimestamp", "t", NULL, offsetof(BootTimes, kernel_time) }, + { "InitRDTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_time) }, + { "UserspaceTimestampMonotonic", "t", NULL, offsetof(BootTimes, userspace_time) }, + { "FinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, finish_time) }, + { "SecurityStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, security_start_time) }, + { "SecurityFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, security_finish_time) }, + { "GeneratorsStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, generators_start_time) }, + { "GeneratorsFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, generators_finish_time) }, + { "UnitsLoadStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, unitsload_start_time) }, + { "UnitsLoadFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, unitsload_finish_time) }, + { "InitRDSecurityStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_security_start_time) }, + { "InitRDSecurityFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_security_finish_time) }, + { "InitRDGeneratorsStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_generators_start_time) }, + { "InitRDGeneratorsFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_generators_finish_time) }, + { "InitRDUnitsLoadStartTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_unitsload_start_time) }, + { "InitRDUnitsLoadFinishTimestampMonotonic", "t", NULL, offsetof(BootTimes, initrd_unitsload_finish_time) }, {}, }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - static struct boot_times times; + static BootTimes times; static bool cached = false; int r; @@ -293,7 +291,7 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) { } else { /* * User-instance-specific or container-system-specific timestamps processing - * (see comment to reverse_offset in struct boot_times). + * (see comment to reverse_offset in BootTimes). */ times.reverse_offset = times.userspace_time; @@ -316,9 +314,9 @@ finish: return 0; } -static void free_host_info(struct host_info *hi) { +static HostInfo* free_host_info(HostInfo *hi) { if (!hi) - return; + return NULL; free(hi->hostname); free(hi->kernel_name); @@ -327,23 +325,23 @@ static void free_host_info(struct host_info *hi) { free(hi->os_pretty_name); free(hi->virtualization); free(hi->architecture); - free(hi); + return mfree(hi); } -DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info *, free_host_info); +DEFINE_TRIVIAL_CLEANUP_FUNC(HostInfo *, free_host_info); -static int acquire_time_data(sd_bus *bus, struct unit_times **out) { +static int acquire_time_data(sd_bus *bus, UnitTimes **out) { static const struct bus_properties_map property_map[] = { - { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(struct unit_times, activating) }, - { "ActiveEnterTimestampMonotonic", "t", NULL, offsetof(struct unit_times, activated) }, - { "ActiveExitTimestampMonotonic", "t", NULL, offsetof(struct unit_times, deactivating) }, - { "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(struct unit_times, deactivated) }, + { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activating) }, + { "ActiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, activated) }, + { "ActiveExitTimestampMonotonic", "t", NULL, offsetof(UnitTimes, deactivating) }, + { "InactiveEnterTimestampMonotonic", "t", NULL, offsetof(UnitTimes, deactivated) }, {}, }; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - _cleanup_(unit_times_freep) struct unit_times *unit_times = NULL; - struct boot_times *boot_times = NULL; + _cleanup_(unit_times_free_arrayp) UnitTimes *unit_times = NULL; + BootTimes *boot_times = NULL; size_t allocated = 0, c = 0; UnitInfo u; int r; @@ -361,7 +359,7 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) { return bus_log_parse_error(r); while ((r = bus_parse_unit_info(reply, &u)) > 0) { - struct unit_times *t; + UnitTimes *t; if (!GREEDY_REALLOC(unit_times, allocated, c + 2)) return log_oom(); @@ -414,28 +412,28 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) { return c; } -static int acquire_host_info(sd_bus *bus, struct host_info **hi) { +static int acquire_host_info(sd_bus *bus, HostInfo **hi) { static const struct bus_properties_map hostname_map[] = { - { "Hostname", "s", NULL, offsetof(struct host_info, hostname) }, - { "KernelName", "s", NULL, offsetof(struct host_info, kernel_name) }, - { "KernelRelease", "s", NULL, offsetof(struct host_info, kernel_release) }, - { "KernelVersion", "s", NULL, offsetof(struct host_info, kernel_version) }, - { "OperatingSystemPrettyName", "s", NULL, offsetof(struct host_info, os_pretty_name) }, + { "Hostname", "s", NULL, offsetof(HostInfo, hostname) }, + { "KernelName", "s", NULL, offsetof(HostInfo, kernel_name) }, + { "KernelRelease", "s", NULL, offsetof(HostInfo, kernel_release) }, + { "KernelVersion", "s", NULL, offsetof(HostInfo, kernel_version) }, + { "OperatingSystemPrettyName", "s", NULL, offsetof(HostInfo, os_pretty_name) }, {} }; static const struct bus_properties_map manager_map[] = { - { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) }, - { "Architecture", "s", NULL, offsetof(struct host_info, architecture) }, + { "Virtualization", "s", NULL, offsetof(HostInfo, virtualization) }, + { "Architecture", "s", NULL, offsetof(HostInfo, architecture) }, {} }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *system_bus = NULL; - _cleanup_(free_host_infop) struct host_info *host; + _cleanup_(free_host_infop) HostInfo *host = NULL; int r; - host = new0(struct host_info, 1); + host = new0(HostInfo, 1); if (!host) return log_oom(); @@ -482,7 +480,7 @@ manager: static int pretty_boot_time(sd_bus *bus, char **_buf) { char ts[FORMAT_TIMESPAN_MAX]; - struct boot_times *t; + BootTimes *t; static char buf[4096]; size_t size; char *ptr; @@ -559,14 +557,12 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) { } static void svg_graph_box(double height, double begin, double end) { - long long i; - /* outside box, fill */ svg("\n", SCALE_X * (end - begin), SCALE_Y * height); - for (i = ((long long) (begin / 100000)) * 100000; i <= end; i += 100000) { + for (long long i = ((long long) (begin / 100000)) * 100000; i <= end; i += 100000) { /* lines for each second */ if (i % 5000000 == 0) svg(" \n" @@ -594,7 +590,7 @@ static void svg_graph_box(double height, double begin, double end) { } } -static int plot_unit_times(struct unit_times *u, double width, int y) { +static int plot_unit_times(UnitTimes *u, double width, int y) { char ts[FORMAT_TIMESPAN_MAX]; bool b; @@ -617,13 +613,13 @@ static int plot_unit_times(struct unit_times *u, double width, int y) { } static int analyze_plot(int argc, char *argv[], void *userdata) { - _cleanup_(free_host_infop) struct host_info *host = NULL; + _cleanup_(free_host_infop) HostInfo *host = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - _cleanup_(unit_times_freep) struct unit_times *times = NULL; + _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL; _cleanup_free_ char *pretty_times = NULL; bool use_full_bus = arg_scope == UNIT_FILE_SYSTEM; - struct boot_times *boot; - struct unit_times *u; + BootTimes *boot; + UnitTimes *u; int n, m = 1, y = 0, r; double width; @@ -837,13 +833,12 @@ static int list_dependencies_print( unsigned level, unsigned branches, bool last, - struct unit_times *times, - struct boot_times *boot) { + UnitTimes *times, + BootTimes *boot) { - unsigned i; char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX]; - for (i = level; i != 0; i--) + for (unsigned i = level; i != 0; i--) printf("%s", special_glyph(branches & (1 << (i-1)) ? SPECIAL_GLYPH_TREE_VERTICAL : SPECIAL_GLYPH_TREE_SPACE)); printf("%s", special_glyph(last ? SPECIAL_GLYPH_TREE_RIGHT : SPECIAL_GLYPH_TREE_BRANCH)); @@ -882,7 +877,7 @@ static Hashmap *unit_times_hashmap; static int list_dependencies_compare(char *const *a, char *const *b) { usec_t usa = 0, usb = 0; - struct unit_times *times; + UnitTimes *times; times = hashmap_get(unit_times_hashmap, *a); if (times) @@ -894,7 +889,7 @@ static int list_dependencies_compare(char *const *a, char *const *b) { return CMP(usb, usa); } -static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) { +static bool times_in_range(const UnitTimes *times, const BootTimes *boot) { return times && times->activated > 0 && times->activated <= boot->finish_time; } @@ -904,8 +899,8 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, int r; usec_t service_longest = 0; int to_print = 0; - struct unit_times *times; - struct boot_times *boot; + UnitTimes *times; + BootTimes *boot; if (strv_extend(units, name)) return log_oom(); @@ -970,13 +965,13 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, static int list_dependencies(sd_bus *bus, const char *name) { _cleanup_strv_free_ char **units = NULL; char ts[FORMAT_TIMESPAN_MAX]; - struct unit_times *times; + UnitTimes *times; int r; const char *id; _cleanup_free_ char *path = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - struct boot_times *boot; + BootTimes *boot; assert(bus); @@ -1021,8 +1016,7 @@ static int list_dependencies(sd_bus *bus, const char *name) { static int analyze_critical_chain(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - _cleanup_(unit_times_freep) struct unit_times *times = NULL; - struct unit_times *u; + _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL; Hashmap *h; int n, r; @@ -1038,7 +1032,7 @@ static int analyze_critical_chain(int argc, char *argv[], void *userdata) { if (!h) return log_oom(); - for (u = times; u->has_data; u++) { + for (UnitTimes *u = times; u->has_data; u++) { r = hashmap_put(h, u->name, u); if (r < 0) return log_error_errno(r, "Failed to add entry to hashmap: %m"); @@ -1063,9 +1057,8 @@ static int analyze_critical_chain(int argc, char *argv[], void *userdata) { static int analyze_blame(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - _cleanup_(unit_times_freep) struct unit_times *times = NULL; + _cleanup_(unit_times_free_arrayp) UnitTimes *times = NULL; _cleanup_(table_unrefp) Table *table = NULL; - struct unit_times *u; TableCell *cell; int n, r; @@ -1097,7 +1090,7 @@ static int analyze_blame(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = table_set_sort(table, (size_t) 0, (size_t) SIZE_MAX); + r = table_set_sort(table, (size_t) 0); if (r < 0) return r; @@ -1105,7 +1098,7 @@ static int analyze_blame(int argc, char *argv[], void *userdata) { if (r < 0) return r; - for (u = times; u->has_data; u++) { + for (UnitTimes *u = times; u->has_data; u++) { if (u->time <= 0) continue; @@ -1279,7 +1272,7 @@ static int dot(int argc, char *argv[], void *userdata) { if (r < 0) return r; - r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, ""); + r = bus_call_method(bus, bus_systemd_mgr, "ListUnits", &error, &reply, NULL); if (r < 0) log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r)); @@ -1364,7 +1357,7 @@ static int dump(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); fflush(stdout); - return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0); + return copy_bytes(fd, STDOUT_FILENO, UINT64_MAX, 0); } static int cat_config(int argc, char *argv[], void *userdata) { @@ -1576,7 +1569,7 @@ static int dump_exit_status(int argc, char *argv[], void *userdata) { status = exit_status_from_string(argv[i]); if (status < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid exit status \"%s\".", argv[i]); + return log_error_errno(status, "Invalid exit status \"%s\".", argv[i]); assert(status >= 0 && (size_t) status < ELEMENTSOF(exit_status_mappings)); r = table_add_many(table, @@ -1629,7 +1622,7 @@ static int dump_capabilities(int argc, char *argv[], void *userdata) { return table_log_add_error(r); } - (void) table_set_sort(table, (size_t) 1, (size_t) -1); + (void) table_set_sort(table, (size_t) 1); } (void) pager_open(arg_pager_flags); @@ -1718,7 +1711,7 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) { if (strv_isempty(strv_skip(argv, 1))) { _cleanup_set_free_ Set *kernel = NULL, *known = NULL; const char *sys; - int i, k; + int k; NULSTR_FOREACH(sys, syscall_filter_sets[SYSCALL_FILTER_SET_KNOWN].value) if (set_put_strdup(&known, sys) < 0) @@ -1726,7 +1719,7 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) { k = load_kernel_syscalls(&kernel); - for (i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { + for (int i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { const SyscallFilterSet *set = syscall_filter_sets + i; if (!first) puts(""); @@ -2223,13 +2216,12 @@ static int help(int argc, char *argv[], void *userdata) { " --generators[=BOOL] Do [not] run unit generators (requires privileges)\n" " --iterations=N Show the specified number of iterations\n" " --base-time=TIMESTAMP Calculate calendar times relative to specified time\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , dot_link - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + dot_link, + link); /* When updating this list, including descriptions, apply changes to * shell-completion/bash/systemd-analyze and shell-completion/zsh/_systemd-analyze too. */ @@ -2349,29 +2341,15 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_MAN: - if (optarg) { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse --man= argument."); - - arg_man = r; - } else - arg_man = true; - + r = parse_boolean_argument("--man", optarg, &arg_man); + if (r < 0) + return r; break; case ARG_GENERATORS: - if (optarg) { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse --generators= argument."); - - arg_generators = r; - } else - arg_generators = true; - + r = parse_boolean_argument("--generators", optarg, &arg_generators); + if (r < 0) + return r; break; case ARG_ITERATIONS: @@ -2449,7 +2427,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_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/analyze/meson.build b/src/analyze/meson.build index 9e4d95b03..f796629cc 100644 --- a/src/analyze/meson.build +++ b/src/analyze/meson.build @@ -9,3 +9,13 @@ systemd_analyze_sources = files(''' analyze-security.c analyze-security.h '''.split()) + +tests += [ + [['src/analyze/test-verify.c', + 'src/analyze/analyze-verify.c', + 'src/analyze/analyze-verify.h'], + [libcore, + libshared], + [], + core_includes], +] diff --git a/src/ask-password/ask-password.c b/src/ask-password/ask-password.c index a24ee9af1..6b89f57e1 100644 --- a/src/ask-password/ask-password.c +++ b/src/ask-password/ask-password.c @@ -44,10 +44,9 @@ static int help(void) { " --accept-cached Accept cached passwords\n" " --multiple List multiple passwords if available\n" " --no-output Do not print password to standard output\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -167,7 +166,7 @@ static int run(int argc, char *argv[]) { return r; if (arg_timeout > 0) - timeout = now(CLOCK_MONOTONIC) + arg_timeout; + timeout = usec_add(now(CLOCK_MONOTONIC), arg_timeout); else timeout = 0; diff --git a/src/backlight/backlight.c b/src/backlight/backlight.c index d1b6a81e3..86927be62 100644 --- a/src/backlight/backlight.c +++ b/src/backlight/backlight.c @@ -33,12 +33,12 @@ static int help(void) { "\n%sSave and restore backlight brightness at shutdown and boot.%s\n\n" " save Save current brightness\n" " load Set brightness to be the previously saved value\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -71,11 +71,9 @@ static int find_pci_or_platform_parent(sd_device *device, sd_device **ret) { return -ENODATA; c += strspn(c, DIGITS); - if (*c == '-') { + if (*c == '-' && !STARTSWITH_SET(c, "-LVDS-", "-Embedded DisplayPort-")) /* A connector DRM device, let's ignore all but LVDS and eDP! */ - if (!STARTSWITH_SET(c, "-LVDS-", "-Embedded DisplayPort-")) - return -EOPNOTSUPP; - } + return -EOPNOTSUPP; } else if (streq(subsystem, "pci") && sd_device_get_sysattr_value(parent, "class", &value) >= 0) { @@ -137,19 +135,14 @@ static int validate_device(sd_device *device) { assert(device); - /* Verify whether we should actually care for a specific - * backlight device. For backlight devices there might be - * multiple ways to access the same control: "firmware" - * (i.e. ACPI), "platform" (i.e. via the machine's EC) and - * "raw" (via the graphics card). In general we should prefer - * "firmware" (i.e. ACPI) or "platform" access over "raw" - * access, in order not to confuse the BIOS/EC, and - * compatibility with possible low-level hotkey handling of - * screen brightness. The kernel will already make sure to - * expose only one of "firmware" and "platform" for the same - * device to userspace. However, we still need to make sure - * that we use "raw" only if no "firmware" or "platform" - * device for the same device exists. */ + /* Verify whether we should actually care for a specific backlight device. For backlight devices + * there might be multiple ways to access the same control: "firmware" (i.e. ACPI), "platform" + * (i.e. via the machine's EC) and "raw" (via the graphics card). In general we should prefer + * "firmware" (i.e. ACPI) or "platform" access over "raw" access, in order not to confuse the + * BIOS/EC, and compatibility with possible low-level hotkey handling of screen brightness. The + * kernel will already make sure to expose only one of "firmware" and "platform" for the same + * device to userspace. However, we still need to make sure that we use "raw" only if no + * "firmware" or "platform" device for the same device exists. */ r = sd_device_get_subsystem(device, &subsystem); if (r < 0) @@ -194,13 +187,12 @@ static int validate_device(sd_device *device) { !STR_IN_SET(v, "platform", "firmware")) continue; - /* OK, so there's another backlight device, and it's a - * platform or firmware device, so, let's see if we - * can verify it belongs to the same device as ours. */ + /* OK, so there's another backlight device, and it's a platform or firmware device. + * Let's see if we can verify it belongs to the same device as ours. */ if (find_pci_or_platform_parent(other, &other_parent) < 0) continue; - if (same_device(parent, other_parent)) { + if (same_device(parent, other_parent) > 0) { const char *device_sysname = NULL, *other_sysname = NULL; /* Both have the same PCI parent, that means we are out. */ @@ -257,11 +249,6 @@ static int get_max_brightness(sd_device *device, unsigned *ret) { return 0; } -/* Some systems turn the backlight all the way off at the lowest levels. - * clamp_brightness clamps the saved brightness to at least 1 or 5% of - * max_brightness in case of 'backlight' subsystem. This avoids preserving - * an unreadably dim screen, which would otherwise force the user to - * disable state restoration. */ static int clamp_brightness(sd_device *device, bool saved, unsigned max_brightness, unsigned *brightness) { unsigned new_brightness, min_brightness; const char *subsystem; @@ -270,6 +257,11 @@ static int clamp_brightness(sd_device *device, bool saved, unsigned max_brightne assert(device); assert(brightness); + /* Some systems turn the backlight all the way off at the lowest levels. This clamps the saved + * brightness to at least 1 or 5% of max_brightness in case of 'backlight' subsystem. This + * avoids preserving an unreadably dim screen, which would otherwise force the user to disable + * state restoration. */ + r = sd_device_get_subsystem(device, &subsystem); if (r < 0) return log_device_warning_errno(device, r, "Failed to get device subsystem: %m"); @@ -380,7 +372,7 @@ static int run(int argc, char *argv[]) { unsigned max_brightness, brightness; int r; - log_setup_service(); + log_setup(); if (strv_contains(strv_skip(argv, 1), "--help")) return help(); @@ -388,6 +380,9 @@ static int run(int argc, char *argv[]) { if (argc != 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires two arguments."); + if (!STR_IN_SET(argv[1], "load", "save")) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", argv[1]); + umask(0022); r = mkdir_p("/var/lib/systemd/backlight", 0755); @@ -409,9 +404,8 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to get backlight or LED device '%s:%s': %m", ss, sysname); - /* If max_brightness is 0, then there is no actual backlight - * device. This happens on desktops with Asus mainboards - * that load the eeepc-wmi module. */ + /* If max_brightness is 0, then there is no actual backlight device. This happens on desktops + * with Asus mainboards that load the eeepc-wmi module. */ if (get_max_brightness(device, &max_brightness) < 0) return 0; @@ -432,14 +426,11 @@ static int run(int argc, char *argv[]) { } else saved = strjoina("/var/lib/systemd/backlight/", escaped_ss, ":", escaped_sysname); - /* If there are multiple conflicting backlight devices, then - * their probing at boot-time might happen in any order. This - * means the validity checking of the device then is not - * reliable, since it might not see other devices conflicting - * with a specific backlight. To deal with this, we will - * actively delete backlight state files at shutdown (where - * device probing should be complete), so that the validity - * check at boot time doesn't have to be reliable. */ + /* If there are multiple conflicting backlight devices, then their probing at boot-time might + * happen in any order. This means the validity checking of the device then is not reliable, + * since it might not see other devices conflicting with a specific backlight. To deal with + * this, we will actively delete backlight state files at shutdown (where device probing should + * be complete), so that the validity check at boot time doesn't have to be reliable. */ if (streq(argv[1], "load")) { _cleanup_free_ char *value = NULL; @@ -503,7 +494,7 @@ static int run(int argc, char *argv[]) { return log_device_error_errno(device, r, "Failed to write %s: %m", saved); } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", argv[1]); + assert_not_reached("Unknown verb."); return 0; } diff --git a/src/basic/af-to-name.awk b/src/basic/af-to-name.awk index 18d0a8972..b9cfbb7e3 100644 --- a/src/basic/af-to-name.awk +++ b/src/basic/af-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "static const char* const af_names[] = { " } diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index f3e192dda..698a6583c 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -80,7 +80,7 @@ void* memdup_suffix0(const void *p, size_t l); /* We can't use _alloc_() here, s }) static inline void freep(void *p) { - free(*(void**) p); + *(void**)p = mfree(*(void**) p); } #define _cleanup_free_ _cleanup_(freep) @@ -158,15 +158,6 @@ void* greedy_realloc0(void **p, size_t *allocated, size_t need, size_t size); (void*)memset(_new_, 0, _xsize_); \ }) -/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time - * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ -#define TAKE_PTR(ptr) \ - ({ \ - typeof(ptr) _ptr_ = (ptr); \ - (ptr) = NULL; \ - _ptr_; \ - }) - #if HAS_FEATURE_MEMORY_SANITIZER # define msan_unpoison(r, s) __msan_unpoison(r, s) #else diff --git a/src/basic/architecture.h b/src/basic/architecture.h index 1db625cf8..9abc1831d 100644 --- a/src/basic/architecture.h +++ b/src/basic/architecture.h @@ -45,7 +45,7 @@ enum { ARCHITECTURE_ARC, ARCHITECTURE_ARC_BE, _ARCHITECTURE_MAX, - _ARCHITECTURE_INVALID = -1 + _ARCHITECTURE_INVALID = -EINVAL, }; int uname_architecture(void); diff --git a/src/basic/arphrd-to-name.awk b/src/basic/arphrd-to-name.awk index db1c739ab..d25a4e9bc 100644 --- a/src/basic/arphrd-to-name.awk +++ b/src/basic/arphrd-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "const char *arphrd_to_name(int id) {" print " switch(id) {" diff --git a/src/basic/audit-util.h b/src/basic/audit-util.h index aa2177113..964082bac 100644 --- a/src/basic/audit-util.h +++ b/src/basic/audit-util.h @@ -5,7 +5,7 @@ #include #include -#define AUDIT_SESSION_INVALID ((uint32_t) -1) +#define AUDIT_SESSION_INVALID UINT32_MAX int audit_session_from_pid(pid_t pid, uint32_t *id); int audit_loginuid_from_pid(pid_t pid, uid_t *uid); diff --git a/src/basic/blockdev-util.c b/src/basic/blockdev-util.c index 0f1e30ccd..676ad9351 100644 --- a/src/basic/blockdev-util.c +++ b/src/basic/blockdev-util.c @@ -68,7 +68,7 @@ int get_block_device(const char *path, dev_t *ret) { /* Gets the block device directly backing a file system. If the block device is encrypted, returns * the device mapper block device. */ - fd = open(path, O_NOFOLLOW|O_CLOEXEC); + fd = open(path, O_RDONLY|O_NOFOLLOW|O_CLOEXEC); if (fd < 0) return -errno; @@ -94,7 +94,8 @@ int block_get_originating(dev_t dt, dev_t *ret) { _cleanup_closedir_ DIR *d = NULL; _cleanup_free_ char *t = NULL; char p[SYS_BLOCK_PATH_MAX("/slaves")]; - struct dirent *de, *found = NULL; + _cleanup_free_ char *first_found = NULL; + struct dirent *de; const char *q; dev_t devt; int r; @@ -115,20 +116,22 @@ int block_get_originating(dev_t dt, dev_t *ret) { if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN)) continue; - if (found) { + if (first_found) { _cleanup_free_ char *u = NULL, *v = NULL, *a = NULL, *b = NULL; - /* We found a device backed by multiple other devices. We don't really support automatic - * discovery on such setups, with the exception of dm-verity partitions. In this case there are - * two backing devices: the data partition and the hash partition. We are fine with such - * setups, however, only if both partitions are on the same physical device. Hence, let's - * verify this. */ + /* We found a device backed by multiple other devices. We don't really support + * automatic discovery on such setups, with the exception of dm-verity partitions. In + * this case there are two backing devices: the data partition and the hash + * partition. We are fine with such setups, however, only if both partitions are on + * the same physical device. Hence, let's verify this by iterating over every node + * in the 'slaves/' directory and comparing them with the first that gets returned by + * readdir(), to ensure they all point to the same device. */ u = path_join(p, de->d_name, "../dev"); if (!u) return -ENOMEM; - v = path_join(p, found->d_name, "../dev"); + v = path_join(p, first_found, "../dev"); if (!v) return -ENOMEM; @@ -144,15 +147,17 @@ int block_get_originating(dev_t dt, dev_t *ret) { * different physical devices, and we don't support that. */ if (!streq(a, b)) return -ENOTUNIQ; + } else { + first_found = strdup(de->d_name); + if (!first_found) + return -ENOMEM; } - - found = de; } - if (!found) + if (!first_found) return -ENOENT; - q = strjoina(p, "/", found->d_name, "/dev"); + q = strjoina(p, "/", first_found, "/dev"); r = read_one_line_file(q, &t); if (r < 0) diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 2634659aa..51aaee71f 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -91,7 +91,7 @@ int btrfs_is_subvol_fd(int fd) { if (fstat(fd, &st) < 0) return -errno; - if (!S_ISDIR(st.st_mode) || st.st_ino != 256) + if (!btrfs_might_be_subvol(&st)) return 0; return btrfs_is_filesystem(fd); @@ -194,7 +194,7 @@ int btrfs_subvol_set_read_only_fd(int fd, bool b) { if (fstat(fd, &st) < 0) return -errno; - if (!S_ISDIR(st.st_mode) || st.st_ino != 256) + if (!btrfs_might_be_subvol(&st)) return -EINVAL; if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0) @@ -229,7 +229,7 @@ int btrfs_subvol_get_read_only_fd(int fd) { if (fstat(fd, &st) < 0) return -errno; - if (!S_ISDIR(st.st_mode) || st.st_ino != 256) + if (!btrfs_might_be_subvol(&st)) return -EINVAL; if (ioctl(fd, BTRFS_IOC_SUBVOL_GETFLAGS, &flags) < 0) @@ -396,18 +396,18 @@ static bool btrfs_ioctl_search_args_inc(struct btrfs_ioctl_search_args *args) { * comparing. This call increases the counter by one, dealing * with the overflow between the overflows */ - if (args->key.min_offset < (uint64_t) -1) { + if (args->key.min_offset < UINT64_MAX) { args->key.min_offset++; return true; } - if (args->key.min_type < (uint8_t) -1) { + if (args->key.min_type < UINT8_MAX) { args->key.min_type++; args->key.min_offset = 0; return true; } - if (args->key.min_objectid < (uint64_t) -1) { + if (args->key.min_objectid < UINT64_MAX) { args->key.min_objectid++; args->key.min_offset = 0; args->key.min_type = 0; @@ -464,11 +464,11 @@ int btrfs_subvol_get_info_fd(int fd, uint64_t subvol_id, BtrfsSubvolInfo *ret) { .key.max_type = BTRFS_ROOT_ITEM_KEY, .key.min_offset = 0, - .key.max_offset = (uint64_t) -1, + .key.max_offset = UINT64_MAX, /* No restrictions on the other components */ .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; bool found = false; @@ -562,7 +562,7 @@ int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) { /* No restrictions on the other components */ .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; bool found_info = false, found_limit = false; @@ -624,12 +624,12 @@ int btrfs_qgroup_get_quota_fd(int fd, uint64_t qgroupid, BtrfsQuotaInfo *ret) { if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_RFER) ret->referenced_max = le64toh(qli->max_rfer); else - ret->referenced_max = (uint64_t) -1; + ret->referenced_max = UINT64_MAX; if (le64toh(qli->flags) & BTRFS_QGROUP_LIMIT_MAX_EXCL) ret->exclusive_max = le64toh(qli->max_excl); else - ret->exclusive_max = (uint64_t) -1; + ret->exclusive_max = UINT64_MAX; found_limit = true; } @@ -648,13 +648,13 @@ finish: return -ENODATA; if (!found_info) { - ret->referenced = (uint64_t) -1; - ret->exclusive = (uint64_t) -1; + ret->referenced = UINT64_MAX; + ret->exclusive = UINT64_MAX; } if (!found_limit) { - ret->referenced_max = (uint64_t) -1; - ret->exclusive_max = (uint64_t) -1; + ret->referenced_max = UINT64_MAX; + ret->exclusive_max = UINT64_MAX; } return 0; @@ -671,9 +671,9 @@ int btrfs_qgroup_get_quota(const char *path, uint64_t qgroupid, BtrfsQuotaInfo * } int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) { - uint64_t level, lowest = (uint64_t) -1, lowest_qgroupid = 0; + uint64_t level, lowest = UINT64_MAX, lowest_qgroupid = 0; _cleanup_free_ uint64_t *qgroups = NULL; - int r, n, i; + int r, n; assert(fd >= 0); assert(ret); @@ -703,7 +703,7 @@ int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) if (n < 0) return n; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { uint64_t id; r = btrfs_qgroupid_split(qgroups[i], &level, &id); @@ -713,13 +713,13 @@ int btrfs_subvol_find_subtree_qgroup(int fd, uint64_t subvol_id, uint64_t *ret) if (id != subvol_id) continue; - if (lowest == (uint64_t) -1 || level < lowest) { + if (lowest == UINT64_MAX || level < lowest) { lowest_qgroupid = qgroups[i]; lowest = level; } } - if (lowest == (uint64_t) -1) { + if (lowest == UINT64_MAX) { /* No suitable higher-level qgroup found, let's return * the leaf qgroup instead, and indicate that with the * return value. */ @@ -824,7 +824,6 @@ int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max .lim.max_rfer = referenced_max, .lim.flags = BTRFS_QGROUP_LIMIT_MAX_RFER, }; - unsigned c; int r; assert(fd >= 0); @@ -843,7 +842,7 @@ int btrfs_qgroup_set_limit_fd(int fd, uint64_t qgroupid, uint64_t referenced_max args.qgroupid = qgroupid; - for (c = 0;; c++) { + for (unsigned c = 0;; c++) { if (ioctl(fd, BTRFS_IOC_QGROUP_LIMIT, &args) < 0) { if (errno == EBUSY && c < 10) { @@ -924,7 +923,6 @@ static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) { .create = b, .qgroupid = qgroupid, }; - unsigned c; int r; r = btrfs_is_filesystem(fd); @@ -933,7 +931,7 @@ static int qgroup_create_or_destroy(int fd, bool b, uint64_t qgroupid) { if (r == 0) return -ENOTTY; - for (c = 0;; c++) { + for (unsigned c = 0;; c++) { if (ioctl(fd, BTRFS_IOC_QGROUP_CREATE, &args) < 0) { /* On old kernels if quota is not enabled, we get EINVAL. On newer kernels we get @@ -968,7 +966,7 @@ int btrfs_qgroup_destroy(int fd, uint64_t qgroupid) { int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) { _cleanup_free_ uint64_t *qgroups = NULL; uint64_t subvol_id; - int i, n, r; + int n, r; /* Destroys the specified qgroup, but unassigns it from all * its parents first. Also, it recursively destroys all @@ -983,7 +981,7 @@ int btrfs_qgroup_destroy_recursive(int fd, uint64_t qgroupid) { if (n < 0) return n; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { uint64_t id; r = btrfs_qgroupid_split(qgroups[i], NULL, &id); @@ -1043,7 +1041,6 @@ static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t pa .src = child, .dst = parent, }; - unsigned c; int r; r = btrfs_is_filesystem(fd); @@ -1052,7 +1049,7 @@ static int qgroup_assign_or_unassign(int fd, bool b, uint64_t child, uint64_t pa if (r == 0) return -ENOTTY; - for (c = 0;; c++) { + for (unsigned c = 0;; c++) { r = ioctl(fd, BTRFS_IOC_QGROUP_ASSIGN, &args); if (r < 0) { if (errno == EBUSY && c < 10) { @@ -1092,7 +1089,7 @@ static int subvol_remove_children(int fd, const char *subvolume, uint64_t subvol .key.max_type = BTRFS_ROOT_BACKREF_KEY, .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; struct btrfs_ioctl_vol_args vol_args = {}; @@ -1268,7 +1265,7 @@ int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupi /* No restrictions on the other components */ .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; int r; @@ -1351,7 +1348,7 @@ int btrfs_qgroup_copy_limits(int fd, uint64_t old_qgroupid, uint64_t new_qgroupi static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_subvol_id) { _cleanup_free_ uint64_t *old_qgroups = NULL, *old_parent_qgroups = NULL; bool copy_from_parent = false, insert_intermediary_qgroup = false; - int n_old_qgroups, n_old_parent_qgroups, r, i; + int n_old_qgroups, n_old_parent_qgroups, r; uint64_t old_parent_id; assert(fd >= 0); @@ -1375,9 +1372,8 @@ static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_sub return n_old_parent_qgroups; } - for (i = 0; i < n_old_qgroups; i++) { + for (int i = 0; i < n_old_qgroups; i++) { uint64_t id; - int j; r = btrfs_qgroupid_split(old_qgroups[i], NULL, &id); if (r < 0) @@ -1392,7 +1388,7 @@ static int copy_quota_hierarchy(int fd, uint64_t old_subvol_id, uint64_t new_sub break; } - for (j = 0; j < n_old_parent_qgroups; j++) + for (int j = 0; j < n_old_parent_qgroups; j++) if (old_parent_qgroups[j] == old_qgroups[i]) /* The old subvolume shared a common * parent qgroup with its parent @@ -1455,7 +1451,7 @@ static int subvol_snapshot_children( .key.max_type = BTRFS_ROOT_BACKREF_KEY, .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; struct btrfs_ioctl_vol_args_v2 vol_args = { @@ -1725,10 +1721,10 @@ int btrfs_qgroup_find_parents(int fd, uint64_t qgroupid, uint64_t **ret) { /* No restrictions on the other components */ .key.min_offset = 0, - .key.max_offset = (uint64_t) -1, + .key.max_offset = UINT64_MAX, .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; _cleanup_free_ uint64_t *items = NULL; @@ -1880,12 +1876,11 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed if (insert_intermediary_qgroup) { uint64_t lowest = 256, new_qgroupid; bool created = false; - int i; /* Determine the lowest qgroup that the parent * subvolume is assigned to. */ - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { uint64_t level; r = btrfs_qgroupid_split(qgroups[i], &level, NULL); @@ -1910,7 +1905,7 @@ int btrfs_subvol_auto_qgroup_fd(int fd, uint64_t subvol_id, bool insert_intermed if (r >= 0) changed = created = true; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { r = btrfs_qgroup_assign(fd, new_qgroupid, qgroups[i]); if (r < 0 && r != -EEXIST) { if (created) @@ -1970,10 +1965,10 @@ int btrfs_subvol_get_parent(int fd, uint64_t subvol_id, uint64_t *ret) { /* No restrictions on the other components */ .key.min_offset = 0, - .key.max_offset = (uint64_t) -1, + .key.max_offset = UINT64_MAX, .key.min_transid = 0, - .key.max_transid = (uint64_t) -1, + .key.max_transid = UINT64_MAX, }; int r; diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index c8b44f616..0f569b6f5 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -127,3 +127,13 @@ static inline int btrfs_log_dev_root(int level, int ret, const char *p) { "File system behind %s is reported by btrfs to be backed by pseudo-device /dev/root, which is not a valid userspace accessible device node. " "Cannot determine correct backing block device.", p); } + +static inline bool btrfs_might_be_subvol(const struct stat *st) { + if (!st) + return false; + + /* Returns true if this 'struct stat' looks like it could refer to a btrfs subvolume. To make a final + * decision, needs to be combined with an fstatfs() check to see if this is actually btrfs. */ + + return S_ISDIR(st->st_mode) && st->st_ino == 256; +} diff --git a/src/basic/build.c b/src/basic/build.c new file mode 100644 index 000000000..45074591a --- /dev/null +++ b/src/basic/build.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "build.h" + +const char* const systemd_features = + + /* PAM and MAC frameworks */ + +#if HAVE_PAM + "+PAM" +#else + "-PAM" +#endif + +#if HAVE_AUDIT + " +AUDIT" +#else + " -AUDIT" +#endif + +#if HAVE_SELINUX + " +SELINUX" +#else + " -SELINUX" +#endif + +#if HAVE_APPARMOR + " +APPARMOR" +#else + " -APPARMOR" +#endif + +#if ENABLE_IMA + " +IMA" +#else + " -IMA" +#endif + +#if ENABLE_SMACK + " +SMACK" +#else + " -SMACK" +#endif + +#if HAVE_SECCOMP + " +SECCOMP" +#else + " -SECCOMP" +#endif + + /* crypto libraries */ + +#if HAVE_GCRYPT + " +GCRYPT" +#else + " -GCRYPT" +#endif + +#if HAVE_GNUTLS + " +GNUTLS" +#else + " -GNUTLS" +#endif + +#if HAVE_OPENSSL + " +OPENSSL" +#else + " -OPENSSL" +#endif + + /* all other libraries, sorted alphabetically */ + +#if HAVE_ACL + " +ACL" +#else + " -ACL" +#endif + +#if HAVE_BLKID + " +BLKID" +#else + " -BLKID" +#endif + +#if HAVE_LIBCURL + " +CURL" +#else + " -CURL" +#endif + +#if HAVE_ELFUTILS + " +ELFUTILS" +#else + " -ELFUTILS" +#endif + +#if HAVE_LIBFIDO2 + " +FIDO2" +#else + " -FIDO2" +#endif + +#if HAVE_LIBIDN2 + " +IDN2" +#else + " -IDN2" +#endif + +#if HAVE_LIBIDN + " +IDN" +#else + " -IDN" +#endif + +#if HAVE_LIBIPTC + " +IPTC" +#else + " -IPTC" +#endif + +#if HAVE_KMOD + " +KMOD" +#else + " -KMOD" +#endif + +#if HAVE_LIBCRYPTSETUP + " +LIBCRYPTSETUP" +#else + " -LIBCRYPTSETUP" +#endif + +#if HAVE_LIBFDISK + " +LIBFDISK" +#else + " -LIBFDISK" +#endif + +#if HAVE_PCRE2 + " +PCRE2" +#else + " -PCRE2" +#endif + +#if HAVE_PWQUALITY + " +PWQUALITY" +#else + " -PWQUALITY" +#endif + +#if HAVE_P11KIT + " +P11KIT" +#else + " -P11KIT" +#endif + +#if HAVE_QRENCODE + " +QRENCODE" +#else + " -QRENCODE" +#endif + + /* compressors */ + +#if HAVE_BZIP2 + " +BZIP2" +#else + " -BZIP2" +#endif + +#if HAVE_LZ4 + " +LZ4" +#else + " -LZ4" +#endif + +#if HAVE_XZ + " +XZ" +#else + " -XZ" +#endif + +#if HAVE_ZLIB + " +ZLIB" +#else + " -ZLIB" +#endif + +#if HAVE_ZSTD + " +ZSTD" +#else + " -ZSTD" +#endif + + /* other stuff that doesn't fit above */ + +#if HAVE_XKBCOMMON + " +XKBCOMMON" +#else + " -XKBCOMMON" +#endif + +#if ENABLE_UTMP + " +UTMP" +#else + " -UTMP" +#endif + +#if HAVE_SYSV_COMPAT + " +SYSVINIT" +#else + " -SYSVINIT" +#endif + + " default-hierarchy=" DEFAULT_HIERARCHY_NAME + ; diff --git a/src/basic/build.h b/src/basic/build.h index 4697639ef..3de0d36cc 100644 --- a/src/basic/build.h +++ b/src/basic/build.h @@ -3,164 +3,7 @@ #include "version.h" -#if HAVE_PAM -#define _PAM_FEATURE_ "+PAM" -#else -#define _PAM_FEATURE_ "-PAM" -#endif - -#if HAVE_AUDIT -#define _AUDIT_FEATURE_ "+AUDIT" -#else -#define _AUDIT_FEATURE_ "-AUDIT" -#endif - -#if HAVE_SELINUX -#define _SELINUX_FEATURE_ "+SELINUX" -#else -#define _SELINUX_FEATURE_ "-SELINUX" -#endif - -#if HAVE_APPARMOR -#define _APPARMOR_FEATURE_ "+APPARMOR" -#else -#define _APPARMOR_FEATURE_ "-APPARMOR" -#endif - -#if ENABLE_IMA -#define _IMA_FEATURE_ "+IMA" -#else -#define _IMA_FEATURE_ "-IMA" -#endif - -#if ENABLE_SMACK -#define _SMACK_FEATURE_ "+SMACK" -#else -#define _SMACK_FEATURE_ "-SMACK" -#endif - -#if HAVE_SYSV_COMPAT -#define _SYSVINIT_FEATURE_ "+SYSVINIT" -#else -#define _SYSVINIT_FEATURE_ "-SYSVINIT" -#endif - -#if ENABLE_UTMP -#define _UTMP_FEATURE_ "+UTMP" -#else -#define _UTMP_FEATURE_ "-UTMP" -#endif - -#if HAVE_LIBCRYPTSETUP -#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP" -#else -#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP" -#endif - -#if HAVE_GCRYPT -#define _GCRYPT_FEATURE_ "+GCRYPT" -#else -#define _GCRYPT_FEATURE_ "-GCRYPT" -#endif - -#if HAVE_GNUTLS -#define _GNUTLS_FEATURE_ "+GNUTLS" -#else -#define _GNUTLS_FEATURE_ "-GNUTLS" -#endif - -#if HAVE_ACL -#define _ACL_FEATURE_ "+ACL" -#else -#define _ACL_FEATURE_ "-ACL" -#endif - -#if HAVE_XZ -#define _XZ_FEATURE_ "+XZ" -#else -#define _XZ_FEATURE_ "-XZ" -#endif - -#if HAVE_LZ4 -#define _LZ4_FEATURE_ "+LZ4" -#else -#define _LZ4_FEATURE_ "-LZ4" -#endif - -#if HAVE_ZSTD -#define _ZSTD_FEATURE_ "+ZSTD" -#else -#define _ZSTD_FEATURE_ "-ZSTD" -#endif - -#if HAVE_SECCOMP -#define _SECCOMP_FEATURE_ "+SECCOMP" -#else -#define _SECCOMP_FEATURE_ "-SECCOMP" -#endif - -#if HAVE_BLKID -#define _BLKID_FEATURE_ "+BLKID" -#else -#define _BLKID_FEATURE_ "-BLKID" -#endif - -#if HAVE_ELFUTILS -#define _ELFUTILS_FEATURE_ "+ELFUTILS" -#else -#define _ELFUTILS_FEATURE_ "-ELFUTILS" -#endif - -#if HAVE_KMOD -#define _KMOD_FEATURE_ "+KMOD" -#else -#define _KMOD_FEATURE_ "-KMOD" -#endif - -#if HAVE_LIBIDN2 -#define _IDN2_FEATURE_ "+IDN2" -#else -#define _IDN2_FEATURE_ "-IDN2" -#endif - -#if HAVE_LIBIDN -#define _IDN_FEATURE_ "+IDN" -#else -#define _IDN_FEATURE_ "-IDN" -#endif - -#if HAVE_PCRE2 -#define _PCRE2_FEATURE_ "+PCRE2" -#else -#define _PCRE2_FEATURE_ "-PCRE2" -#endif - -#define _CGROUP_HIERARCHY_ "default-hierarchy=" DEFAULT_HIERARCHY_NAME - -#define SYSTEMD_FEATURES \ - _PAM_FEATURE_ " " \ - _AUDIT_FEATURE_ " " \ - _SELINUX_FEATURE_ " " \ - _IMA_FEATURE_ " " \ - _APPARMOR_FEATURE_ " " \ - _SMACK_FEATURE_ " " \ - _SYSVINIT_FEATURE_ " " \ - _UTMP_FEATURE_ " " \ - _LIBCRYPTSETUP_FEATURE_ " " \ - _GCRYPT_FEATURE_ " " \ - _GNUTLS_FEATURE_ " " \ - _ACL_FEATURE_ " " \ - _XZ_FEATURE_ " " \ - _LZ4_FEATURE_ " " \ - _ZSTD_FEATURE_ " " \ - _SECCOMP_FEATURE_ " " \ - _BLKID_FEATURE_ " " \ - _ELFUTILS_FEATURE_ " " \ - _KMOD_FEATURE_ " " \ - _IDN2_FEATURE_ " " \ - _IDN_FEATURE_ " " \ - _PCRE2_FEATURE_ " " \ - _CGROUP_HIERARCHY_ +extern const char* const systemd_features; enum { BUILD_MODE_DEVELOPER, diff --git a/src/basic/cap-to-name.awk b/src/basic/cap-to-name.awk index 402a78202..bd8a28c2f 100644 --- a/src/basic/cap-to-name.awk +++ b/src/basic/cap-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "static const char* const capability_names[] = { " } diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index c1520d927..b31a9cb21 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -18,7 +18,7 @@ #include "util.h" int have_effective_cap(int value) { - _cleanup_cap_free_ cap_t cap; + _cleanup_cap_free_ cap_t cap = NULL; cap_flag_value_t fv; cap = cap_get_proc(); @@ -405,7 +405,7 @@ bool capability_quintet_mangle(CapabilityQuintet *q) { combined = q->effective | q->bounding | q->inheritable | q->permitted; - ambient_supported = q->ambient != (uint64_t) -1; + ambient_supported = q->ambient != UINT64_MAX; if (ambient_supported) combined |= q->ambient; @@ -437,7 +437,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { _cleanup_cap_free_ cap_t c = NULL, modified = NULL; int r; - if (q->ambient != (uint64_t) -1) { + if (q->ambient != UINT64_MAX) { bool changed = false; c = cap_get_proc(); @@ -479,7 +479,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { return r; } - if (q->inheritable != (uint64_t) -1 || q->permitted != (uint64_t) -1 || q->effective != (uint64_t) -1) { + if (q->inheritable != UINT64_MAX || q->permitted != UINT64_MAX || q->effective != UINT64_MAX) { bool changed = false; if (!c) { @@ -492,7 +492,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { uint64_t m = UINT64_C(1) << i; cap_value_t cv = (cap_value_t) i; - if (q->inheritable != (uint64_t) -1) { + if (q->inheritable != UINT64_MAX) { cap_flag_value_t old_value, new_value; if (cap_get_flag(c, cv, CAP_INHERITABLE, &old_value) < 0) { @@ -515,7 +515,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { } } - if (q->permitted != (uint64_t) -1) { + if (q->permitted != UINT64_MAX) { cap_flag_value_t old_value, new_value; if (cap_get_flag(c, cv, CAP_PERMITTED, &old_value) < 0) { @@ -535,7 +535,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { } } - if (q->effective != (uint64_t) -1) { + if (q->effective != UINT64_MAX) { cap_flag_value_t old_value, new_value; if (cap_get_flag(c, cv, CAP_EFFECTIVE, &old_value) < 0) { @@ -559,7 +559,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { if (changed) { /* In order to change the bounding caps, we need to keep CAP_SETPCAP for a bit * longer. Let's add it to our list hence for now. */ - if (q->bounding != (uint64_t) -1) { + if (q->bounding != UINT64_MAX) { cap_value_t cv = CAP_SETPCAP; modified = cap_dup(c); @@ -587,7 +587,7 @@ int capability_quintet_enforce(const CapabilityQuintet *q) { } } - if (q->bounding != (uint64_t) -1) { + if (q->bounding != UINT64_MAX) { r = capability_bounding_set_drop(q->bounding, false); if (r < 0) return r; diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index f5ce29052..dbce54531 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -10,7 +10,7 @@ #include "missing_capability.h" #include "util.h" -#define CAP_ALL (uint64_t) -1 +#define CAP_ALL UINT64_MAX unsigned cap_last_cap(void); int have_effective_cap(int value); @@ -25,7 +25,7 @@ int drop_privileges(uid_t uid, gid_t gid, uint64_t keep_capabilities); int drop_capability(cap_value_t cv); -DEFINE_TRIVIAL_CLEANUP_FUNC(cap_t, cap_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(cap_t, cap_free, NULL); #define _cleanup_cap_free_ _cleanup_(cap_freep) static inline void cap_free_charpp(char **p) { @@ -49,7 +49,7 @@ bool ambient_capabilities_supported(void); #define CAP_TO_MASK_CORRECTED(x) (1U << ((x) & 31U)) typedef struct CapabilityQuintet { - /* Stores all five types of capabilities in one go. Note that we use (uint64_t) -1 for unset here. This hence + /* Stores all five types of capabilities in one go. Note that we use UINT64_MAX for unset here. This hence * needs to be updated as soon as Linux learns more than 63 caps. */ uint64_t effective; uint64_t bounding; @@ -60,14 +60,14 @@ typedef struct CapabilityQuintet { assert_cc(CAP_LAST_CAP < 64); -#define CAPABILITY_QUINTET_NULL { (uint64_t) -1, (uint64_t) -1, (uint64_t) -1, (uint64_t) -1, (uint64_t) -1 } +#define CAPABILITY_QUINTET_NULL { UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX } static inline bool capability_quintet_is_set(const CapabilityQuintet *q) { - return q->effective != (uint64_t) -1 || - q->bounding != (uint64_t) -1 || - q->inheritable != (uint64_t) -1 || - q->permitted != (uint64_t) -1 || - q->ambient != (uint64_t) -1; + return q->effective != UINT64_MAX || + q->bounding != UINT64_MAX || + q->inheritable != UINT64_MAX || + q->permitted != UINT64_MAX || + q->ambient != UINT64_MAX; } /* Mangles the specified caps quintet taking the current bounding set into account: diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index f28bf1866..8dd3f8cd9 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -100,7 +100,7 @@ int cg_read_event( if (r < 0) return r; - r = read_full_file(events, &content, NULL); + r = read_full_virtual_file(events, &content, NULL); if (r < 0) return r; @@ -527,41 +527,20 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch return 0; } -static int controller_is_accessible(const char *controller) { - int r; +static int controller_is_v1_accessible(const char *root, const char *controller) { + const char *cpath, *dn; assert(controller); - /* Checks whether a specific controller is accessible, - * i.e. its hierarchy mounted. In the unified hierarchy all - * controllers are considered accessible, except for the named - * hierarchies */ + dn = controller_to_dirname(controller); - if (!cg_controller_is_valid(controller)) - return -EINVAL; + /* If root if specified, we check that: + * - possible subcgroup is created at root, + * - we can modify the hierarchy. */ - r = cg_all_unified(); - if (r < 0) - return r; - if (r > 0) { - /* We don't support named hierarchies if we are using - * the unified hierarchy. */ - - if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) - return 0; - - if (startswith(controller, "name=")) - return -EOPNOTSUPP; - - } else { - const char *cc, *dn; - - dn = controller_to_dirname(controller); - cc = strjoina("/sys/fs/cgroup/", dn); - - if (laccess(cc, F_OK) < 0) - return -errno; - } + cpath = strjoina("/sys/fs/cgroup/", dn, root, root ? "/cgroup.procs" : NULL); + if (laccess(cpath, root ? W_OK : F_OK) < 0) + return -errno; return 0; } @@ -572,10 +551,23 @@ int cg_get_path_and_check(const char *controller, const char *path, const char * assert(controller); assert(fs); - /* Check if the specified controller is actually accessible */ - r = controller_is_accessible(controller); + if (!cg_controller_is_valid(controller)) + return -EINVAL; + + r = cg_all_unified(); if (r < 0) return r; + if (r > 0) { + /* In the unified hierarchy all controllers are considered accessible, + * except for the named hierarchies */ + if (startswith(controller, "name=")) + return -EOPNOTSUPP; + } else { + /* Check if the specified controller is actually accessible */ + r = controller_is_v1_accessible(NULL, controller); + if (r < 0) + return r; + } return cg_get_path(controller, path, suffix, fs); } @@ -635,6 +627,20 @@ int cg_get_xattr_malloc(const char *controller, const char *path, const char *na return r; } +int cg_get_xattr_bool(const char *controller, const char *path, const char *name) { + _cleanup_free_ char *val = NULL; + int r; + + assert(path); + assert(name); + + r = cg_get_xattr_malloc(controller, path, name, &val); + if (r < 0) + return r; + + return parse_boolean(val); +} + int cg_remove_xattr(const char *controller, const char *path, const char *name) { _cleanup_free_ char *fs = NULL; int r; @@ -1131,8 +1137,8 @@ static const char *skip_slices(const char *p) { } int cg_path_get_unit(const char *path, char **ret) { + _cleanup_free_ char *unit = NULL; const char *e; - char *unit; int r; assert(path); @@ -1145,12 +1151,10 @@ int cg_path_get_unit(const char *path, char **ret) { return r; /* We skipped over the slices, don't accept any now */ - if (endswith(unit, ".slice")) { - free(unit); + if (endswith(unit, ".slice")) return -ENXIO; - } - *ret = unit; + *ret = TAKE_PTR(unit); return 0; } @@ -1555,7 +1559,7 @@ bool cg_controller_is_valid(const char *p) { if (!strchr(CONTROLLER_VALID, *t)) return false; - if (t - p > FILENAME_MAX) + if (t - p > NAME_MAX) return false; return true; @@ -1619,7 +1623,7 @@ int cg_slice_to_path(const char *unit, char **ret) { if (!escaped) return -ENOMEM; - if (!strextend(&s, escaped, "/", NULL)) + if (!strextend(&s, escaped, "/")) return -ENOMEM; dash = strchr(dash+1, '-'); @@ -1629,7 +1633,7 @@ int cg_slice_to_path(const char *unit, char **ret) { if (!e) return -ENOMEM; - if (!strextend(&s, e, NULL)) + if (!strextend(&s, e)) return -ENOMEM; *ret = TAKE_PTR(s); @@ -1705,6 +1709,25 @@ int cg_get_attribute_as_bool(const char *controller, const char *path, const cha return 0; } +int cg_get_owner(const char *controller, const char *path, uid_t *ret_uid) { + _cleanup_free_ char *f = NULL; + struct stat stats; + int r; + + assert(ret_uid); + + r = cg_get_path(controller, path, NULL, &f); + if (r < 0) + return r; + + r = stat(f, &stats); + if (r < 0) + return -errno; + + *ret_uid = stats.st_uid; + return 0; +} + int cg_get_keyed_attribute_full( const char *controller, const char *path, @@ -1861,7 +1884,7 @@ int cg_mask_from_string(const char *value, CGroupMask *ret) { return 0; } -int cg_mask_supported(CGroupMask *ret) { +int cg_mask_supported_subtree(const char *root, CGroupMask *ret) { CGroupMask mask; int r; @@ -1873,15 +1896,11 @@ int cg_mask_supported(CGroupMask *ret) { if (r < 0) return r; if (r > 0) { - _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL; + _cleanup_free_ char *controllers = NULL, *path = NULL; /* In the unified hierarchy we can read the supported and accessible controllers from * the top-level cgroup attribute */ - r = cg_get_root_path(&root); - if (r < 0) - return r; - r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path); if (r < 0) return r; @@ -1900,7 +1919,7 @@ int cg_mask_supported(CGroupMask *ret) { } else { CGroupController c; - /* In the legacy hierarchy, we check which hierarchies are mounted. */ + /* In the legacy hierarchy, we check which hierarchies are accessible. */ mask = 0; for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { @@ -1911,7 +1930,7 @@ int cg_mask_supported(CGroupMask *ret) { continue; n = cgroup_controller_to_string(c); - if (controller_is_accessible(n) >= 0) + if (controller_is_v1_accessible(root, n) >= 0) mask |= bit; } } @@ -1920,6 +1939,17 @@ int cg_mask_supported(CGroupMask *ret) { return 0; } +int cg_mask_supported(CGroupMask *ret) { + _cleanup_free_ char *root = NULL; + int r; + + r = cg_get_root_path(&root); + if (r < 0) + return r; + + return cg_mask_supported_subtree(root, ret); +} + int cg_kernel_controllers(Set **ret) { _cleanup_set_free_free_ Set *controllers = NULL; _cleanup_fclose_ FILE *f = NULL; @@ -1944,7 +1974,7 @@ int cg_kernel_controllers(Set **ret) { return r; /* Ignore the header line */ - (void) read_line(f, (size_t) -1, NULL); + (void) read_line(f, SIZE_MAX, NULL); for (;;) { char *controller; @@ -2022,8 +2052,14 @@ int cg_unified_cached(bool flush) { unified_cache = CGROUP_UNIFIED_SYSTEMD; unified_systemd_v232 = false; } else { - if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0) + if (statfs("/sys/fs/cgroup/systemd/", &fs) < 0) { + if (errno == ENOENT) { + /* Some other software may have set up /sys/fs/cgroup in a configuration we do not recognize. */ + log_debug_errno(errno, "Unsupported cgroupsv1 setup detected: name=systemd hierarchy not found."); + return -ENOMEDIUM; + } return log_debug_errno(errno, "statfs(\"/sys/fs/cgroup/systemd\" failed: %m"); + } if (F_TYPE_EQUAL(fs.f_type, CGROUP2_SUPER_MAGIC)) { log_debug("Found cgroup2 on /sys/fs/cgroup/systemd, unified hierarchy for systemd controller (v232 variant)"); @@ -2166,7 +2202,7 @@ CGroupMask get_cpu_accounting_mask(void) { struct utsname u; assert_se(uname(&u) >= 0); - if (str_verscmp(u.release, "4.15") < 0) + if (strverscmp_improved(u.release, "4.15") < 0) needed_mask = CGROUP_MASK_CPU; else needed_mask = 0; @@ -2187,3 +2223,11 @@ static const char* const managed_oom_mode_table[_MANAGED_OOM_MODE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(managed_oom_mode, ManagedOOMMode); + +static const char* const managed_oom_preference_table[_MANAGED_OOM_PREFERENCE_MAX] = { + [MANAGED_OOM_PREFERENCE_NONE] = "none", + [MANAGED_OOM_PREFERENCE_AVOID] = "avoid", + [MANAGED_OOM_PREFERENCE_OMIT] = "omit", +}; + +DEFINE_STRING_TABLE_LOOKUP(managed_oom_preference, ManagedOOMPreference); diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index bdc0d0d08..f79e38414 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -32,7 +32,7 @@ typedef enum CGroupController { CGROUP_CONTROLLER_BPF_DEVICES, _CGROUP_CONTROLLER_MAX, - _CGROUP_CONTROLLER_INVALID = -1, + _CGROUP_CONTROLLER_INVALID = -EINVAL, } CGroupController; #define CGROUP_CONTROLLER_TO_MASK(c) (1U << (c)) @@ -75,13 +75,13 @@ CGroupMask get_cpu_accounting_mask(void); bool cpu_accounting_is_cheap(void); /* Special values for all weight knobs on unified hierarchy */ -#define CGROUP_WEIGHT_INVALID ((uint64_t) -1) +#define CGROUP_WEIGHT_INVALID UINT64_MAX #define CGROUP_WEIGHT_MIN UINT64_C(1) #define CGROUP_WEIGHT_MAX UINT64_C(10000) #define CGROUP_WEIGHT_DEFAULT UINT64_C(100) #define CGROUP_LIMIT_MIN UINT64_C(0) -#define CGROUP_LIMIT_MAX ((uint64_t) -1) +#define CGROUP_LIMIT_MAX UINT64_MAX static inline bool CGROUP_WEIGHT_IS_OK(uint64_t x) { return @@ -97,7 +97,7 @@ typedef enum CGroupIOLimitType { CGROUP_IO_WIOPS_MAX, _CGROUP_IO_LIMIT_TYPE_MAX, - _CGROUP_IO_LIMIT_TYPE_INVALID = -1 + _CGROUP_IO_LIMIT_TYPE_INVALID = -EINVAL, } CGroupIOLimitType; extern const uint64_t cgroup_io_limit_defaults[_CGROUP_IO_LIMIT_TYPE_MAX]; @@ -106,7 +106,7 @@ const char* cgroup_io_limit_type_to_string(CGroupIOLimitType t) _const_; CGroupIOLimitType cgroup_io_limit_type_from_string(const char *s) _pure_; /* Special values for the cpu.shares attribute */ -#define CGROUP_CPU_SHARES_INVALID ((uint64_t) -1) +#define CGROUP_CPU_SHARES_INVALID UINT64_MAX #define CGROUP_CPU_SHARES_MIN UINT64_C(2) #define CGROUP_CPU_SHARES_MAX UINT64_C(262144) #define CGROUP_CPU_SHARES_DEFAULT UINT64_C(1024) @@ -118,7 +118,7 @@ static inline bool CGROUP_CPU_SHARES_IS_OK(uint64_t x) { } /* Special values for the blkio.weight attribute */ -#define CGROUP_BLKIO_WEIGHT_INVALID ((uint64_t) -1) +#define CGROUP_BLKIO_WEIGHT_INVALID UINT64_MAX #define CGROUP_BLKIO_WEIGHT_MIN UINT64_C(10) #define CGROUP_BLKIO_WEIGHT_MAX UINT64_C(1000) #define CGROUP_BLKIO_WEIGHT_DEFAULT UINT64_C(500) @@ -212,10 +212,13 @@ int cg_get_attribute_as_uint64(const char *controller, const char *path, const c int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret); int cg_set_access(const char *controller, const char *path, uid_t uid, gid_t gid); +int cg_get_owner(const char *controller, const char *path, uid_t *ret_uid); int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags); int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size); int cg_get_xattr_malloc(const char *controller, const char *path, const char *name, char **ret); +/* Returns negative on error, and 0 or 1 on success for the bool value */ +int cg_get_xattr_bool(const char *controller, const char *path, const char *name); int cg_remove_xattr(const char *controller, const char *path, const char *name); int cg_install_release_agent(const char *controller, const char *agent); @@ -257,6 +260,7 @@ int cg_slice_to_path(const char *unit, char **ret); typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata); int cg_mask_supported(CGroupMask *ret); +int cg_mask_supported_subtree(const char *root, CGroupMask *ret); int cg_mask_from_string(const char *s, CGroupMask *ret); int cg_mask_to_string(CGroupMask mask, char **ret); @@ -283,8 +287,19 @@ typedef enum ManagedOOMMode { MANAGED_OOM_AUTO, MANAGED_OOM_KILL, _MANAGED_OOM_MODE_MAX, - _MANAGED_OOM_MODE_INVALID = -1, + _MANAGED_OOM_MODE_INVALID = -EINVAL, } ManagedOOMMode; const char* managed_oom_mode_to_string(ManagedOOMMode m) _const_; ManagedOOMMode managed_oom_mode_from_string(const char *s) _pure_; + +typedef enum ManagedOOMPreference { + MANAGED_OOM_PREFERENCE_NONE = 0, + MANAGED_OOM_PREFERENCE_AVOID = 1, + MANAGED_OOM_PREFERENCE_OMIT = 2, + _MANAGED_OOM_PREFERENCE_MAX, + _MANAGED_OOM_PREFERENCE_INVALID = -EINVAL, +} ManagedOOMPreference; + +const char* managed_oom_preference_to_string(ManagedOOMPreference a) _const_; +ManagedOOMPreference managed_oom_preference_from_string(const char *s) _pure_; diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c index c724e1768..10e59875a 100644 --- a/src/basic/chattr-util.c +++ b/src/basic/chattr-util.c @@ -10,25 +10,31 @@ #include "fd-util.h" #include "macro.h" -int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { +int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, bool fallback) { + _cleanup_close_ int fd_will_close = -1; unsigned old_attr, new_attr; struct stat st; - assert(fd >= 0); + assert(path || fd >= 0); + + if (fd < 0) { + fd = fd_will_close = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); + if (fd < 0) + return -errno; + } if (fstat(fd, &st) < 0) return -errno; - /* Explicitly check whether this is a regular file or - * directory. If it is anything else (such as a device node or - * fifo), then the ioctl will not hit the file systems but - * possibly drivers, where the ioctl might have different - * effects. Notably, DRM is using the same ioctl() number. */ + /* Explicitly check whether this is a regular file or directory. If it is anything else (such + * as a device node or fifo), then the ioctl will not hit the file systems but possibly + * drivers, where the ioctl might have different effects. Notably, DRM is using the same + * ioctl() number. */ if (!S_ISDIR(st.st_mode) && !S_ISREG(st.st_mode)) return -ENOTTY; - if (mask == 0 && !previous) + if (mask == 0 && !ret_previous && !ret_final) return 0; if (ioctl(fd, FS_IOC_GETFLAGS, &old_attr) < 0) @@ -36,33 +42,55 @@ int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { new_attr = (old_attr & ~mask) | (value & mask); if (new_attr == old_attr) { - if (previous) - *previous = old_attr; + if (ret_previous) + *ret_previous = old_attr; + if (ret_final) + *ret_final = old_attr; return 0; } - if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) < 0) + if (ioctl(fd, FS_IOC_SETFLAGS, &new_attr) >= 0) { + if (ret_previous) + *ret_previous = old_attr; + if (ret_final) + *ret_final = new_attr; + return 1; + } + + if (errno != EINVAL || !fallback) return -errno; - if (previous) - *previous = old_attr; + /* When -EINVAL is returned, we assume that incompatible attributes are simultaneously + * specified. E.g., compress(c) and nocow(C) attributes cannot be set to files on btrfs. + * As a fallback, let's try to set attributes one by one. */ - return 1; -} + unsigned current_attr = old_attr; + for (unsigned i = 0; i < sizeof(unsigned) * 8; i++) { + unsigned new_one, mask_one = 1u << i; -int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous) { - _cleanup_close_ int fd = -1; + if (!FLAGS_SET(mask, mask_one)) + continue; - assert(p); + new_one = UPDATE_FLAG(current_attr, mask_one, FLAGS_SET(value, mask_one)); + if (new_one == current_attr) + continue; - if (mask == 0) - return 0; + if (ioctl(fd, FS_IOC_SETFLAGS, &new_one) < 0) { + if (errno != EINVAL) + return -errno; + continue; + } - fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW); - if (fd < 0) - return -errno; + if (ioctl(fd, FS_IOC_GETFLAGS, ¤t_attr) < 0) + return -errno; + } - return chattr_fd(fd, value, mask, previous); + if (ret_previous) + *ret_previous = old_attr; + if (ret_final) + *ret_final = current_attr; + + return current_attr == new_attr ? 1 : -ENOANO; /* -ENOANO indicates that some attributes cannot be set. */ } int read_attr_fd(int fd, unsigned *ret) { diff --git a/src/basic/chattr-util.h b/src/basic/chattr-util.h index 2fcdb6443..3f46367c8 100644 --- a/src/basic/chattr-util.h +++ b/src/basic/chattr-util.h @@ -2,6 +2,8 @@ #pragma once #include +#include +#include #include "missing_fs.h" @@ -32,8 +34,13 @@ FS_NOCOW_FL | \ FS_PROJINHERIT_FL) -int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous); -int chattr_path(const char *p, unsigned value, unsigned mask, unsigned *previous); +int chattr_full(const char *path, int fd, unsigned value, unsigned mask, unsigned *ret_previous, unsigned *ret_final, bool fallback); +static inline int chattr_fd(int fd, unsigned value, unsigned mask, unsigned *previous) { + return chattr_full(NULL, fd, value, mask, previous, NULL, false); +} +static inline int chattr_path(const char *path, unsigned value, unsigned mask, unsigned *previous) { + return chattr_full(path, -1, value, mask, previous, NULL, false); +} int read_attr_fd(int fd, unsigned *ret); int read_attr_path(const char *p, unsigned *ret); diff --git a/src/basic/copy.c b/src/basic/copy.c index 6a9c3a396..d25777cc4 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -112,7 +112,7 @@ int copy_bytes_full( copy_progress_bytes_t progress, void *userdata) { - bool try_cfr = true, try_sendfile = true, try_splice = true; + bool try_cfr = true, try_sendfile = true, try_splice = true, copied_something = false; int r, nonblock_pipe = -1; size_t m = SSIZE_MAX; /* that is the maximum that sendfile and c_f_r accept */ @@ -211,9 +211,20 @@ int copy_bytes_full( try_cfr = false; /* use fallback below */ - } else if (n == 0) /* EOF */ - break; - else + } else if (n == 0) { /* likely EOF */ + + if (copied_something) + break; + + /* So, we hit EOF immediately, without having copied a single byte. This + * could indicate two things: the file is actually empty, or we are on some + * virtual file system such as procfs/sysfs where the syscall actually + * doesn't work but doesn't return an error. Try to handle that, by falling + * back to simple read()s in case we encounter empty files. + * + * See: https://lwn.net/Articles/846403/ */ + try_cfr = try_sendfile = try_splice = false; + } else /* Success! */ goto next; } @@ -227,9 +238,14 @@ int copy_bytes_full( try_sendfile = false; /* use fallback below */ - } else if (n == 0) /* EOF */ + } else if (n == 0) { /* likely EOF */ + + if (copied_something) + break; + + try_sendfile = try_splice = false; /* same logic as above for copy_file_range() */ break; - else + } else /* Success! */ goto next; } @@ -239,14 +255,14 @@ int copy_bytes_full( /* splice()'s asynchronous I/O support is a bit weird. When it encounters a pipe file * descriptor, then it will ignore its O_NONBLOCK flag and instead only honour the - * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour here, and - * check if either of the specified fds are a pipe, and if so, let's pass the flag - * automatically, depending on O_NONBLOCK being set. + * SPLICE_F_NONBLOCK flag specified in its flag parameter. Let's hide this behaviour + * here, and check if either of the specified fds are a pipe, and if so, let's pass + * the flag automatically, depending on O_NONBLOCK being set. * - * Here's a twist though: when we use it to move data between two pipes of which one has - * O_NONBLOCK set and the other has not, then we have no individual control over O_NONBLOCK - * behaviour. Hence in that case we can't use splice() and still guarantee systematic - * O_NONBLOCK behaviour, hence don't. */ + * Here's a twist though: when we use it to move data between two pipes of which one + * has O_NONBLOCK set and the other has not, then we have no individual control over + * O_NONBLOCK behaviour. Hence in that case we can't use splice() and still guarantee + * systematic O_NONBLOCK behaviour, hence don't. */ if (nonblock_pipe < 0) { int a, b; @@ -264,12 +280,13 @@ int copy_bytes_full( (a == FD_IS_BLOCKING_PIPE && b == FD_IS_NONBLOCKING_PIPE) || (a == FD_IS_NONBLOCKING_PIPE && b == FD_IS_BLOCKING_PIPE)) - /* splice() only works if one of the fds is a pipe. If neither is, let's skip - * this step right-away. As mentioned above, if one of the two fds refers to a - * blocking pipe and the other to a non-blocking pipe, we can't use splice() - * either, hence don't try either. This hence means we can only use splice() if - * either only one of the two fds is a pipe, or if both are pipes with the same - * nonblocking flag setting. */ + /* splice() only works if one of the fds is a pipe. If neither is, + * let's skip this step right-away. As mentioned above, if one of the + * two fds refers to a blocking pipe and the other to a non-blocking + * pipe, we can't use splice() either, hence don't try either. This + * hence means we can only use splice() if either only one of the two + * fds is a pipe, or if both are pipes with the same nonblocking flag + * setting. */ try_splice = false; else @@ -285,9 +302,13 @@ int copy_bytes_full( try_splice = false; /* use fallback below */ - } else if (n == 0) /* EOF */ - break; - else + } else if (n == 0) { /* likely EOF */ + + if (copied_something) + break; + + try_splice = false; /* same logic as above for copy_file_range() + sendfile() */ + } else /* Success! */ goto next; } @@ -340,16 +361,17 @@ int copy_bytes_full( return r; } - if (max_bytes != (uint64_t) -1) { + if (max_bytes != UINT64_MAX) { assert(max_bytes >= (uint64_t) n); max_bytes -= n; } - /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, - * so reduce our maximum by the amount we already copied, - * but don't go below our copy buffer size, unless we are - * close the limit of bytes we are allowed to copy. */ + /* sendfile accepts at most SSIZE_MAX-offset bytes to copy, so reduce our maximum by the + * amount we already copied, but don't go below our copy buffer size, unless we are close the + * limit of bytes we are allowed to copy. */ m = MAX(MIN(COPY_BUFFER_SIZE, max_bytes), m - n); + + copied_something = true; } return 0; /* return 0 if we hit EOF earlier than the size limit */ @@ -391,9 +413,10 @@ static int fd_copy_symlink( uid_is_valid(override_uid) ? override_uid : st->st_uid, gid_is_valid(override_gid) ? override_gid : st->st_gid, AT_SYMLINK_NOFOLLOW) < 0) - return -errno; + r = -errno; - return 0; + (void) utimensat(dt, to, (struct timespec[]) { st->st_atim, st->st_mtim }, AT_SYMLINK_NOFOLLOW); + return r; } /* Encapsulates the database we store potential hardlink targets in */ @@ -592,7 +615,6 @@ static int fd_copy_regular( void *userdata) { _cleanup_close_ int fdf = -1, fdt = -1; - struct timespec ts[2]; int r, q; assert(from); @@ -620,7 +642,7 @@ static int fd_copy_regular( if (fdt < 0) return -errno; - r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress, userdata); + r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress, userdata); if (r < 0) { (void) unlinkat(dt, to, 0); return r; @@ -634,9 +656,7 @@ static int fd_copy_regular( if (fchmod(fdt, st->st_mode & 07777) < 0) r = -errno; - ts[0] = st->st_atim; - ts[1] = st->st_mtim; - (void) futimens(fdt, ts); + (void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim }); (void) copy_xattr(fdf, fdt); q = close(fdt); @@ -693,6 +713,8 @@ static int fd_copy_fifo( if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) r = -errno; + (void) utimensat(dt, to, (struct timespec[]) { st->st_atim, st->st_mtim }, AT_SYMLINK_NOFOLLOW); + (void) memorize_hardlink(hardlink_context, st, dt, to); return r; } @@ -739,6 +761,8 @@ static int fd_copy_node( if (fchmodat(dt, to, st->st_mode & 07777, 0) < 0) r = -errno; + (void) utimensat(dt, to, (struct timespec[]) { st->st_atim, st->st_mtim }, AT_SYMLINK_NOFOLLOW); + (void) memorize_hardlink(hardlink_context, st, dt, to); return r; } @@ -913,11 +937,6 @@ static int fd_copy_directory( } if (created) { - struct timespec ut[2] = { - st->st_atim, - st->st_mtim - }; - if (fchown(fdt, uid_is_valid(override_uid) ? override_uid : st->st_uid, gid_is_valid(override_gid) ? override_gid : st->st_gid) < 0) @@ -927,7 +946,7 @@ static int fd_copy_directory( r = -errno; (void) copy_xattr(dirfd(d), fdt); - (void) futimens(fdt, ut); + (void) futimens(fdt, (struct timespec[]) { st->st_atim, st->st_mtim }); } return r; @@ -976,6 +995,7 @@ int copy_directory_fd_full( void *userdata) { struct stat st; + int r; assert(dirfd >= 0); assert(to); @@ -983,8 +1003,9 @@ int copy_directory_fd_full( if (fstat(dirfd, &st) < 0) return -errno; - if (!S_ISDIR(st.st_mode)) - return -ENOTDIR; + r = stat_verify_directory(&st); + if (r < 0) + return r; return fd_copy_directory(dirfd, NULL, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata); } @@ -998,6 +1019,7 @@ int copy_directory_full( void *userdata) { struct stat st; + int r; assert(from); assert(to); @@ -1005,8 +1027,9 @@ int copy_directory_full( if (lstat(from, &st) < 0) return -errno; - if (!S_ISDIR(st.st_mode)) - return -ENOTDIR; + r = stat_verify_directory(&st); + if (r < 0) + return r; return fd_copy_directory(AT_FDCWD, from, &st, AT_FDCWD, to, st.st_dev, COPY_DEPTH_MAX, UID_INVALID, GID_INVALID, copy_flags, NULL, NULL, progress_path, progress_bytes, userdata); } @@ -1028,7 +1051,7 @@ int copy_file_fd_full( if (fdf < 0) return -errno; - r = copy_bytes_full(fdf, fdt, (uint64_t) -1, copy_flags, NULL, NULL, progress_bytes, userdata); + r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata); (void) copy_times(fdf, fdt, copy_flags); (void) copy_xattr(fdf, fdt); @@ -1047,18 +1070,29 @@ int copy_file_full( copy_progress_bytes_t progress_bytes, void *userdata) { + _cleanup_close_ int fdf = -1; + struct stat st; int fdt = -1, r; assert(from); assert(to); + fdf = open(from, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fdf < 0) + return -errno; + + if (mode == MODE_INVALID) + if (fstat(fdf, &st) < 0) + return -errno; + RUN_WITH_UMASK(0000) { if (copy_flags & COPY_MAC_CREATE) { r = mac_selinux_create_file_prepare(to, S_IFREG); if (r < 0) return r; } - fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode); + fdt = open(to, flags|O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, + mode != MODE_INVALID ? mode : st.st_mode); if (copy_flags & COPY_MAC_CREATE) mac_selinux_create_file_clear(); if (fdt < 0) @@ -1068,13 +1102,16 @@ int copy_file_full( if (chattr_mask != 0) (void) chattr_fd(fdt, chattr_flags, chattr_mask & CHATTR_EARLY_FL, NULL); - r = copy_file_fd_full(from, fdt, copy_flags, progress_bytes, userdata); + r = copy_bytes_full(fdf, fdt, UINT64_MAX, copy_flags, NULL, NULL, progress_bytes, userdata); if (r < 0) { close(fdt); (void) unlink(to); return r; } + (void) copy_times(fdf, fdt, copy_flags); + (void) copy_xattr(fdf, fdt); + if (chattr_mask != 0) (void) chattr_fd(fdt, chattr_flags, chattr_mask & ~CHATTR_EARLY_FL, NULL); @@ -1110,24 +1147,24 @@ int copy_file_atomic_full( * writing it. */ if (copy_flags & COPY_REPLACE) { - r = tempfn_random(to, NULL, &t); + _cleanup_free_ char *f = NULL; + + r = tempfn_random(to, NULL, &f); if (r < 0) return r; if (copy_flags & COPY_MAC_CREATE) { r = mac_selinux_create_file_prepare(to, S_IFREG); - if (r < 0) { - t = mfree(t); + if (r < 0) return r; - } } - fdt = open(t, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600); + fdt = open(f, O_CREAT|O_EXCL|O_NOFOLLOW|O_NOCTTY|O_WRONLY|O_CLOEXEC, 0600); if (copy_flags & COPY_MAC_CREATE) mac_selinux_create_file_clear(); - if (fdt < 0) { - t = mfree(t); + if (fdt < 0) return -errno; - } + + t = TAKE_PTR(f); } else { if (copy_flags & COPY_MAC_CREATE) { r = mac_selinux_create_file_prepare(to, S_IFREG); @@ -1168,7 +1205,6 @@ int copy_file_atomic_full( } int copy_times(int fdf, int fdt, CopyFlags flags) { - struct timespec ut[2]; struct stat st; assert(fdf >= 0); @@ -1177,10 +1213,7 @@ int copy_times(int fdf, int fdt, CopyFlags flags) { if (fstat(fdf, &st) < 0) return -errno; - ut[0] = st.st_atim; - ut[1] = st.st_mtim; - - if (futimens(fdt, ut) < 0) + if (futimens(fdt, (struct timespec[2]) { st.st_atim, st.st_mtim }) < 0) return -errno; if (FLAGS_SET(flags, COPY_CRTIME)) { @@ -1199,6 +1232,8 @@ int copy_access(int fdf, int fdt) { assert(fdf >= 0); assert(fdt >= 0); + /* Copies just the access mode (and not the ownership) from fdf to fdt */ + if (fstat(fdf, &st) < 0) return -errno; @@ -1208,6 +1243,20 @@ int copy_access(int fdf, int fdt) { return 0; } +int copy_rights(int fdf, int fdt) { + struct stat st; + + assert(fdf >= 0); + assert(fdt >= 0); + + /* Copies both access mode and ownership from fdf to fdt */ + + if (fstat(fdf, &st) < 0) + return -errno; + + return fchmod_and_chown(fdt, st.st_mode & 07777, st.st_uid, st.st_gid); +} + int copy_xattr(int fdf, int fdt) { _cleanup_free_ char *names = NULL; int ret = 0, r; diff --git a/src/basic/copy.h b/src/basic/copy.h index b583dff2c..da3ba07ad 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -64,4 +64,5 @@ static inline int copy_bytes(int fdf, int fdt, uint64_t max_bytes, CopyFlags cop int copy_times(int fdf, int fdt, CopyFlags flags); int copy_access(int fdf, int fdt); +int copy_rights(int fdf, int fdt); int copy_xattr(int fdf, int fdt); diff --git a/src/basic/device-nodes.c b/src/basic/device-nodes.c index 7eb9c351b..158ab738e 100644 --- a/src/basic/device-nodes.c +++ b/src/basic/device-nodes.c @@ -28,7 +28,7 @@ int encode_devnode_name(const char *str, char *str_enc, size_t len) { for (i = 0, j = 0; str[i] != '\0'; i++) { int seqlen; - seqlen = utf8_encoded_valid_unichar(str + i, (size_t) -1); + seqlen = utf8_encoded_valid_unichar(str + i, SIZE_MAX); if (seqlen > 1) { if (len-j < (size_t)seqlen) diff --git a/src/basic/dlfcn-util.h b/src/basic/dlfcn-util.h index 2c94ed51f..aa713d328 100644 --- a/src/basic/dlfcn-util.h +++ b/src/basic/dlfcn-util.h @@ -5,6 +5,12 @@ #include "macro.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(void*, dlclose); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(void*, dlclose, NULL); int dlsym_many_and_warn(void *dl, int level, ...); + +/* Macro useful for putting together variable/symbol name pairs when calling dlsym_many_and_warn(). Assumes + * that each library symbol to resolve will be placed in a variable with the "sym_" prefix, i.e. a symbol + * "foobar" is loaded into a variable "sym_foobar". */ +#define DLSYM_ARG(arg) \ + &sym_##arg, STRINGIFY(arg) diff --git a/src/basic/dns-def.h b/src/basic/dns-def.h new file mode 100644 index 000000000..d70220bcc --- /dev/null +++ b/src/basic/dns-def.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */ +#define DNS_LABEL_MAX 63 + +/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */ +#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) + +/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ +#define DNS_HOSTNAME_MAX 253 + +/* Maximum length of a full hostname, on the wire, including the final NUL byte */ +#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255 + +/* Maximum number of labels per valid hostname */ +#define DNS_N_LABELS_MAX 127 diff --git a/src/basic/efivars.c b/src/basic/efivars.c index 5aeddef7e..26d34bb94 100644 --- a/src/basic/efivars.c +++ b/src/basic/efivars.c @@ -290,8 +290,11 @@ bool is_efi_boot(void) { if (cache < 0) { if (detect_container() > 0) cache = false; - else + else { cache = access("/sys/firmware/efi/", F_OK) >= 0; + if (!cache && errno != ENOENT) + log_debug_errno(errno, "Unable to test whether /sys/firmware/efi/ exists, assuming EFI not available: %m"); + } } return cache; @@ -340,7 +343,7 @@ int cache_efi_options_variable(void) { int r; /* In SecureBoot mode this is probably not what you want. As your cmdline is cryptographically signed - * like when using Type #2 EFI Unified Kernel Images (https://systemd.io/BOOT_LOADER_SPECIFICATION/) + * like when using Type #2 EFI Unified Kernel Images (https://systemd.io/BOOT_LOADER_SPECIFICATION) * The user's intention is then that the cmdline should not be modified. You want to make sure that * the system starts up as exactly specified in the signed artifact. * diff --git a/src/basic/efivars.h b/src/basic/efivars.h index d310dde7d..dcaf87eac 100644 --- a/src/basic/efivars.h +++ b/src/basic/efivars.h @@ -10,7 +10,6 @@ #include "sd-id128.h" -#include "efi/loader-features.h" #include "time-util.h" #define EFI_VENDOR_LOADER SD_ID128_MAKE(4a,67,b0,82,0a,4c,41,cf,b6,c7,44,0b,29,bb,8c,4f) diff --git a/src/basic/env-file.c b/src/basic/env-file.c index 99c3e3f4a..a30090936 100644 --- a/src/basic/env-file.c +++ b/src/basic/env-file.c @@ -20,7 +20,7 @@ static int parse_env_file_internal( void *userdata, int *n_pushed) { - size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = (size_t) -1, last_key_whitespace = (size_t) -1; + size_t key_alloc = 0, n_key = 0, value_alloc = 0, n_value = 0, last_value_whitespace = SIZE_MAX, last_key_whitespace = SIZE_MAX; _cleanup_free_ char *contents = NULL, *key = NULL, *value = NULL; unsigned line = 1; char *p; @@ -56,7 +56,7 @@ static int parse_env_file_internal( state = COMMENT; else if (!strchr(WHITESPACE, c)) { state = KEY; - last_key_whitespace = (size_t) -1; + last_key_whitespace = SIZE_MAX; if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) return -ENOMEM; @@ -72,11 +72,11 @@ static int parse_env_file_internal( n_key = 0; } else if (c == '=') { state = PRE_VALUE; - last_value_whitespace = (size_t) -1; + last_value_whitespace = SIZE_MAX; } else { if (!strchr(WHITESPACE, c)) - last_key_whitespace = (size_t) -1; - else if (last_key_whitespace == (size_t) -1) + last_key_whitespace = SIZE_MAX; + else if (last_key_whitespace == SIZE_MAX) last_key_whitespace = n_key; if (!GREEDY_REALLOC(key, key_alloc, n_key+2)) @@ -97,7 +97,7 @@ static int parse_env_file_internal( value[n_value] = 0; /* strip trailing whitespace from key */ - if (last_key_whitespace != (size_t) -1) + if (last_key_whitespace != SIZE_MAX) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); @@ -136,11 +136,11 @@ static int parse_env_file_internal( value[n_value] = 0; /* Chomp off trailing whitespace from value */ - if (last_value_whitespace != (size_t) -1) + if (last_value_whitespace != SIZE_MAX) value[last_value_whitespace] = 0; /* strip trailing whitespace from key */ - if (last_key_whitespace != (size_t) -1) + if (last_key_whitespace != SIZE_MAX) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); @@ -153,11 +153,11 @@ static int parse_env_file_internal( } else if (c == '\\') { state = VALUE_ESCAPE; - last_value_whitespace = (size_t) -1; + last_value_whitespace = SIZE_MAX; } else { if (!strchr(WHITESPACE, c)) - last_value_whitespace = (size_t) -1; - else if (last_value_whitespace == (size_t) -1) + last_value_whitespace = SIZE_MAX; + else if (last_value_whitespace == SIZE_MAX) last_value_whitespace = n_value; if (!GREEDY_REALLOC(value, value_alloc, n_value+2)) @@ -255,11 +255,11 @@ static int parse_env_file_internal( value[n_value] = 0; if (state == VALUE) - if (last_value_whitespace != (size_t) -1) + if (last_value_whitespace != SIZE_MAX) value[last_value_whitespace] = 0; /* strip trailing whitespace from key */ - if (last_key_whitespace != (size_t) -1) + if (last_key_whitespace != SIZE_MAX) key[last_key_whitespace] = 0; r = push(fname, line, key, value, userdata, n_pushed); @@ -385,11 +385,9 @@ static int load_env_file_push( if (!p) return -ENOMEM; - r = strv_env_replace(m, p); - if (r < 0) { - free(p); + r = strv_env_replace_consume(m, p); + if (r < 0) return r; - } if (n_pushed) (*n_pushed)++; diff --git a/src/basic/env-util.c b/src/basic/env-util.c index b2483af53..c110a750a 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -12,6 +12,9 @@ #include "extract-word.h" #include "macro.h" #include "parse-util.h" +#include "path-util.h" +#include "process-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strv.h" #include "utf8.h" @@ -22,8 +25,6 @@ "_" static bool env_name_is_valid_n(const char *e, size_t n) { - const char *p; - if (!e) return false; @@ -41,7 +42,7 @@ static bool env_name_is_valid_n(const char *e, size_t n) { if (n > (size_t) sysconf(_SC_ARG_MAX) - 2) return false; - for (p = e; p < e + n; p++) + for (const char *p = e; p < e + n; p++) if (!strchr(VALID_BASH_ENV_NAME_CHARS, *p)) return false; @@ -184,14 +185,14 @@ static int env_append(char **r, char ***k, char **a) { char **strv_env_merge(size_t n_lists, ...) { _cleanup_strv_free_ char **ret = NULL; - size_t n = 0, i; + size_t n = 0; char **l, **k; va_list ap; /* Merges an arbitrary number of environment sets */ va_start(ap, n_lists); - for (i = 0; i < n_lists; i++) { + for (size_t i = 0; i < n_lists; i++) { l = va_arg(ap, char**); n += strv_length(l); } @@ -205,7 +206,7 @@ char **strv_env_merge(size_t n_lists, ...) { k = ret; va_start(ap, n_lists); - for (i = 0; i < n_lists; i++) { + for (size_t i = 0; i < n_lists; i++) { l = va_arg(ap, char**); if (env_append(ret, &k, l) < 0) { va_end(ap); @@ -271,10 +272,8 @@ char **strv_env_delete(char **x, size_t n_lists, ...) { return NULL; STRV_FOREACH(k, x) { - size_t v; - va_start(ap, n_lists); - for (v = 0; v < n_lists; v++) { + for (size_t v = 0; v < n_lists; v++) { char **l, **j; l = va_arg(ap, char**); @@ -305,7 +304,6 @@ char **strv_env_delete(char **x, size_t n_lists, ...) { } char **strv_env_unset(char **l, const char *p) { - char **f, **t; if (!l) @@ -366,20 +364,23 @@ char **strv_env_unset_many(char **l, ...) { return l; } -int strv_env_replace(char ***l, char *p) { +int strv_env_replace_consume(char ***l, char *p) { const char *t, *name; char **f; int r; assert(p); - /* Replace first occurrence of the env var or add a new one in the string list. Drop other occurrences. Edits - * in-place. Does not copy p. p must be a valid key=value assignment. - */ + /* Replace first occurrence of the env var or add a new one in the string list. Drop other + * occurrences. Edits in-place. Does not copy p and CONSUMES p EVEN ON FAILURE. + * + * p must be a valid key=value assignment. */ t = strchr(p, '='); - if (!t) + if (!t) { + free(p); return -EINVAL; + } name = strndupa(p, t - p); @@ -391,39 +392,39 @@ int strv_env_replace(char ***l, char *p) { } /* We didn't find a match, we need to append p or create a new strv */ - r = strv_push(l, p); + r = strv_consume(l, p); if (r < 0) return r; return 1; } -char **strv_env_set(char **x, const char *p) { - _cleanup_strv_free_ char **ret = NULL; - size_t n, m; - char **k; +int strv_env_replace_strdup(char ***l, const char *assignment) { + /* Like strv_env_replace_consume(), but copies the argument. */ - /* Overrides the env var setting of p, returns a new copy */ + char *p = strdup(assignment); + if (!p) + return -ENOMEM; - n = strv_length(x); - m = n + 2; - if (m < n) /* overflow? */ - return NULL; + return strv_env_replace_consume(l, p); +} - ret = new(char*, m); - if (!ret) - return NULL; +int strv_env_assign(char ***l, const char *key, const char *value) { + if (!env_name_is_valid(key)) + return -EINVAL; - *ret = NULL; - k = ret; + /* NULL removes assignment, "" creates an empty assignment. */ - if (env_append(ret, &k, x) < 0) - return NULL; + if (!value) { + strv_env_unset(*l, key); + return 0; + } - if (env_append(ret, &k, STRV_MAKE(p)) < 0) - return NULL; + char *p = strjoin(key, "=", value); + if (!p) + return -ENOMEM; - return TAKE_PTR(ret); + return strv_env_replace_consume(l, p); } char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) { @@ -455,6 +456,18 @@ char *strv_env_get(char **l, const char *name) { return strv_env_get_n(l, name, strlen(name), 0); } +char *strv_env_pairs_get(char **l, const char *name) { + char **key, **value, *result = NULL; + + assert(name); + + STRV_FOREACH_PAIR(key, value, l) + if (streq(*key, name)) + result = *value; + + return result; +} + char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const char *p, void *userdata), void *userdata) { char **p, **q; int k = 0; @@ -754,3 +767,78 @@ int set_unset_env(const char *name, const char *value, bool overwrite) { return -errno; return 0; } + +int putenv_dup(const char *assignment, bool override) { + const char *e, *n; + + e = strchr(assignment, '='); + if (!e) + return -EINVAL; + + n = strndupa(assignment, e - assignment); + + /* This is like putenv(), but uses setenv() so that our memory doesn't become part of environ[]. */ + if (setenv(n, e + 1, override) < 0) + return -errno; + return 0; +} + +int setenv_systemd_exec_pid(bool update_only) { + char str[DECIMAL_STR_MAX(pid_t)]; + const char *e; + + /* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */ + + e = secure_getenv("SYSTEMD_EXEC_PID"); + if (!e && update_only) + return 0; + + if (streq_ptr(e, "*")) + return 0; + + xsprintf(str, PID_FMT, getpid_cached()); + + if (setenv("SYSTEMD_EXEC_PID", str, 1) < 0) + return -errno; + + return 1; +} + +int getenv_path_list(const char *name, char ***ret_paths) { + _cleanup_strv_free_ char **l = NULL; + const char *e; + char **p; + int r; + + assert(name); + assert(ret_paths); + + e = secure_getenv(name); + if (!e) + return -ENXIO; + + r = strv_split_full(&l, e, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_debug_errno(r, "Failed to parse $%s: %m", name); + + STRV_FOREACH(p, l) { + if (!path_is_absolute(*p)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Path '%s' is not absolute, refusing.", *p); + + if (!path_is_normalized(*p)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Path '%s' is not normalized, refusing.", *p); + + if (path_equal(*p, "/")) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Path '%s' is the root fs, refusing.", *p); + } + + if (strv_isempty(l)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "No paths specified, refusing."); + + *ret_paths = TAKE_PTR(l); + return 1; +} diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 6684b3350..1fbe7e427 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -42,16 +42,27 @@ bool strv_env_name_or_assignment_is_valid(char **l); char **strv_env_merge(size_t n_lists, ...); char **strv_env_delete(char **x, size_t n_lists, ...); /* New copy */ -char **strv_env_set(char **x, const char *p); /* New copy ... */ char **strv_env_unset(char **l, const char *p); /* In place ... */ char **strv_env_unset_many(char **l, ...) _sentinel_; -int strv_env_replace(char ***l, char *p); /* In place ... */ +int strv_env_replace_consume(char ***l, char *p); /* In place ... */ +int strv_env_replace_strdup(char ***l, const char *assignment); +int strv_env_assign(char ***l, const char *key, const char *value); char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_; char *strv_env_get(char **x, const char *n) _pure_; +char *strv_env_pairs_get(char **l, const char *name) _pure_; int getenv_bool(const char *p); int getenv_bool_secure(const char *p); /* Like setenv, but calls unsetenv if value == NULL. */ int set_unset_env(const char *name, const char *value, bool overwrite); + +/* Like putenv, but duplicates the memory like setenv. */ +int putenv_dup(const char *assignment, bool override); + +int setenv_systemd_exec_pid(bool update_only); + +/* Parses and does sanity checks on an environment variable containing + * PATH-like colon-separated absolute paths */ +int getenv_path_list(const char *name, char ***ret_paths); diff --git a/src/basic/errno-to-name.awk b/src/basic/errno-to-name.awk index 0878abacb..6b18a90e1 100644 --- a/src/basic/errno-to-name.awk +++ b/src/basic/errno-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "static const char* const errno_names[] = { " } diff --git a/src/basic/escape.c b/src/basic/escape.c index 31f3cda47..af785ecfa 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -114,7 +114,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, * instead be copied directly. */ - if (length != (size_t) -1 && length < 1) + if (length != SIZE_MAX && length < 1) return -EINVAL; switch (p[0]) { @@ -159,7 +159,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, /* hexadecimal encoding */ int a, b; - if (length != (size_t) -1 && length < 3) + if (length != SIZE_MAX && length < 3) return -EINVAL; a = unhexchar(p[1]); @@ -187,7 +187,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, size_t i; uint32_t c; - if (length != (size_t) -1 && length < 5) + if (length != SIZE_MAX && length < 5) return -EINVAL; for (i = 0; i < 4; i++) { @@ -214,7 +214,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, size_t i; char32_t c; - if (length != (size_t) -1 && length < 9) + if (length != SIZE_MAX && length < 9) return -EINVAL; for (i = 0; i < 8; i++) { @@ -251,7 +251,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit, int a, b, c; char32_t m; - if (length != (size_t) -1 && length < 3) + if (length != SIZE_MAX && length < 3) return -EINVAL; a = unoctchar(p[0]); diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index 76b3fe12e..d1af11318 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -20,11 +20,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) { _cleanup_free_ char *s = NULL; size_t allocated = 0, sz = 0; - char c; - int r; - char quote = 0; /* 0 or ' or " */ bool backslash = false; /* whether we've just seen a backslash */ + char c; + int r; assert(p); assert(ret); @@ -70,14 +69,14 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra return -ENOMEM; if (c == 0) { - if ((flags & EXTRACT_CUNESCAPE_RELAX) && - (!quote || flags & EXTRACT_RELAX)) { + if ((flags & EXTRACT_UNESCAPE_RELAX) && + (quote == 0 || flags & EXTRACT_RELAX)) { /* If we find an unquoted trailing backslash and we're in - * EXTRACT_CUNESCAPE_RELAX mode, keep it verbatim in the + * EXTRACT_UNESCAPE_RELAX mode, keep it verbatim in the * output. * * Unbalanced quotes will only be allowed in EXTRACT_RELAX - * mode, EXTRACT_CUNESCAPE_RELAX mode does not allow them. + * mode, EXTRACT_UNESCAPE_RELAX mode does not allow them. */ s[sz++] = '\\'; goto finish_force_terminate; @@ -92,7 +91,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra char32_t u; if ((flags & EXTRACT_CUNESCAPE) && - (r = cunescape_one(*p, (size_t) -1, &u, &eight_bit, false)) >= 0) { + (r = cunescape_one(*p, SIZE_MAX, &u, &eight_bit, false)) >= 0) { /* A valid escaped sequence */ assert(r >= 1); @@ -103,10 +102,10 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra else sz += utf8_encode_unichar(s + sz, u); } else if ((flags & EXTRACT_UNESCAPE_SEPARATORS) && - strchr(separators, **p)) - /* An escaped separator char */ + (strchr(separators, **p) || **p == '\\')) + /* An escaped separator char or the escape char itself */ s[sz++] = c; - else if (flags & EXTRACT_CUNESCAPE_RELAX) { + else if (flags & EXTRACT_UNESCAPE_RELAX) { s[sz++] = '\\'; s[sz++] = c; } else @@ -116,7 +115,7 @@ int extract_first_word(const char **p, char **ret, const char *separators, Extra backslash = false; - } else if (quote) { /* inside either single or double quotes */ + } else if (quote != 0) { /* inside either single or double quotes */ for (;; (*p)++, c = **p) { if (c == 0) { if (flags & EXTRACT_RELAX) @@ -197,7 +196,7 @@ int extract_first_word_and_warn( const char *rvalue) { /* Try to unquote it, if it fails, warn about it and try again - * but this time using EXTRACT_CUNESCAPE_RELAX to keep the + * but this time using EXTRACT_UNESCAPE_RELAX to keep the * backslashes verbatim in invalid escape sequences. */ const char *save; @@ -208,11 +207,11 @@ int extract_first_word_and_warn( if (r >= 0) return r; - if (r == -EINVAL && !(flags & EXTRACT_CUNESCAPE_RELAX)) { + if (r == -EINVAL && !(flags & EXTRACT_UNESCAPE_RELAX)) { - /* Retry it with EXTRACT_CUNESCAPE_RELAX. */ + /* Retry it with EXTRACT_UNESCAPE_RELAX. */ *p = save; - r = extract_first_word(p, ret, separators, flags|EXTRACT_CUNESCAPE_RELAX); + r = extract_first_word(p, ret, separators, flags|EXTRACT_UNESCAPE_RELAX); if (r >= 0) { /* It worked this time, hence it must have been an invalid escape sequence. */ log_syntax(unit, LOG_WARNING, filename, line, EINVAL, "Ignoring unknown escape sequences: \"%s\"", *ret); diff --git a/src/basic/extract-word.h b/src/basic/extract-word.h index d1de32e58..0e9e77e93 100644 --- a/src/basic/extract-word.h +++ b/src/basic/extract-word.h @@ -4,13 +4,15 @@ #include "macro.h" typedef enum ExtractFlags { - EXTRACT_RELAX = 1 << 0, - EXTRACT_CUNESCAPE = 1 << 1, - EXTRACT_CUNESCAPE_RELAX = 1 << 2, - EXTRACT_UNESCAPE_SEPARATORS = 1 << 3, - EXTRACT_UNQUOTE = 1 << 4, - EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, - EXTRACT_RETAIN_ESCAPE = 1 << 6, + EXTRACT_RELAX = 1 << 0, /* Allow unbalanced quote and eat up trailing backslash. */ + EXTRACT_CUNESCAPE = 1 << 1, /* Unescape known escape sequences. */ + EXTRACT_UNESCAPE_RELAX = 1 << 2, /* Allow and keep unknown escape sequences, allow and keep trailing backslash. */ + EXTRACT_UNESCAPE_SEPARATORS = 1 << 3, /* Unescape separators (those specified, or whitespace by default). */ + EXTRACT_UNQUOTE = 1 << 4, /* Remove quoting with "" and ''. */ + EXTRACT_DONT_COALESCE_SEPARATORS = 1 << 5, /* Don't treat multiple adjacent separators as one */ + EXTRACT_RETAIN_ESCAPE = 1 << 6, /* Treat escape character '\' as any other character without special meaning */ + + /* Note that if no flags are specified, escaped escape characters will be silently stripped. */ } ExtractFlags; int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags); diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index 07a7b3a30..d63f012ad 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -91,11 +91,9 @@ void safe_close_pair(int p[static 2]) { } void close_many(const int fds[], size_t n_fd) { - size_t i; - assert(fds || n_fd <= 0); - for (i = 0; i < n_fd; i++) + for (size_t i = 0; i < n_fd; i++) safe_close(fds[i]); } @@ -179,11 +177,9 @@ int fd_cloexec(int fd, bool cloexec) { } _pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) { - size_t i; - assert(n_fdset == 0 || fdset); - for (i = 0; i < n_fdset; i++) + for (size_t i = 0; i < n_fdset; i++) if (fdset[i] == fd) return true; @@ -211,10 +207,6 @@ static int get_max_fd(void) { return (int) (m - 1); } -static int cmp_int(const int *a, const int *b) { - return CMP(*a, *b); -} - int close_all_fds(const int except[], size_t n_except) { static bool have_close_range = true; /* Assume we live in the future */ _cleanup_closedir_ DIR *d = NULL; diff --git a/src/basic/fd-util.h b/src/basic/fd-util.h index 2162537b8..f05c2b5a1 100644 --- a/src/basic/fd-util.h +++ b/src/basic/fd-util.h @@ -41,8 +41,8 @@ static inline void fclosep(FILE **f) { safe_fclose(*f); } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, pclose); -DEFINE_TRIVIAL_CLEANUP_FUNC(DIR*, closedir); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, pclose, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL); #define _cleanup_close_ _cleanup_(closep) #define _cleanup_fclose_ _cleanup_(fclosep) diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 973756c89..df30870a1 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -27,7 +27,8 @@ #include "string-util.h" #include "tmpfile-util.h" -#define READ_FULL_BYTES_MAX (4U*1024U*1024U) +/* The maximum size of the file we'll read in one go. */ +#define READ_FULL_BYTES_MAX (4U*1024U*1024U - 1) int fopen_unlocked(const char *path, const char *options, FILE **ret) { assert(ret); @@ -368,7 +369,6 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re struct stat st; size_t n, size; int n_retries; - char *p; assert(ret_contents); @@ -385,16 +385,10 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re if (fd < 0) return -errno; - /* Start size for files in /proc which usually report a file size of 0. */ - size = LINE_MAX / 2; - /* Limit the number of attempts to read the number of bytes returned by fstat(). */ n_retries = 3; for (;;) { - if (n_retries <= 0) - return -EIO; - if (fstat(fd, &st) < 0) return -errno; @@ -402,19 +396,23 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re return -EBADF; /* Be prepared for files from /proc which generally report a file size of 0. */ + assert_cc(READ_FULL_BYTES_MAX < SSIZE_MAX); if (st.st_size > 0) { + if (st.st_size > READ_FULL_BYTES_MAX) + return -EFBIG; + size = st.st_size; n_retries--; - } else - size = size * 2; + } else { + size = READ_FULL_BYTES_MAX; + n_retries = 0; + } - if (size > READ_FULL_BYTES_MAX) - return -E2BIG; - - p = realloc(buf, size + 1); - if (!p) + buf = malloc(size + 1); + if (!buf) return -ENOMEM; - buf = TAKE_PTR(p); + /* Use a bigger allocation if we got it anyway, but not more than the limit. */ + size = MIN(malloc_usable_size(buf) - 1, READ_FULL_BYTES_MAX); for (;;) { ssize_t k; @@ -441,27 +439,32 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re * processing, let's try again either with a bigger guessed size or the new * file size. */ + if (n_retries <= 0) + return st.st_size > 0 ? -EIO : -EFBIG; + if (lseek(fd, 0, SEEK_SET) < 0) return -errno; + + buf = mfree(buf); } if (n < size) { + char *p; + + /* Return rest of the buffer to libc */ p = realloc(buf, n + 1); if (!p) return -ENOMEM; - buf = TAKE_PTR(p); + buf = p; } - if (!ret_size) { - /* Safety check: if the caller doesn't want to know the size of what we - * just read it will rely on the trailing NUL byte. But if there's an - * embedded NUL byte, then we should refuse operation as otherwise - * there'd be ambiguity about what we just read. */ - - if (memchr(buf, 0, n)) - return -EBADMSG; - } else + if (ret_size) *ret_size = n; + else if (memchr(buf, 0, n)) + /* Safety check: if the caller doesn't want to know the size of what we just read it will + * rely on the trailing NUL byte. But if there's an embedded NUL byte, then we should refuse + * operation as otherwise there'd be ambiguity about what we just read. */ + return -EBADMSG; buf[n] = 0; *ret_contents = TAKE_PTR(buf); @@ -472,12 +475,13 @@ int read_full_virtual_file(const char *filename, char **ret_contents, size_t *re int read_full_stream_full( FILE *f, const char *filename, + uint64_t offset, + size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size) { _cleanup_free_ char *buf = NULL; - struct stat st; size_t n, n_next, l; int fd, r; @@ -485,32 +489,45 @@ int read_full_stream_full( assert(ret_contents); assert(!FLAGS_SET(flags, READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)); - n_next = LINE_MAX; /* Start size */ + if (offset != UINT64_MAX && offset > LONG_MAX) + return -ERANGE; + + n_next = size != SIZE_MAX ? size : LINE_MAX; /* Start size */ fd = fileno(f); - if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see fmemopen()), let's - * optimize our buffering */ + if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see + * fmemopen()), let's optimize our buffering */ + struct stat st; if (fstat(fd, &st) < 0) return -errno; if (S_ISREG(st.st_mode)) { + if (size == SIZE_MAX) { + uint64_t rsize = + LESS_BY((uint64_t) st.st_size, offset == UINT64_MAX ? 0 : offset); - /* Safety check */ - if (st.st_size > READ_FULL_BYTES_MAX) - return -E2BIG; + /* Safety check */ + if (rsize > READ_FULL_BYTES_MAX) + return -E2BIG; - /* Start with the right file size. Note that we increase the size - * to read here by one, so that the first read attempt already - * makes us notice the EOF. */ - if (st.st_size > 0) - n_next = st.st_size + 1; + /* Start with the right file size. Note that we increase the size to read + * here by one, so that the first read attempt already makes us notice the + * EOF. If the reported size of the file is zero, we avoid this logic + * however, since quite likely it might be a virtual file in procfs that all + * report a zero file size. */ + if (st.st_size > 0) + n_next = rsize + 1; + } if (flags & READ_FULL_FILE_WARN_WORLD_READABLE) (void) warn_file_is_world_accessible(filename, &st, NULL, 0); } } + if (offset != UINT64_MAX && fseek(f, offset, SEEK_SET) < 0) + return -errno; + n = l = 0; for (;;) { char *t; @@ -532,7 +549,9 @@ int read_full_stream_full( } buf = t; - n = n_next; + /* Unless a size has been explicitly specified, try to read as much as fits into the memory + * we allocated (minus 1, to leave one byte for the safety NUL byte) */ + n = size == SIZE_MAX ? malloc_usable_size(buf) - 1 : n_next; errno = 0; k = fread(buf + l, 1, n - l, f); @@ -547,6 +566,11 @@ int read_full_stream_full( if (feof(f)) break; + if (size != SIZE_MAX) { /* If we got asked to read some specific size, we already sized the buffer right, hence leave */ + assert(l == size); + break; + } + assert(k > 0); /* we can't have read zero bytes because that would have been EOF */ /* Safety check */ @@ -605,15 +629,18 @@ finalize: int read_full_file_full( int dir_fd, const char *filename, + uint64_t offset, + size_t size, ReadFullFileFlags flags, const char *bind_name, - char **contents, size_t *size) { + char **ret_contents, + size_t *ret_size) { _cleanup_fclose_ FILE *f = NULL; int r; assert(filename); - assert(contents); + assert(ret_contents); r = xfopenat(dir_fd, filename, "re", 0, &f); if (r < 0) { @@ -628,6 +655,10 @@ int read_full_file_full( if (!FLAGS_SET(flags, READ_FULL_FILE_CONNECT_SOCKET)) return -ENXIO; + /* Seeking is not supported on AF_UNIX sockets */ + if (offset != UINT64_MAX) + return -ESPIPE; + if (dir_fd == AT_FDCWD) r = sockaddr_un_set_path(&sa.un, filename); else { @@ -681,7 +712,7 @@ int read_full_file_full( (void) __fsetlocking(f, FSETLOCKING_BYCALLER); - return read_full_stream_full(f, filename, flags, contents, size); + return read_full_stream_full(f, filename, offset, size, flags, ret_contents, ret_size); } int executable_is_script(const char *path, char **interpreter) { @@ -1120,7 +1151,7 @@ static EndOfLineMarker categorize_eol(char c, ReadLineFlags flags) { return EOL_NONE; } -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, funlockfile); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, funlockfile, NULL); int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) { size_t n = 0, allocated = 0, count = 0; @@ -1297,15 +1328,6 @@ int warn_file_is_world_accessible(const char *filename, struct stat *st, const c return 0; } -int sync_rights(int from, int to) { - struct stat st; - - if (fstat(from, &st) < 0) - return -errno; - - return fchmod_and_chown(to, st.st_mode & 07777, st.st_uid, st.st_gid); -} - int rename_and_apply_smack_floor_label(const char *from, const char *to) { int r = 0; if (rename(from, to) < 0) diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 0886354cb..64a30ab7b 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -60,14 +60,14 @@ static inline int write_string_file(const char *fn, const char *line, WriteStrin int write_string_filef(const char *fn, WriteStringFileFlags flags, const char *format, ...) _printf_(3, 4); int read_one_line_file(const char *filename, char **line); -int read_full_file_full(int dir_fd, const char *filename, ReadFullFileFlags flags, const char *bind_name, char **contents, size_t *size); -static inline int read_full_file(const char *filename, char **contents, size_t *size) { - return read_full_file_full(AT_FDCWD, filename, 0, NULL, contents, size); +int read_full_file_full(int dir_fd, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, const char *bind_name, char **ret_contents, size_t *ret_size); +static inline int read_full_file(const char *filename, char **ret_contents, size_t *ret_size) { + return read_full_file_full(AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, 0, NULL, ret_contents, ret_size); } int read_full_virtual_file(const char *filename, char **ret_contents, size_t *ret_size); -int read_full_stream_full(FILE *f, const char *filename, ReadFullFileFlags flags, char **contents, size_t *size); -static inline int read_full_stream(FILE *f, char **contents, size_t *size) { - return read_full_stream_full(f, NULL, 0, contents, size); +int read_full_stream_full(FILE *f, const char *filename, uint64_t offset, size_t size, ReadFullFileFlags flags, char **ret_contents, size_t *ret_size); +static inline int read_full_stream(FILE *f, char **ret_contents, size_t *ret_size) { + return read_full_stream_full(f, NULL, UINT64_MAX, SIZE_MAX, 0, ret_contents, ret_size); } int verify_file(const char *fn, const char *blob, bool accept_extra_nl); @@ -118,6 +118,4 @@ int safe_fgetc(FILE *f, char *ret); int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line); -int sync_rights(int from, int to); - int rename_and_apply_smack_floor_label(const char *temp_path, const char *dest_path); diff --git a/src/basic/format-util.c b/src/basic/format-util.c index bf2303779..9920604f3 100644 --- a/src/basic/format-util.c +++ b/src/basic/format-util.c @@ -43,17 +43,17 @@ char *format_bytes_full(char *buf, size_t l, uint64_t t, FormatBytesFlag flag) { { "K", UINT64_C(1000) }, }; const suffix_table *table; - size_t n, i; + size_t n; assert_cc(ELEMENTSOF(table_iec) == ELEMENTSOF(table_si)); - if (t == (uint64_t) -1) + if (t == UINT64_MAX) return NULL; table = flag & FORMAT_BYTES_USE_IEC ? table_iec : table_si; n = ELEMENTSOF(table_iec); - for (i = 0; i < n; i++) + for (size_t i = 0; i < n; i++) if (t >= table[i].factor) { if (flag & FORMAT_BYTES_BELOW_POINT) { snprintf(buf, l, diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 6924f5dfb..b2a4e8036 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -100,7 +100,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char /* renameat2() exists since Linux 3.15, btrfs and FAT added support for it later. If it is not implemented, * fall back to a different method. */ - if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY)) + if (!ERRNO_IS_NOT_SUPPORTED(errno) && errno != EINVAL) return -errno; /* Let's try to use linkat()+unlinkat() as fallback. This doesn't work on directories and on some file systems @@ -117,7 +117,7 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char return 0; } - if (!IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)) /* FAT returns EPERM on link()… */ + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !IN_SET(errno, EINVAL, EPERM)) /* FAT returns EPERM on link()… */ return -errno; /* OK, neither RENAME_NOREPLACE nor linkat()+unlinkat() worked. Let's then fall back to the racy TOCTOU @@ -135,34 +135,34 @@ int rename_noreplace(int olddirfd, const char *oldpath, int newdirfd, const char } int readlinkat_malloc(int fd, const char *p, char **ret) { - size_t l = FILENAME_MAX+1; - int r; + size_t l = PATH_MAX; assert(p); assert(ret); for (;;) { - char *c; + _cleanup_free_ char *c = NULL; ssize_t n; - c = new(char, l); + c = new(char, l+1); if (!c) return -ENOMEM; - n = readlinkat(fd, p, c, l-1); - if (n < 0) { - r = -errno; - free(c); - return r; - } + n = readlinkat(fd, p, c, l); + if (n < 0) + return -errno; - if ((size_t) n < l-1) { + if ((size_t) n < l) { c[n] = 0; - *ret = c; + *ret = TAKE_PTR(c); return 0; } - free(c); + if (l > (SSIZE_MAX-1)/2) /* readlinkat() returns an ssize_t, and we want an extra byte for a + * trailing NUL, hence do an overflow check relative to SSIZE_MAX-1 + * here */ + return -EFBIG; + l *= 2; } } @@ -428,9 +428,9 @@ int symlink_idempotent(const char *from, const char *to, bool make_relative) { if (make_relative) { _cleanup_free_ char *parent = NULL; - parent = dirname_malloc(to); - if (!parent) - return -ENOMEM; + r = path_extract_directory(to, &parent); + if (r < 0) + return r; r = path_make_relative(parent, from, &relpath); if (r < 0) @@ -934,7 +934,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* Preserve the trailing slash */ if (flags & CHASE_TRAIL_SLASH) - if (!strextend(&done, "/", NULL)) + if (!strextend(&done, "/")) return -ENOMEM; break; @@ -1005,7 +1005,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (streq_ptr(done, "/")) *done = '\0'; - if (!strextend(&done, first, todo, NULL)) + if (!strextend(&done, first, todo)) return -ENOMEM; exists = false; @@ -1098,7 +1098,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, if (streq(done, "/")) *done = '\0'; - if (!strextend(&done, first, NULL)) + if (!strextend(&done, first)) return -ENOMEM; } @@ -1413,33 +1413,45 @@ int unlinkat_deallocate(int fd, const char *name, UnlinkDeallocateFlags flags) { int fsync_directory_of_file(int fd) { _cleanup_free_ char *path = NULL; _cleanup_close_ int dfd = -1; + struct stat st; int r; - r = fd_verify_regular(fd); - if (r < 0) - return r; + assert(fd >= 0); - r = fd_get_path(fd, &path); - if (r < 0) { - log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m", - fd, - r == -ENOSYS ? ", ignoring" : ""); + /* We only reasonably can do this for regular files and directories, hence check for that */ + if (fstat(fd, &st) < 0) + return -errno; - if (r == -ENOSYS) - /* If /proc is not available, we're most likely running in some - * chroot environment, and syncing the directory is not very - * important in that case. Let's just silently do nothing. */ - return 0; + if (S_ISREG(st.st_mode)) { - return r; - } + r = fd_get_path(fd, &path); + if (r < 0) { + log_debug_errno(r, "Failed to query /proc/self/fd/%d%s: %m", + fd, + r == -ENOSYS ? ", ignoring" : ""); - if (!path_is_absolute(path)) - return -EINVAL; + if (r == -ENOSYS) + /* If /proc is not available, we're most likely running in some + * chroot environment, and syncing the directory is not very + * important in that case. Let's just silently do nothing. */ + return 0; - dfd = open_parent(path, O_CLOEXEC, 0); - if (dfd < 0) - return dfd; + return r; + } + + if (!path_is_absolute(path)) + return -EINVAL; + + dfd = open_parent(path, O_CLOEXEC|O_NOFOLLOW, 0); + if (dfd < 0) + return dfd; + + } else if (S_ISDIR(st.st_mode)) { + dfd = openat(fd, "..", O_RDONLY|O_DIRECTORY|O_CLOEXEC, 0); + if (dfd < 0) + return -errno; + } else + return -ENOTTY; if (fsync(dfd) < 0) return -errno; @@ -1453,9 +1465,14 @@ int fsync_full(int fd) { /* Sync both the file and the directory */ r = fsync(fd) < 0 ? -errno : 0; - q = fsync_directory_of_file(fd); - return r < 0 ? r : q; + q = fsync_directory_of_file(fd); + if (r < 0) /* Return earlier error */ + return r; + if (q == -ENOTTY) /* Ignore if the 'fd' refers to a block device or so which doesn't really have a + * parent dir */ + return 0; + return q; } int fsync_path_at(int at_fd, const char *path) { @@ -1472,8 +1489,7 @@ int fsync_path_at(int at_fd, const char *path) { } else fd = at_fd; } else { - - opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC); + opened_fd = openat(at_fd, path, O_RDONLY|O_CLOEXEC|O_NONBLOCK); if (opened_fd < 0) return -errno; @@ -1503,16 +1519,11 @@ int syncfs_path(int atfd, const char *path) { int open_parent(const char *path, int flags, mode_t mode) { _cleanup_free_ char *parent = NULL; - int fd; + int fd, r; - if (isempty(path)) - return -EINVAL; - if (path_equal(path, "/")) /* requesting the parent of the root dir is fishy, let's prohibit that */ - return -EINVAL; - - parent = dirname_malloc(path); - if (!parent) - return -ENOMEM; + r = path_extract_directory(path, &parent); + if (r < 0) + return r; /* Let's insist on O_DIRECTORY since the parent of a file or directory is a directory. Except if we open an * O_TMPFILE file, because in that case we are actually create a regular file below the parent directory. */ @@ -1613,3 +1624,94 @@ int path_is_encrypted(const char *path) { return blockdev_is_encrypted(p, 10 /* safety net: maximum recursion depth */); } + +int conservative_renameat( + int olddirfd, const char *oldpath, + int newdirfd, const char *newpath) { + + _cleanup_close_ int old_fd = -1, new_fd = -1; + struct stat old_stat, new_stat; + + /* Renames the old path to thew new path, much like renameat() — except if both are regular files and + * have the exact same contents and basic file attributes already. In that case remove the new file + * instead. This call is useful for reducing inotify wakeups on files that are updated but don't + * actually change. This function is written in a style that we rather rename too often than suppress + * too much. i.e. whenever we are in doubt we rather rename than fail. After all reducing inotify + * events is an optimization only, not more. */ + + old_fd = openat(olddirfd, oldpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW); + if (old_fd < 0) + goto do_rename; + + new_fd = openat(newdirfd, newpath, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_NOFOLLOW); + if (new_fd < 0) + goto do_rename; + + if (fstat(old_fd, &old_stat) < 0) + goto do_rename; + + if (!S_ISREG(old_stat.st_mode)) + goto do_rename; + + if (fstat(new_fd, &new_stat) < 0) + goto do_rename; + + if (new_stat.st_ino == old_stat.st_ino && + new_stat.st_dev == old_stat.st_dev) + goto is_same; + + if (old_stat.st_mode != new_stat.st_mode || + old_stat.st_size != new_stat.st_size || + old_stat.st_uid != new_stat.st_uid || + old_stat.st_gid != new_stat.st_gid) + goto do_rename; + + for (;;) { + uint8_t buf1[16*1024]; + uint8_t buf2[sizeof(buf1)]; + ssize_t l1, l2; + + l1 = read(old_fd, buf1, sizeof(buf1)); + if (l1 < 0) + goto do_rename; + + if (l1 == sizeof(buf1)) + /* Read the full block, hence read a full block in the other file too */ + + l2 = read(new_fd, buf2, l1); + else { + assert((size_t) l1 < sizeof(buf1)); + + /* Short read. This hence was the last block in the first file, and then came + * EOF. Read one byte more in the second file, so that we can verify we hit EOF there + * too. */ + + assert((size_t) (l1 + 1) <= sizeof(buf2)); + l2 = read(new_fd, buf2, l1 + 1); + } + if (l2 != l1) + goto do_rename; + + if (memcmp(buf1, buf2, l1) != 0) + goto do_rename; + + if ((size_t) l1 < sizeof(buf1)) /* We hit EOF on the first file, and the second file too, hence exit + * now. */ + break; + } + +is_same: + /* Everything matches? Then don't rename, instead remove the source file, and leave the existing + * destination in place */ + + if (unlinkat(olddirfd, oldpath, 0) < 0) + goto do_rename; + + return 0; + +do_rename: + if (renameat(olddirfd, oldpath, newdirfd, newpath) < 0) + return -errno; + + return 1; +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 5dc8853ea..45115fd3d 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -11,6 +11,7 @@ #include #include +#include "alloc-util.h" #include "errno-util.h" #include "time-util.h" @@ -43,7 +44,8 @@ int futimens_opath(int fd, const struct timespec ts[2]); int fd_warn_permissions(const char *path, int fd); int stat_warn_permissions(const char *path, const struct stat *st); -#define laccess(path, mode) faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) +#define laccess(path, mode) \ + (faccessat(AT_FDCWD, (path), (mode), AT_SYMLINK_NOFOLLOW) < 0 ? -errno : 0) int touch_file(const char *path, bool parents, usec_t stamp, uid_t uid, gid_t gid, mode_t mode); int touch(const char *path); @@ -99,16 +101,23 @@ int chase_symlinks_and_opendir(const char *path, const char *root, unsigned chas int chase_symlinks_and_stat(const char *path, const char *root, unsigned chase_flags, char **ret_path, struct stat *ret_stat, int *ret_fd); /* Useful for usage with _cleanup_(), removes a directory and frees the pointer */ -static inline void rmdir_and_free(char *p) { +static inline char *rmdir_and_free(char *p) { PROTECT_ERRNO; + + if (!p) + return NULL; + (void) rmdir(p); - free(p); + return mfree(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rmdir_and_free); -static inline void unlink_and_free(char *p) { +static inline char* unlink_and_free(char *p) { + if (!p) + return NULL; + (void) unlink_noerrno(p); - free(p); + return mfree(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, unlink_and_free); @@ -132,3 +141,8 @@ int syncfs_path(int atfd, const char *path); int open_parent(const char *path, int flags, mode_t mode); int path_is_encrypted(const char *path); + +int conservative_renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath); +static inline int conservative_rename(const char *oldpath, const char *newpath) { + return conservative_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath); +} diff --git a/src/basic/gcrypt-util.h b/src/basic/gcrypt-util.h index c07b36cdb..27dcc7202 100644 --- a/src/basic/gcrypt-util.h +++ b/src/basic/gcrypt-util.h @@ -14,7 +14,7 @@ void initialize_libgcrypt(bool secmem); int string_hashsum(const char *s, size_t len, int md_algorithm, char **out); -DEFINE_TRIVIAL_CLEANUP_FUNC(gcry_md_hd_t, gcry_md_close); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gcry_md_hd_t, gcry_md_close, NULL); #endif static inline int string_hashsum_sha224(const char *s, size_t len, char **out) { diff --git a/src/basic/generate-af-list.sh b/src/basic/generate-af-list.sh index 6987877eb..0a5c5c4cd 100755 --- a/src/basic/generate-af-list.sh +++ b/src/basic/generate-af-list.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu $1 -E -dM -include sys/socket.h -include "$2" -include "$3" - b.hash_ops == b->b.hash_ops) + return true; + + SET_FOREACH(p, b) + if (!set_contains(a, p)) + return false; + + return true; +} diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index e99448375..c20ee8eb4 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -133,8 +133,11 @@ HashmapBase* _hashmap_copy(HashmapBase *h HASHMAP_DEBUG_PARAMS); #define ordered_hashmap_copy(h) ((OrderedHashmap*) _hashmap_copy(HASHMAP_BASE(h) HASHMAP_DEBUG_SRC_ARGS)) int _hashmap_ensure_allocated(Hashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); +int _hashmap_ensure_put(Hashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); int _ordered_hashmap_ensure_allocated(OrderedHashmap **h, const struct hash_ops *hash_ops HASHMAP_DEBUG_PARAMS); + #define hashmap_ensure_allocated(h, ops) _hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) +#define hashmap_ensure_put(s, ops, key, value) _hashmap_ensure_put(s, ops, key, value HASHMAP_DEBUG_SRC_ARGS) #define ordered_hashmap_ensure_allocated(h, ops) _ordered_hashmap_ensure_allocated(h, ops HASHMAP_DEBUG_SRC_ARGS) int _ordered_hashmap_ensure_put(OrderedHashmap **h, const struct hash_ops *hash_ops, const void *key, void *value HASHMAP_DEBUG_PARAMS); diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index da60202e5..cb0104670 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -119,7 +119,7 @@ int unhexmem_full(const char *p, size_t l, bool secure, void **ret, size_t *ret_ assert(ret_len); assert(p || l == 0); - if (l == (size_t) -1) + if (l == SIZE_MAX) l = strlen(p); /* Note that the calculation of memory size is an upper boundary, as we ignore whitespace while decoding */ @@ -309,7 +309,7 @@ int unbase32hexmem(const char *p, size_t l, bool padding, void **mem, size_t *_l assert(mem); assert(_len); - if (l == (size_t) -1) + if (l == SIZE_MAX) l = strlen(p); /* padding ensures any base32hex input has input divisible by 8 */ @@ -708,7 +708,7 @@ int unbase64mem_full(const char *p, size_t l, bool secure, void **ret, size_t *r assert(ret); assert(ret_size); - if (l == (size_t) -1) + if (l == SIZE_MAX) l = strlen(p); /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index 09e49ccb7..29d69910d 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -3,30 +3,37 @@ #include #include #include +#include #include #include #include "alloc-util.h" -#include "fd-util.h" -#include "fileio.h" #include "hostname-util.h" -#include "macro.h" +#include "os-util.h" #include "string-util.h" #include "strv.h" -bool hostname_is_set(void) { - struct utsname u; +char* get_default_hostname(void) { + int r; - assert_se(uname(&u) >= 0); + const char *e = secure_getenv("SYSTEMD_DEFAULT_HOSTNAME"); + if (e) { + if (hostname_is_valid(e, 0)) + return strdup(e); + log_debug("Invalid hostname in $SYSTEMD_DEFAULT_HOSTNAME, ignoring: %s", e); + } - if (isempty(u.nodename)) - return false; + _cleanup_free_ char *f = NULL; + r = parse_os_release(NULL, "DEFAULT_HOSTNAME", &f); + if (r < 0) + log_debug_errno(r, "Failed to parse os-release, ignoring: %m"); + else if (f) { + if (hostname_is_valid(f, 0)) + return TAKE_PTR(f); + log_debug("Invalid hostname in os-release, ignoring: %s", f); + } - /* This is the built-in kernel default hostname */ - if (streq(u.nodename, "(none)")) - return false; - - return true; + return strdup(FALLBACK_HOSTNAME); } char* gethostname_malloc(void) { @@ -41,7 +48,7 @@ char* gethostname_malloc(void) { s = u.nodename; if (isempty(s) || streq(s, "(none)")) - s = FALLBACK_HOSTNAME; + return get_default_hostname(); return strdup(s); } @@ -49,6 +56,7 @@ char* gethostname_malloc(void) { char* gethostname_short_malloc(void) { struct utsname u; const char *s; + _cleanup_free_ char *f = NULL; /* Like above, but kills the FQDN part if present. */ @@ -56,7 +64,10 @@ char* gethostname_short_malloc(void) { s = u.nodename; if (isempty(s) || streq(s, "(none)") || s[0] == '.') { - s = FALLBACK_HOSTNAME; + s = f = get_default_hostname(); + if (!s) + return NULL; + assert(s[0] != '.'); } @@ -89,6 +100,8 @@ int gethostname_strict(char **ret) { } bool valid_ldh_char(char c) { + /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || @@ -96,28 +109,24 @@ bool valid_ldh_char(char c) { c == '-'; } -/** - * Check if s looks like a valid hostname or FQDN. This does not do - * full DNS validation, but only checks if the name is composed of - * allowed characters and the length is not above the maximum allowed - * by Linux (c.f. dns_name_is_valid()). Trailing dot is allowed if - * allow_trailing_dot is true and at least two components are present - * in the name. Note that due to the restricted charset and length - * this call is substantially more conservative than - * dns_name_is_valid(). - */ -bool hostname_is_valid(const char *s, bool allow_trailing_dot) { +bool hostname_is_valid(const char *s, ValidHostnameFlags flags) { unsigned n_dots = 0; const char *p; bool dot, hyphen; + /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only + * checks if the name is composed of allowed characters and the length is not above the maximum + * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if + * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note + * that due to the restricted charset and length this call is substantially more conservative than + * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames + * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */ + if (isempty(s)) return false; - /* Doesn't accept empty hostnames, hostnames with - * leading dots, and hostnames with multiple dots in a - * sequence. Also ensures that the length stays below - * HOST_NAME_MAX. */ + if (streq(s, ".host")) /* Used by the container logic to denote the "root container" */ + return FLAGS_SET(flags, VALID_HOSTNAME_DOT_HOST); for (p = s, dot = hyphen = true; *p; p++) if (*p == '.') { @@ -143,14 +152,13 @@ bool hostname_is_valid(const char *s, bool allow_trailing_dot) { hyphen = false; } - if (dot && (n_dots < 2 || !allow_trailing_dot)) + if (dot && (n_dots < 2 || !FLAGS_SET(flags, VALID_HOSTNAME_TRAILING_DOT))) return false; if (hyphen) return false; - if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on - * Linux, but DNS allows domain names - * up to 255 characters */ + if (p-s > HOST_NAME_MAX) /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to + * 255 characters */ return false; return true; @@ -211,119 +219,3 @@ bool is_localhost(const char *hostname) { endswith_no_case(hostname, ".localhost.localdomain") || endswith_no_case(hostname, ".localhost.localdomain."); } - -bool is_gateway_hostname(const char *hostname) { - assert(hostname); - - /* This tries to identify the valid syntaxes for the our - * synthetic "gateway" host. */ - - return - strcaseeq(hostname, "_gateway") || strcaseeq(hostname, "_gateway.") -#if ENABLE_COMPAT_GATEWAY_HOSTNAME - || strcaseeq(hostname, "gateway") || strcaseeq(hostname, "gateway.") -#endif - ; -} - -int sethostname_idempotent(const char *s) { - char buf[HOST_NAME_MAX + 1] = {}; - - assert(s); - - if (gethostname(buf, sizeof(buf)) < 0) - return -errno; - - if (streq(buf, s)) - return 0; - - if (sethostname(s, strlen(s)) < 0) - return -errno; - - return 1; -} - -int shorten_overlong(const char *s, char **ret) { - char *h, *p; - - /* Shorten an overlong name to HOST_NAME_MAX or to the first dot, - * whatever comes earlier. */ - - assert(s); - - h = strdup(s); - if (!h) - return -ENOMEM; - - if (hostname_is_valid(h, false)) { - *ret = h; - return 0; - } - - p = strchr(h, '.'); - if (p) - *p = 0; - - strshorten(h, HOST_NAME_MAX); - - if (!hostname_is_valid(h, false)) { - free(h); - return -EDOM; - } - - *ret = h; - return 1; -} - -int read_etc_hostname_stream(FILE *f, char **ret) { - int r; - - assert(f); - assert(ret); - - for (;;) { - _cleanup_free_ char *line = NULL; - char *p; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return r; - if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */ - return -ENOENT; - - p = strstrip(line); - - /* File may have empty lines or comments, ignore them */ - if (!IN_SET(*p, '\0', '#')) { - char *copy; - - hostname_cleanup(p); /* normalize the hostname */ - - if (!hostname_is_valid(p, true)) /* check that the hostname we return is valid */ - return -EBADMSG; - - copy = strdup(p); - if (!copy) - return -ENOMEM; - - *ret = copy; - return 0; - } - } -} - -int read_etc_hostname(const char *path, char **ret) { - _cleanup_fclose_ FILE *f = NULL; - - assert(ret); - - if (!path) - path = "/etc/hostname"; - - f = fopen(path, "re"); - if (!f) - return -errno; - - return read_etc_hostname_stream(f, ret); - -} diff --git a/src/basic/hostname-util.h b/src/basic/hostname-util.h index c1e47a2a5..576ca083e 100644 --- a/src/basic/hostname-util.h +++ b/src/basic/hostname-util.h @@ -5,25 +5,26 @@ #include #include "macro.h" +#include "strv.h" -bool hostname_is_set(void); - +char* get_default_hostname(void); char* gethostname_malloc(void); char* gethostname_short_malloc(void); int gethostname_strict(char **ret); bool valid_ldh_char(char c) _const_; -bool hostname_is_valid(const char *s, bool allow_trailing_dot) _pure_; + +typedef enum ValidHostnameFlags { + VALID_HOSTNAME_TRAILING_DOT = 1 << 0, /* Accept trailing dot on multi-label names */ + VALID_HOSTNAME_DOT_HOST = 1 << 1, /* Accept ".host" as valid hostname */ +} ValidHostnameFlags; + +bool hostname_is_valid(const char *s, ValidHostnameFlags flags) _pure_; char* hostname_cleanup(char *s); -#define machine_name_is_valid(s) hostname_is_valid(s, false) - bool is_localhost(const char *hostname); -bool is_gateway_hostname(const char *hostname); -int sethostname_idempotent(const char *s); - -int shorten_overlong(const char *s, char **ret); - -int read_etc_hostname_stream(FILE *f, char **ret); -int read_etc_hostname(const char *path, char **ret); +static inline bool is_gateway_hostname(const char *hostname) { + /* This tries to identify the valid syntaxes for the our synthetic "gateway" host. */ + return STRCASE_IN_SET(hostname, "_gateway", "_gateway."); +} diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index a4f13b620..f7a7252f1 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -24,6 +24,12 @@ bool in4_addr_is_null(const struct in_addr *a) { return a->s_addr == 0; } +bool in6_addr_is_null(const struct in6_addr *a) { + assert(a); + + return IN6_IS_ADDR_UNSPECIFIED(a); +} + int in_addr_is_null(int family, const union in_addr_union *u) { assert(u); @@ -31,7 +37,7 @@ int in_addr_is_null(int family, const union in_addr_union *u) { return in4_addr_is_null(&u->in); if (family == AF_INET6) - return IN6_IS_ADDR_UNSPECIFIED(&u->in6); + return in6_addr_is_null(&u->in6); return -EAFNOSUPPORT; } @@ -42,6 +48,12 @@ bool in4_addr_is_link_local(const struct in_addr *a) { return (be32toh(a->s_addr) & UINT32_C(0xFFFF0000)) == (UINT32_C(169) << 24 | UINT32_C(254) << 16); } +bool in6_addr_is_link_local(const struct in6_addr *a) { + assert(a); + + return IN6_IS_ADDR_LINKLOCAL(a); +} + int in_addr_is_link_local(int family, const union in_addr_union *u) { assert(u); @@ -49,7 +61,7 @@ int in_addr_is_link_local(int family, const union in_addr_union *u) { return in4_addr_is_link_local(&u->in); if (family == AF_INET6) - return IN6_IS_ADDR_LINKLOCAL(&u->in6); + return in6_addr_is_link_local(&u->in6); return -EAFNOSUPPORT; } @@ -116,6 +128,13 @@ bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b) { return a->s_addr == b->s_addr; } +bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b) { + assert(a); + assert(b); + + return IN6_ARE_ADDR_EQUAL(a, b); +} + int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b) { assert(a); assert(b); @@ -124,7 +143,7 @@ int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_ return in4_addr_equal(&a->in, &b->in); if (family == AF_INET6) - return IN6_ARE_ADDR_EQUAL(&a->in6, &b->in6); + return in6_addr_equal(&a->in6, &b->in6); return -EAFNOSUPPORT; } @@ -189,8 +208,8 @@ int in_addr_prefix_intersect( int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) { assert(u); - /* Increases the network part of an address by one. Returns - * positive if that succeeds, or -ERANGE if this overflows. */ + /* Increases the network part of an address by one. Returns 0 if that succeeds, or -ERANGE if + * this overflows. */ return in_addr_prefix_nth(family, u, prefixlen, 1); } @@ -198,19 +217,17 @@ int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen) /* * Calculates the nth prefix of size prefixlen starting from the address denoted by u. * - * On success 1 will be returned and the calculated prefix will be available in - * u. In the case nth == 0 the input will be left unchanged and 1 will be returned. - * In case the calculation cannot be performed (invalid prefix length, + * On success 0 will be returned and the calculated prefix will be available in + * u. In case the calculation cannot be performed (invalid prefix length, * overflows would occur) -ERANGE is returned. If the address family given isn't * supported -EAFNOSUPPORT will be returned. * - * * Examples: - * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 1, writes 192.168.2.0 to u - * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 1, no data written + * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 2), returns 0, writes 192.168.2.0 to u + * - in_addr_prefix_nth(AF_INET, 192.168.0.0, 24, 0), returns 0, no data written * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 24, 1), returns -ERANGE, no data written * - in_addr_prefix_nth(AF_INET, 255.255.255.0, 0, 1), returns -ERANGE, no data written - * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 1, writes 2001:0db8:0000:ff00:: to u + * - in_addr_prefix_nth(AF_INET6, 2001:db8, 64, 0xff00) returns 0, writes 2001:0db8:0000:ff00:: to u */ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth) { assert(u); @@ -218,13 +235,11 @@ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, u if (prefixlen <= 0) return -ERANGE; - if (nth == 0) - return 1; - if (family == AF_INET) { uint32_t c, n, t; + if (prefixlen > 32) - prefixlen = 32; + return -ERANGE; c = be32toh(u->in.s_addr); @@ -238,44 +253,40 @@ int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, u n &= UINT32_C(0xFFFFFFFF) << (32 - prefixlen); u->in.s_addr = htobe32(n); - return 1; + return 0; } if (family == AF_INET6) { - struct in6_addr result = {}; - uint8_t overflow = 0; - uint64_t delta; /* this assumes that we only ever have to up to 1<<64 subnets */ - unsigned start_byte = (prefixlen - 1) / 8; + bool overflow = false; if (prefixlen > 128) - prefixlen = 128; - - /* First calculate what we have to add */ - delta = nth << ((128 - prefixlen) % 8); - - for (unsigned i = 16; i > 0; i--) { - unsigned j = i - 1; - unsigned d = 0; - - if (j <= start_byte) { - int16_t t; - - d = delta & 0xFF; - delta >>= 8; - - t = u->in6.s6_addr[j] + d + overflow; - overflow = t > UINT8_MAX ? t - UINT8_MAX : 0; - - result.s6_addr[j] = (uint8_t)t; - } else - result.s6_addr[j] = u->in6.s6_addr[j]; - } - - if (overflow || delta != 0) return -ERANGE; - u->in6 = result; - return 1; + for (unsigned i = 16; i > 0; i--) { + unsigned t, j = i - 1, p = j * 8; + + if (p >= prefixlen) { + u->in6.s6_addr[j] = 0; + continue; + } + + if (prefixlen - p < 8) { + u->in6.s6_addr[j] &= 0xff << (8 - (prefixlen - p)); + t = u->in6.s6_addr[j] + ((nth & 0xff) << (8 - (prefixlen - p))); + nth >>= prefixlen - p; + } else { + t = u->in6.s6_addr[j] + (nth & 0xff) + overflow; + nth >>= 8; + } + + overflow = t > UINT8_MAX; + u->in6.s6_addr[j] = (uint8_t) (t & 0xff); + } + + if (overflow || nth != 0) + return -ERANGE; + + return 0; } return -EAFNOSUPPORT; @@ -358,6 +369,43 @@ int in_addr_random_prefix( return -EAFNOSUPPORT; } +int in_addr_prefix_range( + int family, + const union in_addr_union *in, + unsigned prefixlen, + union in_addr_union *ret_start, + union in_addr_union *ret_end) { + + union in_addr_union start, end; + int r; + + assert(in); + + if (!IN_SET(family, AF_INET, AF_INET6)) + return -EAFNOSUPPORT; + + if (ret_start) { + start = *in; + r = in_addr_prefix_nth(family, &start, prefixlen, 0); + if (r < 0) + return r; + } + + if (ret_end) { + end = *in; + r = in_addr_prefix_nth(family, &end, prefixlen, 1); + if (r < 0) + return r; + } + + if (ret_start) + *ret_start = start; + if (ret_end) + *ret_end = end; + + return 0; +} + int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { _cleanup_free_ char *x = NULL; size_t l; diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 24308b702..519ee53b3 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -21,11 +21,29 @@ struct in_addr_data { }; bool in4_addr_is_null(const struct in_addr *a); +static inline bool in4_addr_is_set(const struct in_addr *a) { + return !in4_addr_is_null(a); +} +bool in6_addr_is_null(const struct in6_addr *a); +static inline bool in6_addr_is_set(const struct in6_addr *a) { + return !in6_addr_is_null(a); +} int in_addr_is_null(int family, const union in_addr_union *u); +static inline bool in_addr_is_set(int family, const union in_addr_union *u) { + return in_addr_is_null(family, u) == 0; +} +static inline int in_addr_data_is_null(const struct in_addr_data *a) { + assert(a); + return in_addr_is_null(a->family, &a->address); +} +static inline bool in_addr_data_is_set(const struct in_addr_data *a) { + return in_addr_data_is_null(a); +} int in_addr_is_multicast(int family, const union in_addr_union *u); bool in4_addr_is_link_local(const struct in_addr *a); +bool in6_addr_is_link_local(const struct in6_addr *a); int in_addr_is_link_local(int family, const union in_addr_union *u); bool in6_addr_is_link_local_all_nodes(const struct in6_addr *a); @@ -36,11 +54,18 @@ bool in4_addr_is_local_multicast(const struct in_addr *a); bool in4_addr_is_non_local(const struct in_addr *a); bool in4_addr_equal(const struct in_addr *a, const struct in_addr *b); +bool in6_addr_equal(const struct in6_addr *a, const struct in6_addr *b); int in_addr_equal(int family, const union in_addr_union *a, const union in_addr_union *b); int in_addr_prefix_intersect(int family, const union in_addr_union *a, unsigned aprefixlen, const union in_addr_union *b, unsigned bprefixlen); int in_addr_prefix_next(int family, union in_addr_union *u, unsigned prefixlen); int in_addr_prefix_nth(int family, union in_addr_union *u, unsigned prefixlen, uint64_t nth); int in_addr_random_prefix(int family, union in_addr_union *u, unsigned prefixlen_fixed_part, unsigned prefixlen); +int in_addr_prefix_range( + int family, + const union in_addr_union *in, + unsigned prefixlen, + union in_addr_union *ret_start, + union in_addr_union *ret_end); int in_addr_to_string(int family, const union in_addr_union *u, char **ret); int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); diff --git a/src/basic/io-util.c b/src/basic/io-util.c index 4d7405296..f0a66da9b 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -159,24 +158,42 @@ int pipe_eof(int fd) { return !!(r & POLLHUP); } -int fd_wait_for_event(int fd, int event, usec_t t) { - - struct pollfd pollfd = { - .fd = fd, - .events = event, - }; - +int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout) { struct timespec ts; int r; - r = ppoll(&pollfd, 1, t == USEC_INFINITY ? NULL : timespec_store(&ts, t), NULL); + assert(fds || nfds == 0); + + if (nfds == 0) + return 0; + + r = ppoll(fds, nfds, timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL); if (r < 0) return -errno; if (r == 0) return 0; - if (pollfd.revents & POLLNVAL) - return -EBADF; + for (size_t i = 0, n = r; i < nfds && n > 0; i++) { + if (fds[i].revents == 0) + continue; + if (fds[i].revents & POLLNVAL) + return -EBADF; + n--; + } + + return r; +} + +int fd_wait_for_event(int fd, int event, usec_t timeout) { + struct pollfd pollfd = { + .fd = fd, + .events = event, + }; + int r; + + r = ppoll_usec(&pollfd, 1, timeout); + if (r <= 0) + return r; return pollfd.revents; } @@ -319,16 +336,14 @@ int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, ch } void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) { - size_t i; - - for (i = 0; i < iovw->count; i++) + for (size_t i = 0; i < iovw->count; i++) iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new; } size_t iovw_size(struct iovec_wrapper *iovw) { - size_t n = 0, i; + size_t n = 0; - for (i = 0; i < iovw->count; i++) + for (size_t i = 0; i < iovw->count; i++) n += iovw->iovec[i].iov_len; return n; diff --git a/src/basic/io-util.h b/src/basic/io-util.h index d817714b0..d98817f76 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include #include #include #include @@ -18,6 +19,7 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll); int pipe_eof(int fd); +int ppoll_usec(struct pollfd *fds, size_t nfds, usec_t timeout); int fd_wait_for_event(int fd, int event, usec_t timeout); ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length); @@ -60,7 +62,7 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) { /* Same as above, but allows one extra value: -1 as indication for infinity. */ - if (l == (uint64_t) -1) + if (l == UINT64_MAX) return true; return FILE_SIZE_VALID(l); diff --git a/src/basic/kbd-util.c b/src/basic/kbd-util.c deleted file mode 100644 index 267803ec2..000000000 --- a/src/basic/kbd-util.c +++ /dev/null @@ -1,109 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include - -#include "kbd-util.h" -#include "log.h" -#include "nulstr-util.h" -#include "path-util.h" -#include "set.h" -#include "string-util.h" -#include "strv.h" -#include "utf8.h" - -static thread_local Set *keymaps = NULL; - -static int nftw_cb( - const char *fpath, - const struct stat *sb, - int tflag, - struct FTW *ftwbuf) { - - _cleanup_free_ char *p = NULL; - char *e; - int r; - - if (tflag != FTW_F) - return 0; - - if (!endswith(fpath, ".map") && - !endswith(fpath, ".map.gz")) - return 0; - - p = strdup(basename(fpath)); - if (!p) - return FTW_STOP; - - e = endswith(p, ".map"); - if (e) - *e = 0; - - e = endswith(p, ".map.gz"); - if (e) - *e = 0; - - if (!keymap_is_valid(p)) - return 0; - - r = set_consume(keymaps, TAKE_PTR(p)); - if (r < 0 && r != -EEXIST) - return r; - - return 0; -} - -int get_keymaps(char ***ret) { - _cleanup_strv_free_ char **l = NULL; - const char *dir; - int r; - - keymaps = set_new(&string_hash_ops); - if (!keymaps) - return -ENOMEM; - - NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { - r = nftw(dir, nftw_cb, 20, FTW_PHYS|FTW_ACTIONRETVAL); - - if (r == FTW_STOP) - log_debug("Directory not found %s", dir); - else if (r < 0) - log_debug_errno(r, "Can't add keymap: %m"); - } - - l = set_get_strv(keymaps); - if (!l) { - set_free_free(keymaps); - return -ENOMEM; - } - - set_free(keymaps); - - if (strv_isempty(l)) - return -ENOENT; - - strv_sort(l); - - *ret = TAKE_PTR(l); - - return 0; -} - -bool keymap_is_valid(const char *name) { - - if (isempty(name)) - return false; - - if (strlen(name) >= 128) - return false; - - if (!utf8_is_valid(name)) - return false; - - if (!filename_is_valid(name)) - return false; - - if (!string_is_safe(name)) - return false; - - return true; -} diff --git a/src/basic/limits-util.c b/src/basic/limits-util.c index 259c311a6..9f8e26d46 100644 --- a/src/basic/limits-util.c +++ b/src/basic/limits-util.c @@ -77,7 +77,13 @@ uint64_t physical_memory(void) { } uint64_t physical_memory_scale(uint64_t v, uint64_t max) { - uint64_t p, m, ps, r; + uint64_t p, m, ps; + + /* Shortcut two special cases */ + if (v == 0) + return 0; + if (v == max) + return physical_memory(); assert(max > 0); @@ -90,17 +96,16 @@ uint64_t physical_memory_scale(uint64_t v, uint64_t max) { p = physical_memory() / ps; assert(p > 0); - m = p * v; - if (m / p != v) + if (v > UINT64_MAX / p) return UINT64_MAX; + m = p * v; m /= max; - r = m * ps; - if (r / ps != m) + if (m > UINT64_MAX / ps) return UINT64_MAX; - return r; + return m * ps; } uint64_t system_tasks_max(void) { @@ -138,6 +143,12 @@ uint64_t system_tasks_max(void) { uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { uint64_t t, m; + /* Shortcut two special cases */ + if (v == 0) + return 0; + if (v == max) + return system_tasks_max(); + assert(max > 0); /* Multiply the system's task value by the fraction v/max. Hence, if max==100 this calculates percentages @@ -146,9 +157,9 @@ uint64_t system_tasks_max_scale(uint64_t v, uint64_t max) { t = system_tasks_max(); assert(t > 0); - m = t * v; - if (m / t != v) /* overflow? */ + if (v > UINT64_MAX / t) /* overflow? */ return UINT64_MAX; + m = t * v; return m / max; } diff --git a/src/basic/linux/batman_adv.h b/src/basic/linux/batman_adv.h new file mode 100644 index 000000000..d035e4cf3 --- /dev/null +++ b/src/basic/linux/batman_adv.h @@ -0,0 +1,704 @@ +/* SPDX-License-Identifier: MIT */ +/* Copyright (C) 2016-2020 B.A.T.M.A.N. contributors: + * + * Matthias Schiffer + */ + +#ifndef _UAPI_LINUX_BATMAN_ADV_H_ +#define _UAPI_LINUX_BATMAN_ADV_H_ + +#define BATADV_NL_NAME "batadv" + +#define BATADV_NL_MCAST_GROUP_CONFIG "config" +#define BATADV_NL_MCAST_GROUP_TPMETER "tpmeter" + +/** + * enum batadv_tt_client_flags - TT client specific flags + * + * Bits from 0 to 7 are called _remote flags_ because they are sent on the wire. + * Bits from 8 to 15 are called _local flags_ because they are used for local + * computations only. + * + * Bits from 4 to 7 - a subset of remote flags - are ensured to be in sync with + * the other nodes in the network. To achieve this goal these flags are included + * in the TT CRC computation. + */ +enum batadv_tt_client_flags { + /** + * @BATADV_TT_CLIENT_DEL: the client has to be deleted from the table + */ + BATADV_TT_CLIENT_DEL = (1 << 0), + + /** + * @BATADV_TT_CLIENT_ROAM: the client roamed to/from another node and + * the new update telling its new real location has not been + * received/sent yet + */ + BATADV_TT_CLIENT_ROAM = (1 << 1), + + /** + * @BATADV_TT_CLIENT_WIFI: this client is connected through a wifi + * interface. This information is used by the "AP Isolation" feature + */ + BATADV_TT_CLIENT_WIFI = (1 << 4), + + /** + * @BATADV_TT_CLIENT_ISOLA: this client is considered "isolated". This + * information is used by the Extended Isolation feature + */ + BATADV_TT_CLIENT_ISOLA = (1 << 5), + + /** + * @BATADV_TT_CLIENT_NOPURGE: this client should never be removed from + * the table + */ + BATADV_TT_CLIENT_NOPURGE = (1 << 8), + + /** + * @BATADV_TT_CLIENT_NEW: this client has been added to the local table + * but has not been announced yet + */ + BATADV_TT_CLIENT_NEW = (1 << 9), + + /** + * @BATADV_TT_CLIENT_PENDING: this client is marked for removal but it + * is kept in the table for one more originator interval for consistency + * purposes + */ + BATADV_TT_CLIENT_PENDING = (1 << 10), + + /** + * @BATADV_TT_CLIENT_TEMP: this global client has been detected to be + * part of the network but no node has already announced it + */ + BATADV_TT_CLIENT_TEMP = (1 << 11), +}; + +/** + * enum batadv_mcast_flags_priv - Private, own multicast flags + * + * These are internal, multicast related flags. Currently they describe certain + * multicast related attributes of the segment this originator bridges into the + * mesh. + * + * Those attributes are used to determine the public multicast flags this + * originator is going to announce via TT. + * + * For netlink, if BATADV_MCAST_FLAGS_BRIDGED is unset then all querier + * related flags are undefined. + */ +enum batadv_mcast_flags_priv { + /** + * @BATADV_MCAST_FLAGS_BRIDGED: There is a bridge on top of the mesh + * interface. + */ + BATADV_MCAST_FLAGS_BRIDGED = (1 << 0), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS: Whether an IGMP querier + * exists in the mesh + */ + BATADV_MCAST_FLAGS_QUERIER_IPV4_EXISTS = (1 << 1), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS: Whether an MLD querier + * exists in the mesh + */ + BATADV_MCAST_FLAGS_QUERIER_IPV6_EXISTS = (1 << 2), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING: If an IGMP querier + * exists, whether it is potentially shadowing multicast listeners + * (i.e. querier is behind our own bridge segment) + */ + BATADV_MCAST_FLAGS_QUERIER_IPV4_SHADOWING = (1 << 3), + + /** + * @BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING: If an MLD querier + * exists, whether it is potentially shadowing multicast listeners + * (i.e. querier is behind our own bridge segment) + */ + BATADV_MCAST_FLAGS_QUERIER_IPV6_SHADOWING = (1 << 4), +}; + +/** + * enum batadv_gw_modes - gateway mode of node + */ +enum batadv_gw_modes { + /** @BATADV_GW_MODE_OFF: gw mode disabled */ + BATADV_GW_MODE_OFF, + + /** @BATADV_GW_MODE_CLIENT: send DHCP requests to gw servers */ + BATADV_GW_MODE_CLIENT, + + /** @BATADV_GW_MODE_SERVER: announce itself as gateway server */ + BATADV_GW_MODE_SERVER, +}; + +/** + * enum batadv_nl_attrs - batman-adv netlink attributes + */ +enum batadv_nl_attrs { + /** + * @BATADV_ATTR_UNSPEC: unspecified attribute to catch errors + */ + BATADV_ATTR_UNSPEC, + + /** + * @BATADV_ATTR_VERSION: batman-adv version string + */ + BATADV_ATTR_VERSION, + + /** + * @BATADV_ATTR_ALGO_NAME: name of routing algorithm + */ + BATADV_ATTR_ALGO_NAME, + + /** + * @BATADV_ATTR_MESH_IFINDEX: index of the batman-adv interface + */ + BATADV_ATTR_MESH_IFINDEX, + + /** + * @BATADV_ATTR_MESH_IFNAME: name of the batman-adv interface + */ + BATADV_ATTR_MESH_IFNAME, + + /** + * @BATADV_ATTR_MESH_ADDRESS: mac address of the batman-adv interface + */ + BATADV_ATTR_MESH_ADDRESS, + + /** + * @BATADV_ATTR_HARD_IFINDEX: index of the non-batman-adv interface + */ + BATADV_ATTR_HARD_IFINDEX, + + /** + * @BATADV_ATTR_HARD_IFNAME: name of the non-batman-adv interface + */ + BATADV_ATTR_HARD_IFNAME, + + /** + * @BATADV_ATTR_HARD_ADDRESS: mac address of the non-batman-adv + * interface + */ + BATADV_ATTR_HARD_ADDRESS, + + /** + * @BATADV_ATTR_ORIG_ADDRESS: originator mac address + */ + BATADV_ATTR_ORIG_ADDRESS, + + /** + * @BATADV_ATTR_TPMETER_RESULT: result of run (see + * batadv_tp_meter_status) + */ + BATADV_ATTR_TPMETER_RESULT, + + /** + * @BATADV_ATTR_TPMETER_TEST_TIME: time (msec) the run took + */ + BATADV_ATTR_TPMETER_TEST_TIME, + + /** + * @BATADV_ATTR_TPMETER_BYTES: amount of acked bytes during run + */ + BATADV_ATTR_TPMETER_BYTES, + + /** + * @BATADV_ATTR_TPMETER_COOKIE: session cookie to match tp_meter session + */ + BATADV_ATTR_TPMETER_COOKIE, + + /** + * @BATADV_ATTR_PAD: attribute used for padding for 64-bit alignment + */ + BATADV_ATTR_PAD, + + /** + * @BATADV_ATTR_ACTIVE: Flag indicating if the hard interface is active + */ + BATADV_ATTR_ACTIVE, + + /** + * @BATADV_ATTR_TT_ADDRESS: Client MAC address + */ + BATADV_ATTR_TT_ADDRESS, + + /** + * @BATADV_ATTR_TT_TTVN: Translation table version + */ + BATADV_ATTR_TT_TTVN, + + /** + * @BATADV_ATTR_TT_LAST_TTVN: Previous translation table version + */ + BATADV_ATTR_TT_LAST_TTVN, + + /** + * @BATADV_ATTR_TT_CRC32: CRC32 over translation table + */ + BATADV_ATTR_TT_CRC32, + + /** + * @BATADV_ATTR_TT_VID: VLAN ID + */ + BATADV_ATTR_TT_VID, + + /** + * @BATADV_ATTR_TT_FLAGS: Translation table client flags + */ + BATADV_ATTR_TT_FLAGS, + + /** + * @BATADV_ATTR_FLAG_BEST: Flags indicating entry is the best + */ + BATADV_ATTR_FLAG_BEST, + + /** + * @BATADV_ATTR_LAST_SEEN_MSECS: Time in milliseconds since last seen + */ + BATADV_ATTR_LAST_SEEN_MSECS, + + /** + * @BATADV_ATTR_NEIGH_ADDRESS: Neighbour MAC address + */ + BATADV_ATTR_NEIGH_ADDRESS, + + /** + * @BATADV_ATTR_TQ: TQ to neighbour + */ + BATADV_ATTR_TQ, + + /** + * @BATADV_ATTR_THROUGHPUT: Estimated throughput to Neighbour + */ + BATADV_ATTR_THROUGHPUT, + + /** + * @BATADV_ATTR_BANDWIDTH_UP: Reported uplink bandwidth + */ + BATADV_ATTR_BANDWIDTH_UP, + + /** + * @BATADV_ATTR_BANDWIDTH_DOWN: Reported downlink bandwidth + */ + BATADV_ATTR_BANDWIDTH_DOWN, + + /** + * @BATADV_ATTR_ROUTER: Gateway router MAC address + */ + BATADV_ATTR_ROUTER, + + /** + * @BATADV_ATTR_BLA_OWN: Flag indicating own originator + */ + BATADV_ATTR_BLA_OWN, + + /** + * @BATADV_ATTR_BLA_ADDRESS: Bridge loop avoidance claim MAC address + */ + BATADV_ATTR_BLA_ADDRESS, + + /** + * @BATADV_ATTR_BLA_VID: BLA VLAN ID + */ + BATADV_ATTR_BLA_VID, + + /** + * @BATADV_ATTR_BLA_BACKBONE: BLA gateway originator MAC address + */ + BATADV_ATTR_BLA_BACKBONE, + + /** + * @BATADV_ATTR_BLA_CRC: BLA CRC + */ + BATADV_ATTR_BLA_CRC, + + /** + * @BATADV_ATTR_DAT_CACHE_IP4ADDRESS: Client IPv4 address + */ + BATADV_ATTR_DAT_CACHE_IP4ADDRESS, + + /** + * @BATADV_ATTR_DAT_CACHE_HWADDRESS: Client MAC address + */ + BATADV_ATTR_DAT_CACHE_HWADDRESS, + + /** + * @BATADV_ATTR_DAT_CACHE_VID: VLAN ID + */ + BATADV_ATTR_DAT_CACHE_VID, + + /** + * @BATADV_ATTR_MCAST_FLAGS: Per originator multicast flags + */ + BATADV_ATTR_MCAST_FLAGS, + + /** + * @BATADV_ATTR_MCAST_FLAGS_PRIV: Private, own multicast flags + */ + BATADV_ATTR_MCAST_FLAGS_PRIV, + + /** + * @BATADV_ATTR_VLANID: VLAN id on top of soft interface + */ + BATADV_ATTR_VLANID, + + /** + * @BATADV_ATTR_AGGREGATED_OGMS_ENABLED: whether the batman protocol + * messages of the mesh interface shall be aggregated or not. + */ + BATADV_ATTR_AGGREGATED_OGMS_ENABLED, + + /** + * @BATADV_ATTR_AP_ISOLATION_ENABLED: whether the data traffic going + * from a wireless client to another wireless client will be silently + * dropped. + */ + BATADV_ATTR_AP_ISOLATION_ENABLED, + + /** + * @BATADV_ATTR_ISOLATION_MARK: the isolation mark which is used to + * classify clients as "isolated" by the Extended Isolation feature. + */ + BATADV_ATTR_ISOLATION_MARK, + + /** + * @BATADV_ATTR_ISOLATION_MASK: the isolation (bit)mask which is used to + * classify clients as "isolated" by the Extended Isolation feature. + */ + BATADV_ATTR_ISOLATION_MASK, + + /** + * @BATADV_ATTR_BONDING_ENABLED: whether the data traffic going through + * the mesh will be sent using multiple interfaces at the same time. + */ + BATADV_ATTR_BONDING_ENABLED, + + /** + * @BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED: whether the bridge loop + * avoidance feature is enabled. This feature detects and avoids loops + * between the mesh and devices bridged with the soft interface + */ + BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED, + + /** + * @BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED: whether the distributed + * arp table feature is enabled. This feature uses a distributed hash + * table to answer ARP requests without flooding the request through + * the whole mesh. + */ + BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED, + + /** + * @BATADV_ATTR_FRAGMENTATION_ENABLED: whether the data traffic going + * through the mesh will be fragmented or silently discarded if the + * packet size exceeds the outgoing interface MTU. + */ + BATADV_ATTR_FRAGMENTATION_ENABLED, + + /** + * @BATADV_ATTR_GW_BANDWIDTH_DOWN: defines the download bandwidth which + * is propagated by this node if %BATADV_ATTR_GW_BANDWIDTH_MODE was set + * to 'server'. + */ + BATADV_ATTR_GW_BANDWIDTH_DOWN, + + /** + * @BATADV_ATTR_GW_BANDWIDTH_UP: defines the upload bandwidth which + * is propagated by this node if %BATADV_ATTR_GW_BANDWIDTH_MODE was set + * to 'server'. + */ + BATADV_ATTR_GW_BANDWIDTH_UP, + + /** + * @BATADV_ATTR_GW_MODE: defines the state of the gateway features. + * Possible values are specified in enum batadv_gw_modes + */ + BATADV_ATTR_GW_MODE, + + /** + * @BATADV_ATTR_GW_SEL_CLASS: defines the selection criteria this node + * will use to choose a gateway if gw_mode was set to 'client'. + */ + BATADV_ATTR_GW_SEL_CLASS, + + /** + * @BATADV_ATTR_HOP_PENALTY: defines the penalty which will be applied + * to an originator message's tq-field on every hop and/or per + * hard interface + */ + BATADV_ATTR_HOP_PENALTY, + + /** + * @BATADV_ATTR_LOG_LEVEL: bitmask with to define which debug messages + * should be send to the debug log/trace ring buffer + */ + BATADV_ATTR_LOG_LEVEL, + + /** + * @BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED: whether multicast + * optimizations should be replaced by simple broadcast-like flooding + * of multicast packets. If set to non-zero then all nodes in the mesh + * are going to use classic flooding for any multicast packet with no + * optimizations. + */ + BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED, + + /** + * @BATADV_ATTR_NETWORK_CODING_ENABLED: whether Network Coding (using + * some magic to send fewer wifi packets but still the same content) is + * enabled or not. + */ + BATADV_ATTR_NETWORK_CODING_ENABLED, + + /** + * @BATADV_ATTR_ORIG_INTERVAL: defines the interval in milliseconds in + * which batman sends its protocol messages. + */ + BATADV_ATTR_ORIG_INTERVAL, + + /** + * @BATADV_ATTR_ELP_INTERVAL: defines the interval in milliseconds in + * which batman emits probing packets for neighbor sensing (ELP). + */ + BATADV_ATTR_ELP_INTERVAL, + + /** + * @BATADV_ATTR_THROUGHPUT_OVERRIDE: defines the throughput value to be + * used by B.A.T.M.A.N. V when estimating the link throughput using + * this interface. If the value is set to 0 then batman-adv will try to + * estimate the throughput by itself. + */ + BATADV_ATTR_THROUGHPUT_OVERRIDE, + + /** + * @BATADV_ATTR_MULTICAST_FANOUT: defines the maximum number of packet + * copies that may be generated for a multicast-to-unicast conversion. + * Once this limit is exceeded distribution will fall back to broadcast. + */ + BATADV_ATTR_MULTICAST_FANOUT, + + /* add attributes above here, update the policy in netlink.c */ + + /** + * @__BATADV_ATTR_AFTER_LAST: internal use + */ + __BATADV_ATTR_AFTER_LAST, + + /** + * @NUM_BATADV_ATTR: total number of batadv_nl_attrs available + */ + NUM_BATADV_ATTR = __BATADV_ATTR_AFTER_LAST, + + /** + * @BATADV_ATTR_MAX: highest attribute number currently defined + */ + BATADV_ATTR_MAX = __BATADV_ATTR_AFTER_LAST - 1 +}; + +/** + * enum batadv_nl_commands - supported batman-adv netlink commands + */ +enum batadv_nl_commands { + /** + * @BATADV_CMD_UNSPEC: unspecified command to catch errors + */ + BATADV_CMD_UNSPEC, + + /** + * @BATADV_CMD_GET_MESH: Get attributes from softif/mesh + */ + BATADV_CMD_GET_MESH, + + /** + * @BATADV_CMD_GET_MESH_INFO: Alias for @BATADV_CMD_GET_MESH + */ + BATADV_CMD_GET_MESH_INFO = BATADV_CMD_GET_MESH, + + /** + * @BATADV_CMD_TP_METER: Start a tp meter session + */ + BATADV_CMD_TP_METER, + + /** + * @BATADV_CMD_TP_METER_CANCEL: Cancel a tp meter session + */ + BATADV_CMD_TP_METER_CANCEL, + + /** + * @BATADV_CMD_GET_ROUTING_ALGOS: Query the list of routing algorithms. + */ + BATADV_CMD_GET_ROUTING_ALGOS, + + /** + * @BATADV_CMD_GET_HARDIF: Get attributes from a hardif of the + * current softif + */ + BATADV_CMD_GET_HARDIF, + + /** + * @BATADV_CMD_GET_HARDIFS: Alias for @BATADV_CMD_GET_HARDIF + */ + BATADV_CMD_GET_HARDIFS = BATADV_CMD_GET_HARDIF, + + /** + * @BATADV_CMD_GET_TRANSTABLE_LOCAL: Query list of local translations + */ + BATADV_CMD_GET_TRANSTABLE_LOCAL, + + /** + * @BATADV_CMD_GET_TRANSTABLE_GLOBAL: Query list of global translations + */ + BATADV_CMD_GET_TRANSTABLE_GLOBAL, + + /** + * @BATADV_CMD_GET_ORIGINATORS: Query list of originators + */ + BATADV_CMD_GET_ORIGINATORS, + + /** + * @BATADV_CMD_GET_NEIGHBORS: Query list of neighbours + */ + BATADV_CMD_GET_NEIGHBORS, + + /** + * @BATADV_CMD_GET_GATEWAYS: Query list of gateways + */ + BATADV_CMD_GET_GATEWAYS, + + /** + * @BATADV_CMD_GET_BLA_CLAIM: Query list of bridge loop avoidance claims + */ + BATADV_CMD_GET_BLA_CLAIM, + + /** + * @BATADV_CMD_GET_BLA_BACKBONE: Query list of bridge loop avoidance + * backbones + */ + BATADV_CMD_GET_BLA_BACKBONE, + + /** + * @BATADV_CMD_GET_DAT_CACHE: Query list of DAT cache entries + */ + BATADV_CMD_GET_DAT_CACHE, + + /** + * @BATADV_CMD_GET_MCAST_FLAGS: Query list of multicast flags + */ + BATADV_CMD_GET_MCAST_FLAGS, + + /** + * @BATADV_CMD_SET_MESH: Set attributes for softif/mesh + */ + BATADV_CMD_SET_MESH, + + /** + * @BATADV_CMD_SET_HARDIF: Set attributes for hardif of the + * current softif + */ + BATADV_CMD_SET_HARDIF, + + /** + * @BATADV_CMD_GET_VLAN: Get attributes from a VLAN of the + * current softif + */ + BATADV_CMD_GET_VLAN, + + /** + * @BATADV_CMD_SET_VLAN: Set attributes for VLAN of the + * current softif + */ + BATADV_CMD_SET_VLAN, + + /* add new commands above here */ + + /** + * @__BATADV_CMD_AFTER_LAST: internal use + */ + __BATADV_CMD_AFTER_LAST, + + /** + * @BATADV_CMD_MAX: highest used command number + */ + BATADV_CMD_MAX = __BATADV_CMD_AFTER_LAST - 1 +}; + +/** + * enum batadv_tp_meter_reason - reason of a tp meter test run stop + */ +enum batadv_tp_meter_reason { + /** + * @BATADV_TP_REASON_COMPLETE: sender finished tp run + */ + BATADV_TP_REASON_COMPLETE = 3, + + /** + * @BATADV_TP_REASON_CANCEL: sender was stopped during run + */ + BATADV_TP_REASON_CANCEL = 4, + + /* error status >= 128 */ + + /** + * @BATADV_TP_REASON_DST_UNREACHABLE: receiver could not be reached or + * didn't answer + */ + BATADV_TP_REASON_DST_UNREACHABLE = 128, + + /** + * @BATADV_TP_REASON_RESEND_LIMIT: (unused) sender retry reached limit + */ + BATADV_TP_REASON_RESEND_LIMIT = 129, + + /** + * @BATADV_TP_REASON_ALREADY_ONGOING: test to or from the same node + * already ongoing + */ + BATADV_TP_REASON_ALREADY_ONGOING = 130, + + /** + * @BATADV_TP_REASON_MEMORY_ERROR: test was stopped due to low memory + */ + BATADV_TP_REASON_MEMORY_ERROR = 131, + + /** + * @BATADV_TP_REASON_CANT_SEND: failed to send via outgoing interface + */ + BATADV_TP_REASON_CANT_SEND = 132, + + /** + * @BATADV_TP_REASON_TOO_MANY: too many ongoing sessions + */ + BATADV_TP_REASON_TOO_MANY = 133, +}; + +/** + * enum batadv_ifla_attrs - batman-adv ifla nested attributes + */ +enum batadv_ifla_attrs { + /** + * @IFLA_BATADV_UNSPEC: unspecified attribute which is not parsed by + * rtnetlink + */ + IFLA_BATADV_UNSPEC, + + /** + * @IFLA_BATADV_ALGO_NAME: routing algorithm (name) which should be + * used by the newly registered batadv net_device. + */ + IFLA_BATADV_ALGO_NAME, + + /* add attributes above here, update the policy in soft-interface.c */ + + /** + * @__IFLA_BATADV_MAX: internal use + */ + __IFLA_BATADV_MAX, +}; + +#define IFLA_BATADV_MAX (__IFLA_BATADV_MAX - 1) + +#endif /* _UAPI_LINUX_BATMAN_ADV_H_ */ diff --git a/src/basic/linux/btrfs_tree.h b/src/basic/linux/btrfs_tree.h index 9ba64ca6b..6b885982e 100644 --- a/src/basic/linux/btrfs_tree.h +++ b/src/basic/linux/btrfs_tree.h @@ -4,6 +4,11 @@ #include #include +#ifdef __KERNEL__ +#include +#else +#include +#endif /* * This header contains the structure definitions and constants used @@ -644,6 +649,15 @@ struct btrfs_root_item { __le64 reserved[8]; /* for future */ } __attribute__ ((__packed__)); +/* + * Btrfs root item used to be smaller than current size. The old format ends + * at where member generation_v2 is. + */ +static inline __u32 btrfs_legacy_root_item_size(void) +{ + return offsetof(struct btrfs_root_item, generation_v2); +} + /* * this is used for both forward and backward root refs */ diff --git a/src/basic/linux/if_bridge.h b/src/basic/linux/if_bridge.h index c1227aecd..4c687686a 100644 --- a/src/basic/linux/if_bridge.h +++ b/src/basic/linux/if_bridge.h @@ -455,10 +455,33 @@ enum { enum { MDBA_MDB_EATTR_UNSPEC, MDBA_MDB_EATTR_TIMER, + MDBA_MDB_EATTR_SRC_LIST, + MDBA_MDB_EATTR_GROUP_MODE, + MDBA_MDB_EATTR_SOURCE, + MDBA_MDB_EATTR_RTPROT, __MDBA_MDB_EATTR_MAX }; #define MDBA_MDB_EATTR_MAX (__MDBA_MDB_EATTR_MAX - 1) +/* per mdb entry source */ +enum { + MDBA_MDB_SRCLIST_UNSPEC, + MDBA_MDB_SRCLIST_ENTRY, + __MDBA_MDB_SRCLIST_MAX +}; +#define MDBA_MDB_SRCLIST_MAX (__MDBA_MDB_SRCLIST_MAX - 1) + +/* per mdb entry per source attributes + * these are embedded in MDBA_MDB_SRCLIST_ENTRY + */ +enum { + MDBA_MDB_SRCATTR_UNSPEC, + MDBA_MDB_SRCATTR_ADDRESS, + MDBA_MDB_SRCATTR_TIMER, + __MDBA_MDB_SRCATTR_MAX +}; +#define MDBA_MDB_SRCATTR_MAX (__MDBA_MDB_SRCATTR_MAX - 1) + /* multicast router types */ enum { MDB_RTR_TYPE_DISABLED, @@ -495,6 +518,8 @@ struct br_mdb_entry { __u8 state; #define MDB_FLAGS_OFFLOAD (1 << 0) #define MDB_FLAGS_FAST_LEAVE (1 << 1) +#define MDB_FLAGS_STAR_EXCL (1 << 2) +#define MDB_FLAGS_BLOCKED (1 << 3) __u8 flags; __u16 vid; struct { @@ -509,10 +534,23 @@ struct br_mdb_entry { enum { MDBA_SET_ENTRY_UNSPEC, MDBA_SET_ENTRY, + MDBA_SET_ENTRY_ATTRS, __MDBA_SET_ENTRY_MAX, }; #define MDBA_SET_ENTRY_MAX (__MDBA_SET_ENTRY_MAX - 1) +/* [MDBA_SET_ENTRY_ATTRS] = { + * [MDBE_ATTR_xxx] + * ... + * } + */ +enum { + MDBE_ATTR_UNSPEC, + MDBE_ATTR_SOURCE, + __MDBE_ATTR_MAX, +}; +#define MDBE_ATTR_MAX (__MDBE_ATTR_MAX - 1) + /* Embedded inside LINK_XSTATS_TYPE_BRIDGE */ enum { BRIDGE_XSTATS_UNSPEC, diff --git a/src/basic/linux/if_link.h b/src/basic/linux/if_link.h index 7fba4de51..82708c6db 100644 --- a/src/basic/linux/if_link.h +++ b/src/basic/linux/if_link.h @@ -7,24 +7,23 @@ /* This struct should be in sync with struct rtnl_link_stats64 */ struct rtnl_link_stats { - __u32 rx_packets; /* total packets received */ - __u32 tx_packets; /* total packets transmitted */ - __u32 rx_bytes; /* total bytes received */ - __u32 tx_bytes; /* total bytes transmitted */ - __u32 rx_errors; /* bad packets received */ - __u32 tx_errors; /* packet transmit problems */ - __u32 rx_dropped; /* no space in linux buffers */ - __u32 tx_dropped; /* no space available in linux */ - __u32 multicast; /* multicast packets received */ + __u32 rx_packets; + __u32 tx_packets; + __u32 rx_bytes; + __u32 tx_bytes; + __u32 rx_errors; + __u32 tx_errors; + __u32 rx_dropped; + __u32 tx_dropped; + __u32 multicast; __u32 collisions; - /* detailed rx_errors: */ __u32 rx_length_errors; - __u32 rx_over_errors; /* receiver ring buff overflow */ - __u32 rx_crc_errors; /* recved pkt with crc error */ - __u32 rx_frame_errors; /* recv'd frame alignment error */ - __u32 rx_fifo_errors; /* recv'r fifo overrun */ - __u32 rx_missed_errors; /* receiver missed packet */ + __u32 rx_over_errors; + __u32 rx_crc_errors; + __u32 rx_frame_errors; + __u32 rx_fifo_errors; + __u32 rx_missed_errors; /* detailed tx_errors */ __u32 tx_aborted_errors; @@ -37,29 +36,201 @@ struct rtnl_link_stats { __u32 rx_compressed; __u32 tx_compressed; - __u32 rx_nohandler; /* dropped, no handler found */ + __u32 rx_nohandler; }; -/* The main device statistics structure */ +/** + * struct rtnl_link_stats64 - The main device statistics structure. + * + * @rx_packets: Number of good packets received by the interface. + * For hardware interfaces counts all good packets received from the device + * by the host, including packets which host had to drop at various stages + * of processing (even in the driver). + * + * @tx_packets: Number of packets successfully transmitted. + * For hardware interfaces counts packets which host was able to successfully + * hand over to the device, which does not necessarily mean that packets + * had been successfully transmitted out of the device, only that device + * acknowledged it copied them out of host memory. + * + * @rx_bytes: Number of good received bytes, corresponding to @rx_packets. + * + * For IEEE 802.3 devices should count the length of Ethernet Frames + * excluding the FCS. + * + * @tx_bytes: Number of good transmitted bytes, corresponding to @tx_packets. + * + * For IEEE 802.3 devices should count the length of Ethernet Frames + * excluding the FCS. + * + * @rx_errors: Total number of bad packets received on this network device. + * This counter must include events counted by @rx_length_errors, + * @rx_crc_errors, @rx_frame_errors and other errors not otherwise + * counted. + * + * @tx_errors: Total number of transmit problems. + * This counter must include events counter by @tx_aborted_errors, + * @tx_carrier_errors, @tx_fifo_errors, @tx_heartbeat_errors, + * @tx_window_errors and other errors not otherwise counted. + * + * @rx_dropped: Number of packets received but not processed, + * e.g. due to lack of resources or unsupported protocol. + * For hardware interfaces this counter may include packets discarded + * due to L2 address filtering but should not include packets dropped + * by the device due to buffer exhaustion which are counted separately in + * @rx_missed_errors (since procfs folds those two counters together). + * + * @tx_dropped: Number of packets dropped on their way to transmission, + * e.g. due to lack of resources. + * + * @multicast: Multicast packets received. + * For hardware interfaces this statistic is commonly calculated + * at the device level (unlike @rx_packets) and therefore may include + * packets which did not reach the host. + * + * For IEEE 802.3 devices this counter may be equivalent to: + * + * - 30.3.1.1.21 aMulticastFramesReceivedOK + * + * @collisions: Number of collisions during packet transmissions. + * + * @rx_length_errors: Number of packets dropped due to invalid length. + * Part of aggregate "frame" errors in `/proc/net/dev`. + * + * For IEEE 802.3 devices this counter should be equivalent to a sum + * of the following attributes: + * + * - 30.3.1.1.23 aInRangeLengthErrors + * - 30.3.1.1.24 aOutOfRangeLengthField + * - 30.3.1.1.25 aFrameTooLongErrors + * + * @rx_over_errors: Receiver FIFO overflow event counter. + * + * Historically the count of overflow events. Such events may be + * reported in the receive descriptors or via interrupts, and may + * not correspond one-to-one with dropped packets. + * + * The recommended interpretation for high speed interfaces is - + * number of packets dropped because they did not fit into buffers + * provided by the host, e.g. packets larger than MTU or next buffer + * in the ring was not available for a scatter transfer. + * + * Part of aggregate "frame" errors in `/proc/net/dev`. + * + * This statistics was historically used interchangeably with + * @rx_fifo_errors. + * + * This statistic corresponds to hardware events and is not commonly used + * on software devices. + * + * @rx_crc_errors: Number of packets received with a CRC error. + * Part of aggregate "frame" errors in `/proc/net/dev`. + * + * For IEEE 802.3 devices this counter must be equivalent to: + * + * - 30.3.1.1.6 aFrameCheckSequenceErrors + * + * @rx_frame_errors: Receiver frame alignment errors. + * Part of aggregate "frame" errors in `/proc/net/dev`. + * + * For IEEE 802.3 devices this counter should be equivalent to: + * + * - 30.3.1.1.7 aAlignmentErrors + * + * @rx_fifo_errors: Receiver FIFO error counter. + * + * Historically the count of overflow events. Those events may be + * reported in the receive descriptors or via interrupts, and may + * not correspond one-to-one with dropped packets. + * + * This statistics was used interchangeably with @rx_over_errors. + * Not recommended for use in drivers for high speed interfaces. + * + * This statistic is used on software devices, e.g. to count software + * packet queue overflow (can) or sequencing errors (GRE). + * + * @rx_missed_errors: Count of packets missed by the host. + * Folded into the "drop" counter in `/proc/net/dev`. + * + * Counts number of packets dropped by the device due to lack + * of buffer space. This usually indicates that the host interface + * is slower than the network interface, or host is not keeping up + * with the receive packet rate. + * + * This statistic corresponds to hardware events and is not used + * on software devices. + * + * @tx_aborted_errors: + * Part of aggregate "carrier" errors in `/proc/net/dev`. + * For IEEE 802.3 devices capable of half-duplex operation this counter + * must be equivalent to: + * + * - 30.3.1.1.11 aFramesAbortedDueToXSColls + * + * High speed interfaces may use this counter as a general device + * discard counter. + * + * @tx_carrier_errors: Number of frame transmission errors due to loss + * of carrier during transmission. + * Part of aggregate "carrier" errors in `/proc/net/dev`. + * + * For IEEE 802.3 devices this counter must be equivalent to: + * + * - 30.3.1.1.13 aCarrierSenseErrors + * + * @tx_fifo_errors: Number of frame transmission errors due to device + * FIFO underrun / underflow. This condition occurs when the device + * begins transmission of a frame but is unable to deliver the + * entire frame to the transmitter in time for transmission. + * Part of aggregate "carrier" errors in `/proc/net/dev`. + * + * @tx_heartbeat_errors: Number of Heartbeat / SQE Test errors for + * old half-duplex Ethernet. + * Part of aggregate "carrier" errors in `/proc/net/dev`. + * + * For IEEE 802.3 devices possibly equivalent to: + * + * - 30.3.2.1.4 aSQETestErrors + * + * @tx_window_errors: Number of frame transmission errors due + * to late collisions (for Ethernet - after the first 64B of transmission). + * Part of aggregate "carrier" errors in `/proc/net/dev`. + * + * For IEEE 802.3 devices this counter must be equivalent to: + * + * - 30.3.1.1.10 aLateCollisions + * + * @rx_compressed: Number of correctly received compressed packets. + * This counters is only meaningful for interfaces which support + * packet compression (e.g. CSLIP, PPP). + * + * @tx_compressed: Number of transmitted compressed packets. + * This counters is only meaningful for interfaces which support + * packet compression (e.g. CSLIP, PPP). + * + * @rx_nohandler: Number of packets received on the interface + * but dropped by the networking stack because the device is + * not designated to receive packets (e.g. backup link in a bond). + */ struct rtnl_link_stats64 { - __u64 rx_packets; /* total packets received */ - __u64 tx_packets; /* total packets transmitted */ - __u64 rx_bytes; /* total bytes received */ - __u64 tx_bytes; /* total bytes transmitted */ - __u64 rx_errors; /* bad packets received */ - __u64 tx_errors; /* packet transmit problems */ - __u64 rx_dropped; /* no space in linux buffers */ - __u64 tx_dropped; /* no space available in linux */ - __u64 multicast; /* multicast packets received */ + __u64 rx_packets; + __u64 tx_packets; + __u64 rx_bytes; + __u64 tx_bytes; + __u64 rx_errors; + __u64 tx_errors; + __u64 rx_dropped; + __u64 tx_dropped; + __u64 multicast; __u64 collisions; /* detailed rx_errors: */ __u64 rx_length_errors; - __u64 rx_over_errors; /* receiver ring buff overflow */ - __u64 rx_crc_errors; /* recved pkt with crc error */ - __u64 rx_frame_errors; /* recv'd frame alignment error */ - __u64 rx_fifo_errors; /* recv'r fifo overrun */ - __u64 rx_missed_errors; /* receiver missed packet */ + __u64 rx_over_errors; + __u64 rx_crc_errors; + __u64 rx_frame_errors; + __u64 rx_fifo_errors; + __u64 rx_missed_errors; /* detailed tx_errors */ __u64 tx_aborted_errors; @@ -71,8 +242,7 @@ struct rtnl_link_stats64 { /* for cslip etc */ __u64 rx_compressed; __u64 tx_compressed; - - __u64 rx_nohandler; /* dropped, no handler found */ + __u64 rx_nohandler; }; /* The struct should be in sync with struct ifmap */ @@ -419,6 +589,8 @@ enum { IFLA_MACVLAN_MACADDR, IFLA_MACVLAN_MACADDR_DATA, IFLA_MACVLAN_MACADDR_COUNT, + IFLA_MACVLAN_BC_QUEUE_LEN, + IFLA_MACVLAN_BC_QUEUE_LEN_USED, __IFLA_MACVLAN_MAX, }; diff --git a/src/basic/linux/l2tp.h b/src/basic/linux/l2tp.h index 61158f5a1..30c80d5ba 100644 --- a/src/basic/linux/l2tp.h +++ b/src/basic/linux/l2tp.h @@ -108,7 +108,7 @@ enum { L2TP_ATTR_VLAN_ID, /* u16 (not used) */ L2TP_ATTR_COOKIE, /* 0, 4 or 8 bytes */ L2TP_ATTR_PEER_COOKIE, /* 0, 4 or 8 bytes */ - L2TP_ATTR_DEBUG, /* u32, enum l2tp_debug_flags */ + L2TP_ATTR_DEBUG, /* u32, enum l2tp_debug_flags (not used) */ L2TP_ATTR_RECV_SEQ, /* u8 */ L2TP_ATTR_SEND_SEQ, /* u8 */ L2TP_ATTR_LNS_MODE, /* u8 */ @@ -144,6 +144,7 @@ enum { L2TP_ATTR_RX_OOS_PACKETS, /* u64 */ L2TP_ATTR_RX_ERRORS, /* u64 */ L2TP_ATTR_STATS_PAD, + L2TP_ATTR_RX_COOKIE_DISCARDS, /* u64 */ __L2TP_ATTR_STATS_MAX, }; @@ -177,7 +178,9 @@ enum l2tp_seqmode { }; /** - * enum l2tp_debug_flags - debug message categories for L2TP tunnels/sessions + * enum l2tp_debug_flags - debug message categories for L2TP tunnels/sessions. + * + * Unused. * * @L2TP_MSG_DEBUG: verbose debug (if compiled in) * @L2TP_MSG_CONTROL: userspace - kernel interface diff --git a/src/basic/linux/loadavg.h b/src/basic/linux/loadavg.h index 521a787e8..83ec54b65 100644 --- a/src/basic/linux/loadavg.h +++ b/src/basic/linux/loadavg.h @@ -12,15 +12,15 @@ * the EXP_n values would be 1981, 2034 and 2043 if still using only * 11 bit fractions. */ -extern unsigned long avenrun[]; /* Load averages */ +extern unsigned long avenrun[]; /* Load averages */ extern void get_avenrun(unsigned long *loads, unsigned long offset, int shift); -#define FSHIFT 11 /* nr of bits of precision */ -#define FIXED_1 (1<= load) - newload += FIXED_1-1; + newload = load * exp + active * (FIXED_1 - exp); + if (active >= load) + newload += FIXED_1-1; - return newload / FIXED_1; + return newload / FIXED_1; } extern unsigned long calc_load_n(unsigned long load, unsigned long exp, - unsigned long active, unsigned int n); + unsigned long active, unsigned int n); #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) -extern void calc_global_load(unsigned long ticks); +extern void calc_global_load(void); #endif /* _LINUX_SCHED_LOADAVG_H */ diff --git a/src/basic/linux/netfilter/nf_tables.h b/src/basic/linux/netfilter/nf_tables.h new file mode 100644 index 000000000..4565456c0 --- /dev/null +++ b/src/basic/linux/netfilter/nf_tables.h @@ -0,0 +1,1869 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _LINUX_NF_TABLES_H +#define _LINUX_NF_TABLES_H + +#define NFT_NAME_MAXLEN 256 +#define NFT_TABLE_MAXNAMELEN NFT_NAME_MAXLEN +#define NFT_CHAIN_MAXNAMELEN NFT_NAME_MAXLEN +#define NFT_SET_MAXNAMELEN NFT_NAME_MAXLEN +#define NFT_OBJ_MAXNAMELEN NFT_NAME_MAXLEN +#define NFT_USERDATA_MAXLEN 256 +#define NFT_OSF_MAXGENRELEN 16 + +/** + * enum nft_registers - nf_tables registers + * + * nf_tables used to have five registers: a verdict register and four data + * registers of size 16. The data registers have been changed to 16 registers + * of size 4. For compatibility reasons, the NFT_REG_[1-4] registers still + * map to areas of size 16, the 4 byte registers are addressed using + * NFT_REG32_00 - NFT_REG32_15. + */ +enum nft_registers { + NFT_REG_VERDICT, + NFT_REG_1, + NFT_REG_2, + NFT_REG_3, + NFT_REG_4, + __NFT_REG_MAX, + + NFT_REG32_00 = 8, + NFT_REG32_01, + NFT_REG32_02, + NFT_REG32_03, + NFT_REG32_04, + NFT_REG32_05, + NFT_REG32_06, + NFT_REG32_07, + NFT_REG32_08, + NFT_REG32_09, + NFT_REG32_10, + NFT_REG32_11, + NFT_REG32_12, + NFT_REG32_13, + NFT_REG32_14, + NFT_REG32_15, +}; +#define NFT_REG_MAX (__NFT_REG_MAX - 1) + +#define NFT_REG_SIZE 16 +#define NFT_REG32_SIZE 4 +#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1) + +/** + * enum nft_verdicts - nf_tables internal verdicts + * + * @NFT_CONTINUE: continue evaluation of the current rule + * @NFT_BREAK: terminate evaluation of the current rule + * @NFT_JUMP: push the current chain on the jump stack and jump to a chain + * @NFT_GOTO: jump to a chain without pushing the current chain on the jump stack + * @NFT_RETURN: return to the topmost chain on the jump stack + * + * The nf_tables verdicts share their numeric space with the netfilter verdicts. + */ +enum nft_verdicts { + NFT_CONTINUE = -1, + NFT_BREAK = -2, + NFT_JUMP = -3, + NFT_GOTO = -4, + NFT_RETURN = -5, +}; + +/** + * enum nf_tables_msg_types - nf_tables netlink message types + * + * @NFT_MSG_NEWTABLE: create a new table (enum nft_table_attributes) + * @NFT_MSG_GETTABLE: get a table (enum nft_table_attributes) + * @NFT_MSG_DELTABLE: delete a table (enum nft_table_attributes) + * @NFT_MSG_NEWCHAIN: create a new chain (enum nft_chain_attributes) + * @NFT_MSG_GETCHAIN: get a chain (enum nft_chain_attributes) + * @NFT_MSG_DELCHAIN: delete a chain (enum nft_chain_attributes) + * @NFT_MSG_NEWRULE: create a new rule (enum nft_rule_attributes) + * @NFT_MSG_GETRULE: get a rule (enum nft_rule_attributes) + * @NFT_MSG_DELRULE: delete a rule (enum nft_rule_attributes) + * @NFT_MSG_NEWSET: create a new set (enum nft_set_attributes) + * @NFT_MSG_GETSET: get a set (enum nft_set_attributes) + * @NFT_MSG_DELSET: delete a set (enum nft_set_attributes) + * @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes) + * @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes) + * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes) + * @NFT_MSG_NEWGEN: announce a new generation, only for events (enum nft_gen_attributes) + * @NFT_MSG_GETGEN: get the rule-set generation (enum nft_gen_attributes) + * @NFT_MSG_TRACE: trace event (enum nft_trace_attributes) + * @NFT_MSG_NEWOBJ: create a stateful object (enum nft_obj_attributes) + * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes) + * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes) + * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes) + * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes) + * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes) + * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes) + */ +enum nf_tables_msg_types { + NFT_MSG_NEWTABLE, + NFT_MSG_GETTABLE, + NFT_MSG_DELTABLE, + NFT_MSG_NEWCHAIN, + NFT_MSG_GETCHAIN, + NFT_MSG_DELCHAIN, + NFT_MSG_NEWRULE, + NFT_MSG_GETRULE, + NFT_MSG_DELRULE, + NFT_MSG_NEWSET, + NFT_MSG_GETSET, + NFT_MSG_DELSET, + NFT_MSG_NEWSETELEM, + NFT_MSG_GETSETELEM, + NFT_MSG_DELSETELEM, + NFT_MSG_NEWGEN, + NFT_MSG_GETGEN, + NFT_MSG_TRACE, + NFT_MSG_NEWOBJ, + NFT_MSG_GETOBJ, + NFT_MSG_DELOBJ, + NFT_MSG_GETOBJ_RESET, + NFT_MSG_NEWFLOWTABLE, + NFT_MSG_GETFLOWTABLE, + NFT_MSG_DELFLOWTABLE, + NFT_MSG_MAX, +}; + +/** + * enum nft_list_attributes - nf_tables generic list netlink attributes + * + * @NFTA_LIST_ELEM: list element (NLA_NESTED) + */ +enum nft_list_attributes { + NFTA_LIST_UNPEC, + NFTA_LIST_ELEM, + __NFTA_LIST_MAX +}; +#define NFTA_LIST_MAX (__NFTA_LIST_MAX - 1) + +/** + * enum nft_hook_attributes - nf_tables netfilter hook netlink attributes + * + * @NFTA_HOOK_HOOKNUM: netfilter hook number (NLA_U32) + * @NFTA_HOOK_PRIORITY: netfilter hook priority (NLA_U32) + * @NFTA_HOOK_DEV: netdevice name (NLA_STRING) + * @NFTA_HOOK_DEVS: list of netdevices (NLA_NESTED) + */ +enum nft_hook_attributes { + NFTA_HOOK_UNSPEC, + NFTA_HOOK_HOOKNUM, + NFTA_HOOK_PRIORITY, + NFTA_HOOK_DEV, + NFTA_HOOK_DEVS, + __NFTA_HOOK_MAX +}; +#define NFTA_HOOK_MAX (__NFTA_HOOK_MAX - 1) + +/** + * enum nft_table_flags - nf_tables table flags + * + * @NFT_TABLE_F_DORMANT: this table is not active + */ +enum nft_table_flags { + NFT_TABLE_F_DORMANT = 0x1, +}; + +/** + * enum nft_table_attributes - nf_tables table netlink attributes + * + * @NFTA_TABLE_NAME: name of the table (NLA_STRING) + * @NFTA_TABLE_FLAGS: bitmask of enum nft_table_flags (NLA_U32) + * @NFTA_TABLE_USE: number of chains in this table (NLA_U32) + */ +enum nft_table_attributes { + NFTA_TABLE_UNSPEC, + NFTA_TABLE_NAME, + NFTA_TABLE_FLAGS, + NFTA_TABLE_USE, + NFTA_TABLE_HANDLE, + NFTA_TABLE_PAD, + __NFTA_TABLE_MAX +}; +#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1) + +/** + * enum nft_chain_attributes - nf_tables chain netlink attributes + * + * @NFTA_CHAIN_TABLE: name of the table containing the chain (NLA_STRING) + * @NFTA_CHAIN_HANDLE: numeric handle of the chain (NLA_U64) + * @NFTA_CHAIN_NAME: name of the chain (NLA_STRING) + * @NFTA_CHAIN_HOOK: hook specification for basechains (NLA_NESTED: nft_hook_attributes) + * @NFTA_CHAIN_POLICY: numeric policy of the chain (NLA_U32) + * @NFTA_CHAIN_USE: number of references to this chain (NLA_U32) + * @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING) + * @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes) + * @NFTA_CHAIN_FLAGS: chain flags + */ +enum nft_chain_attributes { + NFTA_CHAIN_UNSPEC, + NFTA_CHAIN_TABLE, + NFTA_CHAIN_HANDLE, + NFTA_CHAIN_NAME, + NFTA_CHAIN_HOOK, + NFTA_CHAIN_POLICY, + NFTA_CHAIN_USE, + NFTA_CHAIN_TYPE, + NFTA_CHAIN_COUNTERS, + NFTA_CHAIN_PAD, + NFTA_CHAIN_FLAGS, + __NFTA_CHAIN_MAX +}; +#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1) + +/** + * enum nft_rule_attributes - nf_tables rule netlink attributes + * + * @NFTA_RULE_TABLE: name of the table containing the rule (NLA_STRING) + * @NFTA_RULE_CHAIN: name of the chain containing the rule (NLA_STRING) + * @NFTA_RULE_HANDLE: numeric handle of the rule (NLA_U64) + * @NFTA_RULE_EXPRESSIONS: list of expressions (NLA_NESTED: nft_expr_attributes) + * @NFTA_RULE_COMPAT: compatibility specifications of the rule (NLA_NESTED: nft_rule_compat_attributes) + * @NFTA_RULE_POSITION: numeric handle of the previous rule (NLA_U64) + * @NFTA_RULE_USERDATA: user data (NLA_BINARY, NFT_USERDATA_MAXLEN) + * @NFTA_RULE_ID: uniquely identifies a rule in a transaction (NLA_U32) + * @NFTA_RULE_POSITION_ID: transaction unique identifier of the previous rule (NLA_U32) + */ +enum nft_rule_attributes { + NFTA_RULE_UNSPEC, + NFTA_RULE_TABLE, + NFTA_RULE_CHAIN, + NFTA_RULE_HANDLE, + NFTA_RULE_EXPRESSIONS, + NFTA_RULE_COMPAT, + NFTA_RULE_POSITION, + NFTA_RULE_USERDATA, + NFTA_RULE_PAD, + NFTA_RULE_ID, + NFTA_RULE_POSITION_ID, + __NFTA_RULE_MAX +}; +#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1) + +/** + * enum nft_rule_compat_flags - nf_tables rule compat flags + * + * @NFT_RULE_COMPAT_F_INV: invert the check result + */ +enum nft_rule_compat_flags { + NFT_RULE_COMPAT_F_INV = (1 << 1), + NFT_RULE_COMPAT_F_MASK = NFT_RULE_COMPAT_F_INV, +}; + +/** + * enum nft_rule_compat_attributes - nf_tables rule compat attributes + * + * @NFTA_RULE_COMPAT_PROTO: numeric value of handled protocol (NLA_U32) + * @NFTA_RULE_COMPAT_FLAGS: bitmask of enum nft_rule_compat_flags (NLA_U32) + */ +enum nft_rule_compat_attributes { + NFTA_RULE_COMPAT_UNSPEC, + NFTA_RULE_COMPAT_PROTO, + NFTA_RULE_COMPAT_FLAGS, + __NFTA_RULE_COMPAT_MAX +}; +#define NFTA_RULE_COMPAT_MAX (__NFTA_RULE_COMPAT_MAX - 1) + +/** + * enum nft_set_flags - nf_tables set flags + * + * @NFT_SET_ANONYMOUS: name allocation, automatic cleanup on unlink + * @NFT_SET_CONSTANT: set contents may not change while bound + * @NFT_SET_INTERVAL: set contains intervals + * @NFT_SET_MAP: set is used as a dictionary + * @NFT_SET_TIMEOUT: set uses timeouts + * @NFT_SET_EVAL: set can be updated from the evaluation path + * @NFT_SET_OBJECT: set contains stateful objects + * @NFT_SET_CONCAT: set contains a concatenation + */ +enum nft_set_flags { + NFT_SET_ANONYMOUS = 0x1, + NFT_SET_CONSTANT = 0x2, + NFT_SET_INTERVAL = 0x4, + NFT_SET_MAP = 0x8, + NFT_SET_TIMEOUT = 0x10, + NFT_SET_EVAL = 0x20, + NFT_SET_OBJECT = 0x40, + NFT_SET_CONCAT = 0x80, +}; + +/** + * enum nft_set_policies - set selection policy + * + * @NFT_SET_POL_PERFORMANCE: prefer high performance over low memory use + * @NFT_SET_POL_MEMORY: prefer low memory use over high performance + */ +enum nft_set_policies { + NFT_SET_POL_PERFORMANCE, + NFT_SET_POL_MEMORY, +}; + +/** + * enum nft_set_desc_attributes - set element description + * + * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32) + * @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED) + */ +enum nft_set_desc_attributes { + NFTA_SET_DESC_UNSPEC, + NFTA_SET_DESC_SIZE, + NFTA_SET_DESC_CONCAT, + __NFTA_SET_DESC_MAX +}; +#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1) + +/** + * enum nft_set_field_attributes - attributes of concatenated fields + * + * @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32) + */ +enum nft_set_field_attributes { + NFTA_SET_FIELD_UNSPEC, + NFTA_SET_FIELD_LEN, + __NFTA_SET_FIELD_MAX +}; +#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1) + +/** + * enum nft_set_attributes - nf_tables set netlink attributes + * + * @NFTA_SET_TABLE: table name (NLA_STRING) + * @NFTA_SET_NAME: set name (NLA_STRING) + * @NFTA_SET_FLAGS: bitmask of enum nft_set_flags (NLA_U32) + * @NFTA_SET_KEY_TYPE: key data type, informational purpose only (NLA_U32) + * @NFTA_SET_KEY_LEN: key data length (NLA_U32) + * @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32) + * @NFTA_SET_DATA_LEN: mapping data length (NLA_U32) + * @NFTA_SET_POLICY: selection policy (NLA_U32) + * @NFTA_SET_DESC: set description (NLA_NESTED) + * @NFTA_SET_ID: uniquely identifies a set in a transaction (NLA_U32) + * @NFTA_SET_TIMEOUT: default timeout value (NLA_U64) + * @NFTA_SET_GC_INTERVAL: garbage collection interval (NLA_U32) + * @NFTA_SET_USERDATA: user data (NLA_BINARY) + * @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*) + * @NFTA_SET_HANDLE: set handle (NLA_U64) + * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes) + */ +enum nft_set_attributes { + NFTA_SET_UNSPEC, + NFTA_SET_TABLE, + NFTA_SET_NAME, + NFTA_SET_FLAGS, + NFTA_SET_KEY_TYPE, + NFTA_SET_KEY_LEN, + NFTA_SET_DATA_TYPE, + NFTA_SET_DATA_LEN, + NFTA_SET_POLICY, + NFTA_SET_DESC, + NFTA_SET_ID, + NFTA_SET_TIMEOUT, + NFTA_SET_GC_INTERVAL, + NFTA_SET_USERDATA, + NFTA_SET_PAD, + NFTA_SET_OBJ_TYPE, + NFTA_SET_HANDLE, + NFTA_SET_EXPR, + __NFTA_SET_MAX +}; +#define NFTA_SET_MAX (__NFTA_SET_MAX - 1) + +/** + * enum nft_set_elem_flags - nf_tables set element flags + * + * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval + */ +enum nft_set_elem_flags { + NFT_SET_ELEM_INTERVAL_END = 0x1, +}; + +/** + * enum nft_set_elem_attributes - nf_tables set element netlink attributes + * + * @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data) + * @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes) + * @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32) + * @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64) + * @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64) + * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY) + * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes) + * @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING) + * @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data) + */ +enum nft_set_elem_attributes { + NFTA_SET_ELEM_UNSPEC, + NFTA_SET_ELEM_KEY, + NFTA_SET_ELEM_DATA, + NFTA_SET_ELEM_FLAGS, + NFTA_SET_ELEM_TIMEOUT, + NFTA_SET_ELEM_EXPIRATION, + NFTA_SET_ELEM_USERDATA, + NFTA_SET_ELEM_EXPR, + NFTA_SET_ELEM_PAD, + NFTA_SET_ELEM_OBJREF, + NFTA_SET_ELEM_KEY_END, + __NFTA_SET_ELEM_MAX +}; +#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1) + +/** + * enum nft_set_elem_list_attributes - nf_tables set element list netlink attributes + * + * @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING) + * @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING) + * @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes) + * @NFTA_SET_ELEM_LIST_SET_ID: uniquely identifies a set in a transaction (NLA_U32) + */ +enum nft_set_elem_list_attributes { + NFTA_SET_ELEM_LIST_UNSPEC, + NFTA_SET_ELEM_LIST_TABLE, + NFTA_SET_ELEM_LIST_SET, + NFTA_SET_ELEM_LIST_ELEMENTS, + NFTA_SET_ELEM_LIST_SET_ID, + __NFTA_SET_ELEM_LIST_MAX +}; +#define NFTA_SET_ELEM_LIST_MAX (__NFTA_SET_ELEM_LIST_MAX - 1) + +/** + * enum nft_data_types - nf_tables data types + * + * @NFT_DATA_VALUE: generic data + * @NFT_DATA_VERDICT: netfilter verdict + * + * The type of data is usually determined by the kernel directly and is not + * explicitly specified by userspace. The only difference are sets, where + * userspace specifies the key and mapping data types. + * + * The values 0xffffff00-0xffffffff are reserved for internally used types. + * The remaining range can be freely used by userspace to encode types, all + * values are equivalent to NFT_DATA_VALUE. + */ +enum nft_data_types { + NFT_DATA_VALUE, + NFT_DATA_VERDICT = 0xffffff00U, +}; + +#define NFT_DATA_RESERVED_MASK 0xffffff00U + +/** + * enum nft_data_attributes - nf_tables data netlink attributes + * + * @NFTA_DATA_VALUE: generic data (NLA_BINARY) + * @NFTA_DATA_VERDICT: nf_tables verdict (NLA_NESTED: nft_verdict_attributes) + */ +enum nft_data_attributes { + NFTA_DATA_UNSPEC, + NFTA_DATA_VALUE, + NFTA_DATA_VERDICT, + __NFTA_DATA_MAX +}; +#define NFTA_DATA_MAX (__NFTA_DATA_MAX - 1) + +/* Maximum length of a value */ +#define NFT_DATA_VALUE_MAXLEN 64 + +/** + * enum nft_verdict_attributes - nf_tables verdict netlink attributes + * + * @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts) + * @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING) + */ +enum nft_verdict_attributes { + NFTA_VERDICT_UNSPEC, + NFTA_VERDICT_CODE, + NFTA_VERDICT_CHAIN, + __NFTA_VERDICT_MAX +}; +#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1) + +/** + * enum nft_expr_attributes - nf_tables expression netlink attributes + * + * @NFTA_EXPR_NAME: name of the expression type (NLA_STRING) + * @NFTA_EXPR_DATA: type specific data (NLA_NESTED) + */ +enum nft_expr_attributes { + NFTA_EXPR_UNSPEC, + NFTA_EXPR_NAME, + NFTA_EXPR_DATA, + __NFTA_EXPR_MAX +}; +#define NFTA_EXPR_MAX (__NFTA_EXPR_MAX - 1) + +/** + * enum nft_immediate_attributes - nf_tables immediate expression netlink attributes + * + * @NFTA_IMMEDIATE_DREG: destination register to load data into (NLA_U32) + * @NFTA_IMMEDIATE_DATA: data to load (NLA_NESTED: nft_data_attributes) + */ +enum nft_immediate_attributes { + NFTA_IMMEDIATE_UNSPEC, + NFTA_IMMEDIATE_DREG, + NFTA_IMMEDIATE_DATA, + __NFTA_IMMEDIATE_MAX +}; +#define NFTA_IMMEDIATE_MAX (__NFTA_IMMEDIATE_MAX - 1) + +/** + * enum nft_bitwise_ops - nf_tables bitwise operations + * + * @NFT_BITWISE_BOOL: mask-and-xor operation used to implement NOT, AND, OR and + * XOR boolean operations + * @NFT_BITWISE_LSHIFT: left-shift operation + * @NFT_BITWISE_RSHIFT: right-shift operation + */ +enum nft_bitwise_ops { + NFT_BITWISE_BOOL, + NFT_BITWISE_LSHIFT, + NFT_BITWISE_RSHIFT, +}; + +/** + * enum nft_bitwise_attributes - nf_tables bitwise expression netlink attributes + * + * @NFTA_BITWISE_SREG: source register (NLA_U32: nft_registers) + * @NFTA_BITWISE_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_BITWISE_LEN: length of operands (NLA_U32) + * @NFTA_BITWISE_MASK: mask value (NLA_NESTED: nft_data_attributes) + * @NFTA_BITWISE_XOR: xor value (NLA_NESTED: nft_data_attributes) + * @NFTA_BITWISE_OP: type of operation (NLA_U32: nft_bitwise_ops) + * @NFTA_BITWISE_DATA: argument for non-boolean operations + * (NLA_NESTED: nft_data_attributes) + * + * The bitwise expression supports boolean and shift operations. It implements + * the boolean operations by performing the following operation: + * + * dreg = (sreg & mask) ^ xor + * + * with these mask and xor values: + * + * mask xor + * NOT: 1 1 + * OR: ~x x + * XOR: 1 x + * AND: x 0 + */ +enum nft_bitwise_attributes { + NFTA_BITWISE_UNSPEC, + NFTA_BITWISE_SREG, + NFTA_BITWISE_DREG, + NFTA_BITWISE_LEN, + NFTA_BITWISE_MASK, + NFTA_BITWISE_XOR, + NFTA_BITWISE_OP, + NFTA_BITWISE_DATA, + __NFTA_BITWISE_MAX +}; +#define NFTA_BITWISE_MAX (__NFTA_BITWISE_MAX - 1) + +/** + * enum nft_byteorder_ops - nf_tables byteorder operators + * + * @NFT_BYTEORDER_NTOH: network to host operator + * @NFT_BYTEORDER_HTON: host to network operator + */ +enum nft_byteorder_ops { + NFT_BYTEORDER_NTOH, + NFT_BYTEORDER_HTON, +}; + +/** + * enum nft_byteorder_attributes - nf_tables byteorder expression netlink attributes + * + * @NFTA_BYTEORDER_SREG: source register (NLA_U32: nft_registers) + * @NFTA_BYTEORDER_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_BYTEORDER_OP: operator (NLA_U32: enum nft_byteorder_ops) + * @NFTA_BYTEORDER_LEN: length of the data (NLA_U32) + * @NFTA_BYTEORDER_SIZE: data size in bytes (NLA_U32: 2 or 4) + */ +enum nft_byteorder_attributes { + NFTA_BYTEORDER_UNSPEC, + NFTA_BYTEORDER_SREG, + NFTA_BYTEORDER_DREG, + NFTA_BYTEORDER_OP, + NFTA_BYTEORDER_LEN, + NFTA_BYTEORDER_SIZE, + __NFTA_BYTEORDER_MAX +}; +#define NFTA_BYTEORDER_MAX (__NFTA_BYTEORDER_MAX - 1) + +/** + * enum nft_cmp_ops - nf_tables relational operator + * + * @NFT_CMP_EQ: equal + * @NFT_CMP_NEQ: not equal + * @NFT_CMP_LT: less than + * @NFT_CMP_LTE: less than or equal to + * @NFT_CMP_GT: greater than + * @NFT_CMP_GTE: greater than or equal to + */ +enum nft_cmp_ops { + NFT_CMP_EQ, + NFT_CMP_NEQ, + NFT_CMP_LT, + NFT_CMP_LTE, + NFT_CMP_GT, + NFT_CMP_GTE, +}; + +/** + * enum nft_cmp_attributes - nf_tables cmp expression netlink attributes + * + * @NFTA_CMP_SREG: source register of data to compare (NLA_U32: nft_registers) + * @NFTA_CMP_OP: cmp operation (NLA_U32: nft_cmp_ops) + * @NFTA_CMP_DATA: data to compare against (NLA_NESTED: nft_data_attributes) + */ +enum nft_cmp_attributes { + NFTA_CMP_UNSPEC, + NFTA_CMP_SREG, + NFTA_CMP_OP, + NFTA_CMP_DATA, + __NFTA_CMP_MAX +}; +#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1) + +/** + * enum nft_range_ops - nf_tables range operator + * + * @NFT_RANGE_EQ: equal + * @NFT_RANGE_NEQ: not equal + */ +enum nft_range_ops { + NFT_RANGE_EQ, + NFT_RANGE_NEQ, +}; + +/** + * enum nft_range_attributes - nf_tables range expression netlink attributes + * + * @NFTA_RANGE_SREG: source register of data to compare (NLA_U32: nft_registers) + * @NFTA_RANGE_OP: cmp operation (NLA_U32: nft_cmp_ops) + * @NFTA_RANGE_FROM_DATA: data range from (NLA_NESTED: nft_data_attributes) + * @NFTA_RANGE_TO_DATA: data range to (NLA_NESTED: nft_data_attributes) + */ +enum nft_range_attributes { + NFTA_RANGE_UNSPEC, + NFTA_RANGE_SREG, + NFTA_RANGE_OP, + NFTA_RANGE_FROM_DATA, + NFTA_RANGE_TO_DATA, + __NFTA_RANGE_MAX +}; +#define NFTA_RANGE_MAX (__NFTA_RANGE_MAX - 1) + +enum nft_lookup_flags { + NFT_LOOKUP_F_INV = (1 << 0), +}; + +/** + * enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes + * + * @NFTA_LOOKUP_SET: name of the set where to look for (NLA_STRING) + * @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers) + * @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32) + * @NFTA_LOOKUP_FLAGS: flags (NLA_U32: enum nft_lookup_flags) + */ +enum nft_lookup_attributes { + NFTA_LOOKUP_UNSPEC, + NFTA_LOOKUP_SET, + NFTA_LOOKUP_SREG, + NFTA_LOOKUP_DREG, + NFTA_LOOKUP_SET_ID, + NFTA_LOOKUP_FLAGS, + __NFTA_LOOKUP_MAX +}; +#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1) + +enum nft_dynset_ops { + NFT_DYNSET_OP_ADD, + NFT_DYNSET_OP_UPDATE, + NFT_DYNSET_OP_DELETE, +}; + +enum nft_dynset_flags { + NFT_DYNSET_F_INV = (1 << 0), +}; + +/** + * enum nft_dynset_attributes - dynset expression attributes + * + * @NFTA_DYNSET_SET_NAME: name of set the to add data to (NLA_STRING) + * @NFTA_DYNSET_SET_ID: uniquely identifier of the set in the transaction (NLA_U32) + * @NFTA_DYNSET_OP: operation (NLA_U32) + * @NFTA_DYNSET_SREG_KEY: source register of the key (NLA_U32) + * @NFTA_DYNSET_SREG_DATA: source register of the data (NLA_U32) + * @NFTA_DYNSET_TIMEOUT: timeout value for the new element (NLA_U64) + * @NFTA_DYNSET_EXPR: expression (NLA_NESTED: nft_expr_attributes) + * @NFTA_DYNSET_FLAGS: flags (NLA_U32) + */ +enum nft_dynset_attributes { + NFTA_DYNSET_UNSPEC, + NFTA_DYNSET_SET_NAME, + NFTA_DYNSET_SET_ID, + NFTA_DYNSET_OP, + NFTA_DYNSET_SREG_KEY, + NFTA_DYNSET_SREG_DATA, + NFTA_DYNSET_TIMEOUT, + NFTA_DYNSET_EXPR, + NFTA_DYNSET_PAD, + NFTA_DYNSET_FLAGS, + __NFTA_DYNSET_MAX, +}; +#define NFTA_DYNSET_MAX (__NFTA_DYNSET_MAX - 1) + +/** + * enum nft_payload_bases - nf_tables payload expression offset bases + * + * @NFT_PAYLOAD_LL_HEADER: link layer header + * @NFT_PAYLOAD_NETWORK_HEADER: network header + * @NFT_PAYLOAD_TRANSPORT_HEADER: transport header + */ +enum nft_payload_bases { + NFT_PAYLOAD_LL_HEADER, + NFT_PAYLOAD_NETWORK_HEADER, + NFT_PAYLOAD_TRANSPORT_HEADER, +}; + +/** + * enum nft_payload_csum_types - nf_tables payload expression checksum types + * + * @NFT_PAYLOAD_CSUM_NONE: no checksumming + * @NFT_PAYLOAD_CSUM_INET: internet checksum (RFC 791) + */ +enum nft_payload_csum_types { + NFT_PAYLOAD_CSUM_NONE, + NFT_PAYLOAD_CSUM_INET, +}; + +enum nft_payload_csum_flags { + NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0), +}; + +/** + * enum nft_payload_attributes - nf_tables payload expression netlink attributes + * + * @NFTA_PAYLOAD_DREG: destination register to load data into (NLA_U32: nft_registers) + * @NFTA_PAYLOAD_BASE: payload base (NLA_U32: nft_payload_bases) + * @NFTA_PAYLOAD_OFFSET: payload offset relative to base (NLA_U32) + * @NFTA_PAYLOAD_LEN: payload length (NLA_U32) + * @NFTA_PAYLOAD_SREG: source register to load data from (NLA_U32: nft_registers) + * @NFTA_PAYLOAD_CSUM_TYPE: checksum type (NLA_U32) + * @NFTA_PAYLOAD_CSUM_OFFSET: checksum offset relative to base (NLA_U32) + * @NFTA_PAYLOAD_CSUM_FLAGS: checksum flags (NLA_U32) + */ +enum nft_payload_attributes { + NFTA_PAYLOAD_UNSPEC, + NFTA_PAYLOAD_DREG, + NFTA_PAYLOAD_BASE, + NFTA_PAYLOAD_OFFSET, + NFTA_PAYLOAD_LEN, + NFTA_PAYLOAD_SREG, + NFTA_PAYLOAD_CSUM_TYPE, + NFTA_PAYLOAD_CSUM_OFFSET, + NFTA_PAYLOAD_CSUM_FLAGS, + __NFTA_PAYLOAD_MAX +}; +#define NFTA_PAYLOAD_MAX (__NFTA_PAYLOAD_MAX - 1) + +enum nft_exthdr_flags { + NFT_EXTHDR_F_PRESENT = (1 << 0), +}; + +/** + * enum nft_exthdr_op - nf_tables match options + * + * @NFT_EXTHDR_OP_IPV6: match against ipv6 extension headers + * @NFT_EXTHDR_OP_TCP: match against tcp options + * @NFT_EXTHDR_OP_IPV4: match against ipv4 options + */ +enum nft_exthdr_op { + NFT_EXTHDR_OP_IPV6, + NFT_EXTHDR_OP_TCPOPT, + NFT_EXTHDR_OP_IPV4, + __NFT_EXTHDR_OP_MAX +}; +#define NFT_EXTHDR_OP_MAX (__NFT_EXTHDR_OP_MAX - 1) + +/** + * enum nft_exthdr_attributes - nf_tables extension header expression netlink attributes + * + * @NFTA_EXTHDR_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_EXTHDR_TYPE: extension header type (NLA_U8) + * @NFTA_EXTHDR_OFFSET: extension header offset (NLA_U32) + * @NFTA_EXTHDR_LEN: extension header length (NLA_U32) + * @NFTA_EXTHDR_FLAGS: extension header flags (NLA_U32) + * @NFTA_EXTHDR_OP: option match type (NLA_U32) + * @NFTA_EXTHDR_SREG: option match type (NLA_U32) + */ +enum nft_exthdr_attributes { + NFTA_EXTHDR_UNSPEC, + NFTA_EXTHDR_DREG, + NFTA_EXTHDR_TYPE, + NFTA_EXTHDR_OFFSET, + NFTA_EXTHDR_LEN, + NFTA_EXTHDR_FLAGS, + NFTA_EXTHDR_OP, + NFTA_EXTHDR_SREG, + __NFTA_EXTHDR_MAX +}; +#define NFTA_EXTHDR_MAX (__NFTA_EXTHDR_MAX - 1) + +/** + * enum nft_meta_keys - nf_tables meta expression keys + * + * @NFT_META_LEN: packet length (skb->len) + * @NFT_META_PROTOCOL: packet ethertype protocol (skb->protocol), invalid in OUTPUT + * @NFT_META_PRIORITY: packet priority (skb->priority) + * @NFT_META_MARK: packet mark (skb->mark) + * @NFT_META_IIF: packet input interface index (dev->ifindex) + * @NFT_META_OIF: packet output interface index (dev->ifindex) + * @NFT_META_IIFNAME: packet input interface name (dev->name) + * @NFT_META_OIFNAME: packet output interface name (dev->name) + * @NFT_META_IIFTYPE: packet input interface type (dev->type) + * @NFT_META_OIFTYPE: packet output interface type (dev->type) + * @NFT_META_SKUID: originating socket UID (fsuid) + * @NFT_META_SKGID: originating socket GID (fsgid) + * @NFT_META_NFTRACE: packet nftrace bit + * @NFT_META_RTCLASSID: realm value of packet's route (skb->dst->tclassid) + * @NFT_META_SECMARK: packet secmark (skb->secmark) + * @NFT_META_NFPROTO: netfilter protocol + * @NFT_META_L4PROTO: layer 4 protocol number + * @NFT_META_BRI_IIFNAME: packet input bridge interface name + * @NFT_META_BRI_OIFNAME: packet output bridge interface name + * @NFT_META_PKTTYPE: packet type (skb->pkt_type), special handling for loopback + * @NFT_META_CPU: cpu id through smp_processor_id() + * @NFT_META_IIFGROUP: packet input interface group + * @NFT_META_OIFGROUP: packet output interface group + * @NFT_META_CGROUP: socket control group (skb->sk->sk_classid) + * @NFT_META_PRANDOM: a 32bit pseudo-random number + * @NFT_META_SECPATH: boolean, secpath_exists (!!skb->sp) + * @NFT_META_IIFKIND: packet input interface kind name (dev->rtnl_link_ops->kind) + * @NFT_META_OIFKIND: packet output interface kind name (dev->rtnl_link_ops->kind) + * @NFT_META_BRI_IIFPVID: packet input bridge port pvid + * @NFT_META_BRI_IIFVPROTO: packet input bridge vlan proto + * @NFT_META_TIME_NS: time since epoch (in nanoseconds) + * @NFT_META_TIME_DAY: day of week (from 0 = Sunday to 6 = Saturday) + * @NFT_META_TIME_HOUR: hour of day (in seconds) + * @NFT_META_SDIF: slave device interface index + * @NFT_META_SDIFNAME: slave device interface name + */ +enum nft_meta_keys { + NFT_META_LEN, + NFT_META_PROTOCOL, + NFT_META_PRIORITY, + NFT_META_MARK, + NFT_META_IIF, + NFT_META_OIF, + NFT_META_IIFNAME, + NFT_META_OIFNAME, + NFT_META_IIFTYPE, + NFT_META_OIFTYPE, + NFT_META_SKUID, + NFT_META_SKGID, + NFT_META_NFTRACE, + NFT_META_RTCLASSID, + NFT_META_SECMARK, + NFT_META_NFPROTO, + NFT_META_L4PROTO, + NFT_META_BRI_IIFNAME, + NFT_META_BRI_OIFNAME, + NFT_META_PKTTYPE, + NFT_META_CPU, + NFT_META_IIFGROUP, + NFT_META_OIFGROUP, + NFT_META_CGROUP, + NFT_META_PRANDOM, + NFT_META_SECPATH, + NFT_META_IIFKIND, + NFT_META_OIFKIND, + NFT_META_BRI_IIFPVID, + NFT_META_BRI_IIFVPROTO, + NFT_META_TIME_NS, + NFT_META_TIME_DAY, + NFT_META_TIME_HOUR, + NFT_META_SDIF, + NFT_META_SDIFNAME, +}; + +/** + * enum nft_rt_keys - nf_tables routing expression keys + * + * @NFT_RT_CLASSID: realm value of packet's route (skb->dst->tclassid) + * @NFT_RT_NEXTHOP4: routing nexthop for IPv4 + * @NFT_RT_NEXTHOP6: routing nexthop for IPv6 + * @NFT_RT_TCPMSS: fetch current path tcp mss + * @NFT_RT_XFRM: boolean, skb->dst->xfrm != NULL + */ +enum nft_rt_keys { + NFT_RT_CLASSID, + NFT_RT_NEXTHOP4, + NFT_RT_NEXTHOP6, + NFT_RT_TCPMSS, + NFT_RT_XFRM, + __NFT_RT_MAX +}; +#define NFT_RT_MAX (__NFT_RT_MAX - 1) + +/** + * enum nft_hash_types - nf_tables hash expression types + * + * @NFT_HASH_JENKINS: Jenkins Hash + * @NFT_HASH_SYM: Symmetric Hash + */ +enum nft_hash_types { + NFT_HASH_JENKINS, + NFT_HASH_SYM, +}; + +/** + * enum nft_hash_attributes - nf_tables hash expression netlink attributes + * + * @NFTA_HASH_SREG: source register (NLA_U32) + * @NFTA_HASH_DREG: destination register (NLA_U32) + * @NFTA_HASH_LEN: source data length (NLA_U32) + * @NFTA_HASH_MODULUS: modulus value (NLA_U32) + * @NFTA_HASH_SEED: seed value (NLA_U32) + * @NFTA_HASH_OFFSET: add this offset value to hash result (NLA_U32) + * @NFTA_HASH_TYPE: hash operation (NLA_U32: nft_hash_types) + * @NFTA_HASH_SET_NAME: name of the map to lookup (NLA_STRING) + * @NFTA_HASH_SET_ID: id of the map (NLA_U32) + */ +enum nft_hash_attributes { + NFTA_HASH_UNSPEC, + NFTA_HASH_SREG, + NFTA_HASH_DREG, + NFTA_HASH_LEN, + NFTA_HASH_MODULUS, + NFTA_HASH_SEED, + NFTA_HASH_OFFSET, + NFTA_HASH_TYPE, + NFTA_HASH_SET_NAME, /* deprecated */ + NFTA_HASH_SET_ID, /* deprecated */ + __NFTA_HASH_MAX, +}; +#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1) + +/** + * enum nft_meta_attributes - nf_tables meta expression netlink attributes + * + * @NFTA_META_DREG: destination register (NLA_U32) + * @NFTA_META_KEY: meta data item to load (NLA_U32: nft_meta_keys) + * @NFTA_META_SREG: source register (NLA_U32) + */ +enum nft_meta_attributes { + NFTA_META_UNSPEC, + NFTA_META_DREG, + NFTA_META_KEY, + NFTA_META_SREG, + __NFTA_META_MAX +}; +#define NFTA_META_MAX (__NFTA_META_MAX - 1) + +/** + * enum nft_rt_attributes - nf_tables routing expression netlink attributes + * + * @NFTA_RT_DREG: destination register (NLA_U32) + * @NFTA_RT_KEY: routing data item to load (NLA_U32: nft_rt_keys) + */ +enum nft_rt_attributes { + NFTA_RT_UNSPEC, + NFTA_RT_DREG, + NFTA_RT_KEY, + __NFTA_RT_MAX +}; +#define NFTA_RT_MAX (__NFTA_RT_MAX - 1) + +/** + * enum nft_socket_attributes - nf_tables socket expression netlink attributes + * + * @NFTA_SOCKET_KEY: socket key to match + * @NFTA_SOCKET_DREG: destination register + */ +enum nft_socket_attributes { + NFTA_SOCKET_UNSPEC, + NFTA_SOCKET_KEY, + NFTA_SOCKET_DREG, + __NFTA_SOCKET_MAX +}; +#define NFTA_SOCKET_MAX (__NFTA_SOCKET_MAX - 1) + +/* + * enum nft_socket_keys - nf_tables socket expression keys + * + * @NFT_SOCKET_TRANSPARENT: Value of the IP(V6)_TRANSPARENT socket option + * @NFT_SOCKET_MARK: Value of the socket mark + */ +enum nft_socket_keys { + NFT_SOCKET_TRANSPARENT, + NFT_SOCKET_MARK, + __NFT_SOCKET_MAX +}; +#define NFT_SOCKET_MAX (__NFT_SOCKET_MAX - 1) + +/** + * enum nft_ct_keys - nf_tables ct expression keys + * + * @NFT_CT_STATE: conntrack state (bitmask of enum ip_conntrack_info) + * @NFT_CT_DIRECTION: conntrack direction (enum ip_conntrack_dir) + * @NFT_CT_STATUS: conntrack status (bitmask of enum ip_conntrack_status) + * @NFT_CT_MARK: conntrack mark value + * @NFT_CT_SECMARK: conntrack secmark value + * @NFT_CT_EXPIRATION: relative conntrack expiration time in ms + * @NFT_CT_HELPER: connection tracking helper assigned to conntrack + * @NFT_CT_L3PROTOCOL: conntrack layer 3 protocol + * @NFT_CT_SRC: conntrack layer 3 protocol source (IPv4/IPv6 address, deprecated) + * @NFT_CT_DST: conntrack layer 3 protocol destination (IPv4/IPv6 address, deprecated) + * @NFT_CT_PROTOCOL: conntrack layer 4 protocol + * @NFT_CT_PROTO_SRC: conntrack layer 4 protocol source + * @NFT_CT_PROTO_DST: conntrack layer 4 protocol destination + * @NFT_CT_LABELS: conntrack labels + * @NFT_CT_PKTS: conntrack packets + * @NFT_CT_BYTES: conntrack bytes + * @NFT_CT_AVGPKT: conntrack average bytes per packet + * @NFT_CT_ZONE: conntrack zone + * @NFT_CT_EVENTMASK: ctnetlink events to be generated for this conntrack + * @NFT_CT_SRC_IP: conntrack layer 3 protocol source (IPv4 address) + * @NFT_CT_DST_IP: conntrack layer 3 protocol destination (IPv4 address) + * @NFT_CT_SRC_IP6: conntrack layer 3 protocol source (IPv6 address) + * @NFT_CT_DST_IP6: conntrack layer 3 protocol destination (IPv6 address) + * @NFT_CT_ID: conntrack id + */ +enum nft_ct_keys { + NFT_CT_STATE, + NFT_CT_DIRECTION, + NFT_CT_STATUS, + NFT_CT_MARK, + NFT_CT_SECMARK, + NFT_CT_EXPIRATION, + NFT_CT_HELPER, + NFT_CT_L3PROTOCOL, + NFT_CT_SRC, + NFT_CT_DST, + NFT_CT_PROTOCOL, + NFT_CT_PROTO_SRC, + NFT_CT_PROTO_DST, + NFT_CT_LABELS, + NFT_CT_PKTS, + NFT_CT_BYTES, + NFT_CT_AVGPKT, + NFT_CT_ZONE, + NFT_CT_EVENTMASK, + NFT_CT_SRC_IP, + NFT_CT_DST_IP, + NFT_CT_SRC_IP6, + NFT_CT_DST_IP6, + NFT_CT_ID, + __NFT_CT_MAX +}; +#define NFT_CT_MAX (__NFT_CT_MAX - 1) + +/** + * enum nft_ct_attributes - nf_tables ct expression netlink attributes + * + * @NFTA_CT_DREG: destination register (NLA_U32) + * @NFTA_CT_KEY: conntrack data item to load (NLA_U32: nft_ct_keys) + * @NFTA_CT_DIRECTION: direction in case of directional keys (NLA_U8) + * @NFTA_CT_SREG: source register (NLA_U32) + */ +enum nft_ct_attributes { + NFTA_CT_UNSPEC, + NFTA_CT_DREG, + NFTA_CT_KEY, + NFTA_CT_DIRECTION, + NFTA_CT_SREG, + __NFTA_CT_MAX +}; +#define NFTA_CT_MAX (__NFTA_CT_MAX - 1) + +/** + * enum nft_flow_attributes - ct offload expression attributes + * @NFTA_FLOW_TABLE_NAME: flow table name (NLA_STRING) + */ +enum nft_offload_attributes { + NFTA_FLOW_UNSPEC, + NFTA_FLOW_TABLE_NAME, + __NFTA_FLOW_MAX, +}; +#define NFTA_FLOW_MAX (__NFTA_FLOW_MAX - 1) + +enum nft_limit_type { + NFT_LIMIT_PKTS, + NFT_LIMIT_PKT_BYTES +}; + +enum nft_limit_flags { + NFT_LIMIT_F_INV = (1 << 0), +}; + +/** + * enum nft_limit_attributes - nf_tables limit expression netlink attributes + * + * @NFTA_LIMIT_RATE: refill rate (NLA_U64) + * @NFTA_LIMIT_UNIT: refill unit (NLA_U64) + * @NFTA_LIMIT_BURST: burst (NLA_U32) + * @NFTA_LIMIT_TYPE: type of limit (NLA_U32: enum nft_limit_type) + * @NFTA_LIMIT_FLAGS: flags (NLA_U32: enum nft_limit_flags) + */ +enum nft_limit_attributes { + NFTA_LIMIT_UNSPEC, + NFTA_LIMIT_RATE, + NFTA_LIMIT_UNIT, + NFTA_LIMIT_BURST, + NFTA_LIMIT_TYPE, + NFTA_LIMIT_FLAGS, + NFTA_LIMIT_PAD, + __NFTA_LIMIT_MAX +}; +#define NFTA_LIMIT_MAX (__NFTA_LIMIT_MAX - 1) + +enum nft_connlimit_flags { + NFT_CONNLIMIT_F_INV = (1 << 0), +}; + +/** + * enum nft_connlimit_attributes - nf_tables connlimit expression netlink attributes + * + * @NFTA_CONNLIMIT_COUNT: number of connections (NLA_U32) + * @NFTA_CONNLIMIT_FLAGS: flags (NLA_U32: enum nft_connlimit_flags) + */ +enum nft_connlimit_attributes { + NFTA_CONNLIMIT_UNSPEC, + NFTA_CONNLIMIT_COUNT, + NFTA_CONNLIMIT_FLAGS, + __NFTA_CONNLIMIT_MAX +}; +#define NFTA_CONNLIMIT_MAX (__NFTA_CONNLIMIT_MAX - 1) + +/** + * enum nft_counter_attributes - nf_tables counter expression netlink attributes + * + * @NFTA_COUNTER_BYTES: number of bytes (NLA_U64) + * @NFTA_COUNTER_PACKETS: number of packets (NLA_U64) + */ +enum nft_counter_attributes { + NFTA_COUNTER_UNSPEC, + NFTA_COUNTER_BYTES, + NFTA_COUNTER_PACKETS, + NFTA_COUNTER_PAD, + __NFTA_COUNTER_MAX +}; +#define NFTA_COUNTER_MAX (__NFTA_COUNTER_MAX - 1) + +/** + * enum nft_log_attributes - nf_tables log expression netlink attributes + * + * @NFTA_LOG_GROUP: netlink group to send messages to (NLA_U32) + * @NFTA_LOG_PREFIX: prefix to prepend to log messages (NLA_STRING) + * @NFTA_LOG_SNAPLEN: length of payload to include in netlink message (NLA_U32) + * @NFTA_LOG_QTHRESHOLD: queue threshold (NLA_U32) + * @NFTA_LOG_LEVEL: log level (NLA_U32) + * @NFTA_LOG_FLAGS: logging flags (NLA_U32) + */ +enum nft_log_attributes { + NFTA_LOG_UNSPEC, + NFTA_LOG_GROUP, + NFTA_LOG_PREFIX, + NFTA_LOG_SNAPLEN, + NFTA_LOG_QTHRESHOLD, + NFTA_LOG_LEVEL, + NFTA_LOG_FLAGS, + __NFTA_LOG_MAX +}; +#define NFTA_LOG_MAX (__NFTA_LOG_MAX - 1) + +/** + * enum nft_log_level - nf_tables log levels + * + * @NFT_LOGLEVEL_EMERG: system is unusable + * @NFT_LOGLEVEL_ALERT: action must be taken immediately + * @NFT_LOGLEVEL_CRIT: critical conditions + * @NFT_LOGLEVEL_ERR: error conditions + * @NFT_LOGLEVEL_WARNING: warning conditions + * @NFT_LOGLEVEL_NOTICE: normal but significant condition + * @NFT_LOGLEVEL_INFO: informational + * @NFT_LOGLEVEL_DEBUG: debug-level messages + * @NFT_LOGLEVEL_AUDIT: enabling audit logging + */ +enum nft_log_level { + NFT_LOGLEVEL_EMERG, + NFT_LOGLEVEL_ALERT, + NFT_LOGLEVEL_CRIT, + NFT_LOGLEVEL_ERR, + NFT_LOGLEVEL_WARNING, + NFT_LOGLEVEL_NOTICE, + NFT_LOGLEVEL_INFO, + NFT_LOGLEVEL_DEBUG, + NFT_LOGLEVEL_AUDIT, + __NFT_LOGLEVEL_MAX +}; +#define NFT_LOGLEVEL_MAX (__NFT_LOGLEVEL_MAX - 1) + +/** + * enum nft_queue_attributes - nf_tables queue expression netlink attributes + * + * @NFTA_QUEUE_NUM: netlink queue to send messages to (NLA_U16) + * @NFTA_QUEUE_TOTAL: number of queues to load balance packets on (NLA_U16) + * @NFTA_QUEUE_FLAGS: various flags (NLA_U16) + * @NFTA_QUEUE_SREG_QNUM: source register of queue number (NLA_U32: nft_registers) + */ +enum nft_queue_attributes { + NFTA_QUEUE_UNSPEC, + NFTA_QUEUE_NUM, + NFTA_QUEUE_TOTAL, + NFTA_QUEUE_FLAGS, + NFTA_QUEUE_SREG_QNUM, + __NFTA_QUEUE_MAX +}; +#define NFTA_QUEUE_MAX (__NFTA_QUEUE_MAX - 1) + +#define NFT_QUEUE_FLAG_BYPASS 0x01 /* for compatibility with v2 */ +#define NFT_QUEUE_FLAG_CPU_FANOUT 0x02 /* use current CPU (no hashing) */ +#define NFT_QUEUE_FLAG_MASK 0x03 + +enum nft_quota_flags { + NFT_QUOTA_F_INV = (1 << 0), + NFT_QUOTA_F_DEPLETED = (1 << 1), +}; + +/** + * enum nft_quota_attributes - nf_tables quota expression netlink attributes + * + * @NFTA_QUOTA_BYTES: quota in bytes (NLA_U16) + * @NFTA_QUOTA_FLAGS: flags (NLA_U32) + * @NFTA_QUOTA_CONSUMED: quota already consumed in bytes (NLA_U64) + */ +enum nft_quota_attributes { + NFTA_QUOTA_UNSPEC, + NFTA_QUOTA_BYTES, + NFTA_QUOTA_FLAGS, + NFTA_QUOTA_PAD, + NFTA_QUOTA_CONSUMED, + __NFTA_QUOTA_MAX +}; +#define NFTA_QUOTA_MAX (__NFTA_QUOTA_MAX - 1) + +/** + * enum nft_secmark_attributes - nf_tables secmark object netlink attributes + * + * @NFTA_SECMARK_CTX: security context (NLA_STRING) + */ +enum nft_secmark_attributes { + NFTA_SECMARK_UNSPEC, + NFTA_SECMARK_CTX, + __NFTA_SECMARK_MAX, +}; +#define NFTA_SECMARK_MAX (__NFTA_SECMARK_MAX - 1) + +/* Max security context length */ +#define NFT_SECMARK_CTX_MAXLEN 256 + +/** + * enum nft_reject_types - nf_tables reject expression reject types + * + * @NFT_REJECT_ICMP_UNREACH: reject using ICMP unreachable + * @NFT_REJECT_TCP_RST: reject using TCP RST + * @NFT_REJECT_ICMPX_UNREACH: abstracted ICMP unreachable for bridge and inet + */ +enum nft_reject_types { + NFT_REJECT_ICMP_UNREACH, + NFT_REJECT_TCP_RST, + NFT_REJECT_ICMPX_UNREACH, +}; + +/** + * enum nft_reject_code - Generic reject codes for IPv4/IPv6 + * + * @NFT_REJECT_ICMPX_NO_ROUTE: no route to host / network unreachable + * @NFT_REJECT_ICMPX_PORT_UNREACH: port unreachable + * @NFT_REJECT_ICMPX_HOST_UNREACH: host unreachable + * @NFT_REJECT_ICMPX_ADMIN_PROHIBITED: administratively prohibited + * + * These codes are mapped to real ICMP and ICMPv6 codes. + */ +enum nft_reject_inet_code { + NFT_REJECT_ICMPX_NO_ROUTE = 0, + NFT_REJECT_ICMPX_PORT_UNREACH, + NFT_REJECT_ICMPX_HOST_UNREACH, + NFT_REJECT_ICMPX_ADMIN_PROHIBITED, + __NFT_REJECT_ICMPX_MAX +}; +#define NFT_REJECT_ICMPX_MAX (__NFT_REJECT_ICMPX_MAX - 1) + +/** + * enum nft_reject_attributes - nf_tables reject expression netlink attributes + * + * @NFTA_REJECT_TYPE: packet type to use (NLA_U32: nft_reject_types) + * @NFTA_REJECT_ICMP_CODE: ICMP code to use (NLA_U8) + */ +enum nft_reject_attributes { + NFTA_REJECT_UNSPEC, + NFTA_REJECT_TYPE, + NFTA_REJECT_ICMP_CODE, + __NFTA_REJECT_MAX +}; +#define NFTA_REJECT_MAX (__NFTA_REJECT_MAX - 1) + +/** + * enum nft_nat_types - nf_tables nat expression NAT types + * + * @NFT_NAT_SNAT: source NAT + * @NFT_NAT_DNAT: destination NAT + */ +enum nft_nat_types { + NFT_NAT_SNAT, + NFT_NAT_DNAT, +}; + +/** + * enum nft_nat_attributes - nf_tables nat expression netlink attributes + * + * @NFTA_NAT_TYPE: NAT type (NLA_U32: nft_nat_types) + * @NFTA_NAT_FAMILY: NAT family (NLA_U32) + * @NFTA_NAT_REG_ADDR_MIN: source register of address range start (NLA_U32: nft_registers) + * @NFTA_NAT_REG_ADDR_MAX: source register of address range end (NLA_U32: nft_registers) + * @NFTA_NAT_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_NAT_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) + * @NFTA_NAT_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + */ +enum nft_nat_attributes { + NFTA_NAT_UNSPEC, + NFTA_NAT_TYPE, + NFTA_NAT_FAMILY, + NFTA_NAT_REG_ADDR_MIN, + NFTA_NAT_REG_ADDR_MAX, + NFTA_NAT_REG_PROTO_MIN, + NFTA_NAT_REG_PROTO_MAX, + NFTA_NAT_FLAGS, + __NFTA_NAT_MAX +}; +#define NFTA_NAT_MAX (__NFTA_NAT_MAX - 1) + +/** + * enum nft_tproxy_attributes - nf_tables tproxy expression netlink attributes + * + * NFTA_TPROXY_FAMILY: Target address family (NLA_U32: nft_registers) + * NFTA_TPROXY_REG_ADDR: Target address register (NLA_U32: nft_registers) + * NFTA_TPROXY_REG_PORT: Target port register (NLA_U32: nft_registers) + */ +enum nft_tproxy_attributes { + NFTA_TPROXY_UNSPEC, + NFTA_TPROXY_FAMILY, + NFTA_TPROXY_REG_ADDR, + NFTA_TPROXY_REG_PORT, + __NFTA_TPROXY_MAX +}; +#define NFTA_TPROXY_MAX (__NFTA_TPROXY_MAX - 1) + +/** + * enum nft_masq_attributes - nf_tables masquerade expression attributes + * + * @NFTA_MASQ_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + * @NFTA_MASQ_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_MASQ_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) + */ +enum nft_masq_attributes { + NFTA_MASQ_UNSPEC, + NFTA_MASQ_FLAGS, + NFTA_MASQ_REG_PROTO_MIN, + NFTA_MASQ_REG_PROTO_MAX, + __NFTA_MASQ_MAX +}; +#define NFTA_MASQ_MAX (__NFTA_MASQ_MAX - 1) + +/** + * enum nft_redir_attributes - nf_tables redirect expression netlink attributes + * + * @NFTA_REDIR_REG_PROTO_MIN: source register of proto range start (NLA_U32: nft_registers) + * @NFTA_REDIR_REG_PROTO_MAX: source register of proto range end (NLA_U32: nft_registers) + * @NFTA_REDIR_FLAGS: NAT flags (see NF_NAT_RANGE_* in linux/netfilter/nf_nat.h) (NLA_U32) + */ +enum nft_redir_attributes { + NFTA_REDIR_UNSPEC, + NFTA_REDIR_REG_PROTO_MIN, + NFTA_REDIR_REG_PROTO_MAX, + NFTA_REDIR_FLAGS, + __NFTA_REDIR_MAX +}; +#define NFTA_REDIR_MAX (__NFTA_REDIR_MAX - 1) + +/** + * enum nft_dup_attributes - nf_tables dup expression netlink attributes + * + * @NFTA_DUP_SREG_ADDR: source register of address (NLA_U32: nft_registers) + * @NFTA_DUP_SREG_DEV: source register of output interface (NLA_U32: nft_register) + */ +enum nft_dup_attributes { + NFTA_DUP_UNSPEC, + NFTA_DUP_SREG_ADDR, + NFTA_DUP_SREG_DEV, + __NFTA_DUP_MAX +}; +#define NFTA_DUP_MAX (__NFTA_DUP_MAX - 1) + +/** + * enum nft_fwd_attributes - nf_tables fwd expression netlink attributes + * + * @NFTA_FWD_SREG_DEV: source register of output interface (NLA_U32: nft_register) + * @NFTA_FWD_SREG_ADDR: source register of destination address (NLA_U32: nft_register) + * @NFTA_FWD_NFPROTO: layer 3 family of source register address (NLA_U32: enum nfproto) + */ +enum nft_fwd_attributes { + NFTA_FWD_UNSPEC, + NFTA_FWD_SREG_DEV, + NFTA_FWD_SREG_ADDR, + NFTA_FWD_NFPROTO, + __NFTA_FWD_MAX +}; +#define NFTA_FWD_MAX (__NFTA_FWD_MAX - 1) + +/** + * enum nft_objref_attributes - nf_tables stateful object expression netlink attributes + * + * @NFTA_OBJREF_IMM_TYPE: object type for immediate reference (NLA_U32: nft_register) + * @NFTA_OBJREF_IMM_NAME: object name for immediate reference (NLA_STRING) + * @NFTA_OBJREF_SET_SREG: source register of the data to look for (NLA_U32: nft_registers) + * @NFTA_OBJREF_SET_NAME: name of the set where to look for (NLA_STRING) + * @NFTA_OBJREF_SET_ID: id of the set where to look for in this transaction (NLA_U32) + */ +enum nft_objref_attributes { + NFTA_OBJREF_UNSPEC, + NFTA_OBJREF_IMM_TYPE, + NFTA_OBJREF_IMM_NAME, + NFTA_OBJREF_SET_SREG, + NFTA_OBJREF_SET_NAME, + NFTA_OBJREF_SET_ID, + __NFTA_OBJREF_MAX +}; +#define NFTA_OBJREF_MAX (__NFTA_OBJREF_MAX - 1) + +/** + * enum nft_gen_attributes - nf_tables ruleset generation attributes + * + * @NFTA_GEN_ID: Ruleset generation ID (NLA_U32) + */ +enum nft_gen_attributes { + NFTA_GEN_UNSPEC, + NFTA_GEN_ID, + NFTA_GEN_PROC_PID, + NFTA_GEN_PROC_NAME, + __NFTA_GEN_MAX +}; +#define NFTA_GEN_MAX (__NFTA_GEN_MAX - 1) + +/* + * enum nft_fib_attributes - nf_tables fib expression netlink attributes + * + * @NFTA_FIB_DREG: destination register (NLA_U32) + * @NFTA_FIB_RESULT: desired result (NLA_U32) + * @NFTA_FIB_FLAGS: flowi fields to initialize when querying the FIB (NLA_U32) + * + * The FIB expression performs a route lookup according + * to the packet data. + */ +enum nft_fib_attributes { + NFTA_FIB_UNSPEC, + NFTA_FIB_DREG, + NFTA_FIB_RESULT, + NFTA_FIB_FLAGS, + __NFTA_FIB_MAX +}; +#define NFTA_FIB_MAX (__NFTA_FIB_MAX - 1) + +enum nft_fib_result { + NFT_FIB_RESULT_UNSPEC, + NFT_FIB_RESULT_OIF, + NFT_FIB_RESULT_OIFNAME, + NFT_FIB_RESULT_ADDRTYPE, + __NFT_FIB_RESULT_MAX +}; +#define NFT_FIB_RESULT_MAX (__NFT_FIB_RESULT_MAX - 1) + +enum nft_fib_flags { + NFTA_FIB_F_SADDR = 1 << 0, /* look up src */ + NFTA_FIB_F_DADDR = 1 << 1, /* look up dst */ + NFTA_FIB_F_MARK = 1 << 2, /* use skb->mark */ + NFTA_FIB_F_IIF = 1 << 3, /* restrict to iif */ + NFTA_FIB_F_OIF = 1 << 4, /* restrict to oif */ + NFTA_FIB_F_PRESENT = 1 << 5, /* check existence only */ +}; + +enum nft_ct_helper_attributes { + NFTA_CT_HELPER_UNSPEC, + NFTA_CT_HELPER_NAME, + NFTA_CT_HELPER_L3PROTO, + NFTA_CT_HELPER_L4PROTO, + __NFTA_CT_HELPER_MAX, +}; +#define NFTA_CT_HELPER_MAX (__NFTA_CT_HELPER_MAX - 1) + +enum nft_ct_timeout_timeout_attributes { + NFTA_CT_TIMEOUT_UNSPEC, + NFTA_CT_TIMEOUT_L3PROTO, + NFTA_CT_TIMEOUT_L4PROTO, + NFTA_CT_TIMEOUT_DATA, + __NFTA_CT_TIMEOUT_MAX, +}; +#define NFTA_CT_TIMEOUT_MAX (__NFTA_CT_TIMEOUT_MAX - 1) + +enum nft_ct_expectation_attributes { + NFTA_CT_EXPECT_UNSPEC, + NFTA_CT_EXPECT_L3PROTO, + NFTA_CT_EXPECT_L4PROTO, + NFTA_CT_EXPECT_DPORT, + NFTA_CT_EXPECT_TIMEOUT, + NFTA_CT_EXPECT_SIZE, + __NFTA_CT_EXPECT_MAX, +}; +#define NFTA_CT_EXPECT_MAX (__NFTA_CT_EXPECT_MAX - 1) + +#define NFT_OBJECT_UNSPEC 0 +#define NFT_OBJECT_COUNTER 1 +#define NFT_OBJECT_QUOTA 2 +#define NFT_OBJECT_CT_HELPER 3 +#define NFT_OBJECT_LIMIT 4 +#define NFT_OBJECT_CONNLIMIT 5 +#define NFT_OBJECT_TUNNEL 6 +#define NFT_OBJECT_CT_TIMEOUT 7 +#define NFT_OBJECT_SECMARK 8 +#define NFT_OBJECT_CT_EXPECT 9 +#define NFT_OBJECT_SYNPROXY 10 +#define __NFT_OBJECT_MAX 11 +#define NFT_OBJECT_MAX (__NFT_OBJECT_MAX - 1) + +/** + * enum nft_object_attributes - nf_tables stateful object netlink attributes + * + * @NFTA_OBJ_TABLE: name of the table containing the expression (NLA_STRING) + * @NFTA_OBJ_NAME: name of this expression type (NLA_STRING) + * @NFTA_OBJ_TYPE: stateful object type (NLA_U32) + * @NFTA_OBJ_DATA: stateful object data (NLA_NESTED) + * @NFTA_OBJ_USE: number of references to this expression (NLA_U32) + * @NFTA_OBJ_HANDLE: object handle (NLA_U64) + */ +enum nft_object_attributes { + NFTA_OBJ_UNSPEC, + NFTA_OBJ_TABLE, + NFTA_OBJ_NAME, + NFTA_OBJ_TYPE, + NFTA_OBJ_DATA, + NFTA_OBJ_USE, + NFTA_OBJ_HANDLE, + NFTA_OBJ_PAD, + __NFTA_OBJ_MAX +}; +#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1) + +/** + * enum nft_flowtable_flags - nf_tables flowtable flags + * + * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled + * @NFT_FLOWTABLE_COUNTER: enable flow counters + */ +enum nft_flowtable_flags { + NFT_FLOWTABLE_HW_OFFLOAD = 0x1, + NFT_FLOWTABLE_COUNTER = 0x2, + NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD | + NFT_FLOWTABLE_COUNTER) +}; + +/** + * enum nft_flowtable_attributes - nf_tables flow table netlink attributes + * + * @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING) + * @NFTA_FLOWTABLE_NAME: name of this flow table (NLA_STRING) + * @NFTA_FLOWTABLE_HOOK: netfilter hook configuration(NLA_U32) + * @NFTA_FLOWTABLE_USE: number of references to this flow table (NLA_U32) + * @NFTA_FLOWTABLE_HANDLE: object handle (NLA_U64) + * @NFTA_FLOWTABLE_FLAGS: flags (NLA_U32) + */ +enum nft_flowtable_attributes { + NFTA_FLOWTABLE_UNSPEC, + NFTA_FLOWTABLE_TABLE, + NFTA_FLOWTABLE_NAME, + NFTA_FLOWTABLE_HOOK, + NFTA_FLOWTABLE_USE, + NFTA_FLOWTABLE_HANDLE, + NFTA_FLOWTABLE_PAD, + NFTA_FLOWTABLE_FLAGS, + __NFTA_FLOWTABLE_MAX +}; +#define NFTA_FLOWTABLE_MAX (__NFTA_FLOWTABLE_MAX - 1) + +/** + * enum nft_flowtable_hook_attributes - nf_tables flow table hook netlink attributes + * + * @NFTA_FLOWTABLE_HOOK_NUM: netfilter hook number (NLA_U32) + * @NFTA_FLOWTABLE_HOOK_PRIORITY: netfilter hook priority (NLA_U32) + * @NFTA_FLOWTABLE_HOOK_DEVS: input devices this flow table is bound to (NLA_NESTED) + */ +enum nft_flowtable_hook_attributes { + NFTA_FLOWTABLE_HOOK_UNSPEC, + NFTA_FLOWTABLE_HOOK_NUM, + NFTA_FLOWTABLE_HOOK_PRIORITY, + NFTA_FLOWTABLE_HOOK_DEVS, + __NFTA_FLOWTABLE_HOOK_MAX +}; +#define NFTA_FLOWTABLE_HOOK_MAX (__NFTA_FLOWTABLE_HOOK_MAX - 1) + +/** + * enum nft_osf_attributes - nftables osf expression netlink attributes + * + * @NFTA_OSF_DREG: destination register (NLA_U32: nft_registers) + * @NFTA_OSF_TTL: Value of the TTL osf option (NLA_U8) + * @NFTA_OSF_FLAGS: flags (NLA_U32) + */ +enum nft_osf_attributes { + NFTA_OSF_UNSPEC, + NFTA_OSF_DREG, + NFTA_OSF_TTL, + NFTA_OSF_FLAGS, + __NFTA_OSF_MAX, +}; +#define NFTA_OSF_MAX (__NFTA_OSF_MAX - 1) + +enum nft_osf_flags { + NFT_OSF_F_VERSION = (1 << 0), +}; + +/** + * enum nft_synproxy_attributes - nf_tables synproxy expression netlink attributes + * + * @NFTA_SYNPROXY_MSS: mss value sent to the backend (NLA_U16) + * @NFTA_SYNPROXY_WSCALE: wscale value sent to the backend (NLA_U8) + * @NFTA_SYNPROXY_FLAGS: flags (NLA_U32) + */ +enum nft_synproxy_attributes { + NFTA_SYNPROXY_UNSPEC, + NFTA_SYNPROXY_MSS, + NFTA_SYNPROXY_WSCALE, + NFTA_SYNPROXY_FLAGS, + __NFTA_SYNPROXY_MAX, +}; +#define NFTA_SYNPROXY_MAX (__NFTA_SYNPROXY_MAX - 1) + +/** + * enum nft_device_attributes - nf_tables device netlink attributes + * + * @NFTA_DEVICE_NAME: name of this device (NLA_STRING) + */ +enum nft_devices_attributes { + NFTA_DEVICE_UNSPEC, + NFTA_DEVICE_NAME, + __NFTA_DEVICE_MAX +}; +#define NFTA_DEVICE_MAX (__NFTA_DEVICE_MAX - 1) + +/* + * enum nft_xfrm_attributes - nf_tables xfrm expr netlink attributes + * + * @NFTA_XFRM_DREG: destination register (NLA_U32) + * @NFTA_XFRM_KEY: enum nft_xfrm_keys (NLA_U32) + * @NFTA_XFRM_DIR: direction (NLA_U8) + * @NFTA_XFRM_SPNUM: index in secpath array (NLA_U32) + */ +enum nft_xfrm_attributes { + NFTA_XFRM_UNSPEC, + NFTA_XFRM_DREG, + NFTA_XFRM_KEY, + NFTA_XFRM_DIR, + NFTA_XFRM_SPNUM, + __NFTA_XFRM_MAX +}; +#define NFTA_XFRM_MAX (__NFTA_XFRM_MAX - 1) + +enum nft_xfrm_keys { + NFT_XFRM_KEY_UNSPEC, + NFT_XFRM_KEY_DADDR_IP4, + NFT_XFRM_KEY_DADDR_IP6, + NFT_XFRM_KEY_SADDR_IP4, + NFT_XFRM_KEY_SADDR_IP6, + NFT_XFRM_KEY_REQID, + NFT_XFRM_KEY_SPI, + __NFT_XFRM_KEY_MAX, +}; +#define NFT_XFRM_KEY_MAX (__NFT_XFRM_KEY_MAX - 1) + +/** + * enum nft_trace_attributes - nf_tables trace netlink attributes + * + * @NFTA_TRACE_TABLE: name of the table (NLA_STRING) + * @NFTA_TRACE_CHAIN: name of the chain (NLA_STRING) + * @NFTA_TRACE_RULE_HANDLE: numeric handle of the rule (NLA_U64) + * @NFTA_TRACE_TYPE: type of the event (NLA_U32: nft_trace_types) + * @NFTA_TRACE_VERDICT: verdict returned by hook (NLA_NESTED: nft_verdicts) + * @NFTA_TRACE_ID: pseudo-id, same for each skb traced (NLA_U32) + * @NFTA_TRACE_LL_HEADER: linklayer header (NLA_BINARY) + * @NFTA_TRACE_NETWORK_HEADER: network header (NLA_BINARY) + * @NFTA_TRACE_TRANSPORT_HEADER: transport header (NLA_BINARY) + * @NFTA_TRACE_IIF: indev ifindex (NLA_U32) + * @NFTA_TRACE_IIFTYPE: netdev->type of indev (NLA_U16) + * @NFTA_TRACE_OIF: outdev ifindex (NLA_U32) + * @NFTA_TRACE_OIFTYPE: netdev->type of outdev (NLA_U16) + * @NFTA_TRACE_MARK: nfmark (NLA_U32) + * @NFTA_TRACE_NFPROTO: nf protocol processed (NLA_U32) + * @NFTA_TRACE_POLICY: policy that decided fate of packet (NLA_U32) + */ +enum nft_trace_attributes { + NFTA_TRACE_UNSPEC, + NFTA_TRACE_TABLE, + NFTA_TRACE_CHAIN, + NFTA_TRACE_RULE_HANDLE, + NFTA_TRACE_TYPE, + NFTA_TRACE_VERDICT, + NFTA_TRACE_ID, + NFTA_TRACE_LL_HEADER, + NFTA_TRACE_NETWORK_HEADER, + NFTA_TRACE_TRANSPORT_HEADER, + NFTA_TRACE_IIF, + NFTA_TRACE_IIFTYPE, + NFTA_TRACE_OIF, + NFTA_TRACE_OIFTYPE, + NFTA_TRACE_MARK, + NFTA_TRACE_NFPROTO, + NFTA_TRACE_POLICY, + NFTA_TRACE_PAD, + __NFTA_TRACE_MAX +}; +#define NFTA_TRACE_MAX (__NFTA_TRACE_MAX - 1) + +enum nft_trace_types { + NFT_TRACETYPE_UNSPEC, + NFT_TRACETYPE_POLICY, + NFT_TRACETYPE_RETURN, + NFT_TRACETYPE_RULE, + __NFT_TRACETYPE_MAX +}; +#define NFT_TRACETYPE_MAX (__NFT_TRACETYPE_MAX - 1) + +/** + * enum nft_ng_attributes - nf_tables number generator expression netlink attributes + * + * @NFTA_NG_DREG: destination register (NLA_U32) + * @NFTA_NG_MODULUS: maximum counter value (NLA_U32) + * @NFTA_NG_TYPE: operation type (NLA_U32) + * @NFTA_NG_OFFSET: offset to be added to the counter (NLA_U32) + * @NFTA_NG_SET_NAME: name of the map to lookup (NLA_STRING) + * @NFTA_NG_SET_ID: id of the map (NLA_U32) + */ +enum nft_ng_attributes { + NFTA_NG_UNSPEC, + NFTA_NG_DREG, + NFTA_NG_MODULUS, + NFTA_NG_TYPE, + NFTA_NG_OFFSET, + NFTA_NG_SET_NAME, /* deprecated */ + NFTA_NG_SET_ID, /* deprecated */ + __NFTA_NG_MAX +}; +#define NFTA_NG_MAX (__NFTA_NG_MAX - 1) + +enum nft_ng_types { + NFT_NG_INCREMENTAL, + NFT_NG_RANDOM, + __NFT_NG_MAX +}; +#define NFT_NG_MAX (__NFT_NG_MAX - 1) + +enum nft_tunnel_key_ip_attributes { + NFTA_TUNNEL_KEY_IP_UNSPEC, + NFTA_TUNNEL_KEY_IP_SRC, + NFTA_TUNNEL_KEY_IP_DST, + __NFTA_TUNNEL_KEY_IP_MAX +}; +#define NFTA_TUNNEL_KEY_IP_MAX (__NFTA_TUNNEL_KEY_IP_MAX - 1) + +enum nft_tunnel_ip6_attributes { + NFTA_TUNNEL_KEY_IP6_UNSPEC, + NFTA_TUNNEL_KEY_IP6_SRC, + NFTA_TUNNEL_KEY_IP6_DST, + NFTA_TUNNEL_KEY_IP6_FLOWLABEL, + __NFTA_TUNNEL_KEY_IP6_MAX +}; +#define NFTA_TUNNEL_KEY_IP6_MAX (__NFTA_TUNNEL_KEY_IP6_MAX - 1) + +enum nft_tunnel_opts_attributes { + NFTA_TUNNEL_KEY_OPTS_UNSPEC, + NFTA_TUNNEL_KEY_OPTS_VXLAN, + NFTA_TUNNEL_KEY_OPTS_ERSPAN, + NFTA_TUNNEL_KEY_OPTS_GENEVE, + __NFTA_TUNNEL_KEY_OPTS_MAX +}; +#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1) + +enum nft_tunnel_opts_vxlan_attributes { + NFTA_TUNNEL_KEY_VXLAN_UNSPEC, + NFTA_TUNNEL_KEY_VXLAN_GBP, + __NFTA_TUNNEL_KEY_VXLAN_MAX +}; +#define NFTA_TUNNEL_KEY_VXLAN_MAX (__NFTA_TUNNEL_KEY_VXLAN_MAX - 1) + +enum nft_tunnel_opts_erspan_attributes { + NFTA_TUNNEL_KEY_ERSPAN_UNSPEC, + NFTA_TUNNEL_KEY_ERSPAN_VERSION, + NFTA_TUNNEL_KEY_ERSPAN_V1_INDEX, + NFTA_TUNNEL_KEY_ERSPAN_V2_HWID, + NFTA_TUNNEL_KEY_ERSPAN_V2_DIR, + __NFTA_TUNNEL_KEY_ERSPAN_MAX +}; +#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1) + +enum nft_tunnel_opts_geneve_attributes { + NFTA_TUNNEL_KEY_GENEVE_UNSPEC, + NFTA_TUNNEL_KEY_GENEVE_CLASS, + NFTA_TUNNEL_KEY_GENEVE_TYPE, + NFTA_TUNNEL_KEY_GENEVE_DATA, + __NFTA_TUNNEL_KEY_GENEVE_MAX +}; +#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1) + +enum nft_tunnel_flags { + NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0), + NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1), + NFT_TUNNEL_F_SEQ_NUMBER = (1 << 2), +}; +#define NFT_TUNNEL_F_MASK (NFT_TUNNEL_F_ZERO_CSUM_TX | \ + NFT_TUNNEL_F_DONT_FRAGMENT | \ + NFT_TUNNEL_F_SEQ_NUMBER) + +enum nft_tunnel_key_attributes { + NFTA_TUNNEL_KEY_UNSPEC, + NFTA_TUNNEL_KEY_ID, + NFTA_TUNNEL_KEY_IP, + NFTA_TUNNEL_KEY_IP6, + NFTA_TUNNEL_KEY_FLAGS, + NFTA_TUNNEL_KEY_TOS, + NFTA_TUNNEL_KEY_TTL, + NFTA_TUNNEL_KEY_SPORT, + NFTA_TUNNEL_KEY_DPORT, + NFTA_TUNNEL_KEY_OPTS, + __NFTA_TUNNEL_KEY_MAX +}; +#define NFTA_TUNNEL_KEY_MAX (__NFTA_TUNNEL_KEY_MAX - 1) + +enum nft_tunnel_keys { + NFT_TUNNEL_PATH, + NFT_TUNNEL_ID, + __NFT_TUNNEL_MAX +}; +#define NFT_TUNNEL_MAX (__NFT_TUNNEL_MAX - 1) + +enum nft_tunnel_mode { + NFT_TUNNEL_MODE_NONE, + NFT_TUNNEL_MODE_RX, + NFT_TUNNEL_MODE_TX, + __NFT_TUNNEL_MODE_MAX +}; +#define NFT_TUNNEL_MODE_MAX (__NFT_TUNNEL_MODE_MAX - 1) + +enum nft_tunnel_attributes { + NFTA_TUNNEL_UNSPEC, + NFTA_TUNNEL_KEY, + NFTA_TUNNEL_DREG, + NFTA_TUNNEL_MODE, + __NFTA_TUNNEL_MAX +}; +#define NFTA_TUNNEL_MAX (__NFTA_TUNNEL_MAX - 1) + +#endif /* _LINUX_NF_TABLES_H */ diff --git a/src/basic/linux/netfilter/nfnetlink.h b/src/basic/linux/netfilter/nfnetlink.h new file mode 100644 index 000000000..a89f3a56a --- /dev/null +++ b/src/basic/linux/netfilter/nfnetlink.h @@ -0,0 +1,81 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _NFNETLINK_H +#define _NFNETLINK_H +#include +#include + +enum nfnetlink_groups { + NFNLGRP_NONE, +#define NFNLGRP_NONE NFNLGRP_NONE + NFNLGRP_CONNTRACK_NEW, +#define NFNLGRP_CONNTRACK_NEW NFNLGRP_CONNTRACK_NEW + NFNLGRP_CONNTRACK_UPDATE, +#define NFNLGRP_CONNTRACK_UPDATE NFNLGRP_CONNTRACK_UPDATE + NFNLGRP_CONNTRACK_DESTROY, +#define NFNLGRP_CONNTRACK_DESTROY NFNLGRP_CONNTRACK_DESTROY + NFNLGRP_CONNTRACK_EXP_NEW, +#define NFNLGRP_CONNTRACK_EXP_NEW NFNLGRP_CONNTRACK_EXP_NEW + NFNLGRP_CONNTRACK_EXP_UPDATE, +#define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE + NFNLGRP_CONNTRACK_EXP_DESTROY, +#define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY + NFNLGRP_NFTABLES, +#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES + NFNLGRP_ACCT_QUOTA, +#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA + NFNLGRP_NFTRACE, +#define NFNLGRP_NFTRACE NFNLGRP_NFTRACE + __NFNLGRP_MAX, +}; +#define NFNLGRP_MAX (__NFNLGRP_MAX - 1) + +/* General form of address family dependent message. + */ +struct nfgenmsg { + __u8 nfgen_family; /* AF_xxx */ + __u8 version; /* nfnetlink version */ + __be16 res_id; /* resource id */ +}; + +#define NFNETLINK_V0 0 + +/* netfilter netlink message types are split in two pieces: + * 8 bit subsystem, 8bit operation. + */ + +#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) +#define NFNL_MSG_TYPE(x) (x & 0x00ff) + +/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS() + * won't work anymore */ +#define NFNL_SUBSYS_NONE 0 +#define NFNL_SUBSYS_CTNETLINK 1 +#define NFNL_SUBSYS_CTNETLINK_EXP 2 +#define NFNL_SUBSYS_QUEUE 3 +#define NFNL_SUBSYS_ULOG 4 +#define NFNL_SUBSYS_OSF 5 +#define NFNL_SUBSYS_IPSET 6 +#define NFNL_SUBSYS_ACCT 7 +#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 +#define NFNL_SUBSYS_CTHELPER 9 +#define NFNL_SUBSYS_NFTABLES 10 +#define NFNL_SUBSYS_NFT_COMPAT 11 +#define NFNL_SUBSYS_COUNT 12 + +/* Reserved control nfnetlink messages */ +#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE +#define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1 + +/** + * enum nfnl_batch_attributes - nfnetlink batch netlink attributes + * + * @NFNL_BATCH_GENID: generation ID for this changeset (NLA_U32) + */ +enum nfnl_batch_attributes { + NFNL_BATCH_UNSPEC, + NFNL_BATCH_GENID, + __NFNL_BATCH_MAX +}; +#define NFNL_BATCH_MAX (__NFNL_BATCH_MAX - 1) + +#endif /* _NFNETLINK_H */ diff --git a/src/basic/linux/netlink.h b/src/basic/linux/netlink.h index eac8a6a64..c3816ff7b 100644 --- a/src/basic/linux/netlink.h +++ b/src/basic/linux/netlink.h @@ -129,6 +129,7 @@ struct nlmsgerr { * @NLMSGERR_ATTR_COOKIE: arbitrary subsystem specific cookie to * be used - in the success case - to identify a created * object or operation or similar (binary) + * @NLMSGERR_ATTR_POLICY: policy for a rejected attribute * @__NLMSGERR_ATTR_MAX: number of attributes * @NLMSGERR_ATTR_MAX: highest attribute number */ @@ -137,6 +138,7 @@ enum nlmsgerr_attrs { NLMSGERR_ATTR_MSG, NLMSGERR_ATTR_OFFS, NLMSGERR_ATTR_COOKIE, + NLMSGERR_ATTR_POLICY, __NLMSGERR_ATTR_MAX, NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1 @@ -331,6 +333,7 @@ enum netlink_attribute_type { * the index, if limited inside the nesting (U32) * @NL_POLICY_TYPE_ATTR_BITFIELD32_MASK: valid mask for the * bitfield32 type (U32) + * @NL_POLICY_TYPE_ATTR_MASK: mask of valid bits for unsigned integers (U64) * @NL_POLICY_TYPE_ATTR_PAD: pad attribute for 64-bit alignment */ enum netlink_policy_type_attr { @@ -346,6 +349,7 @@ enum netlink_policy_type_attr { NL_POLICY_TYPE_ATTR_POLICY_MAXTYPE, NL_POLICY_TYPE_ATTR_BITFIELD32_MASK, NL_POLICY_TYPE_ATTR_PAD, + NL_POLICY_TYPE_ATTR_MASK, /* keep last */ __NL_POLICY_TYPE_ATTR_MAX, diff --git a/src/shared/linux/nl80211.h b/src/basic/linux/nl80211.h similarity index 90% rename from src/shared/linux/nl80211.h rename to src/basic/linux/nl80211.h index 65edfff1c..47700a2b9 100644 --- a/src/shared/linux/nl80211.h +++ b/src/basic/linux/nl80211.h @@ -1,5 +1,3 @@ -/* SPDX-License-Identifier: MIT */ - #ifndef __LINUX_NL80211_H #define __LINUX_NL80211_H /* @@ -13,7 +11,7 @@ * Copyright 2008 Jouni Malinen * Copyright 2008 Colin McCabe * Copyright 2015-2017 Intel Deutschland GmbH - * Copyright (C) 2018-2019 Intel Corporation + * Copyright (C) 2018-2020 Intel Corporation * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -185,18 +183,27 @@ * * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_PSK flag drivers * can indicate they support offloading EAPOL handshakes for WPA/WPA2 - * preshared key authentication. In %NL80211_CMD_CONNECT the preshared - * key should be specified using %NL80211_ATTR_PMK. Drivers supporting - * this offload may reject the %NL80211_CMD_CONNECT when no preshared - * key material is provided, for example when that driver does not - * support setting the temporal keys through %CMD_NEW_KEY. + * preshared key authentication in station mode. In %NL80211_CMD_CONNECT + * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers + * supporting this offload may reject the %NL80211_CMD_CONNECT when no + * preshared key material is provided, for example when that driver does + * not support setting the temporal keys through %NL80211_CMD_NEW_KEY. * * Similarly @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_STA_1X flag can be * set by drivers indicating offload support of the PTK/GTK EAPOL - * handshakes during 802.1X authentication. In order to use the offload - * the %NL80211_CMD_CONNECT should have %NL80211_ATTR_WANT_1X_4WAY_HS - * attribute flag. Drivers supporting this offload may reject the - * %NL80211_CMD_CONNECT when the attribute flag is not present. + * handshakes during 802.1X authentication in station mode. In order to + * use the offload the %NL80211_CMD_CONNECT should have + * %NL80211_ATTR_WANT_1X_4WAY_HS attribute flag. Drivers supporting this + * offload may reject the %NL80211_CMD_CONNECT when the attribute flag is + * not present. + * + * By setting @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK flag drivers + * can indicate they support offloading EAPOL handshakes for WPA/WPA2 + * preshared key authentication in AP mode. In %NL80211_CMD_START_AP + * the preshared key should be specified using %NL80211_ATTR_PMK. Drivers + * supporting this offload may reject the %NL80211_CMD_START_AP when no + * preshared key material is provided, for example when that driver does + * not support setting the temporal keys through %NL80211_CMD_NEW_KEY. * * For 802.1X the PMK or PMK-R0 are set by providing %NL80211_ATTR_PMK * using %NL80211_CMD_SET_PMK. For offloaded FT support also @@ -245,9 +252,52 @@ * DOC: SAE authentication offload * * By setting @NL80211_EXT_FEATURE_SAE_OFFLOAD flag drivers can indicate they - * support offloading SAE authentication for WPA3-Personal networks. In - * %NL80211_CMD_CONNECT the password for SAE should be specified using - * %NL80211_ATTR_SAE_PASSWORD. + * support offloading SAE authentication for WPA3-Personal networks in station + * mode. Similarly @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP flag can be set by + * drivers indicating the offload support in AP mode. + * + * The password for SAE should be specified using %NL80211_ATTR_SAE_PASSWORD in + * %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP for station and AP mode + * respectively. + */ + +/** + * DOC: VLAN offload support for setting group keys and binding STAs to VLANs + * + * By setting @NL80211_EXT_FEATURE_VLAN_OFFLOAD flag drivers can indicate they + * support offloading VLAN functionality in a manner where the driver exposes a + * single netdev that uses VLAN tagged frames and separate VLAN-specific netdevs + * can then be added using RTM_NEWLINK/IFLA_VLAN_ID similarly to the Ethernet + * case. Frames received from stations that are not assigned to any VLAN are + * delivered on the main netdev and frames to such stations can be sent through + * that main netdev. + * + * %NL80211_CMD_NEW_KEY (for group keys), %NL80211_CMD_NEW_STATION, and + * %NL80211_CMD_SET_STATION will optionally specify vlan_id using + * %NL80211_ATTR_VLAN_ID. + */ + +/** + * DOC: TID configuration + * + * TID config support can be checked in the %NL80211_ATTR_TID_CONFIG + * attribute given in wiphy capabilities. + * + * The necessary configuration parameters are mentioned in + * &enum nl80211_tid_config_attr and it will be passed to the + * %NL80211_CMD_SET_TID_CONFIG command in %NL80211_ATTR_TID_CONFIG. + * + * If the configuration needs to be applied for specific peer then the MAC + * address of the peer needs to be passed in %NL80211_ATTR_MAC, otherwise the + * configuration will be applied for all the connected peers in the vif except + * any peers that have peer specific configuration for the TID by default; if + * the %NL80211_TID_CONFIG_ATTR_OVERRIDE flag is set, peer specific values + * will be overwritten. + * + * All this configuration is valid only for STA's current connection + * i.e. the configuration will be reset to default when the STA connects back + * after disconnection/roaming, and this configuration will be cleared when + * the interface goes down. */ /** @@ -259,13 +309,14 @@ * to get a list of all present wiphys. * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, - * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the - * attributes determining the channel width; this is used for setting - * monitor mode channel), %NL80211_ATTR_WIPHY_RETRY_SHORT, - * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, - * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD. - * However, for setting the channel, see %NL80211_CMD_SET_CHANNEL - * instead, the support here is for backward compatibility only. + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_FREQ_OFFSET (and the attributes determining the + * channel width; this is used for setting monitor mode channel), + * %NL80211_ATTR_WIPHY_RETRY_SHORT, %NL80211_ATTR_WIPHY_RETRY_LONG, + * %NL80211_ATTR_WIPHY_FRAG_THRESHOLD, and/or + * %NL80211_ATTR_WIPHY_RTS_THRESHOLD. However, for setting the channel, + * see %NL80211_CMD_SET_CHANNEL instead, the support here is for backward + * compatibility only. * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request * or rename notification. Has attributes %NL80211_ATTR_WIPHY and * %NL80211_ATTR_WIPHY_NAME. @@ -314,7 +365,8 @@ * %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_INACTIVITY_TIMEOUT, * %NL80211_ATTR_ACL_POLICY and %NL80211_ATTR_MAC_ADDRS. * The channel to use can be set on the interface or be given using the - * %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width. + * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_FREQ_OFFSET, and the + * attributes determining channel width. * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP @@ -324,7 +376,7 @@ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the - * the interface identified by %NL80211_ATTR_IFINDEX. + * interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC * or, if no MAC address given, all stations, on the interface identified * by %NL80211_ATTR_IFINDEX. %NL80211_ATTR_MGMT_SUBTYPE and @@ -344,7 +396,7 @@ * @NL80211_CMD_DEL_MPATH: Delete a mesh path to the destination given by * %NL80211_ATTR_MAC. * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the - * the interface identified by %NL80211_ATTR_IFINDEX. + * interface identified by %NL80211_ATTR_IFINDEX. * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC * or, if no MAC address given, all mesh paths, on the interface identified * by %NL80211_ATTR_IFINDEX. @@ -499,11 +551,12 @@ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify * the SSID (mainly for association, but is included in authentication - * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used - * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE - * is used to specify the authentication type. %NL80211_ATTR_IE is used to - * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs) - * to be added to the frame. + * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ + + * %NL80211_ATTR_WIPHY_FREQ_OFFSET is used to specify the frequence of the + * channel in MHz. %NL80211_ATTR_AUTH_TYPE is used to specify the + * authentication type. %NL80211_ATTR_IE is used to define IEs + * (VendorSpecificInfo, but also including RSN IE and FT IEs) to be added + * to the frame. * When used as an event, this reports reception of an Authentication * frame in station and IBSS modes when the local MLME processed the * frame, i.e., it was for the local STA and was received in correct @@ -558,8 +611,9 @@ * requests to connect to a specified network but without separating * auth and assoc steps. For this, you need to specify the SSID in a * %NL80211_ATTR_SSID attribute, and can optionally specify the association - * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_USE_MFP, - * %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, %NL80211_ATTR_CONTROL_PORT, + * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, + * %NL80211_ATTR_USE_MFP, %NL80211_ATTR_MAC, %NL80211_ATTR_WIPHY_FREQ, + * %NL80211_ATTR_WIPHY_FREQ_OFFSET, %NL80211_ATTR_CONTROL_PORT, * %NL80211_ATTR_CONTROL_PORT_ETHERTYPE, * %NL80211_ATTR_CONTROL_PORT_NO_ENCRYPT, * %NL80211_ATTR_CONTROL_PORT_OVER_NL80211, %NL80211_ATTR_MAC_HINT, and @@ -573,6 +627,14 @@ * set of BSSID,frequency parameters is used (i.e., either the enforcing * %NL80211_ATTR_MAC,%NL80211_ATTR_WIPHY_FREQ or the less strict * %NL80211_ATTR_MAC_HINT and %NL80211_ATTR_WIPHY_FREQ_HINT). + * Driver shall not modify the IEs specified through %NL80211_ATTR_IE if + * %NL80211_ATTR_MAC is included. However, if %NL80211_ATTR_MAC_HINT is + * included, these IEs through %NL80211_ATTR_IE are specified by the user + * space based on the best possible BSS selected. Thus, if the driver ends + * up selecting a different BSS, it can modify these IEs accordingly (e.g. + * userspace asks the driver to perform PMKSA caching with BSS1 and the + * driver ends up selecting BSS2 with different PMKSA cache entry; RSNIE + * has to get updated with the apt PMKID). * %NL80211_ATTR_PREV_BSSID can be used to request a reassociation within * the ESS in case the device is already associated and an association with * a different BSS is desired. @@ -589,13 +651,9 @@ * authentication/association or not receiving a response from the AP. * Non-zero %NL80211_ATTR_STATUS_CODE value is indicated in that case as * well to remain backwards compatible. - * When establishing a security association, drivers that support 4 way - * handshake offload should send %NL80211_CMD_PORT_AUTHORIZED event when - * the 4 way handshake is completed successfully. * @NL80211_CMD_ROAM: Notification indicating the card/driver roamed by itself. - * When a security association was established with the new AP (e.g. if - * the FT protocol was used for roaming or the driver completed the 4 way - * handshake), this event should be followed by an + * When a security association was established on an 802.1X network using + * fast transition, this event should be followed by an * %NL80211_CMD_PORT_AUTHORIZED event. * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify * userspace that a connection was dropped by the AP or due to other @@ -642,6 +700,10 @@ * four bytes for vendor frames including the OUI. The registration * cannot be dropped, but is removed automatically when the netlink * socket is closed. Multiple registrations can be made. + * The %NL80211_ATTR_RECEIVE_MULTICAST flag attribute can be given if + * %NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS is available, in which + * case the registration can also be modified to include/exclude the + * flag, rather than requiring unregistration to change it. * @NL80211_CMD_REGISTER_ACTION: Alias for @NL80211_CMD_REGISTER_FRAME for * backward compatibility * @NL80211_CMD_FRAME: Management frame TX request and RX notification. This @@ -741,7 +803,7 @@ * various triggers. These triggers can be configured through this * command with the %NL80211_ATTR_WOWLAN_TRIGGERS attribute. For * more background information, see - * http://wireless.kernel.org/en/users/Documentation/WoWLAN. + * https://wireless.wiki.kernel.org/en/users/Documentation/WoWLAN. * The @NL80211_CMD_SET_WOWLAN command can also be used as a notification * from the driver reporting the wakeup reason. In this case, the * @NL80211_ATTR_WOWLAN_TRIGGERS attribute will contain the reason @@ -881,7 +943,7 @@ * @NL80211_CMD_SET_COALESCE: Configure coalesce rules or clear existing rules. * * @NL80211_CMD_CHANNEL_SWITCH: Perform a channel switch by announcing the - * the new channel information (Channel Switch Announcement - CSA) + * new channel information (Channel Switch Announcement - CSA) * in the beacon for some time (as defined in the * %NL80211_ATTR_CH_SWITCH_COUNT parameter) and then change to the * new channel. Userspace provides the new channel information (using @@ -1005,13 +1067,11 @@ * @NL80211_CMD_DEL_PMK: For offloaded 4-Way handshake, delete the previously * configured PMK for the authenticator address identified by * %NL80211_ATTR_MAC. - * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates that the 4 way - * handshake was completed successfully by the driver. The BSSID is - * specified with %NL80211_ATTR_MAC. Drivers that support 4 way handshake - * offload should send this event after indicating 802.11 association with - * %NL80211_CMD_CONNECT or %NL80211_CMD_ROAM. If the 4 way handshake failed - * %NL80211_CMD_DISCONNECT should be indicated instead. - * + * @NL80211_CMD_PORT_AUTHORIZED: An event that indicates an 802.1X FT roam was + * completed successfully. Drivers that support 4 way handshake offload + * should send this event after indicating 802.1X FT assocation with + * %NL80211_CMD_ROAM. If the 4 way handshake failed %NL80211_CMD_DISCONNECT + * should be indicated instead. * @NL80211_CMD_CONTROL_PORT_FRAME: Control Port (e.g. PAE) frame TX request * and RX notification. This command is used both as a request to transmit * a control port frame and as a notification that a control port frame @@ -1060,7 +1120,7 @@ * randomization may be enabled and configured by specifying the * %NL80211_ATTR_MAC and %NL80211_ATTR_MAC_MASK attributes. * If a timeout is requested, use the %NL80211_ATTR_TIMEOUT attribute. - * A u64 cookie for further %NL80211_ATTR_COOKIE use is is returned in + * A u64 cookie for further %NL80211_ATTR_COOKIE use is returned in * the netlink extended ack message. * * To cancel a measurement, close the socket that requested it. @@ -1103,6 +1163,20 @@ * peer MAC address and %NL80211_ATTR_FRAME is used to specify the frame * content. The frame is ethernet data. * + * @NL80211_CMD_SET_TID_CONFIG: Data frame TID specific configuration + * is passed using %NL80211_ATTR_TID_CONFIG attribute. + * + * @NL80211_CMD_UNPROT_BEACON: Unprotected or incorrectly protected Beacon + * frame. This event is used to indicate that a received Beacon frame was + * dropped because it did not include a valid MME MIC while beacon + * protection was enabled (BIGTK configured in station mode). + * + * @NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS: Report TX status of a control + * port frame transmitted with %NL80211_CMD_CONTROL_PORT_FRAME. + * %NL80211_ATTR_COOKIE identifies the TX command and %NL80211_ATTR_FRAME + * includes the contents of the frame. %NL80211_ATTR_ACK flag is included + * if the recipient acknowledged the frame. + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -1327,6 +1401,12 @@ enum nl80211_commands { NL80211_CMD_PROBE_MESH_LINK, + NL80211_CMD_SET_TID_CONFIG, + + NL80211_CMD_UNPROT_BEACON, + + NL80211_CMD_CONTROL_PORT_FRAME_TX_STATUS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -1372,7 +1452,8 @@ enum nl80211_commands { * of &enum nl80211_chan_width, describing the channel width. See the * documentation of the enum for more information. * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the - * channel, used for anything but 20 MHz bandwidth + * channel, used for anything but 20 MHz bandwidth. In S1G this is the + * operating channel center frequency. * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the * channel, used only for 80+80 MHz bandwidth * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ @@ -1582,7 +1663,8 @@ enum nl80211_commands { * flag is included, then control port frames are sent over NL80211 instead * using %CMD_CONTROL_PORT_FRAME. If control port routing over NL80211 is * to be used then userspace must also use the %NL80211_ATTR_SOCKET_OWNER - * flag. + * flag. When used with %NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, pre-auth + * frames are not forwared over the control port. * * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver. * We recommend using nested, driver-specific attributes within this. @@ -1998,10 +2080,10 @@ enum nl80211_commands { * operation). * @NL80211_ATTR_CSA_IES: Nested set of attributes containing the IE information * for the time while performing a channel switch. - * @NL80211_ATTR_CSA_C_OFF_BEACON: An array of offsets (u16) to the channel - * switch counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL). - * @NL80211_ATTR_CSA_C_OFF_PRESP: An array of offsets (u16) to the channel - * switch counters in the probe response (%NL80211_ATTR_PROBE_RESP). + * @NL80211_ATTR_CNTDWN_OFFS_BEACON: An array of offsets (u16) to the channel + * switch or color change counters in the beacons tail (%NL80211_ATTR_BEACON_TAIL). + * @NL80211_ATTR_CNTDWN_OFFS_PRESP: An array of offsets (u16) to the channel + * switch or color change counters in the probe response (%NL80211_ATTR_PROBE_RESP). * * @NL80211_ATTR_RXMGMT_FLAGS: flags for nl80211_send_mgmt(), u32. * As specified in the &enum nl80211_rxmgmt_flags. @@ -2009,7 +2091,7 @@ enum nl80211_commands { * @NL80211_ATTR_STA_SUPPORTED_CHANNELS: array of supported channels. * * @NL80211_ATTR_STA_SUPPORTED_OPER_CLASSES: array of supported - * supported operating classes. + * operating classes. * * @NL80211_ATTR_HANDLE_DFS: A flag indicating whether user space * controls DFS operation in IBSS mode. If the flag is included in @@ -2287,10 +2369,11 @@ enum nl80211_commands { * * @NL80211_ATTR_PMK: attribute for passing PMK key material. Used with * %NL80211_CMD_SET_PMKSA for the PMKSA identified by %NL80211_ATTR_PMKID. - * For %NL80211_CMD_CONNECT it is used to provide PSK for offloading 4-way - * handshake for WPA/WPA2-PSK networks. For 802.1X authentication it is - * used with %NL80211_CMD_SET_PMK. For offloaded FT support this attribute - * specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME is included as well. + * For %NL80211_CMD_CONNECT and %NL80211_CMD_START_AP it is used to provide + * PSK for offloading 4-way handshake for WPA/WPA2-PSK networks. For 802.1X + * authentication it is used with %NL80211_CMD_SET_PMK. For offloaded FT + * support this attribute specifies the PMK-R0 if NL80211_ATTR_PMKR0_NAME + * is included as well. * * @NL80211_ATTR_SCHED_SCAN_MULTI: flag attribute which user-space shall use to * indicate that it supports multiple active scheduled scan requests. @@ -2320,7 +2403,7 @@ enum nl80211_commands { * nl80211_txq_stats) * @NL80211_ATTR_TXQ_LIMIT: Total packet limit for the TXQ queues for this phy. * The smaller of this and the memory limit is enforced. - * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory memory limit (in bytes) for the + * @NL80211_ATTR_TXQ_MEMORY_LIMIT: Total memory limit (in bytes) for the * TXQ queues for this phy. The smaller of this and the packet limit is * enforced. * @NL80211_ATTR_TXQ_QUANTUM: TXQ scheduler quantum (bytes). Number of bytes @@ -2375,6 +2458,75 @@ enum nl80211_commands { * the allowed channel bandwidth configurations. (u8 attribute) * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13. * + * @NL80211_ATTR_VLAN_ID: VLAN ID (1..4094) for the station and VLAN group key + * (u16). + * + * @NL80211_ATTR_HE_BSS_COLOR: nested attribute for BSS Color Settings. + * + * @NL80211_ATTR_IFTYPE_AKM_SUITES: nested array attribute, with each entry + * using attributes from &enum nl80211_iftype_akm_attributes. This + * attribute is sent in a response to %NL80211_CMD_GET_WIPHY indicating + * supported AKM suites capability per interface. AKMs advertised in + * %NL80211_ATTR_AKM_SUITES are default capabilities if AKM suites not + * advertised for a specific interface type. + * + * @NL80211_ATTR_TID_CONFIG: TID specific configuration in a + * nested attribute with &enum nl80211_tid_config_attr sub-attributes; + * on output (in wiphy attributes) it contains only the feature sub- + * attributes. + * + * @NL80211_ATTR_CONTROL_PORT_NO_PREAUTH: disable preauth frame rx on control + * port in order to forward/receive them as ordinary data frames. + * + * @NL80211_ATTR_PMK_LIFETIME: Maximum lifetime for PMKSA in seconds (u32, + * dot11RSNAConfigPMKReauthThreshold; 0 is not a valid value). + * An optional parameter configured through %NL80211_CMD_SET_PMKSA. + * Drivers that trigger roaming need to know the lifetime of the + * configured PMKSA for triggering the full vs. PMKSA caching based + * authentication. This timeout helps authentication methods like SAE, + * where PMK gets updated only by going through a full (new SAE) + * authentication instead of getting updated during an association for EAP + * authentication. No new full authentication within the PMK expiry shall + * result in a disassociation at the end of the lifetime. + * + * @NL80211_ATTR_PMK_REAUTH_THRESHOLD: Reauthentication threshold time, in + * terms of percentage of %NL80211_ATTR_PMK_LIFETIME + * (u8, dot11RSNAConfigPMKReauthThreshold, 1..100). This is an optional + * parameter configured through %NL80211_CMD_SET_PMKSA. Requests the + * driver to trigger a full authentication roam (without PMKSA caching) + * after the reauthentication threshold time, but before the PMK lifetime + * has expired. + * + * Authentication methods like SAE need to be able to generate a new PMKSA + * entry without having to force a disconnection after the PMK timeout. If + * no roaming occurs between the reauth threshold and PMK expiration, + * disassociation is still forced. + * @NL80211_ATTR_RECEIVE_MULTICAST: multicast flag for the + * %NL80211_CMD_REGISTER_FRAME command, see the description there. + * @NL80211_ATTR_WIPHY_FREQ_OFFSET: offset of the associated + * %NL80211_ATTR_WIPHY_FREQ in positive KHz. Only valid when supplied with + * an %NL80211_ATTR_WIPHY_FREQ_OFFSET. + * @NL80211_ATTR_CENTER_FREQ1_OFFSET: Center frequency offset in KHz for the + * first channel segment specified in %NL80211_ATTR_CENTER_FREQ1. + * @NL80211_ATTR_SCAN_FREQ_KHZ: nested attribute with KHz frequencies + * + * @NL80211_ATTR_HE_6GHZ_CAPABILITY: HE 6 GHz Band Capability element (from + * association request when used with NL80211_CMD_NEW_STATION). + * + * @NL80211_ATTR_FILS_DISCOVERY: Optional parameter to configure FILS + * discovery. It is a nested attribute, see + * &enum nl80211_fils_discovery_attributes. + * + * @NL80211_ATTR_UNSOL_BCAST_PROBE_RESP: Optional parameter to configure + * unsolicited broadcast probe response. It is a nested attribute, see + * &enum nl80211_unsol_bcast_probe_resp_attributes. + * + * @NL80211_ATTR_S1G_CAPABILITY: S1G Capability information element (from + * association request when used with NL80211_CMD_NEW_STATION) + * @NL80211_ATTR_S1G_CAPABILITY_MASK: S1G Capability Information element + * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in + * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. + * * @NUM_NL80211_ATTR: total number of nl80211_attrs available * @NL80211_ATTR_MAX: highest attribute number currently defined * @__NL80211_ATTR_AFTER_LAST: internal use @@ -2681,8 +2833,8 @@ enum nl80211_attrs { NL80211_ATTR_CH_SWITCH_COUNT, NL80211_ATTR_CH_SWITCH_BLOCK_TX, NL80211_ATTR_CSA_IES, - NL80211_ATTR_CSA_C_OFF_BEACON, - NL80211_ATTR_CSA_C_OFF_PRESP, + NL80211_ATTR_CNTDWN_OFFS_BEACON, + NL80211_ATTR_CNTDWN_OFFS_PRESP, NL80211_ATTR_RXMGMT_FLAGS, @@ -2837,6 +2989,33 @@ enum nl80211_attrs { NL80211_ATTR_WIPHY_EDMG_CHANNELS, NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, + NL80211_ATTR_VLAN_ID, + + NL80211_ATTR_HE_BSS_COLOR, + + NL80211_ATTR_IFTYPE_AKM_SUITES, + + NL80211_ATTR_TID_CONFIG, + + NL80211_ATTR_CONTROL_PORT_NO_PREAUTH, + + NL80211_ATTR_PMK_LIFETIME, + NL80211_ATTR_PMK_REAUTH_THRESHOLD, + + NL80211_ATTR_RECEIVE_MULTICAST, + NL80211_ATTR_WIPHY_FREQ_OFFSET, + NL80211_ATTR_CENTER_FREQ1_OFFSET, + NL80211_ATTR_SCAN_FREQ_KHZ, + + NL80211_ATTR_HE_6GHZ_CAPABILITY, + + NL80211_ATTR_FILS_DISCOVERY, + + NL80211_ATTR_UNSOL_BCAST_PROBE_RESP, + + NL80211_ATTR_S1G_CAPABILITY, + NL80211_ATTR_S1G_CAPABILITY_MASK, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -2849,6 +3028,8 @@ enum nl80211_attrs { #define NL80211_ATTR_MESH_PARAMS NL80211_ATTR_MESH_CONFIG #define NL80211_ATTR_IFACE_SOCKET_OWNER NL80211_ATTR_SOCKET_OWNER #define NL80211_ATTR_SAE_DATA NL80211_ATTR_AUTH_DATA +#define NL80211_ATTR_CSA_C_OFF_BEACON NL80211_ATTR_CNTDWN_OFFS_BEACON +#define NL80211_ATTR_CSA_C_OFF_PRESP NL80211_ATTR_CNTDWN_OFFS_PRESP /* * Allow user space programs to use #ifdef on new attributes by defining them @@ -3026,6 +3207,18 @@ enum nl80211_he_gi { NL80211_RATE_INFO_HE_GI_3_2, }; +/** + * enum nl80211_he_ltf - HE long training field + * @NL80211_RATE_INFO_HE_1xLTF: 3.2 usec + * @NL80211_RATE_INFO_HE_2xLTF: 6.4 usec + * @NL80211_RATE_INFO_HE_4xLTF: 12.8 usec + */ +enum nl80211_he_ltf { + NL80211_RATE_INFO_HE_1XLTF, + NL80211_RATE_INFO_HE_2XLTF, + NL80211_RATE_INFO_HE_4XLTF, +}; + /** * enum nl80211_he_ru_alloc - HE RU allocation values * @NL80211_RATE_INFO_HE_RU_ALLOC_26: 26-tone RU allocation @@ -3220,6 +3413,8 @@ enum nl80211_sta_bss_param { * @NL80211_STA_INFO_AIRTIME_LINK_METRIC: airtime link metric for mesh station * @NL80211_STA_INFO_ASSOC_AT_BOOTTIME: Timestamp (CLOCK_BOOTTIME, nanoseconds) * of STA's association + * @NL80211_STA_INFO_CONNECTED_TO_AS: set to true if STA has a path to a + * authentication server (u8, 0 or 1) * @__NL80211_STA_INFO_AFTER_LAST: internal * @NL80211_STA_INFO_MAX: highest possible station info attribute */ @@ -3267,6 +3462,7 @@ enum nl80211_sta_info { NL80211_STA_INFO_AIRTIME_WEIGHT, NL80211_STA_INFO_AIRTIME_LINK_METRIC, NL80211_STA_INFO_ASSOC_AT_BOOTTIME, + NL80211_STA_INFO_CONNECTED_TO_AS, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -3415,6 +3611,8 @@ enum nl80211_mpath_info { * defined in HE capabilities IE * @NL80211_BAND_IFTYPE_ATTR_MAX: highest band HE capability attribute currently * defined + * @NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA: HE 6GHz band capabilities (__le16), + * given for all 6 GHz band channels * @__NL80211_BAND_IFTYPE_ATTR_AFTER_LAST: internal use */ enum nl80211_band_iftype_attr { @@ -3425,6 +3623,7 @@ enum nl80211_band_iftype_attr { NL80211_BAND_IFTYPE_ATTR_HE_CAP_PHY, NL80211_BAND_IFTYPE_ATTR_HE_CAP_MCS_SET, NL80211_BAND_IFTYPE_ATTR_HE_CAP_PPE, + NL80211_BAND_IFTYPE_ATTR_HE_6GHZ_CAPA, /* keep last */ __NL80211_BAND_IFTYPE_ATTR_AFTER_LAST, @@ -3556,6 +3755,19 @@ enum nl80211_wmm_rule { * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations. * This is a nested attribute that contains the wmm limitation per AC. * (see &enum nl80211_wmm_rule) + * @NL80211_FREQUENCY_ATTR_NO_HE: HE operation is not allowed on this channel + * in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_OFFSET: frequency offset in KHz + * @NL80211_FREQUENCY_ATTR_1MHZ: 1 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_2MHZ: 2 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_4MHZ: 4 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_8MHZ: 8 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed + * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use @@ -3585,6 +3797,13 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_NO_20MHZ, NL80211_FREQUENCY_ATTR_NO_10MHZ, NL80211_FREQUENCY_ATTR_WMM, + NL80211_FREQUENCY_ATTR_NO_HE, + NL80211_FREQUENCY_ATTR_OFFSET, + NL80211_FREQUENCY_ATTR_1MHZ, + NL80211_FREQUENCY_ATTR_2MHZ, + NL80211_FREQUENCY_ATTR_4MHZ, + NL80211_FREQUENCY_ATTR_8MHZ, + NL80211_FREQUENCY_ATTR_16MHZ, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, @@ -3782,6 +4001,7 @@ enum nl80211_sched_scan_match_attr { * @NL80211_RRF_NO_HT40PLUS: channels can't be used in HT40+ operation * @NL80211_RRF_NO_80MHZ: 80MHz operation not allowed * @NL80211_RRF_NO_160MHZ: 160MHz operation not allowed + * @NL80211_RRF_NO_HE: HE operation not allowed */ enum nl80211_reg_rule_flags { NL80211_RRF_NO_OFDM = 1<<0, @@ -3799,6 +4019,7 @@ enum nl80211_reg_rule_flags { NL80211_RRF_NO_HT40PLUS = 1<<14, NL80211_RRF_NO_80MHZ = 1<<15, NL80211_RRF_NO_160MHZ = 1<<16, + NL80211_RRF_NO_HE = 1<<17, }; #define NL80211_RRF_PASSIVE_SCAN NL80211_RRF_NO_IR @@ -3876,6 +4097,7 @@ enum nl80211_user_reg_hint_type { * receiving frames destined to the local BSS * @NL80211_SURVEY_INFO_MAX: highest survey info attribute number * currently defined + * @NL80211_SURVEY_INFO_FREQUENCY_OFFSET: center frequency offset in KHz * @__NL80211_SURVEY_INFO_AFTER_LAST: internal use */ enum nl80211_survey_info { @@ -3891,6 +4113,7 @@ enum nl80211_survey_info { NL80211_SURVEY_INFO_TIME_SCAN, NL80211_SURVEY_INFO_PAD, NL80211_SURVEY_INFO_TIME_BSS_RX, + NL80211_SURVEY_INFO_FREQUENCY_OFFSET, /* keep last */ __NL80211_SURVEY_INFO_AFTER_LAST, @@ -4076,6 +4299,16 @@ enum nl80211_mesh_power_mode { * field. If left unset then the mesh formation field will only * advertise such if there is an active root mesh path. * + * @NL80211_MESHCONF_NOLEARN: Try to avoid multi-hop path discovery (e.g. + * PREQ/PREP for HWMP) if the destination is a direct neighbor. Note that + * this might not be the optimal decision as a multi-hop route might be + * better. So if using this setting you will likely also want to disable + * dot11MeshForwarding and use another mesh routing protocol on top. + * + * @NL80211_MESHCONF_CONNECTED_TO_AS: If set to true then this mesh STA + * will advertise that it is connected to a authentication server + * in the mesh formation field. + * * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use */ enum nl80211_meshconf_params { @@ -4109,6 +4342,8 @@ enum nl80211_meshconf_params { NL80211_MESHCONF_AWAKE_WINDOW, NL80211_MESHCONF_PLINK_TIMEOUT, NL80211_MESHCONF_CONNECTED_TO_GATE, + NL80211_MESHCONF_NOLEARN, + NL80211_MESHCONF_CONNECTED_TO_AS, /* keep last */ __NL80211_MESHCONF_ATTR_AFTER_LAST, @@ -4277,6 +4512,11 @@ enum nl80211_key_mode { * attribute must be provided as well * @NL80211_CHAN_WIDTH_5: 5 MHz OFDM channel * @NL80211_CHAN_WIDTH_10: 10 MHz OFDM channel + * @NL80211_CHAN_WIDTH_1: 1 MHz OFDM channel + * @NL80211_CHAN_WIDTH_2: 2 MHz OFDM channel + * @NL80211_CHAN_WIDTH_4: 4 MHz OFDM channel + * @NL80211_CHAN_WIDTH_8: 8 MHz OFDM channel + * @NL80211_CHAN_WIDTH_16: 16 MHz OFDM channel */ enum nl80211_chan_width { NL80211_CHAN_WIDTH_20_NOHT, @@ -4287,6 +4527,11 @@ enum nl80211_chan_width { NL80211_CHAN_WIDTH_160, NL80211_CHAN_WIDTH_5, NL80211_CHAN_WIDTH_10, + NL80211_CHAN_WIDTH_1, + NL80211_CHAN_WIDTH_2, + NL80211_CHAN_WIDTH_4, + NL80211_CHAN_WIDTH_8, + NL80211_CHAN_WIDTH_16, }; /** @@ -4297,11 +4542,15 @@ enum nl80211_chan_width { * @NL80211_BSS_CHAN_WIDTH_20: control channel is 20 MHz wide or compatible * @NL80211_BSS_CHAN_WIDTH_10: control channel is 10 MHz wide * @NL80211_BSS_CHAN_WIDTH_5: control channel is 5 MHz wide + * @NL80211_BSS_CHAN_WIDTH_1: control channel is 1 MHz wide + * @NL80211_BSS_CHAN_WIDTH_2: control channel is 2 MHz wide */ enum nl80211_bss_scan_width { NL80211_BSS_CHAN_WIDTH_20, NL80211_BSS_CHAN_WIDTH_10, NL80211_BSS_CHAN_WIDTH_5, + NL80211_BSS_CHAN_WIDTH_1, + NL80211_BSS_CHAN_WIDTH_2, }; /** @@ -4353,6 +4602,7 @@ enum nl80211_bss_scan_width { * @NL80211_BSS_CHAIN_SIGNAL: per-chain signal strength of last BSS update. * Contains a nested array of signal strength attributes (u8, dBm), * using the nesting index as the antenna number. + * @NL80211_BSS_FREQUENCY_OFFSET: frequency offset in KHz * @__NL80211_BSS_AFTER_LAST: internal * @NL80211_BSS_MAX: highest BSS attribute */ @@ -4377,6 +4627,7 @@ enum nl80211_bss { NL80211_BSS_PARENT_TSF, NL80211_BSS_PARENT_BSSID, NL80211_BSS_CHAIN_SIGNAL, + NL80211_BSS_FREQUENCY_OFFSET, /* keep last */ __NL80211_BSS_AFTER_LAST, @@ -4505,6 +4756,7 @@ enum nl80211_key_default_types { * See &enum nl80211_key_default_types. * @NL80211_KEY_MODE: the mode from enum nl80211_key_mode. * Defaults to @NL80211_KEY_RX_TX. + * @NL80211_KEY_DEFAULT_BEACON: flag indicating default Beacon frame key * * @__NL80211_KEY_AFTER_LAST: internal * @NL80211_KEY_MAX: highest key attribute @@ -4520,6 +4772,7 @@ enum nl80211_key_attributes { NL80211_KEY_TYPE, NL80211_KEY_DEFAULT_TYPES, NL80211_KEY_MODE, + NL80211_KEY_DEFAULT_BEACON, /* keep last */ __NL80211_KEY_AFTER_LAST, @@ -4538,6 +4791,10 @@ enum nl80211_key_attributes { * @NL80211_TXRATE_VHT: VHT rates allowed for TX rate selection, * see &struct nl80211_txrate_vht * @NL80211_TXRATE_GI: configure GI, see &enum nl80211_txrate_gi + * @NL80211_TXRATE_HE: HE rates allowed for TX rate selection, + * see &struct nl80211_txrate_he + * @NL80211_TXRATE_HE_GI: configure HE GI, 0.8us, 1.6us and 3.2us. + * @NL80211_TXRATE_HE_LTF: configure HE LTF, 1XLTF, 2XLTF and 4XLTF. * @__NL80211_TXRATE_AFTER_LAST: internal * @NL80211_TXRATE_MAX: highest TX rate attribute */ @@ -4547,6 +4804,9 @@ enum nl80211_tx_rate_attributes { NL80211_TXRATE_HT, NL80211_TXRATE_VHT, NL80211_TXRATE_GI, + NL80211_TXRATE_HE, + NL80211_TXRATE_HE_GI, + NL80211_TXRATE_HE_LTF, /* keep last */ __NL80211_TXRATE_AFTER_LAST, @@ -4564,6 +4824,15 @@ struct nl80211_txrate_vht { __u16 mcs[NL80211_VHT_NSS_MAX]; }; +#define NL80211_HE_NSS_MAX 8 +/** + * struct nl80211_txrate_he - HE MCS/NSS txrate bitmap + * @mcs: MCS bitmap table for each NSS (array index 0 for 1 stream, etc.) + */ +struct nl80211_txrate_he { + __u16 mcs[NL80211_HE_NSS_MAX]; +}; + enum nl80211_txrate_gi { NL80211_TXRATE_DEFAULT_GI, NL80211_TXRATE_FORCE_SGI, @@ -4576,6 +4845,7 @@ enum nl80211_txrate_gi { * @NL80211_BAND_5GHZ: around 5 GHz band (4.9 - 5.7 GHz) * @NL80211_BAND_60GHZ: around 60 GHz band (58.32 - 69.12 GHz) * @NL80211_BAND_6GHZ: around 6 GHz band (5.9 - 7.2 GHz) + * @NL80211_BAND_S1GHZ: around 900MHz, supported by S1G PHYs * @NUM_NL80211_BANDS: number of bands, avoid using this in userspace * since newer kernel versions may support more bands */ @@ -4584,6 +4854,7 @@ enum nl80211_band { NL80211_BAND_5GHZ, NL80211_BAND_60GHZ, NL80211_BAND_6GHZ, + NL80211_BAND_S1GHZ, NUM_NL80211_BANDS, }; @@ -4675,6 +4946,92 @@ enum nl80211_tx_power_setting { NL80211_TX_POWER_FIXED, }; +/** + * enum nl80211_tid_config - TID config state + * @NL80211_TID_CONFIG_ENABLE: Enable config for the TID + * @NL80211_TID_CONFIG_DISABLE: Disable config for the TID + */ +enum nl80211_tid_config { + NL80211_TID_CONFIG_ENABLE, + NL80211_TID_CONFIG_DISABLE, +}; + +/* enum nl80211_tx_rate_setting - TX rate configuration type + * @NL80211_TX_RATE_AUTOMATIC: automatically determine TX rate + * @NL80211_TX_RATE_LIMITED: limit the TX rate by the TX rate parameter + * @NL80211_TX_RATE_FIXED: fix TX rate to the TX rate parameter + */ +enum nl80211_tx_rate_setting { + NL80211_TX_RATE_AUTOMATIC, + NL80211_TX_RATE_LIMITED, + NL80211_TX_RATE_FIXED, +}; + +/* enum nl80211_tid_config_attr - TID specific configuration. + * @NL80211_TID_CONFIG_ATTR_PAD: pad attribute for 64-bit values + * @NL80211_TID_CONFIG_ATTR_VIF_SUPP: a bitmap (u64) of attributes supported + * for per-vif configuration; doesn't list the ones that are generic + * (%NL80211_TID_CONFIG_ATTR_TIDS, %NL80211_TID_CONFIG_ATTR_OVERRIDE). + * @NL80211_TID_CONFIG_ATTR_PEER_SUPP: same as the previous per-vif one, but + * per peer instead. + * @NL80211_TID_CONFIG_ATTR_OVERRIDE: flag attribue, if set indicates + * that the new configuration overrides all previous peer + * configurations, otherwise previous peer specific configurations + * should be left untouched. + * @NL80211_TID_CONFIG_ATTR_TIDS: a bitmask value of TIDs (bit 0 to 7) + * Its type is u16. + * @NL80211_TID_CONFIG_ATTR_NOACK: Configure ack policy for the TID. + * specified in %NL80211_TID_CONFIG_ATTR_TID. see %enum nl80211_tid_config. + * Its type is u8. + * @NL80211_TID_CONFIG_ATTR_RETRY_SHORT: Number of retries used with data frame + * transmission, user-space sets this configuration in + * &NL80211_CMD_SET_TID_CONFIG. It is u8 type, min value is 1 and + * the max value is advertised by the driver in this attribute on + * output in wiphy capabilities. + * @NL80211_TID_CONFIG_ATTR_RETRY_LONG: Number of retries used with data frame + * transmission, user-space sets this configuration in + * &NL80211_CMD_SET_TID_CONFIG. Its type is u8, min value is 1 and + * the max value is advertised by the driver in this attribute on + * output in wiphy capabilities. + * @NL80211_TID_CONFIG_ATTR_AMPDU_CTRL: Enable/Disable MPDU aggregation + * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. + * Its type is u8, using the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL: Enable/Disable RTS_CTS for the TIDs + * specified in %NL80211_TID_CONFIG_ATTR_TIDS. It is u8 type, using + * the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_AMSDU_CTRL: Enable/Disable MSDU aggregation + * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. + * Its type is u8, using the values from &nl80211_tid_config. + * @NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE: This attribute will be useful + * to notfiy the driver that what type of txrate should be used + * for the TIDs specified in %NL80211_TID_CONFIG_ATTR_TIDS. using + * the values form &nl80211_tx_rate_setting. + * @NL80211_TID_CONFIG_ATTR_TX_RATE: Data frame TX rate mask should be applied + * with the parameters passed through %NL80211_ATTR_TX_RATES. + * configuration is applied to the data frame for the tid to that connected + * station. + */ +enum nl80211_tid_config_attr { + __NL80211_TID_CONFIG_ATTR_INVALID, + NL80211_TID_CONFIG_ATTR_PAD, + NL80211_TID_CONFIG_ATTR_VIF_SUPP, + NL80211_TID_CONFIG_ATTR_PEER_SUPP, + NL80211_TID_CONFIG_ATTR_OVERRIDE, + NL80211_TID_CONFIG_ATTR_TIDS, + NL80211_TID_CONFIG_ATTR_NOACK, + NL80211_TID_CONFIG_ATTR_RETRY_SHORT, + NL80211_TID_CONFIG_ATTR_RETRY_LONG, + NL80211_TID_CONFIG_ATTR_AMPDU_CTRL, + NL80211_TID_CONFIG_ATTR_RTSCTS_CTRL, + NL80211_TID_CONFIG_ATTR_AMSDU_CTRL, + NL80211_TID_CONFIG_ATTR_TX_RATE_TYPE, + NL80211_TID_CONFIG_ATTR_TX_RATE, + + /* keep last */ + __NL80211_TID_CONFIG_ATTR_AFTER_LAST, + NL80211_TID_CONFIG_ATTR_MAX = __NL80211_TID_CONFIG_ATTR_AFTER_LAST - 1 +}; + /** * enum nl80211_packet_pattern_attr - packet pattern attribute * @__NL80211_PKTPAT_INVALID: invalid number for nested attribute @@ -5146,6 +5503,8 @@ enum plink_actions { #define NL80211_KCK_LEN 16 #define NL80211_KEK_LEN 16 +#define NL80211_KCK_EXT_LEN 24 +#define NL80211_KEK_EXT_LEN 32 #define NL80211_REPLAY_CTR_LEN 8 /** @@ -5154,6 +5513,7 @@ enum plink_actions { * @NL80211_REKEY_DATA_KEK: key encryption key (binary) * @NL80211_REKEY_DATA_KCK: key confirmation key (binary) * @NL80211_REKEY_DATA_REPLAY_CTR: replay counter (binary) + * @NL80211_REKEY_DATA_AKM: AKM data (OUI, suite type) * @NUM_NL80211_REKEY_DATA: number of rekey attributes (internal) * @MAX_NL80211_REKEY_DATA: highest rekey attribute (internal) */ @@ -5162,6 +5522,7 @@ enum nl80211_rekey_data { NL80211_REKEY_DATA_KEK, NL80211_REKEY_DATA_KCK, NL80211_REKEY_DATA_REPLAY_CTR, + NL80211_REKEY_DATA_AKM, /* keep last */ NUM_NL80211_REKEY_DATA, @@ -5382,7 +5743,7 @@ enum nl80211_feature_flags { * enum nl80211_ext_feature_index - bit index of extended features. * @NL80211_EXT_FEATURE_VHT_IBSS: This driver supports IBSS with VHT datarates. * @NL80211_EXT_FEATURE_RRM: This driver supports RRM. When featured, user can - * can request to use RRM (see %NL80211_ATTR_USE_RRM) with + * request to use RRM (see %NL80211_ATTR_USE_RRM) with * %NL80211_CMD_ASSOCIATE and %NL80211_CMD_CONNECT requests, which will set * the ASSOC_REQ_USE_RRM flag in the association request even if * NL80211_FEATURE_QUIET is not advertized. @@ -5486,6 +5847,55 @@ enum nl80211_feature_flags { * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in * station mode (SAE password is passed as part of the connect command). * + * @NL80211_EXT_FEATURE_VLAN_OFFLOAD: The driver supports a single netdev + * with VLAN tagged frames and separate VLAN-specific netdevs added using + * vconfig similarly to the Ethernet case. + * + * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL) + * feature, which prevents bufferbloat by using the expected transmission + * time to limit the amount of data buffered in the hardware. + * + * @NL80211_EXT_FEATURE_BEACON_PROTECTION: The driver supports Beacon protection + * and can receive key configuration for BIGTK using key indexes 6 and 7. + * @NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT: The driver supports Beacon + * protection as a client only and cannot transmit protected beacons. + * + * @NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH: The driver can disable the + * forwarding of preauth frames over the control port. They are then + * handled as ordinary data frames. + * + * @NL80211_EXT_FEATURE_PROTECTED_TWT: Driver supports protected TWT frames + * + * @NL80211_EXT_FEATURE_DEL_IBSS_STA: The driver supports removing stations + * in IBSS mode, essentially by dropping their state. + * + * @NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS: management frame registrations + * are possible for multicast frames and those will be reported properly. + * + * @NL80211_EXT_FEATURE_SCAN_FREQ_KHZ: This driver supports receiving and + * reporting scan request with %NL80211_ATTR_SCAN_FREQ_KHZ. In order to + * report %NL80211_ATTR_SCAN_FREQ_KHZ, %NL80211_SCAN_FLAG_FREQ_KHZ must be + * included in the scan request. + * + * @NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS: The driver + * can report tx status for control port over nl80211 tx operations. + * + * @NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION: Driver supports Operating + * Channel Validation (OCV) when using driver's SME for RSNA handshakes. + * + * @NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK: Device wants to do 4-way + * handshake with PSK in AP mode (PSK is passed as part of the start AP + * command). + * + * @NL80211_EXT_FEATURE_SAE_OFFLOAD_AP: Device wants to do SAE authentication + * in AP mode (SAE password is passed as part of the start AP command). + * + * @NL80211_EXT_FEATURE_FILS_DISCOVERY: Driver/device supports FILS discovery + * frames transmission + * + * @NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP: Driver/device supports + * unsolicited broadcast probe response transmission + * * @NUM_NL80211_EXT_FEATURES: number of extended features. * @MAX_NL80211_EXT_FEATURES: highest extended feature index. */ @@ -5531,6 +5941,21 @@ enum nl80211_ext_feature_index { NL80211_EXT_FEATURE_EXT_KEY_ID, NL80211_EXT_FEATURE_STA_TX_PWR, NL80211_EXT_FEATURE_SAE_OFFLOAD, + NL80211_EXT_FEATURE_VLAN_OFFLOAD, + NL80211_EXT_FEATURE_AQL, + NL80211_EXT_FEATURE_BEACON_PROTECTION, + NL80211_EXT_FEATURE_CONTROL_PORT_NO_PREAUTH, + NL80211_EXT_FEATURE_PROTECTED_TWT, + NL80211_EXT_FEATURE_DEL_IBSS_STA, + NL80211_EXT_FEATURE_MULTICAST_REGISTRATIONS, + NL80211_EXT_FEATURE_BEACON_PROTECTION_CLIENT, + NL80211_EXT_FEATURE_SCAN_FREQ_KHZ, + NL80211_EXT_FEATURE_CONTROL_PORT_OVER_NL80211_TX_STATUS, + NL80211_EXT_FEATURE_OPERATING_CHANNEL_VALIDATION, + NL80211_EXT_FEATURE_4WAY_HANDSHAKE_AP_PSK, + NL80211_EXT_FEATURE_SAE_OFFLOAD_AP, + NL80211_EXT_FEATURE_FILS_DISCOVERY, + NL80211_EXT_FEATURE_UNSOL_BCAST_PROBE_RESP, /* add new features before the definition below */ NUM_NL80211_EXT_FEATURES, @@ -5642,6 +6067,11 @@ enum nl80211_timeout_reason { * @NL80211_SCAN_FLAG_MIN_PREQ_CONTENT: minimize probe request content to * only have supported rates and no additional capabilities (unless * added by userspace explicitly.) + * @NL80211_SCAN_FLAG_FREQ_KHZ: report scan results with + * %NL80211_ATTR_SCAN_FREQ_KHZ. This also means + * %NL80211_ATTR_SCAN_FREQUENCIES will not be included. + * @NL80211_SCAN_FLAG_COLOCATED_6GHZ: scan for colocated APs reported by + * 2.4/5 GHz APs */ enum nl80211_scan_flags { NL80211_SCAN_FLAG_LOW_PRIORITY = 1<<0, @@ -5657,6 +6087,8 @@ enum nl80211_scan_flags { NL80211_SCAN_FLAG_HIGH_ACCURACY = 1<<10, NL80211_SCAN_FLAG_RANDOM_SN = 1<<11, NL80211_SCAN_FLAG_MIN_PREQ_CONTENT = 1<<12, + NL80211_SCAN_FLAG_FREQ_KHZ = 1<<13, + NL80211_SCAN_FLAG_COLOCATED_6GHZ = 1<<14, }; /** @@ -5744,7 +6176,7 @@ enum nl80211_dfs_state { }; /** - * enum enum nl80211_protocol_features - nl80211 protocol features + * enum nl80211_protocol_features - nl80211 protocol features * @NL80211_PROTOCOL_FEATURE_SPLIT_WIPHY_DUMP: nl80211 supports splitting * wiphy dumps (if requested by the application with the attribute * %NL80211_ATTR_SPLIT_WIPHY_DUMP. Also supported is filtering the @@ -6153,12 +6585,14 @@ enum nl80211_ftm_responder_stats { * @NL80211_PREAMBLE_HT: HT preamble * @NL80211_PREAMBLE_VHT: VHT preamble * @NL80211_PREAMBLE_DMG: DMG preamble + * @NL80211_PREAMBLE_HE: HE preamble */ enum nl80211_preamble { NL80211_PREAMBLE_LEGACY, NL80211_PREAMBLE_HT, NL80211_PREAMBLE_VHT, NL80211_PREAMBLE_DMG, + NL80211_PREAMBLE_HE, }; /** @@ -6351,6 +6785,10 @@ enum nl80211_peer_measurement_attrs { * is valid) * @NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST: u32 attribute indicating * the maximum FTMs per burst (if not present anything is valid) + * @NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED: flag attribute indicating if + * trigger based ranging measurement is supported + * @NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED: flag attribute indicating + * if non trigger based ranging measurement is supported * * @NUM_NL80211_PMSR_FTM_CAPA_ATTR: internal * @NL80211_PMSR_FTM_CAPA_ATTR_MAX: highest attribute number @@ -6366,6 +6804,8 @@ enum nl80211_peer_measurement_ftm_capa { NL80211_PMSR_FTM_CAPA_ATTR_BANDWIDTHS, NL80211_PMSR_FTM_CAPA_ATTR_MAX_BURSTS_EXPONENT, NL80211_PMSR_FTM_CAPA_ATTR_MAX_FTMS_PER_BURST, + NL80211_PMSR_FTM_CAPA_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_CAPA_ATTR_NON_TRIGGER_BASED, /* keep last */ NUM_NL80211_PMSR_FTM_CAPA_ATTR, @@ -6395,6 +6835,20 @@ enum nl80211_peer_measurement_ftm_capa { * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI: request LCI data (flag) * @NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC: request civic location data * (flag) + * @NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED: request trigger based ranging + * measurement (flag). + * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED are + * mutually exclusive. + * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based + * ranging will be used. + * @NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED: request non trigger based + * ranging measurement (flag) + * This attribute and %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED are + * mutually exclusive. + * if neither %NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED nor + * %NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED is set, EDCA based + * ranging will be used. * * @NUM_NL80211_PMSR_FTM_REQ_ATTR: internal * @NL80211_PMSR_FTM_REQ_ATTR_MAX: highest attribute number @@ -6411,6 +6865,8 @@ enum nl80211_peer_measurement_ftm_req { NL80211_PMSR_FTM_REQ_ATTR_NUM_FTMR_RETRIES, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_LCI, NL80211_PMSR_FTM_REQ_ATTR_REQUEST_CIVICLOC, + NL80211_PMSR_FTM_REQ_ATTR_TRIGGER_BASED, + NL80211_PMSR_FTM_REQ_ATTR_NON_TRIGGER_BASED, /* keep last */ NUM_NL80211_PMSR_FTM_REQ_ATTR, @@ -6535,6 +6991,13 @@ enum nl80211_peer_measurement_ftm_resp { * * @NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET: the OBSS PD minimum tx power offset. * @NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET: the OBSS PD maximum tx power offset. + * @NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET: the non-SRG OBSS PD maximum + * tx power offset. + * @NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP: bitmap that indicates the BSS color + * values used by members of the SRG. + * @NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP: bitmap that indicates the partial + * BSSID values used by members of the SRG. + * @NL80211_HE_OBSS_PD_ATTR_SR_CTRL: The SR Control field of SRP element. * * @__NL80211_HE_OBSS_PD_ATTR_LAST: Internal * @NL80211_HE_OBSS_PD_ATTR_MAX: highest OBSS PD attribute. @@ -6544,11 +7007,121 @@ enum nl80211_obss_pd_attributes { NL80211_HE_OBSS_PD_ATTR_MIN_OFFSET, NL80211_HE_OBSS_PD_ATTR_MAX_OFFSET, + NL80211_HE_OBSS_PD_ATTR_NON_SRG_MAX_OFFSET, + NL80211_HE_OBSS_PD_ATTR_BSS_COLOR_BITMAP, + NL80211_HE_OBSS_PD_ATTR_PARTIAL_BSSID_BITMAP, + NL80211_HE_OBSS_PD_ATTR_SR_CTRL, /* keep last */ __NL80211_HE_OBSS_PD_ATTR_LAST, NL80211_HE_OBSS_PD_ATTR_MAX = __NL80211_HE_OBSS_PD_ATTR_LAST - 1, }; +/** + * enum nl80211_bss_color_attributes - BSS Color attributes + * @__NL80211_HE_BSS_COLOR_ATTR_INVALID: Invalid + * + * @NL80211_HE_BSS_COLOR_ATTR_COLOR: the current BSS Color. + * @NL80211_HE_BSS_COLOR_ATTR_DISABLED: is BSS coloring disabled. + * @NL80211_HE_BSS_COLOR_ATTR_PARTIAL: the AID equation to be used.. + * + * @__NL80211_HE_BSS_COLOR_ATTR_LAST: Internal + * @NL80211_HE_BSS_COLOR_ATTR_MAX: highest BSS Color attribute. + */ +enum nl80211_bss_color_attributes { + __NL80211_HE_BSS_COLOR_ATTR_INVALID, + NL80211_HE_BSS_COLOR_ATTR_COLOR, + NL80211_HE_BSS_COLOR_ATTR_DISABLED, + NL80211_HE_BSS_COLOR_ATTR_PARTIAL, + + /* keep last */ + __NL80211_HE_BSS_COLOR_ATTR_LAST, + NL80211_HE_BSS_COLOR_ATTR_MAX = __NL80211_HE_BSS_COLOR_ATTR_LAST - 1, +}; + +/** + * enum nl80211_iftype_akm_attributes - interface type AKM attributes + * @__NL80211_IFTYPE_AKM_ATTR_INVALID: Invalid + * + * @NL80211_IFTYPE_AKM_ATTR_IFTYPES: nested attribute containing a flag + * attribute for each interface type that supports AKM suites specified in + * %NL80211_IFTYPE_AKM_ATTR_SUITES + * @NL80211_IFTYPE_AKM_ATTR_SUITES: an array of u32. Used to indicate supported + * AKM suites for the specified interface types. + * + * @__NL80211_IFTYPE_AKM_ATTR_LAST: Internal + * @NL80211_IFTYPE_AKM_ATTR_MAX: highest interface type AKM attribute. + */ +enum nl80211_iftype_akm_attributes { + __NL80211_IFTYPE_AKM_ATTR_INVALID, + + NL80211_IFTYPE_AKM_ATTR_IFTYPES, + NL80211_IFTYPE_AKM_ATTR_SUITES, + + /* keep last */ + __NL80211_IFTYPE_AKM_ATTR_LAST, + NL80211_IFTYPE_AKM_ATTR_MAX = __NL80211_IFTYPE_AKM_ATTR_LAST - 1, +}; + +/** + * enum nl80211_fils_discovery_attributes - FILS discovery configuration + * from IEEE Std 802.11ai-2016, Annex C.3 MIB detail. + * + * @__NL80211_FILS_DISCOVERY_ATTR_INVALID: Invalid + * + * @NL80211_FILS_DISCOVERY_ATTR_INT_MIN: Minimum packet interval (u32, TU). + * Allowed range: 0..10000 (TU = Time Unit) + * @NL80211_FILS_DISCOVERY_ATTR_INT_MAX: Maximum packet interval (u32, TU). + * Allowed range: 0..10000 (TU = Time Unit) + * @NL80211_FILS_DISCOVERY_ATTR_TMPL: Template data for FILS discovery action + * frame including the headers. + * + * @__NL80211_FILS_DISCOVERY_ATTR_LAST: Internal + * @NL80211_FILS_DISCOVERY_ATTR_MAX: highest attribute + */ +enum nl80211_fils_discovery_attributes { + __NL80211_FILS_DISCOVERY_ATTR_INVALID, + + NL80211_FILS_DISCOVERY_ATTR_INT_MIN, + NL80211_FILS_DISCOVERY_ATTR_INT_MAX, + NL80211_FILS_DISCOVERY_ATTR_TMPL, + + /* keep last */ + __NL80211_FILS_DISCOVERY_ATTR_LAST, + NL80211_FILS_DISCOVERY_ATTR_MAX = __NL80211_FILS_DISCOVERY_ATTR_LAST - 1 +}; + +/* + * FILS discovery template minimum length with action frame headers and + * mandatory fields. + */ +#define NL80211_FILS_DISCOVERY_TMPL_MIN_LEN 42 + +/** + * enum nl80211_unsol_bcast_probe_resp_attributes - Unsolicited broadcast probe + * response configuration. Applicable only in 6GHz. + * + * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID: Invalid + * + * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT: Maximum packet interval (u32, TU). + * Allowed range: 0..20 (TU = Time Unit). IEEE P802.11ax/D6.0 + * 26.17.2.3.2 (AP behavior for fast passive scanning). + * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL: Unsolicited broadcast probe response + * frame template (binary). + * + * @__NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST: Internal + * @NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX: highest attribute + */ +enum nl80211_unsol_bcast_probe_resp_attributes { + __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INVALID, + + NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_INT, + NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_TMPL, + + /* keep last */ + __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST, + NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_MAX = + __NL80211_UNSOL_BCAST_PROBE_RESP_ATTR_LAST - 1 +}; #endif /* __LINUX_NL80211_H */ diff --git a/src/basic/linux/update.sh b/src/basic/linux/update.sh index b0b0cdc94..ca0b9ec07 100755 --- a/src/basic/linux/update.sh +++ b/src/basic/linux/update.sh @@ -1,9 +1,13 @@ #!/usr/bin/env bash - +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu for i in *.h */*.h; do - curl https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/$i -o $i + if [[ $i == 'loadavg.h' ]]; then + curl --fail https://raw.githubusercontent.com/torvalds/linux/master/include/linux/sched/$i -o $i + else + curl --fail https://raw.githubusercontent.com/torvalds/linux/master/include/uapi/linux/$i -o $i + fi sed -i -e 's/__user //g' -e '/^#include / d' $i done diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index 4c81cb944..93261e675 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -98,7 +98,6 @@ static int add_locales_from_archive(Set *locales) { _cleanup_close_ int fd = -1; size_t sz = 0; struct stat st; - size_t i; int r; fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); @@ -129,7 +128,7 @@ static int add_locales_from_archive(Set *locales) { } e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset); - for (i = 0; i < h->namehash_size; i++) { + for (size_t i = 0; i < h->namehash_size; i++) { char *z; if (e[i].locrec_offset == 0) @@ -356,6 +355,9 @@ const char *special_glyph(SpecialGlyph code) { [SPECIAL_GLYPH_TREE_SPACE] = " ", [SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">", [SPECIAL_GLYPH_BLACK_CIRCLE] = "*", + [SPECIAL_GLYPH_WHITE_CIRCLE] = "*", + [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = "x", + [SPECIAL_GLYPH_CIRCLE_ARROW] = "*", [SPECIAL_GLYPH_BULLET] = "*", [SPECIAL_GLYPH_MU] = "u", [SPECIAL_GLYPH_CHECK_MARK] = "+", @@ -388,6 +390,9 @@ const char *special_glyph(SpecialGlyph code) { /* Single glyphs in both cases */ [SPECIAL_GLYPH_TRIANGULAR_BULLET] = "\342\200\243", /* ‣ */ [SPECIAL_GLYPH_BLACK_CIRCLE] = "\342\227\217", /* ● */ + [SPECIAL_GLYPH_WHITE_CIRCLE] = "\u25CB", /* ○ */ + [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = "\u00D7", /* × */ + [SPECIAL_GLYPH_CIRCLE_ARROW] = "\u21BB", /* ↻ */ [SPECIAL_GLYPH_BULLET] = "\342\200\242", /* • */ [SPECIAL_GLYPH_MU] = "\316\274", /* μ (actually called: GREEK SMALL LETTER MU) */ [SPECIAL_GLYPH_CHECK_MARK] = "\342\234\223", /* ✓ */ @@ -428,12 +433,10 @@ const char *special_glyph(SpecialGlyph code) { } void locale_variables_free(char *l[_VARIABLE_LC_MAX]) { - LocaleVariable i; - if (!l) return; - for (i = 0; i < _VARIABLE_LC_MAX; i++) + for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) l[i] = mfree(l[i]); } diff --git a/src/basic/locale-util.h b/src/basic/locale-util.h index 2d672e2f9..558c5a898 100644 --- a/src/basic/locale-util.h +++ b/src/basic/locale-util.h @@ -26,7 +26,7 @@ typedef enum LocaleVariable { VARIABLE_LC_MEASUREMENT, VARIABLE_LC_IDENTIFICATION, _VARIABLE_LC_MAX, - _VARIABLE_LC_INVALID = -1 + _VARIABLE_LC_INVALID = -EINVAL, } LocaleVariable; int get_locales(char ***l); @@ -46,6 +46,9 @@ typedef enum { SPECIAL_GLYPH_TREE_SPACE, SPECIAL_GLYPH_TRIANGULAR_BULLET, SPECIAL_GLYPH_BLACK_CIRCLE, + SPECIAL_GLYPH_WHITE_CIRCLE, + SPECIAL_GLYPH_MULTIPLICATION_SIGN, + SPECIAL_GLYPH_CIRCLE_ARROW, SPECIAL_GLYPH_BULLET, SPECIAL_GLYPH_MU, SPECIAL_GLYPH_CHECK_MARK, @@ -87,3 +90,7 @@ void locale_variables_free(char* l[_VARIABLE_LC_MAX]); static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) { locale_variables_free(*l); } + +static inline const char *special_glyph_check_mark(bool b) { + return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK); +} diff --git a/src/basic/log.c b/src/basic/log.c index d4054cf46..595db0c39 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -40,8 +40,7 @@ #define SNDBUF_SIZE (8*1024*1024) static LogTarget log_target = LOG_TARGET_CONSOLE; -static int log_max_level[] = {LOG_INFO, LOG_INFO}; -assert_cc(ELEMENTSOF(log_max_level) == _LOG_REALM_MAX); +static int log_max_level = LOG_INFO; static int log_facility = LOG_DAEMON; static int console_fd = STDERR_FILENO; @@ -51,7 +50,7 @@ static int journal_fd = -1; static bool syslog_is_stream = false; -static bool show_color = false; +static int show_color = -1; /* tristate */ static bool show_location = false; static bool show_time = false; static bool show_tid = false; @@ -253,11 +252,14 @@ int log_open(void) { /* Do not call from library code. */ - /* If we don't use the console we close it here, to not get - * killed by SAK. If we don't use syslog we close it here so - * that we are not confused by somebody deleting the socket in - * the fs, and to make sure we don't use it if prohibit_ipc is - * set. If we don't use /dev/kmsg we still keep it open, + /* This function is often called in preparation for logging. Let's make sure we don't clobber errno, + * so that a call to a logging function immediately following a log_open() call can still easily + * reference an error that happened immediately before the log_open() call. */ + PROTECT_ERRNO; + + /* If we don't use the console, we close it here to not get killed by SAK. If we don't use syslog, we + * close it here too, so that we are not confused by somebody deleting the socket in the fs, and to + * make sure we don't use it if prohibit_ipc is set. If we don't use /dev/kmsg we still keep it open, * because there is no reason to close it. */ if (log_target == LOG_TARGET_NULL) { @@ -352,11 +354,10 @@ void log_forget_fds(void) { console_fd = kmsg_fd = syslog_fd = journal_fd = -1; } -void log_set_max_level_realm(LogRealm realm, int level) { +void log_set_max_level(int level) { assert((level & LOG_PRIMASK) == level); - assert(realm < ELEMENTSOF(log_max_level)); - log_max_level[realm] = level; + log_max_level = level; } void log_set_facility(int facility) { @@ -387,11 +388,10 @@ static int write_to_console( iovec[n++] = IOVEC_MAKE_STRING(prefix); } - if (show_time) { - if (format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) { - iovec[n++] = IOVEC_MAKE_STRING(header_time); - iovec[n++] = IOVEC_MAKE_STRING(" "); - } + if (show_time && + format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) { + iovec[n++] = IOVEC_MAKE_STRING(header_time); + iovec[n++] = IOVEC_MAKE_STRING(" "); } if (show_tid) { @@ -399,14 +399,14 @@ static int write_to_console( iovec[n++] = IOVEC_MAKE_STRING(tid_string); } - if (show_color) + if (log_get_show_color()) get_log_colors(LOG_PRI(level), &on, &off, NULL); if (show_location) { const char *lon = "", *loff = ""; - if (show_color) { - lon = ANSI_HIGHLIGHT_YELLOW4; - loff = ANSI_NORMAL; + if (log_get_show_color()) { + lon = ansi_highlight_yellow4(); + loff = ansi_normal(); } (void) snprintf(location, sizeof location, "%s%s:%i%s: ", lon, file, line, loff); @@ -717,18 +717,17 @@ int log_dump_internal( const char *func, char *buffer) { - LogRealm realm = LOG_REALM_REMOVE_LEVEL(level); PROTECT_ERRNO; /* This modifies the buffer... */ - if (_likely_(LOG_PRI(level) > log_max_level[realm])) + if (_likely_(LOG_PRI(level) > log_max_level)) return -ERRNO_VALUE(error); return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer); } -int log_internalv_realm( +int log_internalv( int level, int error, const char *file, @@ -737,11 +736,10 @@ int log_internalv_realm( const char *format, va_list ap) { - LogRealm realm = LOG_REALM_REMOVE_LEVEL(level); char buffer[LINE_MAX]; PROTECT_ERRNO; - if (_likely_(LOG_PRI(level) > log_max_level[realm])) + if (_likely_(LOG_PRI(level) > log_max_level)) return -ERRNO_VALUE(error); /* Make sure that %m maps to the specified error (or "Success"). */ @@ -752,7 +750,7 @@ int log_internalv_realm( return log_dispatch_internal(level, error, file, line, func, NULL, NULL, NULL, NULL, buffer); } -int log_internal_realm( +int log_internal( int level, int error, const char *file, @@ -764,7 +762,7 @@ int log_internal_realm( int r; va_start(ap, format); - r = log_internalv_realm(level, error, file, line, func, format, ap); + r = log_internalv(level, error, file, line, func, format, ap); va_end(ap); return r; @@ -786,7 +784,7 @@ int log_object_internalv( PROTECT_ERRNO; char *buffer, *b; - if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD])) + if (_likely_(LOG_PRI(level) > log_max_level)) return -ERRNO_VALUE(error); /* Make sure that %m maps to the specified error (or "Success"). */ @@ -839,9 +837,8 @@ static void log_assert( const char *format) { static char buffer[LINE_MAX]; - LogRealm realm = LOG_REALM_REMOVE_LEVEL(level); - if (_likely_(LOG_PRI(level) > log_max_level[realm])) + if (_likely_(LOG_PRI(level) > log_max_level)) return; DISABLE_WARNING_FORMAT_NONLITERAL; @@ -853,42 +850,38 @@ static void log_assert( log_dispatch_internal(level, 0, file, line, func, NULL, NULL, NULL, NULL, buffer); } -_noreturn_ void log_assert_failed_realm( - LogRealm realm, +_noreturn_ void log_assert_failed( const char *text, const char *file, int line, const char *func) { - log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func, + log_assert(LOG_CRIT, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Aborting."); abort(); } -_noreturn_ void log_assert_failed_unreachable_realm( - LogRealm realm, +_noreturn_ void log_assert_failed_unreachable( const char *text, const char *file, int line, const char *func) { - log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_CRIT), text, file, line, func, + log_assert(LOG_CRIT, text, file, line, func, "Code should not be reached '%s' at %s:%u, function %s(). Aborting."); abort(); } -void log_assert_failed_return_realm( - LogRealm realm, +void log_assert_failed_return( const char *text, const char *file, int line, const char *func) { PROTECT_ERRNO; - log_assert(LOG_REALM_PLUS_LEVEL(realm, LOG_DEBUG), text, file, line, func, + log_assert(LOG_DEBUG, text, file, line, func, "Assertion '%s' failed at %s:%u, function %s(). Ignoring."); } -int log_oom_internal(LogRealm realm, const char *file, int line, const char *func) { - return log_internal_realm(LOG_REALM_PLUS_LEVEL(realm, LOG_ERR), - ENOMEM, file, line, func, "Out of memory."); +int log_oom_internal(int level, const char *file, int line, const char *func) { + return log_internal(level, ENOMEM, file, line, func, "Out of memory."); } int log_format_iovec( @@ -943,13 +936,12 @@ int log_struct_internal( const char *func, const char *format, ...) { - LogRealm realm = LOG_REALM_REMOVE_LEVEL(level); char buf[LINE_MAX]; bool found = false; PROTECT_ERRNO; va_list ap; - if (_likely_(LOG_PRI(level) > log_max_level[realm]) || + if (_likely_(LOG_PRI(level) > log_max_level) || log_target == LOG_TARGET_NULL) return -ERRNO_VALUE(error); @@ -1043,12 +1035,11 @@ int log_struct_iovec_internal( const struct iovec input_iovec[], size_t n_input_iovec) { - LogRealm realm = LOG_REALM_REMOVE_LEVEL(level); PROTECT_ERRNO; size_t i; char *m; - if (_likely_(LOG_PRI(level) > log_max_level[realm]) || + if (_likely_(LOG_PRI(level) > log_max_level) || log_target == LOG_TARGET_NULL) return -ERRNO_VALUE(error); @@ -1097,20 +1088,20 @@ int log_set_target_from_string(const char *e) { t = log_target_from_string(e); if (t < 0) - return -EINVAL; + return t; log_set_target(t); return 0; } -int log_set_max_level_from_string_realm(LogRealm realm, const char *e) { +int log_set_max_level_from_string(const char *e) { int t; t = log_level_from_string(e); if (t < 0) - return -EINVAL; + return t; - log_set_max_level_realm(realm, t); + log_set_max_level(t); return 0; } @@ -1169,27 +1160,47 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return 0; } -void log_parse_environment_realm(LogRealm realm) { - 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); +static bool should_parse_proc_cmdline(void) { + const char *e; + pid_t p; - log_parse_environment_cli_realm(realm); + /* PID1 always reads the kernel command line. */ + if (getpid_cached() == 1) + return true; + + /* If the process is directly executed by PID1 (e.g. ExecStart= or generator), systemd-importd, + * or systemd-homed, then $SYSTEMD_EXEC_PID= is set, and read the command line. */ + e = getenv("SYSTEMD_EXEC_PID"); + if (!e) + return false; + + if (streq(e, "*")) + /* For testing. */ + return true; + + if (parse_pid(e, &p) < 0) { + /* We know that systemd sets the variable correctly. Something else must have set it. */ + log_debug("Failed to parse \"$SYSTEMD_EXEC_PID=%s\". Ignoring.", e); + return false; + } + + return getpid_cached() == p; } -void log_parse_environment_cli_realm(LogRealm realm) { +void log_parse_environment(void) { + const char *e; + /* Do not call from library code. */ - const char *e; + if (should_parse_proc_cmdline()) + (void) proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX); e = getenv("SYSTEMD_LOG_TARGET"); if (e && log_set_target_from_string(e) < 0) log_warning("Failed to parse log target '%s'. Ignoring.", e); e = getenv("SYSTEMD_LOG_LEVEL"); - if (e && log_set_max_level_from_string_realm(realm, e) < 0) + if (e && log_set_max_level_from_string(e) < 0) log_warning("Failed to parse log level '%s'. Ignoring.", e); e = getenv("SYSTEMD_LOG_COLOR"); @@ -1213,8 +1224,8 @@ LogTarget log_get_target(void) { return log_target; } -int log_get_max_level_realm(LogRealm realm) { - return log_max_level[realm]; +int log_get_max_level(void) { + return log_max_level; } void log_show_color(bool b) { @@ -1222,7 +1233,7 @@ void log_show_color(bool b) { } bool log_get_show_color(void) { - return show_color; + return show_color > 0; /* Defaults to false. */ } void log_show_location(bool b) { @@ -1302,15 +1313,15 @@ bool log_on_console(void) { } static const char *const log_target_table[_LOG_TARGET_MAX] = { - [LOG_TARGET_CONSOLE] = "console", + [LOG_TARGET_CONSOLE] = "console", [LOG_TARGET_CONSOLE_PREFIXED] = "console-prefixed", - [LOG_TARGET_KMSG] = "kmsg", - [LOG_TARGET_JOURNAL] = "journal", - [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg", - [LOG_TARGET_SYSLOG] = "syslog", - [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", - [LOG_TARGET_AUTO] = "auto", - [LOG_TARGET_NULL] = "null", + [LOG_TARGET_KMSG] = "kmsg", + [LOG_TARGET_JOURNAL] = "journal", + [LOG_TARGET_JOURNAL_OR_KMSG] = "journal-or-kmsg", + [LOG_TARGET_SYSLOG] = "syslog", + [LOG_TARGET_SYSLOG_OR_KMSG] = "syslog-or-kmsg", + [LOG_TARGET_AUTO] = "auto", + [LOG_TARGET_NULL] = "null", }; DEFINE_STRING_TABLE_LOOKUP(log_target, LogTarget); @@ -1349,7 +1360,7 @@ int log_syntax_internal( va_list ap; const char *unit_fmt = NULL; - if (_likely_(LOG_PRI(level) > log_max_level[LOG_REALM_SYSTEMD]) || + if (_likely_(LOG_PRI(level) > log_max_level) || log_target == LOG_TARGET_NULL) return -ERRNO_VALUE(error); @@ -1365,7 +1376,7 @@ int log_syntax_internal( if (config_file) { if (config_line > 0) return log_struct_internal( - LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level), + level, error, file, line, func, "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, @@ -1376,7 +1387,7 @@ int log_syntax_internal( NULL); else return log_struct_internal( - LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level), + level, error, file, line, func, "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, @@ -1386,7 +1397,7 @@ int log_syntax_internal( NULL); } else if (unit) return log_struct_internal( - LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level), + level, error, file, line, func, "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, @@ -1395,7 +1406,7 @@ int log_syntax_internal( NULL); else return log_struct_internal( - LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level), + level, error, file, line, func, "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, @@ -1472,20 +1483,10 @@ int log_dup_console(void) { return 0; } -void log_setup_service(void) { - /* Sets up logging the way it is most appropriate for running a program as a service. Note that using this - * doesn't make the binary unsuitable for invocation on the command line, as log output will still go to the - * terminal if invoked interactively. */ - +void log_setup(void) { log_set_target(LOG_TARGET_AUTO); 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(); + if (log_on_console() && show_color < 0) + log_show_color(true); } diff --git a/src/basic/log.h b/src/basic/log.h index a2aae16df..b3d32abfc 100644 --- a/src/basic/log.h +++ b/src/basic/log.h @@ -12,16 +12,6 @@ struct iovec; struct signalfd_siginfo; -typedef enum LogRealm { - LOG_REALM_SYSTEMD, - LOG_REALM_UDEV, - _LOG_REALM_MAX, -} LogRealm; - -#ifndef LOG_REALM -# define LOG_REALM LOG_REALM_SYSTEMD -#endif - typedef enum LogTarget{ LOG_TARGET_CONSOLE, LOG_TARGET_CONSOLE_PREFIXED, @@ -33,28 +23,26 @@ typedef enum LogTarget{ LOG_TARGET_AUTO, /* console if stderr is not journal, JOURNAL_OR_KMSG otherwise */ LOG_TARGET_NULL, _LOG_TARGET_MAX, - _LOG_TARGET_INVALID = -1 + _LOG_TARGET_INVALID = -EINVAL, } LogTarget; /* Note to readers: << and >> have lower precedence than & and | */ -#define LOG_REALM_PLUS_LEVEL(realm, level) ((realm) << 10 | (level)) -#define LOG_REALM_REMOVE_LEVEL(realm_level) ((realm_level) >> 10) #define SYNTHETIC_ERRNO(num) (1 << 30 | (num)) #define IS_SYNTHETIC_ERRNO(val) ((val) >> 30 & 1) #define ERRNO_VALUE(val) (abs(val) & 255) +const char *log_target_to_string(LogTarget target) _const_; +LogTarget log_target_from_string(const char *s) _pure_; void log_set_target(LogTarget target); -void log_set_max_level_realm(LogRealm realm, int level); -#define log_set_max_level(level) \ - log_set_max_level_realm(LOG_REALM, (level)) +int log_set_target_from_string(const char *e); +LogTarget log_get_target(void) _pure_; + +void log_set_max_level(int level); +int log_set_max_level_from_string(const char *e); +int log_get_max_level(void) _pure_; void log_set_facility(int facility); -int log_set_target_from_string(const char *e); -int log_set_max_level_from_string_realm(LogRealm realm, const char *e); -#define log_set_max_level_from_string(e) \ - log_set_max_level_from_string_realm(LOG_REALM, (e)) - void log_show_color(bool b); bool log_get_show_color(void) _pure_; void log_show_location(bool b); @@ -69,15 +57,9 @@ int log_show_location_from_string(const char *e); int log_show_time_from_string(const char *e); int log_show_tid_from_string(const char *e); -LogTarget log_get_target(void) _pure_; -int log_get_max_level_realm(LogRealm realm) _pure_; -#define log_get_max_level() \ - log_get_max_level_realm(LOG_REALM) - /* Functions below that open and close logs or configure logging based on the * environment should not be called from library code — this is always a job - * for the application itself. - */ + * for the application itself. */ assert_cc(STRLEN(__FILE__) > STRLEN(RELATIVE_SOURCE_PATH) + 1); #define PROJECT_FILE (&__FILE__[STRLEN(RELATIVE_SOURCE_PATH) + 1]) @@ -86,12 +68,7 @@ int log_open(void); 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) +void log_parse_environment(void); int log_dispatch_internal( int level, @@ -105,17 +82,15 @@ int log_dispatch_internal( const char *extra_field, char *buffer); -int log_internal_realm( +int log_internal( int level, int error, const char *file, int line, const char *func, const char *format, ...) _printf_(6,7); -#define log_internal(level, ...) \ - log_internal_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__) -int log_internalv_realm( +int log_internalv( int level, int error, const char *file, @@ -123,10 +98,7 @@ int log_internalv_realm( const char *func, const char *format, va_list ap) _printf_(6,0); -#define log_internalv(level, ...) \ - log_internalv_realm(LOG_REALM_PLUS_LEVEL(LOG_REALM, (level)), __VA_ARGS__) -/* Realm is fixed to LOG_REALM_SYSTEMD for those */ int log_object_internalv( int level, int error, @@ -161,7 +133,7 @@ int log_struct_internal( const char *format, ...) _printf_(6,0) _sentinel_; int log_oom_internal( - LogRealm realm, + int level, const char *file, int line, const char *func); @@ -194,49 +166,36 @@ int log_dump_internal( char *buffer); /* Logging for various assertions */ -_noreturn_ void log_assert_failed_realm( - LogRealm realm, +_noreturn_ void log_assert_failed( const char *text, const char *file, int line, const char *func); -#define log_assert_failed(text, ...) \ - log_assert_failed_realm(LOG_REALM, (text), __VA_ARGS__) -_noreturn_ void log_assert_failed_unreachable_realm( - LogRealm realm, +_noreturn_ void log_assert_failed_unreachable( const char *text, const char *file, int line, const char *func); -#define log_assert_failed_unreachable(text, ...) \ - log_assert_failed_unreachable_realm(LOG_REALM, (text), __VA_ARGS__) -void log_assert_failed_return_realm( - LogRealm realm, +void log_assert_failed_return( const char *text, const char *file, int line, const char *func); -#define log_assert_failed_return(text, ...) \ - log_assert_failed_return_realm(LOG_REALM, (text), __VA_ARGS__) #define log_dispatch(level, error, buffer) \ log_dispatch_internal(level, error, PROJECT_FILE, __LINE__, __func__, NULL, NULL, NULL, NULL, buffer) /* Logging with level */ -#define log_full_errno_realm(realm, level, error, ...) \ +#define log_full_errno(level, error, ...) \ ({ \ - int _level = (level), _e = (error), _realm = (realm); \ - (log_get_max_level_realm(_realm) >= LOG_PRI(_level)) \ - ? log_internal_realm(LOG_REALM_PLUS_LEVEL(_realm, _level), _e, \ - PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ + int _level = (level), _e = (error); \ + (log_get_max_level() >= LOG_PRI(_level)) \ + ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ : -ERRNO_VALUE(_e); \ }) -#define log_full_errno(level, error, ...) \ - log_full_errno_realm(LOG_REALM, (level), (error), __VA_ARGS__) - #define log_full(level, ...) (void) log_full_errno((level), 0, __VA_ARGS__) int log_emergency_level(void); @@ -257,35 +216,30 @@ int log_emergency_level(void); #define log_error_errno(error, ...) log_full_errno(LOG_ERR, error, __VA_ARGS__) #define log_emergency_errno(error, ...) log_full_errno(log_emergency_level(), error, __VA_ARGS__) -#ifdef LOG_TRACE +#if LOG_TRACE # define log_trace(...) log_debug(__VA_ARGS__) #else # define log_trace(...) do {} while (0) #endif /* Structured logging */ -#define log_struct_errno(level, error, ...) \ - log_struct_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \ - error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL) +#define log_struct_errno(level, error, ...) \ + log_struct_internal(level, error, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__, NULL) #define log_struct(level, ...) log_struct_errno(level, 0, __VA_ARGS__) #define log_struct_iovec_errno(level, error, iovec, n_iovec) \ - log_struct_iovec_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \ - error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) + log_struct_iovec_internal(level, error, PROJECT_FILE, __LINE__, __func__, iovec, n_iovec) #define log_struct_iovec(level, iovec, n_iovec) log_struct_iovec_errno(level, 0, iovec, n_iovec) /* This modifies the buffer passed! */ -#define log_dump(level, buffer) \ - log_dump_internal(LOG_REALM_PLUS_LEVEL(LOG_REALM, level), \ - 0, PROJECT_FILE, __LINE__, __func__, buffer) +#define log_dump(level, buffer) \ + log_dump_internal(level, 0, PROJECT_FILE, __LINE__, __func__, buffer) -#define log_oom() log_oom_internal(LOG_REALM, PROJECT_FILE, __LINE__, __func__) +#define log_oom() log_oom_internal(LOG_ERR, PROJECT_FILE, __LINE__, __func__) +#define log_oom_debug() log_oom_internal(LOG_DEBUG, PROJECT_FILE, __LINE__, __func__) bool log_on_console(void) _pure_; -const char *log_target_to_string(LogTarget target) _const_; -LogTarget log_target_from_string(const char *s) _pure_; - /* Helper to prepare various field for structured logging */ #define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ @@ -346,5 +300,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); +void log_setup(void); diff --git a/src/basic/login-util.h b/src/basic/login-util.h index 00a124dc9..dff87697a 100644 --- a/src/basic/login-util.h +++ b/src/basic/login-util.h @@ -4,6 +4,14 @@ #include #include +#define SD_LOGIND_ROOT_CHECK_INHIBITORS (UINT64_C(1) << 0) + +/* For internal use only */ +#define SD_LOGIND_INTERACTIVE (UINT64_C(1) << 63) + +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC (SD_LOGIND_ROOT_CHECK_INHIBITORS) +#define SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_ALL (SD_LOGIND_ROOT_CHECK_INHIBITORS|SD_LOGIND_INTERACTIVE) + bool session_id_valid(const char *id); static inline bool logind_running(void) { diff --git a/src/basic/macro.h b/src/basic/macro.h index 278255375..f1d5e0894 100644 --- a/src/basic/macro.h +++ b/src/basic/macro.h @@ -9,6 +9,8 @@ #include #include +#include "macro-fundamental.h" + #define _printf_(a, b) __attribute__((__format__(printf, a, b))) #ifdef __clang__ # define _alloc_(...) @@ -18,10 +20,7 @@ #define _sentinel_ __attribute__((__sentinel__)) #define _section_(x) __attribute__((__section__(x))) #define _used_ __attribute__((__used__)) -#define _unused_ __attribute__((__unused__)) #define _destructor_ __attribute__((__destructor__)) -#define _pure_ __attribute__((__pure__)) -#define _const_ __attribute__((__const__)) #define _deprecated_ __attribute__((__deprecated__)) #define _packed_ __attribute__((__packed__)) #define _malloc_ __attribute__((__malloc__)) @@ -34,7 +33,6 @@ #define _align_(x) __attribute__((__aligned__(x))) #define _alignas_(x) __attribute__((__aligned__(__alignof(x)))) #define _alignptr_ __attribute__((__aligned__(sizeof(void*)))) -#define _cleanup_(x) __attribute__((__cleanup__(x))) #if __GNUC__ >= 7 #define _fallthrough_ __attribute__((__fallthrough__)) #else @@ -143,12 +141,6 @@ #define XSTRINGIFY(x) #x #define STRINGIFY(x) XSTRINGIFY(x) -#define XCONCATENATE(x, y) x ## y -#define CONCATENATE(x, y) XCONCATENATE(x, y) - -#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) -#define UNIQ __COUNTER__ - /* builtins */ #if __SIZEOF_INT__ == 4 #define BUILTIN_FFS_U32(x) __builtin_ffs(x); @@ -222,18 +214,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { return m; } -#ifndef __COVERITY__ -# define VOID_0 ((void)0) -#else -# define VOID_0 ((void*)0) -#endif - -#define ELEMENTSOF(x) \ - (__builtin_choose_expr( \ - !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ - sizeof(x)/sizeof((x)[0]), \ - VOID_0)) - /* * STRLEN - return the length of a string literal, minus the trailing NUL byte. * Contrary to strlen(), this is a constant expression. @@ -254,106 +234,6 @@ static inline size_t GREEDY_ALLOC_ROUND_UP(size_t l) { (type*)( (char *)UNIQ_T(A, uniq) - offsetof(type, member) ); \ }) -#undef MAX -#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) -#define __MAX(aq, a, bq, b) \ - ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ - }) - -/* evaluates to (void) if _A or _B are not constant or of different types */ -#define CONST_MAX(_A, _B) \ - (__builtin_choose_expr( \ - __builtin_constant_p(_A) && \ - __builtin_constant_p(_B) && \ - __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ - ((_A) > (_B)) ? (_A) : (_B), \ - VOID_0)) - -/* takes two types and returns the size of the larger one */ -#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) - -#define MAX3(x, y, z) \ - ({ \ - const typeof(x) _c = MAX(x, y); \ - MAX(_c, z); \ - }) - -#define MAX4(x, y, z, a) \ - ({ \ - const typeof(x) _d = MAX3(x, y, z); \ - MAX(_d, a); \ - }) - -#undef MIN -#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) -#define __MIN(aq, a, bq, b) \ - ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ - }) - -/* evaluates to (void) if _A or _B are not constant or of different types */ -#define CONST_MIN(_A, _B) \ - (__builtin_choose_expr( \ - __builtin_constant_p(_A) && \ - __builtin_constant_p(_B) && \ - __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ - ((_A) < (_B)) ? (_A) : (_B), \ - VOID_0)) - -#define MIN3(x, y, z) \ - ({ \ - const typeof(x) _c = MIN(x, y); \ - MIN(_c, z); \ - }) - -#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) -#define __LESS_BY(aq, a, bq, b) \ - ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \ - }) - -#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b)) -#define __CMP(aq, a, bq, b) \ - ({ \ - const typeof(a) UNIQ_T(A, aq) = (a); \ - const typeof(b) UNIQ_T(B, bq) = (b); \ - UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \ - UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \ - }) - -#undef CLAMP -#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) -#define __CLAMP(xq, x, lowq, low, highq, high) \ - ({ \ - const typeof(x) UNIQ_T(X, xq) = (x); \ - const typeof(low) UNIQ_T(LOW, lowq) = (low); \ - const typeof(high) UNIQ_T(HIGH, highq) = (high); \ - UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \ - UNIQ_T(HIGH, highq) : \ - UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \ - UNIQ_T(LOW, lowq) : \ - UNIQ_T(X, xq); \ - }) - -/* [(x + y - 1) / y] suffers from an integer overflow, even though the - * computation should be possible in the given type. Therefore, we use - * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the - * quotient and the remainder, so both should be equally fast. */ -#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y)) -#define __DIV_ROUND_UP(xq, x, yq, y) \ - ({ \ - const typeof(x) UNIQ_T(X, xq) = (x); \ - const typeof(y) UNIQ_T(Y, yq) = (y); \ - (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \ - }) - #ifdef __COVERITY__ /* Use special definitions of assertion macros in order to prevent @@ -410,16 +290,6 @@ static inline int __coverity_check_and_return__(int condition) { #define assert_not_reached(t) \ log_assert_failed_unreachable(t, PROJECT_FILE, __LINE__, __PRETTY_FUNCTION__) -#if defined(static_assert) -#define assert_cc(expr) \ - static_assert(expr, #expr) -#else -#define assert_cc(expr) \ - struct CONCATENATE(_assert_struct_, __COUNTER__) { \ - char x[(expr) ? 0 : -1]; \ - } -#endif - #define assert_return(expr, r) \ do { \ if (!assert_log(expr, #expr)) \ @@ -498,53 +368,6 @@ static inline int __coverity_check_and_return__(int condition) { #define FLAGS_SET(v, flags) \ ((~(v) & (flags)) == 0) -#define CASE_F(X) case X: -#define CASE_F_1(CASE, X) CASE_F(X) -#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) -#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) -#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__) -#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__) -#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__) -#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__) -#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__) -#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__) -#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__) -#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__) -#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__) -#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__) -#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__) -#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__) -#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__) -#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__) -#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__) -#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__) -#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__) - -#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME -#define FOR_EACH_MAKE_CASE(...) \ - GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ - CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ - (CASE_F,__VA_ARGS__) - -#define IN_SET(x, ...) \ - ({ \ - bool _found = false; \ - /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \ - * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \ - * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \ - * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \ - static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \ - assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ - switch(x) { \ - FOR_EACH_MAKE_CASE(__VA_ARGS__) \ - _found = true; \ - break; \ - default: \ - break; \ - } \ - _found; \ - }) - #define SWAP_TWO(x, y) do { \ typeof(x) _t = (x); \ (x) = (y); \ @@ -553,6 +376,7 @@ static inline int __coverity_check_and_return__(int condition) { #define STRV_MAKE(...) ((char**) ((const char*[]) { __VA_ARGS__, NULL })) #define STRV_MAKE_EMPTY ((char*[1]) { NULL }) +#define STRV_MAKE_CONST(...) ((const char* const*) ((const char*[]) { __VA_ARGS__, NULL })) /* Pointers range from NULL to POINTER_MAX */ #define POINTER_MAX ((void*) UINTPTR_MAX) @@ -582,10 +406,20 @@ static inline int __coverity_check_and_return__(int condition) { func(p); \ } +/* When func() returns the void value (NULL, -1, …) of the appropriate type */ #define DEFINE_TRIVIAL_CLEANUP_FUNC(type, func) \ static inline void func##p(type *p) { \ if (*p) \ + *p = func(*p); \ + } + +/* When func() doesn't return the appropriate type, set variable to empty afterwards */ +#define DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(type, func, empty) \ + static inline void func##p(type *p) { \ + if (*p != (empty)) { \ func(*p); \ + *p = (empty); \ + } \ } #define _DEFINE_TRIVIAL_REF_FUNC(type, name, scope) \ diff --git a/src/basic/meson.build b/src/basic/meson.build index 1183ea83a..60ef801a2 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -19,6 +19,7 @@ basic_sources = files(''' blockdev-util.h btrfs-util.c btrfs-util.h + build.c build.h bus-label.c bus-label.h @@ -41,6 +42,7 @@ basic_sources = files(''' dirent-util.h dlfcn-util.c dlfcn-util.h + dns-def.h efivars.c efivars.h env-file.c @@ -81,8 +83,6 @@ basic_sources = files(''' io-util.c io-util.h ioprio.h - kbd-util.c - kbd-util.h khash.c khash.h label.c @@ -113,7 +113,12 @@ basic_sources = files(''' linux/libc-compat.h linux/loadavg.h linux/netdevice.h + linux/netfilter/nf_tables.h + linux/netfilter/nfnetlink.h linux/netlink.h + linux/nexthop.h + linux/nl80211.h + linux/pkt_sched.h linux/rtnetlink.h linux/wireguard.h list.h @@ -163,12 +168,16 @@ basic_sources = files(''' nulstr-util.h ordered-set.c ordered-set.h + os-util.c + os-util.h parse-util.c parse-util.h path-lookup.c path-lookup.h path-util.c path-util.h + percent-util.c + percent-util.h prioq.c prioq.h proc-cmdline.c @@ -186,6 +195,8 @@ basic_sources = files(''' ratelimit.h raw-clone.h raw-reboot.h + recovery-key.c + recovery-key.h replace-var.c replace-var.h rlimit-util.c @@ -224,6 +235,8 @@ basic_sources = files(''' strv.h strxcpyx.c strxcpyx.h + sysctl-util.c + sysctl-util.h syslog-util.c syslog-util.h terminal-util.c @@ -236,6 +249,8 @@ basic_sources = files(''' unaligned.h unit-def.c unit-def.h + unit-file.c + unit-file.h unit-name.c unit-name.h user-util.c @@ -254,6 +269,9 @@ missing_audit_h = files('missing_audit.h') missing_capability_h = files('missing_capability.h') missing_socket_h = files('missing_socket.h') +missing_syscall_def_h = files('missing_syscall_def.h') +basic_sources += missing_syscall_def_h + generate_af_list = find_program('generate-af-list.sh') af_list_txt = custom_target( 'af-list.txt', @@ -322,14 +340,53 @@ foreach item : [['af', af_list_txt, 'af', ''], endforeach basic_sources += generated_gperf_headers -basic_gcrypt_sources = files( - 'gcrypt-util.c', - 'gcrypt-util.h') + +############################################################ + +arch_list = [ + 'alpha', + 'arc', + 'arm', + 'arm64', + 'i386', + 'ia64', + 'm68k', + 'mips64', + 'mips64n32', + 'mipso32', + 'powerpc', + 'powerpc64', + 's390', + 's390x', + 'sparc', + 'x86_64'] + +run_target( + 'update-syscall-tables', + command : [update_syscall_tables_sh, meson.current_source_dir()] + arch_list) + +syscall_list_txt = files('syscall-list.txt') + +syscall_lists = [] +foreach arch: arch_list + syscall_lists += files('syscalls-@0@.txt'.format(arch)) +endforeach + +missing_syscalls_py = find_program('missing_syscalls.py') + +run_target( + 'update-syscall-header', + command : [missing_syscalls_py, + missing_syscall_def_h, + syscall_lists]) + +############################################################ libbasic = static_library( 'basic', basic_sources, - include_directories : includes, + fundamental_sources, + include_directories : basic_includes, dependencies : [versiondep, threads, libcap, @@ -340,11 +397,17 @@ libbasic = static_library( c_args : ['-fvisibility=default'], install : false) +############################################################ + +basic_gcrypt_sources = files( + 'gcrypt-util.c', + 'gcrypt-util.h') + # A convenience library that is separate from libbasic to avoid # unnecessary linking to libgcrypt. libbasic_gcrypt = static_library( 'basic-gcrypt', basic_gcrypt_sources, - include_directories : includes, + include_directories : basic_includes, dependencies : [libgcrypt], c_args : ['-fvisibility=default']) diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 17bc1a5a0..30ac297e1 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -67,6 +67,14 @@ struct sockaddr_vm { #define IPV6_FREEBIND 78 #endif +#ifndef IP_RECVFRAGSIZE +#define IP_RECVFRAGSIZE 25 +#endif + +#ifndef IPV6_RECVFRAGSIZE +#define IPV6_RECVFRAGSIZE 77 +#endif + /* linux/sockios.h */ #ifndef SIOCGSKNS #define SIOCGSKNS 0x894C diff --git a/src/basic/missing_syscall.h b/src/basic/missing_syscall.h index 0594a1b93..138432480 100644 --- a/src/basic/missing_syscall.h +++ b/src/basic/missing_syscall.h @@ -5,6 +5,11 @@ #include #include +#if HAVE_LINUX_TIME_TYPES_H +/* This header defines __kernel_timespec for us, but is only available since Linux 5.1, hence conditionally + * include this. */ +#include +#endif #include #include #include @@ -15,34 +20,17 @@ #include #endif -#if defined(__x86_64__) && defined(__ILP32__) -# define systemd_SC_arch_bias(x) ((x) | /* __X32_SYSCALL_BIT */ 0x40000000) -#elif defined(__ia64__) -# define systemd_SC_arch_bias(x) (1024 + (x)) -#elif defined __alpha__ -# define systemd_SC_arch_bias(x) (110 + (x)) -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_SC_arch_bias(x) (4000 + (x)) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_SC_arch_bias(x) (6000 + (x)) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_SC_arch_bias(x) (5000 + (x)) -# else -# error "Unknown MIPS ABI" -# endif -#else -# define systemd_SC_arch_bias(x) (x) -#endif - #include "missing_keyctl.h" #include "missing_stat.h" +#include "missing_syscall_def.h" /* linux/kcmp.h */ #ifndef KCMP_FILE /* 3f4994cfc15f38a3159c6e3a4b3ab2e1481a6b02 (3.19) */ #define KCMP_FILE 0 #endif +/* ======================================================================= */ + #if !HAVE_PIVOT_ROOT static inline int missing_pivot_root(const char *new_root, const char *put_old) { return syscall(__NR_pivot_root, new_root, put_old); @@ -53,48 +41,6 @@ static inline int missing_pivot_root(const char *new_root, const char *put_old) /* ======================================================================= */ -#if defined __x86_64__ -# define systemd_NR_memfd_create systemd_SC_arch_bias(319) -#elif defined __arm__ -# define systemd_NR_memfd_create 385 -#elif defined __aarch64__ -# define systemd_NR_memfd_create 279 -#elif defined __alpha__ -# define systemd_NR_memfd_create 512 -#elif defined(__powerpc__) -# define systemd_NR_memfd_create 360 -#elif defined __s390__ -# define systemd_NR_memfd_create 350 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_memfd_create systemd_SC_arch_bias(354) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_memfd_create systemd_SC_arch_bias(318) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_memfd_create systemd_SC_arch_bias(314) -# endif -#elif defined __i386__ -# define systemd_NR_memfd_create 356 -#elif defined __arc__ -# define systemd_NR_memfd_create 279 -#else -# warning "memfd_create() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_memfd_create && __NR_memfd_create >= 0 -# if defined systemd_NR_memfd_create -assert_cc(__NR_memfd_create == systemd_NR_memfd_create); -# endif -#else -# if defined __NR_memfd_create -# undef __NR_memfd_create -# endif -# if defined systemd_NR_memfd_create -# define __NR_memfd_create systemd_NR_memfd_create -# endif -#endif - #if !HAVE_MEMFD_CREATE static inline int missing_memfd_create(const char *name, unsigned int flags) { # ifdef __NR_memfd_create @@ -110,52 +56,6 @@ static inline int missing_memfd_create(const char *name, unsigned int flags) { /* ======================================================================= */ -#if defined __x86_64__ -# define systemd_NR_getrandom systemd_SC_arch_bias(318) -#elif defined(__i386__) -# define systemd_NR_getrandom 355 -#elif defined(__arm__) -# define systemd_NR_getrandom 384 -#elif defined(__aarch64__) -# define systemd_NR_getrandom 278 -#elif defined(__alpha__) -# define systemd_NR_getrandom 511 -#elif defined(__ia64__) -# define systemd_NR_getrandom systemd_SC_arch_bias(318) -#elif defined(__m68k__) -# define systemd_NR_getrandom 352 -#elif defined(__s390x__) -# define systemd_NR_getrandom 349 -#elif defined(__powerpc__) -# define systemd_NR_getrandom 359 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_getrandom systemd_SC_arch_bias(353) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_getrandom systemd_SC_arch_bias(317) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_getrandom systemd_SC_arch_bias(313) -# endif -#elif defined(__arc__) -# define systemd_NR_getrandom 278 -#else -# warning "getrandom() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_getrandom && __NR_getrandom >= 0 -# if defined systemd_NR_getrandom -assert_cc(__NR_getrandom == systemd_NR_getrandom); -# endif -#else -# if defined __NR_getrandom -# undef __NR_getrandom -# endif -# if defined systemd_NR_getrandom -# define __NR_getrandom systemd_NR_getrandom -# endif -#endif - #if !HAVE_GETRANDOM static inline int missing_getrandom(void *buffer, size_t count, unsigned flags) { # ifdef __NR_getrandom @@ -186,48 +86,6 @@ static inline pid_t missing_gettid(void) { /* ======================================================================= */ -#if defined(__x86_64__) -# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303) -#elif defined(__i386__) -# define systemd_NR_name_to_handle_at 341 -#elif defined(__arm__) -# define systemd_NR_name_to_handle_at 370 -#elif defined __aarch64__ -# define systemd_NR_name_to_handle_at 264 -#elif defined(__alpha__) -# define systemd_NR_name_to_handle_at 497 -#elif defined(__powerpc__) -# define systemd_NR_name_to_handle_at 345 -#elif defined __s390__ || defined __s390x__ -# define systemd_NR_name_to_handle_at 335 -#elif defined(__arc__) -# define systemd_NR_name_to_handle_at 264 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(339) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(303) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_name_to_handle_at systemd_SC_arch_bias(298) -# endif -#else -# warning "name_to_handle_at number is not defined" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0 -# if defined systemd_NR_name_to_handle_at -assert_cc(__NR_name_to_handle_at == systemd_NR_name_to_handle_at); -# endif -#else -# if defined __NR_name_to_handle_at -# undef __NR_name_to_handle_at -# endif -# if defined systemd_NR_name_to_handle_at -# define __NR_name_to_handle_at systemd_NR_name_to_handle_at -# endif -#endif - #if !HAVE_NAME_TO_HANDLE_AT struct file_handle { unsigned int handle_bytes; @@ -249,48 +107,6 @@ static inline int missing_name_to_handle_at(int fd, const char *name, struct fil /* ======================================================================= */ -#if defined __aarch64__ -# define systemd_NR_setns 268 -#elif defined __arm__ -# define systemd_NR_setns 375 -#elif defined __alpha__ -# define systemd_NR_setns 501 -#elif defined(__x86_64__) -# define systemd_NR_setns systemd_SC_arch_bias(308) -#elif defined(__i386__) -# define systemd_NR_setns 346 -#elif defined(__powerpc__) -# define systemd_NR_setns 350 -#elif defined __s390__ || defined __s390x__ -# define systemd_NR_setns 339 -#elif defined(__arc__) -# define systemd_NR_setns 268 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_setns systemd_SC_arch_bias(344) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_setns systemd_SC_arch_bias(308) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_setns systemd_SC_arch_bias(303) -# endif -#else -# warning "setns() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_setns && __NR_setns >= 0 -# if defined systemd_NR_setns -assert_cc(__NR_setns == systemd_NR_setns); -# endif -#else -# if defined __NR_setns -# undef __NR_setns -# endif -# if defined systemd_NR_setns -# define __NR_setns systemd_NR_setns -# endif -#endif - #if !HAVE_SETNS static inline int missing_setns(int fd, int nstype) { # ifdef __NR_setns @@ -316,48 +132,6 @@ static inline pid_t raw_getpid(void) { /* ======================================================================= */ -#if defined __x86_64__ -# define systemd_NR_renameat2 systemd_SC_arch_bias(316) -#elif defined __arm__ -# define systemd_NR_renameat2 382 -#elif defined __aarch64__ -# define systemd_NR_renameat2 276 -#elif defined __alpha__ -# define systemd_NR_renameat2 510 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_renameat2 systemd_SC_arch_bias(351) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_renameat2 systemd_SC_arch_bias(315) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_renameat2 systemd_SC_arch_bias(311) -# endif -#elif defined __i386__ -# define systemd_NR_renameat2 353 -#elif defined __powerpc64__ -# define systemd_NR_renameat2 357 -#elif defined __s390__ || defined __s390x__ -# define systemd_NR_renameat2 347 -#elif defined __arc__ -# define systemd_NR_renameat2 276 -#else -# warning "renameat2() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_renameat2 && __NR_renameat2 >= 0 -# if defined systemd_NR_renameat2 -assert_cc(__NR_renameat2 == systemd_NR_renameat2); -# endif -#else -# if defined __NR_renameat2 -# undef __NR_renameat2 -# endif -# if defined systemd_NR_renameat2 -# define __NR_renameat2 systemd_NR_renameat2 -# endif -#endif - #if !HAVE_RENAMEAT2 static inline int missing_renameat2(int oldfd, const char *oldname, int newfd, const char *newname, unsigned flags) { # ifdef __NR_renameat2 @@ -425,48 +199,6 @@ static inline key_serial_t missing_request_key(const char *type, const char *des /* ======================================================================= */ -#if defined(__x86_64__) -# define systemd_NR_copy_file_range systemd_SC_arch_bias(326) -#elif defined(__i386__) -# define systemd_NR_copy_file_range 377 -#elif defined __s390__ -# define systemd_NR_copy_file_range 375 -#elif defined __arm__ -# define systemd_NR_copy_file_range 391 -#elif defined __aarch64__ -# define systemd_NR_copy_file_range 285 -#elif defined __alpha__ -# define systemd_NR_copy_file_range 519 -#elif defined __powerpc__ -# define systemd_NR_copy_file_range 379 -#elif defined __arc__ -# define systemd_NR_copy_file_range 285 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_copy_file_range systemd_SC_arch_bias(360) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_copy_file_range systemd_SC_arch_bias(324) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_copy_file_range systemd_SC_arch_bias(320) -# endif -#else -# warning "copy_file_range() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_copy_file_range && __NR_copy_file_range >= 0 -# if defined systemd_NR_copy_file_range -assert_cc(__NR_copy_file_range == systemd_NR_copy_file_range); -# endif -#else -# if defined __NR_copy_file_range -# undef __NR_copy_file_range -# endif -# if defined systemd_NR_copy_file_range -# define __NR_copy_file_range systemd_NR_copy_file_range -# endif -#endif - #if !HAVE_COPY_FILE_RANGE static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, int fd_out, loff_t *off_out, @@ -485,50 +217,6 @@ static inline ssize_t missing_copy_file_range(int fd_in, loff_t *off_in, /* ======================================================================= */ -#if defined __i386__ -# define systemd_NR_bpf 357 -#elif defined __x86_64__ -# define systemd_NR_bpf systemd_SC_arch_bias(321) -#elif defined __aarch64__ -# define systemd_NR_bpf 280 -#elif defined __arm__ -# define systemd_NR_bpf 386 -#elif defined __alpha__ -# define systemd_NR_bpf 515 -#elif defined(__powerpc__) -# define systemd_NR_bpf 361 -#elif defined __sparc__ -# define systemd_NR_bpf 349 -#elif defined __s390__ -# define systemd_NR_bpf 351 -#elif defined __tilegx__ -# define systemd_NR_bpf 280 -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_bpf systemd_SC_arch_bias(355) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_bpf systemd_SC_arch_bias(319) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_bpf systemd_SC_arch_bias(315) -# endif -#else -# warning "bpf() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_bpf && __NR_bpf >= 0 -# if defined systemd_NR_bpf -assert_cc(__NR_bpf == systemd_NR_bpf); -# endif -#else -# if defined __NR_bpf -# undef __NR_bpf -# endif -# if defined systemd_NR_bpf -# define __NR_bpf systemd_NR_bpf -# endif -#endif - #if !HAVE_BPF union bpf_attr; @@ -546,90 +234,6 @@ static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) { /* ======================================================================= */ -#ifndef __IGNORE_pkey_mprotect -# if defined __i386__ -# define systemd_NR_pkey_mprotect 380 -# elif defined __x86_64__ -# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(329) -# elif defined __aarch64__ -# define systemd_NR_pkey_mprotect 288 -# elif defined __arm__ -# define systemd_NR_pkey_mprotect 394 -# elif defined __alpha__ -# define systemd_NR_pkey_mprotect 524 -# elif defined __powerpc__ -# define systemd_NR_pkey_mprotect 386 -# elif defined __s390__ -# define systemd_NR_pkey_mprotect 384 -# elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(363) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(327) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_pkey_mprotect systemd_SC_arch_bias(323) -# endif -# else -# warning "pkey_mprotect() syscall number unknown for your architecture" -# endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -# if defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0 -# if defined systemd_NR_pkey_mprotect -assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect); -# endif -# else -# if defined __NR_pkey_mprotect -# undef __NR_pkey_mprotect -# endif -# if defined systemd_NR_pkey_mprotect -# define __NR_pkey_mprotect systemd_NR_pkey_mprotect -# endif -# endif -#endif - -/* ======================================================================= */ - -#if defined __aarch64__ -# define systemd_NR_statx 291 -#elif defined __arm__ -# define systemd_NR_statx 397 -#elif defined __alpha__ -# define systemd_NR_statx 522 -#elif defined __i386__ || defined __powerpc64__ -# define systemd_NR_statx 383 -#elif defined __s390__ || defined __s390x__ -# define systemd_NR_statx 379 -#elif defined __sparc__ -# define systemd_NR_statx 360 -#elif defined __x86_64__ -# define systemd_NR_statx systemd_SC_arch_bias(332) -#elif defined _MIPS_SIM -# if _MIPS_SIM == _MIPS_SIM_ABI32 -# define systemd_NR_statx systemd_SC_arch_bias(366) -# elif _MIPS_SIM == _MIPS_SIM_NABI32 -# define systemd_NR_statx systemd_SC_arch_bias(330) -# elif _MIPS_SIM == _MIPS_SIM_ABI64 -# define systemd_NR_statx systemd_SC_arch_bias(326) -# endif -#else -# warning "statx() syscall number unknown for your architecture" -#endif - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_statx && __NR_statx >= 0 -# if defined systemd_NR_statx -assert_cc(__NR_statx == systemd_NR_statx); -# endif -#else -# if defined __NR_statx -# undef __NR_statx -# endif -# if defined systemd_NR_statx -# define __NR_statx systemd_NR_statx -# endif -#endif - #if !HAVE_STATX struct statx; @@ -695,21 +299,6 @@ static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask, /* ======================================================================= */ -/* should be always defined, see kernel 39036cd2727395c3369b1051005da74059a85317 */ -#define systemd_NR_pidfd_send_signal systemd_SC_arch_bias(424) - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0 -# if defined systemd_NR_pidfd_send_signal -assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal); -# endif -#else -# if defined __NR_pidfd_send_signal -# undef __NR_pidfd_send_signal -# endif -# define __NR_pidfd_send_signal systemd_NR_pidfd_send_signal -#endif - #if !HAVE_PIDFD_SEND_SIGNAL static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) { # ifdef __NR_pidfd_send_signal @@ -723,21 +312,6 @@ static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, un # define pidfd_send_signal missing_pidfd_send_signal #endif -/* should be always defined, see kernel 7615d9e1780e26e0178c93c55b73309a5dc093d7 */ -#define systemd_NR_pidfd_open systemd_SC_arch_bias(434) - -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_pidfd_open && __NR_pidfd_open >= 0 -# if defined systemd_NR_pidfd_open -assert_cc(__NR_pidfd_open == systemd_NR_pidfd_open); -# endif -#else -# if defined __NR_pidfd_open -# undef __NR_pidfd_open -# endif -# define __NR_pidfd_open systemd_NR_pidfd_open -#endif - #if !HAVE_PIDFD_OPEN static inline int missing_pidfd_open(pid_t pid, unsigned flags) { # ifdef __NR_pidfd_open @@ -767,22 +341,25 @@ static inline int missing_rt_sigqueueinfo(pid_t tgid, int sig, siginfo_t *info) /* ======================================================================= */ -#define systemd_NR_close_range systemd_SC_arch_bias(436) +#if !HAVE_EXECVEAT +static inline int missing_execveat(int dirfd, const char *pathname, + char *const argv[], char *const envp[], + int flags) { +# if defined __NR_execveat && __NR_execveat >= 0 + return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags); +# else + errno = ENOSYS; + return -1; +# endif +} -/* may be (invalid) negative number due to libseccomp, see PR 13319 */ -#if defined __NR_close_range && __NR_close_range >= 0 -# if defined systemd_NR_close_range -assert_cc(__NR_close_range == systemd_NR_close_range); -# endif -#else -# if defined __NR_close_range -# undef __NR_close_range -# endif -# if defined systemd_NR_close_range -# define __NR_close_range systemd_NR_close_range -# endif +# undef AT_EMPTY_PATH +# define AT_EMPTY_PATH 0x1000 +# define execveat missing_execveat #endif +/* ======================================================================= */ + #if !HAVE_CLOSE_RANGE static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) { # ifdef __NR_close_range @@ -810,3 +387,41 @@ static inline int missing_close_range(int first_fd, int end_fd, unsigned flags) # define close_range missing_close_range #endif + +/* ======================================================================= */ + +#if !HAVE_EPOLL_PWAIT2 + +/* Defined to be equivalent to the kernel's _NSIG_WORDS, i.e. the size of the array of longs that is + * encapsulated by sigset_t. */ +#define KERNEL_NSIG_WORDS (64 / (sizeof(long) * 8)) +#define KERNEL_NSIG_BYTES (KERNEL_NSIG_WORDS * sizeof(long)) + +struct epoll_event; + +static inline int missing_epoll_pwait2( + int fd, + struct epoll_event *events, + int maxevents, + const struct timespec *timeout, + const sigset_t *sigset) { + +# if defined(__NR_epoll_pwait2) && HAVE_LINUX_TIME_TYPES_H + if (timeout) { + /* Convert from userspace timespec to kernel timespec */ + struct __kernel_timespec ts = { + .tv_sec = timeout->tv_sec, + .tv_nsec = timeout->tv_nsec, + }; + + return syscall(__NR_epoll_pwait2, fd, events, maxevents, &ts, sigset, sigset ? KERNEL_NSIG_BYTES : 0); + } else + return syscall(__NR_epoll_pwait2, fd, events, maxevents, NULL, sigset, sigset ? KERNEL_NSIG_BYTES : 0); +# else + errno = ENOSYS; + return -1; +# endif +} + +# define epoll_pwait2 missing_epoll_pwait2 +#endif diff --git a/src/basic/missing_syscall_def.h b/src/basic/missing_syscall_def.h new file mode 100644 index 000000000..a66977cfe --- /dev/null +++ b/src/basic/missing_syscall_def.h @@ -0,0 +1,730 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later + * This file is generated. Do not edit! */ + +#ifndef __IGNORE_bpf +# if defined(__aarch64__) +# define systemd_NR_bpf 280 +# elif defined(__alpha__) +# define systemd_NR_bpf 515 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_bpf 280 +# elif defined(__arm__) +# define systemd_NR_bpf 386 +# elif defined(__i386__) +# define systemd_NR_bpf 357 +# elif defined(__ia64__) +# define systemd_NR_bpf 1341 +# elif defined(__m68k__) +# define systemd_NR_bpf 354 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_bpf 4355 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_bpf 6319 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_bpf 5315 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_bpf 361 +# elif defined(__s390__) +# define systemd_NR_bpf 351 +# elif defined(__sparc__) +# define systemd_NR_bpf 349 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_bpf (321 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_bpf 321 +# endif +# else +# warning "bpf() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_bpf && __NR_bpf >= 0 +# if defined systemd_NR_bpf +assert_cc(__NR_bpf == systemd_NR_bpf); +# endif +# else +# if defined __NR_bpf +# undef __NR_bpf +# endif +# if defined systemd_NR_bpf && systemd_NR_bpf >= 0 +# define __NR_bpf systemd_NR_bpf +# endif +# endif +#endif + +#ifndef __IGNORE_close_range +# if defined(__aarch64__) +# define systemd_NR_close_range 436 +# elif defined(__alpha__) +# define systemd_NR_close_range 546 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_close_range 436 +# elif defined(__arm__) +# define systemd_NR_close_range 436 +# elif defined(__i386__) +# define systemd_NR_close_range 436 +# elif defined(__ia64__) +# define systemd_NR_close_range 1460 +# elif defined(__m68k__) +# define systemd_NR_close_range 436 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_close_range 4436 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_close_range 6436 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_close_range 5436 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_close_range 436 +# elif defined(__s390__) +# define systemd_NR_close_range 436 +# elif defined(__sparc__) +# define systemd_NR_close_range 436 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_close_range (436 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_close_range 436 +# endif +# else +# warning "close_range() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_close_range && __NR_close_range >= 0 +# if defined systemd_NR_close_range +assert_cc(__NR_close_range == systemd_NR_close_range); +# endif +# else +# if defined __NR_close_range +# undef __NR_close_range +# endif +# if defined systemd_NR_close_range && systemd_NR_close_range >= 0 +# define __NR_close_range systemd_NR_close_range +# endif +# endif +#endif + +#ifndef __IGNORE_copy_file_range +# if defined(__aarch64__) +# define systemd_NR_copy_file_range 285 +# elif defined(__alpha__) +# define systemd_NR_copy_file_range 519 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_copy_file_range 285 +# elif defined(__arm__) +# define systemd_NR_copy_file_range 391 +# elif defined(__i386__) +# define systemd_NR_copy_file_range 377 +# elif defined(__ia64__) +# define systemd_NR_copy_file_range 1347 +# elif defined(__m68k__) +# define systemd_NR_copy_file_range 376 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_copy_file_range 4360 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_copy_file_range 6324 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_copy_file_range 5320 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_copy_file_range 379 +# elif defined(__s390__) +# define systemd_NR_copy_file_range 375 +# elif defined(__sparc__) +# define systemd_NR_copy_file_range 357 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_copy_file_range (326 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_copy_file_range 326 +# endif +# else +# warning "copy_file_range() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_copy_file_range && __NR_copy_file_range >= 0 +# if defined systemd_NR_copy_file_range +assert_cc(__NR_copy_file_range == systemd_NR_copy_file_range); +# endif +# else +# if defined __NR_copy_file_range +# undef __NR_copy_file_range +# endif +# if defined systemd_NR_copy_file_range && systemd_NR_copy_file_range >= 0 +# define __NR_copy_file_range systemd_NR_copy_file_range +# endif +# endif +#endif + +#ifndef __IGNORE_getrandom +# if defined(__aarch64__) +# define systemd_NR_getrandom 278 +# elif defined(__alpha__) +# define systemd_NR_getrandom 511 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_getrandom 278 +# elif defined(__arm__) +# define systemd_NR_getrandom 384 +# elif defined(__i386__) +# define systemd_NR_getrandom 355 +# elif defined(__ia64__) +# define systemd_NR_getrandom 1339 +# elif defined(__m68k__) +# define systemd_NR_getrandom 352 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_getrandom 4353 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_getrandom 6317 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_getrandom 5313 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_getrandom 359 +# elif defined(__s390__) +# define systemd_NR_getrandom 349 +# elif defined(__sparc__) +# define systemd_NR_getrandom 347 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_getrandom (318 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_getrandom 318 +# endif +# else +# warning "getrandom() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_getrandom && __NR_getrandom >= 0 +# if defined systemd_NR_getrandom +assert_cc(__NR_getrandom == systemd_NR_getrandom); +# endif +# else +# if defined __NR_getrandom +# undef __NR_getrandom +# endif +# if defined systemd_NR_getrandom && systemd_NR_getrandom >= 0 +# define __NR_getrandom systemd_NR_getrandom +# endif +# endif +#endif + +#ifndef __IGNORE_memfd_create +# if defined(__aarch64__) +# define systemd_NR_memfd_create 279 +# elif defined(__alpha__) +# define systemd_NR_memfd_create 512 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_memfd_create 279 +# elif defined(__arm__) +# define systemd_NR_memfd_create 385 +# elif defined(__i386__) +# define systemd_NR_memfd_create 356 +# elif defined(__ia64__) +# define systemd_NR_memfd_create 1340 +# elif defined(__m68k__) +# define systemd_NR_memfd_create 353 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_memfd_create 4354 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_memfd_create 6318 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_memfd_create 5314 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_memfd_create 360 +# elif defined(__s390__) +# define systemd_NR_memfd_create 350 +# elif defined(__sparc__) +# define systemd_NR_memfd_create 348 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_memfd_create (319 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_memfd_create 319 +# endif +# else +# warning "memfd_create() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_memfd_create && __NR_memfd_create >= 0 +# if defined systemd_NR_memfd_create +assert_cc(__NR_memfd_create == systemd_NR_memfd_create); +# endif +# else +# if defined __NR_memfd_create +# undef __NR_memfd_create +# endif +# if defined systemd_NR_memfd_create && systemd_NR_memfd_create >= 0 +# define __NR_memfd_create systemd_NR_memfd_create +# endif +# endif +#endif + +#ifndef __IGNORE_name_to_handle_at +# if defined(__aarch64__) +# define systemd_NR_name_to_handle_at 264 +# elif defined(__alpha__) +# define systemd_NR_name_to_handle_at 497 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_name_to_handle_at 264 +# elif defined(__arm__) +# define systemd_NR_name_to_handle_at 370 +# elif defined(__i386__) +# define systemd_NR_name_to_handle_at 341 +# elif defined(__ia64__) +# define systemd_NR_name_to_handle_at 1326 +# elif defined(__m68k__) +# define systemd_NR_name_to_handle_at 340 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_name_to_handle_at 4339 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_name_to_handle_at 6303 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_name_to_handle_at 5298 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_name_to_handle_at 345 +# elif defined(__s390__) +# define systemd_NR_name_to_handle_at 335 +# elif defined(__sparc__) +# define systemd_NR_name_to_handle_at 332 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_name_to_handle_at (303 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_name_to_handle_at 303 +# endif +# else +# warning "name_to_handle_at() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_name_to_handle_at && __NR_name_to_handle_at >= 0 +# if defined systemd_NR_name_to_handle_at +assert_cc(__NR_name_to_handle_at == systemd_NR_name_to_handle_at); +# endif +# else +# if defined __NR_name_to_handle_at +# undef __NR_name_to_handle_at +# endif +# if defined systemd_NR_name_to_handle_at && systemd_NR_name_to_handle_at >= 0 +# define __NR_name_to_handle_at systemd_NR_name_to_handle_at +# endif +# endif +#endif + +#ifndef __IGNORE_pidfd_open +# if defined(__aarch64__) +# define systemd_NR_pidfd_open 434 +# elif defined(__alpha__) +# define systemd_NR_pidfd_open 544 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_pidfd_open 434 +# elif defined(__arm__) +# define systemd_NR_pidfd_open 434 +# elif defined(__i386__) +# define systemd_NR_pidfd_open 434 +# elif defined(__ia64__) +# define systemd_NR_pidfd_open 1458 +# elif defined(__m68k__) +# define systemd_NR_pidfd_open 434 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_pidfd_open 4434 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_pidfd_open 6434 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_pidfd_open 5434 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_pidfd_open 434 +# elif defined(__s390__) +# define systemd_NR_pidfd_open 434 +# elif defined(__sparc__) +# define systemd_NR_pidfd_open 434 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_pidfd_open (434 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_pidfd_open 434 +# endif +# else +# warning "pidfd_open() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_pidfd_open && __NR_pidfd_open >= 0 +# if defined systemd_NR_pidfd_open +assert_cc(__NR_pidfd_open == systemd_NR_pidfd_open); +# endif +# else +# if defined __NR_pidfd_open +# undef __NR_pidfd_open +# endif +# if defined systemd_NR_pidfd_open && systemd_NR_pidfd_open >= 0 +# define __NR_pidfd_open systemd_NR_pidfd_open +# endif +# endif +#endif + +#ifndef __IGNORE_pidfd_send_signal +# if defined(__aarch64__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__alpha__) +# define systemd_NR_pidfd_send_signal 534 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__arm__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__i386__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__ia64__) +# define systemd_NR_pidfd_send_signal 1448 +# elif defined(__m68k__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_pidfd_send_signal 4424 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_pidfd_send_signal 6424 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_pidfd_send_signal 5424 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__s390__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__sparc__) +# define systemd_NR_pidfd_send_signal 424 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_pidfd_send_signal (424 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_pidfd_send_signal 424 +# endif +# else +# warning "pidfd_send_signal() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_pidfd_send_signal && __NR_pidfd_send_signal >= 0 +# if defined systemd_NR_pidfd_send_signal +assert_cc(__NR_pidfd_send_signal == systemd_NR_pidfd_send_signal); +# endif +# else +# if defined __NR_pidfd_send_signal +# undef __NR_pidfd_send_signal +# endif +# if defined systemd_NR_pidfd_send_signal && systemd_NR_pidfd_send_signal >= 0 +# define __NR_pidfd_send_signal systemd_NR_pidfd_send_signal +# endif +# endif +#endif + +#ifndef __IGNORE_pkey_mprotect +# if defined(__aarch64__) +# define systemd_NR_pkey_mprotect 288 +# elif defined(__alpha__) +# define systemd_NR_pkey_mprotect 524 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_pkey_mprotect 288 +# elif defined(__arm__) +# define systemd_NR_pkey_mprotect 394 +# elif defined(__i386__) +# define systemd_NR_pkey_mprotect 380 +# elif defined(__ia64__) +# define systemd_NR_pkey_mprotect 1354 +# elif defined(__m68k__) +# define systemd_NR_pkey_mprotect 381 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_pkey_mprotect 4363 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_pkey_mprotect 6327 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_pkey_mprotect 5323 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_pkey_mprotect 386 +# elif defined(__s390__) +# define systemd_NR_pkey_mprotect 384 +# elif defined(__sparc__) +# define systemd_NR_pkey_mprotect 362 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_pkey_mprotect (329 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_pkey_mprotect 329 +# endif +# else +# warning "pkey_mprotect() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_pkey_mprotect && __NR_pkey_mprotect >= 0 +# if defined systemd_NR_pkey_mprotect +assert_cc(__NR_pkey_mprotect == systemd_NR_pkey_mprotect); +# endif +# else +# if defined __NR_pkey_mprotect +# undef __NR_pkey_mprotect +# endif +# if defined systemd_NR_pkey_mprotect && systemd_NR_pkey_mprotect >= 0 +# define __NR_pkey_mprotect systemd_NR_pkey_mprotect +# endif +# endif +#endif + +#ifndef __IGNORE_renameat2 +# if defined(__aarch64__) +# define systemd_NR_renameat2 276 +# elif defined(__alpha__) +# define systemd_NR_renameat2 510 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_renameat2 276 +# elif defined(__arm__) +# define systemd_NR_renameat2 382 +# elif defined(__i386__) +# define systemd_NR_renameat2 353 +# elif defined(__ia64__) +# define systemd_NR_renameat2 1338 +# elif defined(__m68k__) +# define systemd_NR_renameat2 351 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_renameat2 4351 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_renameat2 6315 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_renameat2 5311 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_renameat2 357 +# elif defined(__s390__) +# define systemd_NR_renameat2 347 +# elif defined(__sparc__) +# define systemd_NR_renameat2 345 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_renameat2 (316 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_renameat2 316 +# endif +# else +# warning "renameat2() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_renameat2 && __NR_renameat2 >= 0 +# if defined systemd_NR_renameat2 +assert_cc(__NR_renameat2 == systemd_NR_renameat2); +# endif +# else +# if defined __NR_renameat2 +# undef __NR_renameat2 +# endif +# if defined systemd_NR_renameat2 && systemd_NR_renameat2 >= 0 +# define __NR_renameat2 systemd_NR_renameat2 +# endif +# endif +#endif + +#ifndef __IGNORE_setns +# if defined(__aarch64__) +# define systemd_NR_setns 268 +# elif defined(__alpha__) +# define systemd_NR_setns 501 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_setns 268 +# elif defined(__arm__) +# define systemd_NR_setns 375 +# elif defined(__i386__) +# define systemd_NR_setns 346 +# elif defined(__ia64__) +# define systemd_NR_setns 1330 +# elif defined(__m68k__) +# define systemd_NR_setns 344 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_setns 4344 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_setns 6308 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_setns 5303 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_setns 350 +# elif defined(__s390__) +# define systemd_NR_setns 339 +# elif defined(__sparc__) +# define systemd_NR_setns 337 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_setns (308 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_setns 308 +# endif +# else +# warning "setns() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_setns && __NR_setns >= 0 +# if defined systemd_NR_setns +assert_cc(__NR_setns == systemd_NR_setns); +# endif +# else +# if defined __NR_setns +# undef __NR_setns +# endif +# if defined systemd_NR_setns && systemd_NR_setns >= 0 +# define __NR_setns systemd_NR_setns +# endif +# endif +#endif + +#ifndef __IGNORE_statx +# if defined(__aarch64__) +# define systemd_NR_statx 291 +# elif defined(__alpha__) +# define systemd_NR_statx 522 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_statx 291 +# elif defined(__arm__) +# define systemd_NR_statx 397 +# elif defined(__i386__) +# define systemd_NR_statx 383 +# elif defined(__ia64__) +# define systemd_NR_statx 1350 +# elif defined(__m68k__) +# define systemd_NR_statx 379 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_statx 4366 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_statx 6330 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_statx 5326 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_statx 383 +# elif defined(__s390__) +# define systemd_NR_statx 379 +# elif defined(__sparc__) +# define systemd_NR_statx 360 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_statx (332 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_statx 332 +# endif +# else +# warning "statx() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_statx && __NR_statx >= 0 +# if defined systemd_NR_statx +assert_cc(__NR_statx == systemd_NR_statx); +# endif +# else +# if defined __NR_statx +# undef __NR_statx +# endif +# if defined systemd_NR_statx && systemd_NR_statx >= 0 +# define __NR_statx systemd_NR_statx +# endif +# endif +#endif + +#ifndef __IGNORE_epoll_pwait2 +# if defined(__aarch64__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__alpha__) +# define systemd_NR_epoll_pwait2 551 +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__arm__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__i386__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__ia64__) +# define systemd_NR_epoll_pwait2 1465 +# elif defined(__m68k__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_epoll_pwait2 4441 +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_epoll_pwait2 6441 +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_epoll_pwait2 5441 +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__s390__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__sparc__) +# define systemd_NR_epoll_pwait2 441 +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_epoll_pwait2 (441 | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_epoll_pwait2 441 +# endif +# else +# warning "epoll_pwait2() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_epoll_pwait2 && __NR_epoll_pwait2 >= 0 +# if defined systemd_NR_epoll_pwait2 +assert_cc(__NR_epoll_pwait2 == systemd_NR_epoll_pwait2); +# endif +# else +# if defined __NR_epoll_pwait2 +# undef __NR_epoll_pwait2 +# endif +# if defined systemd_NR_epoll_pwait2 && systemd_NR_epoll_pwait2 >= 0 +# define __NR_epoll_pwait2 systemd_NR_epoll_pwait2 +# endif +# endif +#endif diff --git a/src/basic/missing_syscalls.py b/src/basic/missing_syscalls.py new file mode 100644 index 000000000..550be48cf --- /dev/null +++ b/src/basic/missing_syscalls.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + +import sys +import functools + +# We only generate numbers for a dozen or so syscalls +SYSCALLS = [ + 'bpf', + 'close_range', + 'copy_file_range', + 'getrandom', + 'memfd_create', + 'name_to_handle_at', + 'pidfd_open', + 'pidfd_send_signal', + 'pkey_mprotect', + 'renameat2', + 'setns', + 'statx', + 'epoll_pwait2'] + +def dictify(f): + def wrap(*args, **kwargs): + return dict(f(*args, **kwargs)) + return functools.update_wrapper(wrap, f) + +@dictify +def parse_syscall_table(filename): + print(f'Reading {filename}…') + for line in open(filename): + items = line.split() + if len(items) >= 2: + yield items[0], int(items[1]) + +def parse_syscall_tables(filenames): + return {filename.split('-')[-1][:-4]: parse_syscall_table(filename) + for filename in filenames} + +DEF_TEMPLATE = ''' +#ifndef __IGNORE_{syscall} +# if defined(__aarch64__) +# define systemd_NR_{syscall} {nr_arm64} +# elif defined(__alpha__) +# define systemd_NR_{syscall} {nr_alpha} +# elif defined(__arc__) || defined(__tilegx__) +# define systemd_NR_{syscall} {nr_arc} +# elif defined(__arm__) +# define systemd_NR_{syscall} {nr_arm} +# elif defined(__i386__) +# define systemd_NR_{syscall} {nr_i386} +# elif defined(__ia64__) +# define systemd_NR_{syscall} {nr_ia64} +# elif defined(__m68k__) +# define systemd_NR_{syscall} {nr_m68k} +# elif defined(_MIPS_SIM) +# if _MIPS_SIM == _MIPS_SIM_ABI32 +# define systemd_NR_{syscall} {nr_mipso32} +# elif _MIPS_SIM == _MIPS_SIM_NABI32 +# define systemd_NR_{syscall} {nr_mips64n32} +# elif _MIPS_SIM == _MIPS_SIM_ABI64 +# define systemd_NR_{syscall} {nr_mips64} +# else +# error "Unknown MIPS ABI" +# endif +# elif defined(__powerpc__) +# define systemd_NR_{syscall} {nr_powerpc} +# elif defined(__s390__) +# define systemd_NR_{syscall} {nr_s390} +# elif defined(__sparc__) +# define systemd_NR_{syscall} {nr_sparc} +# elif defined(__x86_64__) +# if defined(__ILP32__) +# define systemd_NR_{syscall} ({nr_x86_64} | /* __X32_SYSCALL_BIT */ 0x40000000) +# else +# define systemd_NR_{syscall} {nr_x86_64} +# endif +# else +# warning "{syscall}() syscall number is unknown for your architecture" +# endif + +/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ +# if defined __NR_{syscall} && __NR_{syscall} >= 0 +# if defined systemd_NR_{syscall} +assert_cc(__NR_{syscall} == systemd_NR_{syscall}); +# endif +# else +# if defined __NR_{syscall} +# undef __NR_{syscall} +# endif +# if defined systemd_NR_{syscall} && systemd_NR_{syscall} >= 0 +# define __NR_{syscall} systemd_NR_{syscall} +# endif +# endif +#endif +''' + +def print_syscall_def(syscall, tables, out): + mappings = {f'nr_{arch}':t.get(syscall, -1) + for arch, t in tables.items()} + print(DEF_TEMPLATE.format(syscall=syscall, **mappings), + file=out, end='') + +def print_syscall_defs(syscalls, tables, out): + print('''\ +/* SPDX-License-Identifier: LGPL-2.1-or-later + * This file is generated. Do not edit! */ +''' , file=out, end='') + for syscall in syscalls: + print_syscall_def(syscall, tables, out) + +if __name__ == '__main__': + output_file = sys.argv[1] + arch_files = sys.argv[2:] + out = open(output_file, 'wt') + + tables = parse_syscall_tables(arch_files) + print_syscall_defs(SYSCALLS, tables, out) + + print(f'Wrote {output_file}') diff --git a/src/basic/mountpoint-util.c b/src/basic/mountpoint-util.c index a6602ad53..c8f6675eb 100644 --- a/src/basic/mountpoint-util.c +++ b/src/basic/mountpoint-util.c @@ -8,14 +8,17 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "label.h" #include "missing_stat.h" #include "missing_syscall.h" +#include "mkdir.h" #include "mountpoint-util.h" #include "parse-util.h" #include "path-util.h" #include "stat-util.h" #include "stdio-util.h" #include "strv.h" +#include "user-util.h" /* This is the original MAX_HANDLE_SZ definition from the kernel, when the API was introduced. We use that in place of * any more currently defined value to future-proof things: if the size is increased in the API headers, and our code @@ -111,7 +114,7 @@ static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *ret_mn xsprintf(path, "/proc/self/fdinfo/%i", subfd); } - r = read_full_file(path, &fdinfo, NULL); + r = read_full_virtual_file(path, &fdinfo, NULL); if (r == -ENOENT) /* The fdinfo directory is a relatively new addition */ return -EOPNOTSUPP; if (r < 0) @@ -145,7 +148,7 @@ static bool filename_possibly_with_slash_suffix(const char *s) { if (!slash) return filename_is_valid(s); - if (slash - s > FILENAME_MAX) /* We want to allocate on the stack below, hence do a size check first */ + if (slash - s > PATH_MAX) /* We want to allocate on the stack below, hence do a size check first */ return false; if (slash[strspn(slash, "/")] != 0) /* Check that the suffix consist only of one or more slashes */ @@ -509,3 +512,25 @@ int mount_propagation_flags_from_string(const char *name, unsigned long *ret) { return -EINVAL; return 0; } + +int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode) { + assert(st); + assert(dest); + + if (S_ISDIR(st->st_mode)) + return mkdir_label(dest, mode); + else + return mknod(dest, S_IFREG|(mode & ~0111), 0); +} + +int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode) { + struct stat st; + + assert(source); + assert(dest); + + if (stat(source, &st) < 0) + return -errno; + + return make_mount_point_inode_from_stat(&st, dest, mode); +} diff --git a/src/basic/mountpoint-util.h b/src/basic/mountpoint-util.h index aadb2123d..cebcec5e7 100644 --- a/src/basic/mountpoint-util.h +++ b/src/basic/mountpoint-util.h @@ -23,3 +23,7 @@ int dev_is_devtmpfs(void); const char *mount_propagation_flags_to_string(unsigned long flags); int mount_propagation_flags_from_string(const char *name, unsigned long *ret); + +/* Creates a mount point (not parents) based on the source path or stat - ie, a file or a directory */ +int make_mount_point_inode_from_stat(const struct stat *st, const char *dest, mode_t mode); +int make_mount_point_inode_from_path(const char *source, const char *dest, mode_t mode); diff --git a/src/basic/namespace-util.c b/src/basic/namespace-util.c index 833a18a20..a55b76df9 100644 --- a/src/basic/namespace-util.c +++ b/src/basic/namespace-util.c @@ -10,6 +10,7 @@ #include "namespace-util.h" #include "process-util.h" #include "stat-util.h" +#include "stdio-util.h" #include "user-util.h" int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd) { @@ -82,15 +83,14 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int * } int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd) { - if (userns_fd >= 0) { - /* Can't setns to your own userns, since then you could - * escalate from non-root to root in your own namespace, so - * check if namespaces equal before attempting to enter. */ - _cleanup_free_ char *userns_fd_path = NULL; - int r; - if (asprintf(&userns_fd_path, "/proc/self/fd/%d", userns_fd) < 0) - return -ENOMEM; + int r; + if (userns_fd >= 0) { + /* Can't setns to your own userns, since then you could escalate from non-root to root in + * your own namespace, so check if namespaces are equal before attempting to enter. */ + + char userns_fd_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + xsprintf(userns_fd_path, "/proc/self/fd/%d", userns_fd); r = files_same(userns_fd_path, "/proc/self/ns/user", 0); if (r < 0) return r; @@ -125,13 +125,13 @@ int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int return reset_uid_gid(); } -int fd_is_network_ns(int fd) { +int fd_is_ns(int fd, unsigned long nsflag) { struct statfs s; int r; - /* Checks whether the specified file descriptor refers to a network namespace. On old kernels there's no nice - * way to detect that, hence on those we'll return a recognizable error (EUCLEAN), so that callers can handle - * this somewhat nicely. + /* Checks whether the specified file descriptor refers to a namespace created by specifying nsflag in clone(). + * On old kernels there's no nice way to detect that, hence on those we'll return a recognizable error (EUCLEAN), + * so that callers can handle this somewhat nicely. * * This function returns > 0 if the fd definitely refers to a network namespace, 0 if it definitely does not * refer to a network namespace, -EUCLEAN if we can't determine, and other negative error codes on error. */ @@ -168,7 +168,7 @@ int fd_is_network_ns(int fd) { return -errno; } - return r == CLONE_NEWNET; + return (unsigned long) r == nsflag; } int detach_mount_namespace(void) { diff --git a/src/basic/namespace-util.h b/src/basic/namespace-util.h index 7f7d06687..daa9accda 100644 --- a/src/basic/namespace-util.h +++ b/src/basic/namespace-util.h @@ -6,6 +6,6 @@ int namespace_open(pid_t pid, int *pidns_fd, int *mntns_fd, int *netns_fd, int *userns_fd, int *root_fd); int namespace_enter(int pidns_fd, int mntns_fd, int netns_fd, int userns_fd, int root_fd); -int fd_is_network_ns(int fd); +int fd_is_ns(int fd, unsigned long nsflag); int detach_mount_namespace(void); diff --git a/src/shared/os-util.c b/src/basic/os-util.c similarity index 52% rename from src/shared/os-util.c rename to src/basic/os-util.c index 3b7e49584..51c685bc6 100644 --- a/src/shared/os-util.c +++ b/src/basic/os-util.c @@ -2,15 +2,35 @@ #include "alloc-util.h" #include "env-file.h" +#include "env-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" #include "macro.h" #include "os-util.h" +#include "path-util.h" #include "string-util.h" #include "strv.h" +#include "utf8.h" -int path_is_os_tree(const char *path) { +bool image_name_is_valid(const char *s) { + if (!filename_is_valid(s)) + return false; + + if (string_has_cc(s, NULL)) + return false; + + if (!utf8_is_valid(s)) + return false; + + /* Temporary files for atomically creating new files */ + if (startswith(s, ".#")) + return false; + + return true; +} + +int path_is_extension_tree(const char *path, const char *extension) { int r; assert(path); @@ -21,8 +41,9 @@ int path_is_os_tree(const char *path) { if (laccess(path, F_OK) < 0) return -errno; - /* We use {/etc|/usr/lib}/os-release as flag file if something is an OS */ - r = open_os_release(path, NULL, NULL); + /* We use /usr/lib/extension-release.d/extension-release.NAME as flag file if something is a system extension, + * and {/etc|/usr/lib}/os-release as flag file if something is an OS (in case extension == NULL) */ + r = open_extension_release(path, extension, NULL, NULL); if (r == -ENOENT) /* We got nothing */ return 0; if (r < 0) @@ -31,17 +52,31 @@ int path_is_os_tree(const char *path) { return 1; } -int open_os_release(const char *root, char **ret_path, int *ret_fd) { +int open_extension_release(const char *root, const char *extension, char **ret_path, int *ret_fd) { _cleanup_free_ char *q = NULL; - const char *p; int r, fd; - FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") { - r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, + if (extension) { + const char *extension_full_path; + + if (!image_name_is_valid(extension)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "The extension name %s is invalid.", extension); + + extension_full_path = strjoina("/usr/lib/extension-release.d/extension-release.", extension); + r = chase_symlinks(extension_full_path, root, CHASE_PREFIX_ROOT, ret_path ? &q : NULL, ret_fd ? &fd : NULL); - if (r != -ENOENT) - break; + } else { + const char *p; + + FOREACH_STRING(p, "/etc/os-release", "/usr/lib/os-release") { + r = chase_symlinks(p, root, CHASE_PREFIX_ROOT, + ret_path ? &q : NULL, + ret_fd ? &fd : NULL); + if (r != -ENOENT) + break; + } } if (r < 0) return r; @@ -64,16 +99,16 @@ int open_os_release(const char *root, char **ret_path, int *ret_fd) { return 0; } -int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) { +int fopen_extension_release(const char *root, const char *extension, char **ret_path, FILE **ret_file) { _cleanup_free_ char *p = NULL; _cleanup_close_ int fd = -1; FILE *f; int r; if (!ret_file) - return open_os_release(root, ret_path, NULL); + return open_extension_release(root, extension, ret_path, NULL); - r = open_os_release(root, ret_path ? &p : NULL, &fd); + r = open_extension_release(root, extension, ret_path ? &p : NULL, &fd); if (r < 0) return r; @@ -81,26 +116,42 @@ int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) { if (!f) return -errno; - *ret_file = f; - if (ret_path) *ret_path = TAKE_PTR(p); + *ret_file = f; return 0; } -int parse_os_release(const char *root, ...) { +static int parse_release_internal(const char *root, const char *extension, va_list ap) { _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *p = NULL; - va_list ap; int r; - r = fopen_os_release(root, &p, &f); + r = fopen_extension_release(root, extension, &p, &f); if (r < 0) return r; + return parse_env_filev(f, p, ap); +} + +int _parse_extension_release(const char *root, const char *extension, ...) { + va_list ap; + int r; + + va_start(ap, extension); + r = parse_release_internal(root, extension, ap); + va_end(ap); + + return r; +} + +int _parse_os_release(const char *root, ...) { + va_list ap; + int r; + va_start(ap, root); - r = parse_env_filev(f, p, ap); + r = parse_release_internal(root, NULL, ap); va_end(ap); return r; @@ -147,3 +198,15 @@ int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char return 0; } + +int load_extension_release_pairs(const char *root, const char *extension, char ***ret) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_free_ char *p = NULL; + int r; + + r = fopen_extension_release(root, extension, &p, &f); + if (r < 0) + return r; + + return load_env_file_pairs(f, p, ret); +} diff --git a/src/basic/os-util.h b/src/basic/os-util.h new file mode 100644 index 000000000..271b35fa4 --- /dev/null +++ b/src/basic/os-util.h @@ -0,0 +1,33 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +/* The *_extension_release flavours will look for /usr/lib/extension-release/extension-release.NAME + * in accordance with the OS extension specification, rather than for /usr/lib/ or /etc/os-release. */ + +bool image_name_is_valid(const char *s) _pure_; + +int path_is_extension_tree(const char *path, const char *extension); +static inline int path_is_os_tree(const char *path) { + return path_is_extension_tree(path, NULL); +} + +int open_extension_release(const char *root, const char *extension, char **ret_path, int *ret_fd); +static inline int open_os_release(const char *root, char **ret_path, int *ret_fd) { + return open_extension_release(root, NULL, ret_path, ret_fd); +} + +int fopen_extension_release(const char *root, const char *extension, char **ret_path, FILE **ret_file); +static inline int fopen_os_release(const char *root, char **ret_path, FILE **ret_file) { + return fopen_extension_release(root, NULL, ret_path, ret_file); +} + +int _parse_extension_release(const char *root, const char *extension, ...) _sentinel_; +int _parse_os_release(const char *root, ...) _sentinel_; +#define parse_extension_release(root, extension, ...) _parse_extension_release(root, extension, __VA_ARGS__, NULL) +#define parse_os_release(root, ...) _parse_os_release(root, __VA_ARGS__, NULL) + +int load_extension_release_pairs(const char *root, const char *extension, char ***ret); +int load_os_release_pairs(const char *root, char ***ret); +int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret); diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 5d4dafe3a..b79c885df 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -16,9 +16,6 @@ #include "missing_network.h" #include "parse-util.h" #include "process-util.h" -#if HAVE_SECCOMP -#include "seccomp-util.h" -#endif #include "stat-util.h" #include "string-util.h" #include "strv.h" @@ -317,46 +314,6 @@ int parse_errno(const char *t) { return e; } -#if HAVE_SECCOMP -int parse_syscall_and_errno(const char *in, char **name, int *error) { - _cleanup_free_ char *n = NULL; - char *p; - int e = -1; - - assert(in); - assert(name); - assert(error); - - /* - * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255". - * If errno is omitted, then error is set to -1. - * Empty syscall name is not allowed. - * Here, we do not check that the syscall name is valid or not. - */ - - p = strchr(in, ':'); - if (p) { - e = seccomp_parse_errno_or_action(p + 1); - if (e < 0) - return e; - - n = strndup(in, p - in); - } else - n = strdup(in); - - if (!n) - return -ENOMEM; - - if (isempty(n)) - return -EINVAL; - - *error = e; - *name = TAKE_PTR(n); - - return 0; -} -#endif - static const char *mangle_base(const char *s, unsigned *base) { const char *k; @@ -636,14 +593,13 @@ int safe_atod(const char *s, double *ret_d) { } int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { - size_t i; unsigned val = 0; const char *s; s = *p; /* accept any number of digits, strtoull is limited to 19 */ - for (i=0; i < digits; i++,s++) { + for (size_t i = 0; i < digits; i++,s++) { if (*s < '0' || *s > '9') { if (i == 0) return -EINVAL; @@ -671,87 +627,6 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { return 0; } -int parse_percent_unbounded(const char *p) { - const char *pc, *n; - int r, v; - - pc = endswith(p, "%"); - if (!pc) - return -EINVAL; - - n = strndupa(p, pc - p); - r = safe_atoi(n, &v); - if (r < 0) - return r; - if (v < 0) - return -ERANGE; - - return v; -} - -int parse_percent(const char *p) { - int v; - - v = parse_percent_unbounded(p); - if (v > 100) - return -ERANGE; - - return v; -} - -int parse_permille_unbounded(const char *p) { - const char *pc, *pm, *dot, *n; - int r, q, v; - - pm = endswith(p, "‰"); - if (pm) { - n = strndupa(p, pm - p); - r = safe_atoi(n, &v); - if (r < 0) - return r; - if (v < 0) - return -ERANGE; - } else { - pc = endswith(p, "%"); - if (!pc) - return -EINVAL; - - dot = memchr(p, '.', pc - p); - if (dot) { - if (dot + 2 != pc) - return -EINVAL; - if (dot[1] < '0' || dot[1] > '9') - return -EINVAL; - q = dot[1] - '0'; - n = strndupa(p, dot - p); - } else { - q = 0; - n = strndupa(p, pc - p); - } - r = safe_atoi(n, &v); - if (r < 0) - return r; - if (v < 0) - return -ERANGE; - if (v > (INT_MAX - q) / 10) - return -ERANGE; - - v = v * 10 + q; - } - - return v; -} - -int parse_permille(const char *p) { - int v; - - v = parse_permille_unbounded(p); - if (v > 1000) - return -ERANGE; - - return v; -} - int parse_nice(const char *p, int *ret) { int n, r; diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 81478ed05..908202daf 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -22,9 +22,6 @@ int parse_mtu(int family, const char *s, uint32_t *ret); int parse_size(const char *t, uint64_t base, uint64_t *size); int parse_range(const char *t, unsigned *lower, unsigned *upper); int parse_errno(const char *t); -#if HAVE_SECCOMP -int parse_syscall_and_errno(const char *in, char **name, int *error); -#endif #define SAFE_ATO_REFUSE_PLUS_MINUS (1U << 30) #define SAFE_ATO_REFUSE_LEADING_ZERO (1U << 29) @@ -130,12 +127,6 @@ int safe_atod(const char *s, double *ret_d); int parse_fractional_part_u(const char **s, size_t digits, unsigned *res); -int parse_percent_unbounded(const char *p); -int parse_percent(const char *p); - -int parse_permille_unbounded(const char *p); -int parse_permille(const char *p); - int parse_nice(const char *p, int *ret); int parse_ip_port(const char *s, uint16_t *ret); diff --git a/src/basic/path-util.c b/src/basic/path-util.c index 794599a17..50ba44492 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -585,22 +585,52 @@ char* path_join_internal(const char *first, ...) { return joined; } -int find_executable_full(const char *name, bool use_path_envvar, char **ret) { +static int check_x_access(const char *path, int *ret_fd) { + _cleanup_close_ int fd = -1; + int r; + + /* We need to use O_PATH because there may be executables for which we have only exec + * permissions, but not read (usually suid executables). */ + fd = open(path, O_PATH|O_CLOEXEC); + if (fd < 0) + return -errno; + + r = fd_verify_regular(fd); + if (r < 0) + return r; + + r = access_fd(fd, X_OK); + if (r < 0) + return r; + + if (ret_fd) + *ret_fd = TAKE_FD(fd); + + return 0; +} + +int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd) { int last_error, r; const char *p = NULL; assert(name); if (is_path(name)) { - if (access(name, X_OK) < 0) - return -errno; + _cleanup_close_ int fd = -1; - if (ret) { - r = path_make_absolute_cwd(name, ret); + r = check_x_access(name, ret_fd ? &fd : NULL); + if (r < 0) + return r; + + if (ret_filename) { + r = path_make_absolute_cwd(name, ret_filename); if (r < 0) return r; } + if (ret_fd) + *ret_fd = TAKE_FD(fd); + return 0; } @@ -613,8 +643,10 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) { last_error = -ENOENT; + /* Resolve a single-component name to a full path */ for (;;) { _cleanup_free_ char *j = NULL, *element = NULL; + _cleanup_close_ int fd = -1; r = extract_first_word(&p, &element, ":", EXTRACT_RELAX|EXTRACT_DONT_COALESCE_SEPARATORS); if (r < 0) @@ -629,30 +661,21 @@ int find_executable_full(const char *name, bool use_path_envvar, char **ret) { if (!j) return -ENOMEM; - if (access(j, X_OK) >= 0) { - _cleanup_free_ char *with_dash; - - with_dash = strjoin(j, "/"); - if (!with_dash) - return -ENOMEM; - - /* If this passes, it must be a directory, and so should be skipped. */ - if (access(with_dash, X_OK) >= 0) - continue; - - /* We can't just `continue` inverting this case, since we need to update last_error. */ - if (errno == ENOTDIR) { - /* Found it! */ - if (ret) - *ret = path_simplify(TAKE_PTR(j), false); - - return 0; - } + r = check_x_access(j, ret_fd ? &fd : NULL); + if (r < 0) { + /* PATH entries which we don't have access to are ignored, as per tradition. */ + if (r != -EACCES) + last_error = r; + continue; } - /* PATH entries which we don't have access to are ignored, as per tradition. */ - if (errno != EACCES) - last_error = -errno; + /* Found it! */ + if (ret_filename) + *ret_filename = path_simplify(TAKE_PTR(j), false); + if (ret_fd) + *ret_fd = TAKE_FD(fd); + + return 0; } return last_error; @@ -729,38 +752,6 @@ int fsck_exists(const char *fstype) { return executable_is_good(checker); } -int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg) { - char *p; - int r; - - /* - * This function is intended to be used in command line - * parsers, to handle paths that are passed in. It makes the - * path absolute, and reduces it to NULL if omitted or - * root (the latter optionally). - * - * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON - * SUCCESS! Hence, do not pass in uninitialized pointers. - */ - - if (isempty(path)) { - *arg = mfree(*arg); - return 0; - } - - r = path_make_absolute_cwd(path, &p); - if (r < 0) - return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); - - path_simplify(p, false); - if (suppress_root && empty_or_root(p)) - p = mfree(p); - - free_and_replace(*arg, p); - - return 0; -} - char* dirname_malloc(const char *path) { char *d, *dir, *dir2; @@ -800,6 +791,8 @@ const char *last_path_component(const char *path) { * Also, the empty string is mapped to itself. * * This is different than basename(), which returns "" when a trailing slash is present. + * + * This always succeeds (except if you pass NULL in which case it returns NULL, too). */ unsigned l, k; @@ -825,24 +818,35 @@ const char *last_path_component(const char *path) { int path_extract_filename(const char *p, char **ret) { _cleanup_free_ char *a = NULL; - const char *c, *e = NULL, *q; + const char *c; + size_t n; /* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes - * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. */ + * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing + * slashes. Returns: + * + * -EINVAL → if the passed in path is not a valid path + * -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir itself is specified + * -ENOMEM → no memory + * + * Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to indicate + * the referenced file must be a directory. + * + * This function guarantees to return a fully valid filename, i.e. one that passes + * filename_is_valid() – this means "." and ".." are not accepted. */ - if (!p) + if (!path_is_valid(p)) return -EINVAL; + /* Special case the root dir, because in that case we simply have no filename, but + * last_path_component() won't complain */ + if (path_equal(p, "/")) + return -EADDRNOTAVAIL; + c = last_path_component(p); + n = strcspn(c, "/"); - for (q = c; *q != 0; q++) - if (*q != '/') - e = q + 1; - - if (!e) /* no valid character? */ - return -EINVAL; - - a = strndup(c, e - c); + a = strndup(c, n); if (!a) return -ENOMEM; @@ -850,7 +854,48 @@ int path_extract_filename(const char *p, char **ret) { return -EINVAL; *ret = TAKE_PTR(a); + return c[n] == '/' ? O_DIRECTORY : 0; +} +int path_extract_directory(const char *p, char **ret) { + _cleanup_free_ char *a = NULL; + const char *c; + + /* The inverse of path_extract_filename(), i.e. returns the directory path prefix. Returns: + * + * -EINVAL → if the passed in path is not a valid path + * -EDESTADDRREQ → if no directory was specified in the passed in path, i.e. only a filename was passed + * -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e. the root dir itself was specified + * -ENOMEM → no memory (surprise!) + * + * This function guarantees to return a fully valid path, i.e. one that passes path_is_valid(). + */ + + if (!path_is_valid(p)) + return -EINVAL; + + /* Special case the root dir, because otherwise for an input of "///" last_path_component() returns + * the pointer to the last slash only, which might be seen as a valid path below. */ + if (path_equal(p, "/")) + return -EADDRNOTAVAIL; + + c = last_path_component(p); + + /* Delete trailing slashes, but keep one */ + while (c > p+1 && c[-1] == '/') + c--; + + if (p == c) /* No path whatsoever? Then return a recognizable error */ + return -EDESTADDRREQ; + + a = strndup(p, c - p); + if (!a) + return -ENOMEM; + + if (!path_is_valid(a)) + return -EINVAL; + + *ret = TAKE_PTR(a); return 0; } @@ -867,7 +912,7 @@ bool filename_is_valid(const char *p) { if (*e != 0) return false; - if (e - p > FILENAME_MAX) /* FILENAME_MAX is counted *without* the trailing NUL byte */ + if (e - p > NAME_MAX) /* NAME_MAX is counted *without* the trailing NUL byte */ return false; return true; @@ -878,10 +923,25 @@ bool path_is_valid(const char *p) { if (isempty(p)) return false; - if (strlen(p) >= PATH_MAX) /* PATH_MAX is counted *with* the trailing NUL byte */ - return false; + for (const char *e = p;;) { + size_t n; - return true; + /* Skip over slashes */ + e += strspn(e, "/"); + if (e - p >= PATH_MAX) /* Already reached the maximum length for a path? (PATH_MAX is counted + * *with* the trailing NUL byte) */ + return false; + if (*e == 0) /* End of string? Yay! */ + return true; + + /* Skip over one component */ + n = strcspn(e, "/"); + if (n > NAME_MAX) /* One component larger than NAME_MAX? (NAME_MAX is counted *without* the + * trailing NUL byte) */ + return false; + + e += n; + } } bool path_is_normalized(const char *p) { diff --git a/src/basic/path-util.h b/src/basic/path-util.h index d613709f0..74ee6362e 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -88,9 +88,9 @@ int path_strv_make_absolute_cwd(char **l); char** path_strv_resolve(char **l, const char *root); char** path_strv_resolve_uniq(char **l, const char *root); -int find_executable_full(const char *name, bool use_path_envvar, char **ret); -static inline int find_executable(const char *name, char **ret) { - return find_executable_full(name, true, ret); +int find_executable_full(const char *name, bool use_path_envvar, char **ret_filename, int *ret_fd); +static inline int find_executable(const char *name, char **ret_filename) { + return find_executable_full(name, true, ret_filename, NULL); } bool paths_check_timestamp(const char* const* paths, usec_t *paths_ts_usec, bool update); @@ -144,11 +144,10 @@ int fsck_exists(const char *fstype); _ret; \ }) -int parse_path_argument_and_warn(const char *path, bool suppress_root, char **arg); - char* dirname_malloc(const char *path); const char *last_path_component(const char *path); int path_extract_filename(const char *p, char **ret); +int path_extract_directory(const char *p, char **ret); bool filename_is_valid(const char *p) _pure_; bool path_is_valid(const char *p) _pure_; diff --git a/src/basic/percent-util.c b/src/basic/percent-util.c new file mode 100644 index 000000000..06f20fd61 --- /dev/null +++ b/src/basic/percent-util.c @@ -0,0 +1,157 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "percent-util.h" +#include "string-util.h" +#include "parse-util.h" + +static int parse_parts_value_whole(const char *p, const char *symbol) { + const char *pc, *n; + int r, v; + + pc = endswith(p, symbol); + if (!pc) + return -EINVAL; + + n = strndupa(p, pc - p); + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v < 0) + return -ERANGE; + + return v; +} + +static int parse_parts_value_with_tenths_place(const char *p, const char *symbol) { + const char *pc, *dot, *n; + int r, q, v; + + pc = endswith(p, symbol); + if (!pc) + return -EINVAL; + + dot = memchr(p, '.', pc - p); + if (dot) { + if (dot + 2 != pc) + return -EINVAL; + if (dot[1] < '0' || dot[1] > '9') + return -EINVAL; + q = dot[1] - '0'; + n = strndupa(p, dot - p); + } else { + q = 0; + n = strndupa(p, pc - p); + } + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v < 0) + return -ERANGE; + if (v > (INT_MAX - q) / 10) + return -ERANGE; + + v = v * 10 + q; + return v; +} + +static int parse_parts_value_with_hundredths_place(const char *p, const char *symbol) { + const char *pc, *dot, *n; + int r, q, v; + + pc = endswith(p, symbol); + if (!pc) + return -EINVAL; + + dot = memchr(p, '.', pc - p); + if (dot) { + if (dot + 3 == pc) { + /* Support two places after the dot */ + + if (dot[1] < '0' || dot[1] > '9' || dot[2] < '0' || dot[2] > '9') + return -EINVAL; + q = (dot[1] - '0') * 10 + (dot[2] - '0'); + + } else if (dot + 2 == pc) { + /* Support one place after the dot */ + + if (dot[1] < '0' || dot[1] > '9') + return -EINVAL; + q = (dot[1] - '0') * 10; + } else + /* We do not support zero or more than two places */ + return -EINVAL; + + n = strndupa(p, dot - p); + } else { + q = 0; + n = strndupa(p, pc - p); + } + r = safe_atoi(n, &v); + if (r < 0) + return r; + if (v < 0) + return -ERANGE; + if (v > (INT_MAX - q) / 100) + return -ERANGE; + + v = v * 100 + q; + return v; +} + +int parse_percent_unbounded(const char *p) { + return parse_parts_value_whole(p, "%"); +} + +int parse_percent(const char *p) { + int v; + + v = parse_percent_unbounded(p); + if (v > 100) + return -ERANGE; + + return v; +} + +int parse_permille_unbounded(const char *p) { + const char *pm; + + pm = endswith(p, "‰"); + if (pm) + return parse_parts_value_whole(p, "‰"); + + return parse_parts_value_with_tenths_place(p, "%"); +} + +int parse_permille(const char *p) { + int v; + + v = parse_permille_unbounded(p); + if (v > 1000) + return -ERANGE; + + return v; +} + +int parse_permyriad_unbounded(const char *p) { + const char *pm; + + pm = endswith(p, "‱"); + if (pm) + return parse_parts_value_whole(p, "‱"); + + pm = endswith(p, "‰"); + if (pm) + return parse_parts_value_with_tenths_place(p, "‰"); + + return parse_parts_value_with_hundredths_place(p, "%"); +} + +int parse_permyriad(const char *p) { + int v; + + v = parse_permyriad_unbounded(p); + if (v > 10000) + return -ERANGE; + + return v; +} diff --git a/src/basic/percent-util.h b/src/basic/percent-util.h new file mode 100644 index 000000000..24f4c3bde --- /dev/null +++ b/src/basic/percent-util.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +#include "macro.h" + +int parse_percent_unbounded(const char *p); +int parse_percent(const char *p); + +int parse_permille_unbounded(const char *p); +int parse_permille(const char *p); + +int parse_permyriad_unbounded(const char *p); +int parse_permyriad(const char *p); + +/* Some macro-like helpers that convert a percent/permille/permyriad value (as parsed by parse_percent()) to + * a value relative to 100% == 2^32-1. Rounds to closest. */ +static inline uint32_t UINT32_SCALE_FROM_PERCENT(int percent) { + assert_cc(INT_MAX <= UINT32_MAX); + return (uint32_t) (((uint64_t) percent * UINT32_MAX + 50) / 100U); +} + +static inline uint32_t UINT32_SCALE_FROM_PERMILLE(int permille) { + return (uint32_t) (((uint64_t) permille * UINT32_MAX + 500) / 1000U); +} + +static inline uint32_t UINT32_SCALE_FROM_PERMYRIAD(int permyriad) { + return (uint32_t) (((uint64_t) permyriad * UINT32_MAX + 5000) / 10000U); +} + +static inline int UINT32_SCALE_TO_PERCENT(uint32_t scale) { + uint32_t u; + + u = (uint32_t) ((((uint64_t) scale) * 100U + UINT32_MAX/2) / UINT32_MAX); + if (u > INT_MAX) + return -ERANGE; + + return (int) u; +} + +static inline int UINT32_SCALE_TO_PERMILLE(uint32_t scale) { + uint32_t u; + + u = (uint32_t) ((((uint64_t) scale) * 1000U + UINT32_MAX/2) / UINT32_MAX); + if (u > INT_MAX) + return -ERANGE; + + return (int) u; +} + +static inline int UINT32_SCALE_TO_PERMYRIAD(uint32_t scale) { + uint32_t u; + + u = (uint32_t) ((((uint64_t) scale) * 10000U + UINT32_MAX/2) / UINT32_MAX); + if (u > INT_MAX) + return -ERANGE; + + return (int) u; +} + +#define PERMYRIAD_AS_PERCENT_FORMAT_STR "%i.%02i%%" +#define PERMYRIAD_AS_PERCENT_FORMAT_VAL(x) ((x)/100), ((x)%100) diff --git a/src/basic/prioq.h b/src/basic/prioq.h index 951576c02..7c7664761 100644 --- a/src/basic/prioq.h +++ b/src/basic/prioq.h @@ -8,7 +8,7 @@ typedef struct Prioq Prioq; -#define PRIOQ_IDX_NULL ((unsigned) -1) +#define PRIOQ_IDX_NULL (UINT_MAX) Prioq *prioq_new(compare_func_t compare); Prioq *prioq_free(Prioq *q); diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 0851613fc..7d4301ead 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -124,14 +124,10 @@ int get_process_comm(pid_t pid, char **ret) { } int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags, char **line) { - _cleanup_fclose_ FILE *f = NULL; _cleanup_free_ char *t = NULL, *ans = NULL; const char *p; - int r; size_t k; - - /* This is supposed to be a safety guard against runaway command lines. */ - size_t max_length = sc_arg_max(); + int r; assert(line); assert(pid >= 0); @@ -147,36 +143,18 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags * comm_fallback is false). Returns 0 and sets *line otherwise. */ p = procfs_file_alloca(pid, "cmdline"); - r = fopen_unlocked(p, "re", &f); + r = read_full_virtual_file(p, &t, &k); if (r == -ENOENT) return -ESRCH; if (r < 0) return r; - /* We assume that each four-byte character uses one or two columns. If we ever check for combining - * characters, this assumption will need to be adjusted. */ - if ((size_t) 4 * max_columns + 1 < max_columns) - max_length = MIN(max_length, (size_t) 4 * max_columns + 1); - - t = new(char, max_length); - if (!t) - return -ENOMEM; - - k = fread(t, 1, max_length, f); if (k > 0) { /* Arguments are separated by NULs. Let's replace those with spaces. */ for (size_t i = 0; i < k - 1; i++) if (t[i] == '\0') t[i] = ' '; - - t[k] = '\0'; /* Normally, t[k] is already NUL, so this is just a guard in case of short read */ } else { - /* We only treat getting nothing as an error. We *could* also get an error after reading some - * data, but we ignore that case, as such an error is rather unlikely and we prefer to get - * some data rather than none. */ - if (ferror(f)) - return -errno; - if (!(flags & PROCESS_CMDLINE_COMM_FALLBACK)) return -ENOENT; @@ -187,7 +165,7 @@ int get_process_cmdline(pid_t pid, size_t max_columns, ProcessCmdlineFlags flags if (r < 0) return r; - mfree(t); + free(t); t = strjoin("[", t2, "]"); if (!t) return -ENOMEM; @@ -756,7 +734,7 @@ int wait_for_terminate_with_timeout(pid_t pid, usec_t timeout) { /* Drop into a sigtimewait-based timeout. Waiting for the * pid to exit. */ - until = now(CLOCK_MONOTONIC) + timeout; + until = usec_add(now(CLOCK_MONOTONIC), timeout); for (;;) { usec_t n; siginfo_t status = {}; @@ -1230,6 +1208,11 @@ int safe_fork_full( original_pid = getpid_cached(); + if (flags & FORK_FLUSH_STDIO) { + fflush(stdout); + fflush(stderr); /* This one shouldn't be necessary, stderr should be unbuffered anyway, but let's better be safe than sorry */ + } + if (flags & (FORK_RESET_SIGNALS|FORK_DEATHSIG)) { /* We temporarily block all signals, so that the new child has them blocked initially. This way, we can * be sure that SIGTERMs are not lost we might send to the child. */ @@ -1462,7 +1445,11 @@ int fork_agent(const char *name, const int except[], size_t n_except, pid_t *ret /* Spawns a temporary TTY agent, making sure it goes away when we go away */ - r = safe_fork_full(name, except, n_except, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS, ret_pid); + r = safe_fork_full(name, + except, + n_except, + FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG, + ret_pid); if (r < 0) return r; if (r > 0) @@ -1543,7 +1530,7 @@ int pidfd_get_pid(int fd, pid_t *ret) { xsprintf(path, "/proc/self/fdinfo/%i", fd); - r = read_full_file(path, &fdinfo, NULL); + r = read_full_virtual_file(path, &fdinfo, NULL); if (r == -ENOENT) /* if fdinfo doesn't exist we assume the process does not exist */ return -ESRCH; if (r < 0) @@ -1620,6 +1607,16 @@ int setpriority_closest(int priority) { return 0; } +bool invoked_as(char *argv[], const char *token) { + if (!argv || isempty(argv[0])) + return false; + + if (isempty(token)) + return false; + + return strstr(last_path_component(argv[0]), token); +} + static const char *const ioprio_class_table[] = { [IOPRIO_CLASS_NONE] = "none", [IOPRIO_CLASS_RT] = "realtime", diff --git a/src/basic/process-util.h b/src/basic/process-util.h index 6144f142c..ddce7bd27 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -162,6 +162,7 @@ typedef enum ForkFlags { FORK_MOUNTNS_SLAVE = 1 << 9, /* Make child's mount namespace MS_SLAVE */ FORK_RLIMIT_NOFILE_SAFE = 1 << 10, /* Set RLIMIT_NOFILE soft limit to 1K for select() compat */ FORK_STDOUT_TO_STDERR = 1 << 11, /* Make stdout a copy of stderr */ + FORK_FLUSH_STDIO = 1 << 12, /* fflush() stdout (and stderr) before forking */ } ForkFlags; int safe_fork_full(const char *name, const int except_fds[], size_t n_except_fds, ForkFlags flags, pid_t *ret_pid); @@ -199,3 +200,5 @@ assert_cc(TASKS_MAX <= (unsigned long) PID_T_MAX); int pidfd_get_pid(int fd, pid_t *ret); int setpriority_closest(int priority); + +bool invoked_as(char *argv[], const char *token); diff --git a/src/basic/random-util.c b/src/basic/random-util.c index c8c34a203..a125e5228 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -452,10 +452,21 @@ size_t random_pool_size(void) { } int random_write_entropy(int fd, const void *seed, size_t size, bool credit) { + _cleanup_close_ int opened_fd = -1; int r; - assert(fd >= 0); - assert(seed && size > 0); + assert(seed || size == 0); + + if (size == 0) + return 0; + + if (fd < 0) { + opened_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY); + if (opened_fd < 0) + return -errno; + + fd = opened_fd; + } if (credit) { _cleanup_free_ struct rand_pool_info *info = NULL; @@ -481,5 +492,24 @@ int random_write_entropy(int fd, const void *seed, size_t size, bool credit) { return r; } - return 0; + return 1; +} + +uint64_t random_u64_range(uint64_t m) { + uint64_t x, remainder; + + /* Generates a random number in the range 0…m-1, unbiased. (Java's algorithm) */ + + if (m == 0) /* Let's take m == 0 as special case to return an integer from the full range */ + return random_u64(); + if (m == 1) + return 0; + + remainder = UINT64_MAX % m; + + do { + x = random_u64(); + } while (x >= UINT64_MAX - remainder); + + return x % m; } diff --git a/src/basic/random-util.h b/src/basic/random-util.h index f661fc093..e6528ddc7 100644 --- a/src/basic/random-util.h +++ b/src/basic/random-util.h @@ -40,3 +40,5 @@ int rdrand(unsigned long *ret); size_t random_pool_size(void); int random_write_entropy(int fd, const void *seed, size_t size, bool credit); + +uint64_t random_u64_range(uint64_t max); diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index bae2ec3ff..005bf31dc 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -19,7 +19,7 @@ bool ratelimit_below(RateLimit *r) { ts = now(CLOCK_MONOTONIC); if (r->begin <= 0 || - ts - r->begin > r->interval) { + usec_sub_unsigned(ts, r->begin) > r->interval) { r->begin = ts; /* Reset counter */ diff --git a/src/home/modhex.c b/src/basic/recovery-key.c similarity index 51% rename from src/home/modhex.c rename to src/basic/recovery-key.c index ae5f89572..a3c4500df 100644 --- a/src/home/modhex.c +++ b/src/basic/recovery-key.c @@ -1,10 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - -#include "modhex.h" -#include "macro.h" #include "memory-util.h" +#include "random-util.h" +#include "recovery-key.h" const char modhex_alphabet[16] = { 'c', 'b', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'n', 'r', 't', 'u', 'v' @@ -29,24 +27,24 @@ int normalize_recovery_key(const char *password, char **ret) { l = strlen(password); if (!IN_SET(l, - MODHEX_RAW_LENGTH*2, /* syntax without dashes */ - MODHEX_FORMATTED_LENGTH-1)) /* syntax with dashes */ + RECOVERY_KEY_MODHEX_RAW_LENGTH*2, /* syntax without dashes */ + RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1)) /* syntax with dashes */ return -EINVAL; - mangled = new(char, MODHEX_FORMATTED_LENGTH); + mangled = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH); if (!mangled) return -ENOMEM; - for (size_t i = 0, j = 0; i < MODHEX_RAW_LENGTH; i++) { + for (size_t i = 0, j = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) { size_t k; int a, b; - if (l == MODHEX_RAW_LENGTH*2) + if (l == RECOVERY_KEY_MODHEX_RAW_LENGTH*2) /* Syntax without dashes */ k = i * 2; else { /* Syntax with dashes */ - assert(l == MODHEX_FORMATTED_LENGTH-1); + assert(l == RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1); k = i * 2 + i / 4; if (i > 0 && i % 4 == 0 && password[k-1] != '-') @@ -67,8 +65,42 @@ int normalize_recovery_key(const char *password, char **ret) { mangled[j++] = '-'; } - mangled[MODHEX_FORMATTED_LENGTH-1] = 0; + mangled[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; *ret = TAKE_PTR(mangled); return 0; } + +int make_recovery_key(char **ret) { + _cleanup_(erase_and_freep) char *formatted = NULL; + _cleanup_(erase_and_freep) uint8_t *key = NULL; + int r; + + assert(ret); + + key = new(uint8_t, RECOVERY_KEY_MODHEX_RAW_LENGTH); + if (!key) + return -ENOMEM; + + r = genuine_random_bytes(key, RECOVERY_KEY_MODHEX_RAW_LENGTH, RANDOM_BLOCK); + if (r < 0) + return r; + + /* Let's now format it as 64 modhex chars, and after each 8 chars insert a dash */ + formatted = new(char, RECOVERY_KEY_MODHEX_FORMATTED_LENGTH); + if (!formatted) + return -ENOMEM; + + for (size_t i = 0, j = 0; i < RECOVERY_KEY_MODHEX_RAW_LENGTH; i++) { + formatted[j++] = modhex_alphabet[key[i] >> 4]; + formatted[j++] = modhex_alphabet[key[i] & 0xF]; + + if (i % 4 == 3) + formatted[j++] = '-'; + } + + formatted[RECOVERY_KEY_MODHEX_FORMATTED_LENGTH-1] = 0; + + *ret = TAKE_PTR(formatted); + return 0; +} diff --git a/src/home/modhex.h b/src/basic/recovery-key.h similarity index 68% rename from src/home/modhex.h rename to src/basic/recovery-key.h index 7776ed0ee..68e8051a9 100644 --- a/src/home/modhex.h +++ b/src/basic/recovery-key.h @@ -2,10 +2,12 @@ #pragma once /* 256 bit keys = 32 bytes */ -#define MODHEX_RAW_LENGTH 32 +#define RECOVERY_KEY_MODHEX_RAW_LENGTH 32 /* Formatted as sequences of 64 modhex characters, with dashes inserted after multiples of 8 chars (incl. trailing NUL) */ -#define MODHEX_FORMATTED_LENGTH (MODHEX_RAW_LENGTH*2/8*9) +#define RECOVERY_KEY_MODHEX_FORMATTED_LENGTH (RECOVERY_KEY_MODHEX_RAW_LENGTH*2/8*9) + +int make_recovery_key(char **ret); extern const char modhex_alphabet[16]; diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 880976312..23d108d5d 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -43,6 +43,8 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) { fixed.rlim_max == highest.rlim_max) return 0; + log_debug("Failed at setting rlimit " RLIM_FMT " for resource RLIMIT_%s. Will attempt setting value " RLIM_FMT " instead.", rlim->rlim_max, rlimit_to_string(resource), fixed.rlim_max); + if (setrlimit(resource, &fixed) < 0) return -errno; @@ -50,13 +52,13 @@ int setrlimit_closest(int resource, const struct rlimit *rlim) { } int setrlimit_closest_all(const struct rlimit *const *rlim, int *which_failed) { - int i, r; + int r; assert(rlim); /* On failure returns the limit's index that failed in *which_failed, but only if non-NULL */ - for (i = 0; i < _RLIMIT_MAX; i++) { + for (int i = 0; i < _RLIMIT_MAX; i++) { if (!rlim[i]) continue; diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index b0d682f76..2f2ebc39e 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -23,23 +23,14 @@ static bool is_physical_fs(const struct statfs *sfs) { return !is_temporary_fs(sfs) && !is_cgroup_fs(sfs); } -static int unlinkat_harder( +static int patch_dirfd_mode( int dfd, - const char *filename, - int unlink_flags, - RemoveFlags remove_flags) { + mode_t *ret_old_mode) { struct stat st; - int r; - /* Like unlinkat(), but tries harder: if we get EACCESS we'll try to set the r/w/x bits on the - * directory. This is useful if we run unprivileged and have some files where the w bit is - * missing. */ - - if (unlinkat(dfd, filename, unlink_flags) >= 0) - return 0; - if (errno != EACCES || !FLAGS_SET(remove_flags, REMOVE_CHMOD)) - return -errno; + assert(dfd >= 0); + assert(ret_old_mode); if (fstat(dfd, &st) < 0) return -errno; @@ -53,10 +44,68 @@ static int unlinkat_harder( if (fchmod(dfd, (st.st_mode | 0700) & 07777) < 0) return -errno; + *ret_old_mode = st.st_mode; + return 0; +} + +static int unlinkat_harder( + int dfd, + const char *filename, + int unlink_flags, + RemoveFlags remove_flags) { + + mode_t old_mode; + int r; + + /* Like unlinkat(), but tries harder: if we get EACCESS we'll try to set the r/w/x bits on the + * directory. This is useful if we run unprivileged and have some files where the w bit is + * missing. */ + + if (unlinkat(dfd, filename, unlink_flags) >= 0) + return 0; + if (errno != EACCES || !FLAGS_SET(remove_flags, REMOVE_CHMOD)) + return -errno; + + r = patch_dirfd_mode(dfd, &old_mode); + if (r < 0) + return r; + if (unlinkat(dfd, filename, unlink_flags) < 0) { r = -errno; /* Try to restore the original access mode if this didn't work */ - (void) fchmod(dfd, st.st_mode & 07777); + (void) fchmod(dfd, old_mode); + return r; + } + + /* If this worked, we won't reset the old mode, since we'll need it for other entries too, and we + * should destroy the whole thing */ + return 0; +} + +static int fstatat_harder( + int dfd, + const char *filename, + struct stat *ret, + int fstatat_flags, + RemoveFlags remove_flags) { + + mode_t old_mode; + int r; + + /* Like unlink_harder() but does the same for fstatat() */ + + if (fstatat(dfd, filename, ret, fstatat_flags) >= 0) + return 0; + if (errno != EACCES || !FLAGS_SET(remove_flags, REMOVE_CHMOD)) + return -errno; + + r = patch_dirfd_mode(dfd, &old_mode); + if (r < 0) + return r; + + if (fstatat(dfd, filename, ret, fstatat_flags) < 0) { + r = -errno; + (void) fchmod(dfd, old_mode); return r; } @@ -112,9 +161,10 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { if (de->d_type == DT_UNKNOWN || (de->d_type == DT_DIR && (root_dev || (flags & REMOVE_SUBVOLUME)))) { - if (fstatat(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) { - if (ret == 0 && errno != ENOENT) - ret = -errno; + r = fstatat_harder(fd, de->d_name, &st, AT_SYMLINK_NOFOLLOW, flags); + if (r < 0) { + if (ret == 0 && r != -ENOENT) + ret = r; continue; } @@ -147,7 +197,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) { if (r > 0) continue; - if ((flags & REMOVE_SUBVOLUME) && st.st_ino == 256) { + if ((flags & REMOVE_SUBVOLUME) && btrfs_might_be_subvol(&st)) { /* This could be a subvolume, try to remove it */ diff --git a/src/basic/rm-rf.h b/src/basic/rm-rf.h index ec56232b5..87be9b341 100644 --- a/src/basic/rm-rf.h +++ b/src/basic/rm-rf.h @@ -3,6 +3,7 @@ #include +#include "alloc-util.h" #include "errno-util.h" typedef enum RemoveFlags { @@ -18,17 +19,25 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev); int rm_rf(const char *path, RemoveFlags flags); /* Useful for usage with _cleanup_(), destroys a directory and frees the pointer */ -static inline void rm_rf_physical_and_free(char *p) { +static inline char *rm_rf_physical_and_free(char *p) { PROTECT_ERRNO; - (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL); - free(p); + + if (!p) + return NULL; + + (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_MISSING_OK|REMOVE_CHMOD); + return mfree(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_physical_and_free); /* Similar as above, but also has magic btrfs subvolume powers */ -static inline void rm_rf_subvolume_and_free(char *p) { +static inline char *rm_rf_subvolume_and_free(char *p) { PROTECT_ERRNO; - (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - free(p); + + if (!p) + return NULL; + + (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME|REMOVE_MISSING_OK|REMOVE_CHMOD); + return mfree(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, rm_rf_subvolume_and_free); diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index 4989f4f37..ee9e34ed4 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -29,7 +29,7 @@ #include "time-util.h" #if HAVE_SELINUX -DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(context_t, context_free, NULL); #define _cleanup_context_free_ _cleanup_(context_freep) static int mac_selinux_reload(int seqno); @@ -50,7 +50,7 @@ static struct selabel_handle *label_hnd = NULL; int _e = (error); \ \ int _r = (log_get_max_level() >= LOG_PRI(_level)) \ - ? log_internal_realm(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ + ? log_internal(_level, _e, PROJECT_FILE, __LINE__, __func__, __VA_ARGS__) \ : -ERRNO_VALUE(_e); \ _enforcing ? _r : 0; \ }) @@ -272,6 +272,8 @@ int mac_selinux_fix_container_fd(int fd, const char *path, const char *inside_pa /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ mac_selinux_maybe_reload(); + if (!label_hnd) + return 0; if (selabel_lookup_raw(label_hnd, &fcon, inside_path, st.st_mode) < 0) { /* If there's no label to set, then exit without warning */ @@ -484,6 +486,8 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ mac_selinux_maybe_reload(); + if (!label_hnd) + return 0; r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode); if (r < 0) { @@ -506,7 +510,6 @@ int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) _cleanup_free_ char *abspath = NULL; int r; - assert(path); if (!label_hnd) @@ -628,6 +631,8 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) { /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */ mac_selinux_maybe_reload(); + if (!label_hnd) + goto skipped; if (path_is_absolute(path)) r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK); diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index 1236d6efd..1095bdef0 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -11,7 +11,7 @@ #if HAVE_SELINUX #include -DEFINE_TRIVIAL_CLEANUP_FUNC(char*, freecon); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(char*, freecon, NULL); #define _cleanup_freecon_ _cleanup_(freeconp) #endif diff --git a/src/basic/set.h b/src/basic/set.h index 57ff71303..52b6f4984 100644 --- a/src/basic/set.h +++ b/src/basic/set.h @@ -152,3 +152,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); #define _cleanup_set_free_free_ _cleanup_(set_free_freep) int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret); + +bool set_equal(Set *a, Set *b); diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c index 4c2e9ec33..8ff060a8d 100644 --- a/src/basic/sigbus.c +++ b/src/basic/sigbus.c @@ -23,12 +23,10 @@ static void* volatile sigbus_queue[SIGBUS_QUEUE_MAX]; static volatile sig_atomic_t n_sigbus_queue = 0; static void sigbus_push(void *addr) { - unsigned u; - assert(addr); /* Find a free place, increase the number of entries and leave, if we can */ - for (u = 0; u < SIGBUS_QUEUE_MAX; u++) + for (size_t u = 0; u < SIGBUS_QUEUE_MAX; u++) if (__sync_bool_compare_and_swap(&sigbus_queue[u], NULL, addr)) { __sync_fetch_and_add(&n_sigbus_queue, 1); return; diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 63b833b21..131fd3ba0 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -15,9 +15,9 @@ int reset_all_signal_handlers(void) { .sa_handler = SIG_DFL, .sa_flags = SA_RESTART, }; - int sig, r = 0; + int r = 0; - for (sig = 1; sig < _NSIG; sig++) { + for (int sig = 1; sig < _NSIG; sig++) { /* These two cannot be caught... */ if (IN_SET(sig, SIGKILL, SIGSTOP)) @@ -45,11 +45,14 @@ int reset_signal_mask(void) { return 0; } -static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) { - int r = 0; +int sigaction_many_internal(const struct sigaction *sa, ...) { + int sig, r = 0; + va_list ap; + + va_start(ap, sa); /* negative signal ends the list. 0 signal is skipped. */ - for (; sig >= 0; sig = va_arg(ap, int)) { + while ((sig = va_arg(ap, int)) >= 0) { if (sig == 0) continue; @@ -60,49 +63,6 @@ static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) { } } - return r; -} - -int sigaction_many(const struct sigaction *sa, ...) { - va_list ap; - int r; - - va_start(ap, sa); - r = sigaction_many_ap(sa, 0, ap); - va_end(ap); - - return r; -} - -int ignore_signals(int sig, ...) { - - static const struct sigaction sa = { - .sa_handler = SIG_IGN, - .sa_flags = SA_RESTART, - }; - - va_list ap; - int r; - - va_start(ap, sig); - r = sigaction_many_ap(&sa, sig, ap); - va_end(ap); - - return r; -} - -int default_signals(int sig, ...) { - - static const struct sigaction sa = { - .sa_handler = SIG_DFL, - .sa_flags = SA_RESTART, - }; - - va_list ap; - int r; - - va_start(ap, sig); - r = sigaction_many_ap(&sa, sig, ap); va_end(ap); return r; @@ -198,7 +158,7 @@ static const char *const __signal_table[] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); const char *signal_to_string(int signo) { - static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1]; + static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)]; const char *name; name = __signal_to_string(signo); diff --git a/src/basic/signal-util.h b/src/basic/signal-util.h index bdd39d429..37271d7a6 100644 --- a/src/basic/signal-util.h +++ b/src/basic/signal-util.h @@ -8,9 +8,28 @@ int reset_all_signal_handlers(void); int reset_signal_mask(void); -int ignore_signals(int sig, ...); -int default_signals(int sig, ...); -int sigaction_many(const struct sigaction *sa, ...); +int sigaction_many_internal(const struct sigaction *sa, ...); + +#define ignore_signals(...) \ + sigaction_many_internal( \ + &(const struct sigaction) { \ + .sa_handler = SIG_IGN, \ + .sa_flags = SA_RESTART \ + }, \ + __VA_ARGS__, \ + -1) + +#define default_signals(...) \ + sigaction_many_internal( \ + &(const struct sigaction) { \ + .sa_handler = SIG_DFL, \ + .sa_flags = SA_RESTART \ + }, \ + __VA_ARGS__, \ + -1) + +#define sigaction_many(sa, ...) \ + sigaction_many_internal(sa, __VA_ARGS__, -1) int sigset_add_many(sigset_t *ss, ...); int sigprocmask_many(int how, sigset_t *old, ...); diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index d0b235242..36fdc7208 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -24,7 +24,7 @@ typedef enum SmackAttr { SMACK_ATTR_IPIN, SMACK_ATTR_IPOUT, _SMACK_ATTR_MAX, - _SMACK_ATTR_INVALID = -1, + _SMACK_ATTR_INVALID = -EINVAL, } SmackAttr; bool mac_smack_use(void); diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 48d0718d5..552ec053f 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -23,10 +23,7 @@ #include "format-util.h" #include "io-util.h" #include "log.h" -#include "macro.h" #include "memory-util.h" -#include "missing_socket.h" -#include "missing_network.h" #include "parse-util.h" #include "path-util.h" #include "process-util.h" @@ -34,6 +31,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "sysctl-util.h" #include "user-util.h" #include "utf8.h" @@ -280,10 +278,48 @@ const char* socket_address_get_path(const SocketAddress *a) { } bool socket_ipv6_is_supported(void) { - if (access("/proc/net/if_inet6", F_OK) != 0) + static int cached = -1; + + if (cached < 0) { + + if (access("/proc/net/if_inet6", F_OK) < 0) { + + if (errno != ENOENT) { + log_debug_errno(errno, "Unexpected error when checking whether /proc/net/if_inet6 exists: %m"); + return false; + } + + cached = false; + } else + cached = true; + } + + return cached; +} + +bool socket_ipv6_is_enabled(void) { + _cleanup_free_ char *v = NULL; + int r; + + /* Much like socket_ipv6_is_supported(), but also checks that the sysctl that disables IPv6 on all + * interfaces isn't turned on */ + + if (!socket_ipv6_is_supported()) return false; - return true; + r = sysctl_read_ip_property(AF_INET6, "all", "disable_ipv6", &v); + if (r < 0) { + log_debug_errno(r, "Unexpected error reading 'net.ipv6.conf.all.disable_ipv6' sysctl: %m"); + return true; + } + + r = parse_boolean(v); + if (r < 0) { + log_debug_errno(r, "Failed to pare 'net.ipv6.conf.all.disable_ipv6' sysctl: %m"); + return true; + } + + return !r; } bool socket_address_matches_fd(const SocketAddress *a, int fd) { @@ -320,7 +356,7 @@ bool socket_address_matches_fd(const SocketAddress *a, int fd) { } int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) { - union sockaddr_union *sa = (union sockaddr_union*) _sa; + const union sockaddr_union *sa = (const union sockaddr_union*) _sa; /* Note, this returns the port as 'unsigned' rather than 'uint16_t', as AF_VSOCK knows larger ports */ @@ -345,6 +381,25 @@ int sockaddr_port(const struct sockaddr *_sa, unsigned *ret_port) { } } +const union in_addr_union *sockaddr_in_addr(const struct sockaddr *_sa) { + const union sockaddr_union *sa = (const union sockaddr_union*) _sa; + + if (!sa) + return NULL; + + switch (sa->sa.sa_family) { + + case AF_INET: + return (const union in_addr_union*) &sa->in.sin_addr; + + case AF_INET6: + return (const union in_addr_union*) &sa->in6.sin6_addr; + + default: + return NULL; + } +} + int sockaddr_pretty( const struct sockaddr *_sa, socklen_t salen, @@ -705,6 +760,10 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) { if (isempty(p)) return false; + /* A valid ifindex? If so, it's valid iff IFNAME_VALID_NUMERIC is set */ + if (parse_ifindex(p) >= 0) + return flags & IFNAME_VALID_NUMERIC; + if (flags & IFNAME_VALID_ALTERNATIVE) { if (strlen(p) >= ALTIFNAMSIZ) return false; @@ -716,6 +775,11 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) { if (dot_or_dot_dot(p)) return false; + /* Let's refuse "all" and "default" as interface name, to avoid collisions with the special sysctl + * directories /proc/sys/net/{ipv4,ipv6}/conf/{all,default} */ + if (STR_IN_SET(p, "all", "default")) + return false; + for (const char *t = p; *t; t++) { if ((unsigned char) *t >= 127U) return false; @@ -723,20 +787,19 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) { if ((unsigned char) *t <= 32U) return false; - if (IN_SET(*t, ':', '/')) + if (IN_SET(*t, + ':', /* colons are used by the legacy "alias" interface logic */ + '/', /* slashes cannot work, since we need to use network interfaces in sysfs paths, and in paths slashes are separators */ + '%')) /* %d is used in the kernel's weird foo%d format string naming feature which we really really don't want to ever run into by accident */ return false; numeric = numeric && (*t >= '0' && *t <= '9'); } - if (numeric) { - if (!(flags & IFNAME_VALID_NUMERIC)) - return false; - - /* Verify that the number is well-formatted and in range. */ - if (parse_ifindex(p) < 0) - return false; - } + /* It's fully numeric but didn't parse as valid ifindex above? if so, it must be too large or zero or + * so, let's refuse that. */ + if (numeric) + return false; return true; } @@ -1248,72 +1311,6 @@ int socket_set_recvpktinfo(int fd, int af, bool b) { } } -int socket_set_recverr(int fd, int af, bool b) { - int r; - - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; - } - - switch (af) { - - case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_RECVERR, b); - - case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVERR, b); - - default: - return -EAFNOSUPPORT; - } -} - -int socket_set_recvttl(int fd, int af, bool b) { - int r; - - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; - } - - switch (af) { - - case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_RECVTTL, b); - - case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, b); - - default: - return -EAFNOSUPPORT; - } -} - -int socket_set_ttl(int fd, int af, int ttl) { - int r; - - if (af == AF_UNSPEC) { - r = socket_get_family(fd, &af); - if (r < 0) - return r; - } - - switch (af) { - - case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_TTL, ttl); - - case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, ttl); - - default: - return -EAFNOSUPPORT; - } -} - int socket_set_unicast_if(int fd, int af, int ifi) { be32_t ifindex_be = htobe32(ifi); int r; @@ -1343,7 +1340,7 @@ int socket_set_unicast_if(int fd, int af, int ifi) { } } -int socket_set_freebind(int fd, int af, bool b) { +int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val) { int r; if (af == AF_UNSPEC) { @@ -1355,18 +1352,18 @@ int socket_set_freebind(int fd, int af, bool b) { switch (af) { case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_FREEBIND, b); + return setsockopt_int(fd, IPPROTO_IP, opt_ipv4, val); case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_FREEBIND, b); + return setsockopt_int(fd, IPPROTO_IPV6, opt_ipv6, val); default: return -EAFNOSUPPORT; } } -int socket_set_transparent(int fd, int af, bool b) { - int r; +int socket_get_mtu(int fd, int af, size_t *ret) { + int mtu, r; if (af == AF_UNSPEC) { r = socket_get_family(fd, &af); @@ -1377,12 +1374,22 @@ int socket_set_transparent(int fd, int af, bool b) { switch (af) { case AF_INET: - return setsockopt_int(fd, IPPROTO_IP, IP_TRANSPARENT, b); + r = getsockopt_int(fd, IPPROTO_IP, IP_MTU, &mtu); + break; case AF_INET6: - return setsockopt_int(fd, IPPROTO_IPV6, IPV6_TRANSPARENT, b); + r = getsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, &mtu); + break; default: return -EAFNOSUPPORT; } + + if (r < 0) + return r; + if (mtu <= 0) + return -EINVAL; + + *ret = (size_t) mtu; + return 0; } diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 9f7928040..507a599d7 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -15,6 +15,7 @@ #include #include "macro.h" +#include "missing_network.h" #include "missing_socket.h" #include "sparse-endian.h" @@ -62,7 +63,7 @@ typedef enum SocketAddressBindIPv6Only { SOCKET_ADDRESS_BOTH, SOCKET_ADDRESS_IPV6_ONLY, _SOCKET_ADDRESS_BIND_IPV6_ONLY_MAX, - _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -1 + _SOCKET_ADDRESS_BIND_IPV6_ONLY_INVALID = -EINVAL, } SocketAddressBindIPv6Only; #define socket_address_family(a) ((a)->sockaddr.sa.sa_family) @@ -100,8 +101,10 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) _pure_ const char* socket_address_get_path(const SocketAddress *a); bool socket_ipv6_is_supported(void); +bool socket_ipv6_is_enabled(void); int sockaddr_port(const struct sockaddr *_sa, unsigned *port); +const union in_addr_union *sockaddr_in_addr(const struct sockaddr *sa); int sockaddr_pretty(const struct sockaddr *_sa, socklen_t salen, bool translate_ipv6, bool include_port, char **ret); int getpeername_pretty(int fd, bool include_port, char **ret); @@ -131,9 +134,9 @@ int ip_tos_to_string_alloc(int i, char **s); int ip_tos_from_string(const char *s); typedef enum { - IFNAME_VALID_ALTERNATIVE = 1 << 0, - IFNAME_VALID_NUMERIC = 1 << 1, - _IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC, + IFNAME_VALID_ALTERNATIVE = 1 << 0, + IFNAME_VALID_NUMERIC = 1 << 1, + _IFNAME_VALID_ALL = IFNAME_VALID_ALTERNATIVE | IFNAME_VALID_NUMERIC, } IfnameValidFlags; bool ifname_valid_full(const char *p, IfnameValidFlags flags); static inline bool ifname_valid(const char *p) { @@ -256,6 +259,19 @@ static inline int setsockopt_int(int fd, int level, int optname, int value) { return 0; } +static inline int getsockopt_int(int fd, int level, int optname, int *ret) { + int v; + socklen_t sl = sizeof(v); + + if (getsockopt(fd, level, optname, &v, &sl) < 0) + return -errno; + if (sl != sizeof(v)) + return -EIO; + + *ret = v; + return 0; +} + int socket_bind_to_ifname(int fd, const char *ifname); int socket_bind_to_ifindex(int fd, int ifindex); @@ -263,9 +279,26 @@ ssize_t recvmsg_safe(int sockfd, struct msghdr *msg, int flags); int socket_get_family(int fd, int *ret); int socket_set_recvpktinfo(int fd, int af, bool b); -int socket_set_recverr(int fd, int af, bool b); -int socket_set_recvttl(int fd, int af, bool b); -int socket_set_ttl(int fd, int af, int ttl); int socket_set_unicast_if(int fd, int af, int ifi); -int socket_set_freebind(int fd, int af, bool b); -int socket_set_transparent(int fd, int af, bool b); + +int socket_set_option(int fd, int af, int opt_ipv4, int opt_ipv6, int val); +static inline int socket_set_recverr(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVERR, IPV6_RECVERR, b); +} +static inline int socket_set_recvttl(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVTTL, IPV6_RECVHOPLIMIT, b); +} +static inline int socket_set_ttl(int fd, int af, int ttl) { + return socket_set_option(fd, af, IP_TTL, IPV6_UNICAST_HOPS, ttl); +} +static inline int socket_set_freebind(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_FREEBIND, IPV6_FREEBIND, b); +} +static inline int socket_set_transparent(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_TRANSPARENT, IPV6_TRANSPARENT, b); +} +static inline int socket_set_recvfragsize(int fd, int af, bool b) { + return socket_set_option(fd, af, IP_RECVFRAGSIZE, IPV6_RECVFRAGSIZE, b); +} + +int socket_get_mtu(int fd, int af, size_t *ret); diff --git a/src/basic/sort-util.c b/src/basic/sort-util.c index 92d7b8588..a9c68b7e3 100644 --- a/src/basic/sort-util.c +++ b/src/basic/sort-util.c @@ -27,3 +27,7 @@ void *xbsearch_r(const void *key, const void *base, size_t nmemb, size_t size, } return NULL; } + +int cmp_int(const int *a, const int *b) { + return CMP(*a, *b); +} diff --git a/src/basic/sort-util.h b/src/basic/sort-util.h index 1d194a1f0..49586a4a2 100644 --- a/src/basic/sort-util.h +++ b/src/basic/sort-util.h @@ -68,3 +68,5 @@ static inline void qsort_r_safe(void *base, size_t nmemb, size_t size, __compar_ int (*_func_)(const typeof(p[0])*, const typeof(p[0])*, typeof(userdata)) = func; \ qsort_r_safe((p), (n), sizeof((p)[0]), (__compar_d_fn_t) _func_, userdata); \ }) + +int cmp_int(const int *a, const int *b); diff --git a/src/basic/special.h b/src/basic/special.h index d55b3289d..b9b7be7a7 100644 --- a/src/basic/special.h +++ b/src/basic/special.h @@ -42,6 +42,7 @@ #define SPECIAL_SWAP_TARGET "swap.target" #define SPECIAL_NETWORK_ONLINE_TARGET "network-online.target" #define SPECIAL_TIME_SYNC_TARGET "time-sync.target" /* LSB's $time */ +#define SPECIAL_TIME_SET_TARGET "time-set.target" #define SPECIAL_BASIC_TARGET "basic.target" /* LSB compatibility */ diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index f99968163..72a7e4a48 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -72,12 +72,17 @@ int dir_is_empty_at(int dir_fd, const char *path) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; - if (path) + if (path) { fd = openat(dir_fd, path, O_RDONLY|O_DIRECTORY|O_CLOEXEC); - else - fd = fcntl(fd, F_DUPFD_CLOEXEC, 3); - if (fd < 0) - return -errno; + if (fd < 0) + return -errno; + } else { + /* Note that DUPing is not enough, as the internal pointer + * would still be shared and moved by FOREACH_DIRENT. */ + fd = fd_reopen(dir_fd, O_CLOEXEC); + if (fd < 0) + return fd; + } d = take_fdopendir(&fd); if (!d) diff --git a/src/basic/static-destruct.h b/src/basic/static-destruct.h index 0f961328e..7c5734d96 100644 --- a/src/basic/static-destruct.h +++ b/src/basic/static-destruct.h @@ -30,15 +30,16 @@ typedef struct StaticDestructor { _alignptr_ \ /* Make sure this is not dropped from the image because not explicitly referenced */ \ _used_ \ - /* Make sure that AddressSanitizer doesn't pad this variable: we want everything in this section packed next to each other so that we can enumerate it. */ \ + /* Make sure that AddressSanitizer doesn't pad this variable: we want everything in this section + * packed next to each other so that we can enumerate it. */ \ _variable_no_sanitize_address_ \ static const StaticDestructor UNIQ_T(static_destructor_entry, uq) = { \ .data = &(variable), \ .destroy = UNIQ_T(static_destructor_wrapper, uq), \ } -/* Beginning and end of our section listing the destructors. We define these as weak as we want this to work even if - * there's not a single destructor is defined in which case the section will be missing. */ +/* Beginning and end of our section listing the destructors. We define these as weak as we want this to work + * even if no destructors are defined and the section is missing. */ extern const struct StaticDestructor _weak_ __start_SYSTEMD_STATIC_DESTRUCT[]; extern const struct StaticDestructor _weak_ __stop_SYSTEMD_STATIC_DESTRUCT[]; diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index aee6647e3..212b561fa 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -26,7 +26,7 @@ * ... */ -struct strbuf *strbuf_new(void) { +struct strbuf* strbuf_new(void) { struct strbuf *str; str = new(struct strbuf, 1); @@ -65,13 +65,13 @@ void strbuf_complete(struct strbuf *str) { } /* clean up everything */ -void strbuf_cleanup(struct strbuf *str) { +struct strbuf* strbuf_free(struct strbuf *str) { if (!str) - return; + return NULL; strbuf_complete(str); free(str->buf); - free(str); + return mfree(str); } static int strbuf_children_cmp(const struct strbuf_child_entry *n1, diff --git a/src/basic/strbuf.h b/src/basic/strbuf.h index 82758d721..6187c0868 100644 --- a/src/basic/strbuf.h +++ b/src/basic/strbuf.h @@ -32,8 +32,8 @@ struct strbuf_child_entry { struct strbuf_node *child; }; -struct strbuf *strbuf_new(void); +struct strbuf* strbuf_new(void); ssize_t strbuf_add_string(struct strbuf *str, const char *s, size_t len); void strbuf_complete(struct strbuf *str); -void strbuf_cleanup(struct strbuf *str); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct strbuf*, strbuf_cleanup); +struct strbuf* strbuf_free(struct strbuf *str); +DEFINE_TRIVIAL_CLEANUP_FUNC(struct strbuf*, strbuf_free); diff --git a/src/basic/string-table.c b/src/basic/string-table.c index 116021df8..3a6376714 100644 --- a/src/basic/string-table.c +++ b/src/basic/string-table.c @@ -5,11 +5,11 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) { if (!key) - return -1; + return -EINVAL; for (size_t i = 0; i < len; ++i) if (streq_ptr(table[i], key)) return (ssize_t) i; - return -1; + return -EINVAL; } diff --git a/src/basic/string-table.h b/src/basic/string-table.h index b6b3611ac..97c1adc07 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -28,13 +28,12 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) \ scope type name##_from_string(const char *s) { \ - int b; \ if (!s) \ - return -1; \ - b = parse_boolean(s); \ + return -EINVAL; \ + int b = parse_boolean(s); \ if (b == 0) \ return (type) 0; \ - else if (b > 0) \ + if (b > 0) \ return yes; \ return (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ } @@ -61,14 +60,16 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k unsigned u = 0; \ type i; \ if (!s) \ - return (type) -1; \ + return -EINVAL; \ i = (type) string_table_lookup(name##_table, ELEMENTSOF(name##_table), s); \ if (i >= 0) \ return i; \ - if (safe_atou(s, &u) >= 0 && u <= max) \ - return (type) u; \ - return (type) -1; \ - } \ + if (safe_atou(s, &u) < 0) \ + return -EINVAL; \ + if (u > max) \ + return -EINVAL; \ + return (type) u; \ + } #define _DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,scope) \ @@ -79,11 +80,16 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,scope) #define DEFINE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,) +#define DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) _DEFINE_STRING_TABLE_LOOKUP(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_TO_STRING(name,type,static) #define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(name,type) _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(name,type,static) #define DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes) _DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(name,type,yes,static) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes) \ + _DEFINE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(name,type,yes,static) /* For string conversions where numbers are also acceptable */ #define DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(name,type,max) \ @@ -97,9 +103,8 @@ ssize_t string_table_lookup(const char * const *table, size_t len, const char *k #define DUMP_STRING_TABLE(name,type,max) \ do { \ - type _k; \ flockfile(stdout); \ - for (_k = 0; _k < (max); _k++) { \ + for (type _k = 0; _k < (max); _k++) { \ const char *_t; \ _t = name##_to_string(_k); \ if (!_t) \ diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 7ab460faa..058eec54f 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -20,64 +20,6 @@ #include "utf8.h" #include "util.h" -int strcmp_ptr(const char *a, const char *b) { - /* Like strcmp(), but tries to make sense of NULL pointers */ - - if (a && b) - return strcmp(a, b); - return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */ -} - -int strcasecmp_ptr(const char *a, const char *b) { - /* Like strcasecmp(), but tries to make sense of NULL pointers */ - - if (a && b) - return strcasecmp(a, b); - return CMP(a, b); /* Direct comparison of pointers, one of which is NULL */ -} - -char* endswith(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (memcmp(s + sl - pl, postfix, pl) != 0) - return NULL; - - return (char*) s + sl - pl; -} - -char* endswith_no_case(const char *s, const char *postfix) { - size_t sl, pl; - - assert(s); - assert(postfix); - - sl = strlen(s); - pl = strlen(postfix); - - if (pl == 0) - return (char*) s + sl; - - if (sl < pl) - return NULL; - - if (strcasecmp(s + sl - pl, postfix) != 0) - return NULL; - - return (char*) s + sl - pl; -} - char* first_word(const char *s, const char *word) { size_t sl, wl; const char *p; @@ -129,7 +71,7 @@ char *strnappend(const char *s, const char *suffix, size_t b) { assert(suffix); a = strlen(s); - if (b > ((size_t) -1) - a) + if (b > SIZE_MAX - a) return NULL; r = new(char, a+b+1); @@ -365,7 +307,7 @@ static char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_le assert(s); assert(percent <= 100); - assert(new_length != (size_t) -1); + assert(new_length != SIZE_MAX); if (old_length <= new_length) return strndup(s, old_length); @@ -436,7 +378,7 @@ char *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigne assert(s); assert(percent <= 100); - if (new_length == (size_t) -1) + if (new_length == SIZE_MAX) return strndup(s, old_length); if (new_length == 0) @@ -791,10 +733,10 @@ char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]) { return *ibuf; } -char *strextend_with_separator(char **x, const char *separator, ...) { - bool need_separator; +char *strextend_with_separator_internal(char **x, const char *separator, ...) { size_t f, l, l_separator; - char *r, *p; + bool need_separator; + char *nr, *p; va_list ap; assert(x); @@ -818,7 +760,7 @@ char *strextend_with_separator(char **x, const char *separator, ...) { if (need_separator) n += l_separator; - if (n > ((size_t) -1) - l) { + if (n >= SIZE_MAX - l) { va_end(ap); return NULL; } @@ -830,11 +772,12 @@ char *strextend_with_separator(char **x, const char *separator, ...) { need_separator = !isempty(*x); - r = realloc(*x, l+1); - if (!r) + nr = realloc(*x, GREEDY_ALLOC_ROUND_UP(l+1)); + if (!nr) return NULL; - p = r + f; + *x = nr; + p = nr + f; va_start(ap, separator); for (;;) { @@ -853,18 +796,16 @@ char *strextend_with_separator(char **x, const char *separator, ...) { } va_end(ap); - assert(p == r + l); + assert(p == nr + l); *p = 0; - *x = r; - return r + l; + return p; } char *strrep(const char *s, unsigned n) { - size_t l; char *r, *p; - unsigned i; + size_t l; assert(s); @@ -873,7 +814,7 @@ char *strrep(const char *s, unsigned n) { if (!r) return NULL; - for (i = 0; i < n; i++) + for (unsigned i = 0; i < n; i++) p = stpcpy(p, s); *p = 0; diff --git a/src/basic/string-util.h b/src/basic/string-util.h index fdd3ce736..cb2881b64 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "macro.h" +#include "string-util-fundamental.h" /* What is interpreted as whitespace? */ #define WHITESPACE " \t\n\r" @@ -21,18 +22,6 @@ #define ALPHANUMERICAL LETTERS DIGITS #define HEXDIGITS DIGITS "abcdefABCDEF" -#define streq(a,b) (strcmp((a),(b)) == 0) -#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) -#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) - -int strcmp_ptr(const char *a, const char *b) _pure_; -int strcasecmp_ptr(const char *a, const char *b) _pure_; - -static inline bool streq_ptr(const char *a, const char *b) { - return strcmp_ptr(a, b) == 0; -} - static inline char* strstr_ptr(const char *haystack, const char *needle) { if (!haystack || !needle) return NULL; @@ -51,10 +40,6 @@ static inline const char *strna(const char *s) { return s ?: "n/a"; } -static inline const char* yes_no(bool b) { - return b ? "yes" : "no"; -} - static inline const char* true_false(bool b) { return b ? "true" : "false"; } @@ -71,10 +56,6 @@ static inline const char* enable_disable(bool b) { return b ? "enable" : "disable"; } -static inline bool isempty(const char *p) { - return !p || !p[0]; -} - static inline const char *empty_to_null(const char *p) { return isempty(p) ? NULL : p; } @@ -93,29 +74,6 @@ static inline const char *empty_or_dash_to_null(const char *p) { return empty_or_dash(p) ? NULL : p; } -static inline char *startswith(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -static inline char *startswith_no_case(const char *s, const char *prefix) { - size_t l; - - l = strlen(prefix); - if (strncasecmp(s, prefix, l) == 0) - return (char*) s + l; - - return NULL; -} - -char *endswith(const char *s, const char *postfix) _pure_; -char *endswith_no_case(const char *s, const char *postfix) _pure_; - char *first_word(const char *s, const char *word) _pure_; char *strnappend(const char *s, const char *suffix, size_t length); @@ -189,9 +147,10 @@ char *strreplace(const char *text, const char *old_string, const char *new_strin char *strip_tab_ansi(char **ibuf, size_t *_isz, size_t highlight[2]); -char *strextend_with_separator(char **x, const char *separator, ...) _sentinel_; +char *strextend_with_separator_internal(char **x, const char *separator, ...) _sentinel_; -#define strextend(x, ...) strextend_with_separator(x, NULL, __VA_ARGS__) +#define strextend_with_separator(x, separator, ...) strextend_with_separator_internal(x, separator, __VA_ARGS__, NULL) +#define strextend(x, ...) strextend_with_separator_internal(x, NULL, __VA_ARGS__, NULL) char *strrep(const char *s, unsigned n); diff --git a/src/basic/strv.c b/src/basic/strv.c index 492dfe400..765da04a7 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -240,27 +240,28 @@ int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix) { return 0; } -char **strv_split_newlines(const char *s) { - char **l; +int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags) { + _cleanup_strv_free_ char **l = NULL; size_t n; + int r; assert(s); - /* Special version of strv_split() that splits on newlines and - * suppresses an empty string at the end */ + /* Special version of strv_split_full() that splits on newlines and + * suppresses an empty string at the end. */ - l = strv_split(s, NEWLINE); - if (!l) - return NULL; + r = strv_split_full(&l, s, NEWLINE, flags); + if (r < 0) + return r; n = strv_length(l); - if (n <= 0) - return l; - - if (isempty(l[n - 1])) + if (n > 0 && isempty(l[n - 1])) { l[n - 1] = mfree(l[n - 1]); + n--; + } - return l; + *ret = TAKE_PTR(l); + return n; } int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags) { diff --git a/src/basic/strv.h b/src/basic/strv.h index 6b3e8e7f8..911528fab 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -73,15 +73,21 @@ static inline bool strv_isempty(char * const *l) { return !l || !*l; } -char **strv_split_newlines(const char *s); - int strv_split_full(char ***t, const char *s, const char *separators, ExtractFlags flags); static inline char **strv_split(const char *s, const char *separators) { char **ret; - int r; - r = strv_split_full(&ret, s, separators, 0); - if (r < 0) + if (strv_split_full(&ret, s, separators, 0) < 0) + return NULL; + + return ret; +} + +int strv_split_newlines_full(char ***ret, const char *s, ExtractFlags flags); +static inline char **strv_split_newlines(const char *s) { + char **ret; + + if (strv_split_newlines_full(&ret, s, 0) < 0) return NULL; return ret; diff --git a/src/shared/syscall-names.text b/src/basic/syscall-list.txt similarity index 98% rename from src/shared/syscall-names.text rename to src/basic/syscall-list.txt index f1b7e29d5..8a602cff3 100644 --- a/src/shared/syscall-names.text +++ b/src/basic/syscall-list.txt @@ -13,15 +13,12 @@ arc_settls arc_usr_cmpxchg arch_prctl arm_fadvise64_64 -arm_sync_file_range atomic_barrier atomic_cmpxchg_32 bdflush -bfin_spinlock bind bpf brk -cache_sync cachectl cacheflush capget @@ -60,6 +57,7 @@ epoll_create1 epoll_ctl epoll_ctl_old epoll_pwait +epoll_pwait2 epoll_wait epoll_wait_old eventfd @@ -216,6 +214,7 @@ mmap mmap2 modify_ldt mount +mount_setattr move_mount move_pages mprotect @@ -241,7 +240,6 @@ name_to_handle_at nanosleep newfstatat nfsservctl -ni_syscall nice old_adjtimex old_getpagesize @@ -568,7 +566,6 @@ times tkill truncate truncate64 -udftrap ugetrlimit umask umount @@ -584,7 +581,6 @@ utime utimensat utimensat_time64 utimes -utimesat utrap_install vfork vhangup diff --git a/src/basic/syscalls-alpha.txt b/src/basic/syscalls-alpha.txt new file mode 100644 index 000000000..2a859c5ef --- /dev/null +++ b/src/basic/syscalls-alpha.txt @@ -0,0 +1,594 @@ +_llseek +_newselect +_sysctl 319 +accept 99 +accept4 502 +access 33 +acct 51 +add_key 439 +adjtimex 366 +alarm +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 300 +bind 104 +bpf 515 +brk 17 +cachectl +cacheflush +capget 368 +capset 369 +chdir 12 +chmod 15 +chown 16 +chown32 +chroot 61 +clock_adjtime 499 +clock_adjtime64 +clock_getres 421 +clock_getres_time64 +clock_gettime 420 +clock_gettime64 +clock_nanosleep 422 +clock_nanosleep_time64 +clock_settime 419 +clock_settime64 +clone 312 +clone2 +clone3 +close 6 +close_range 546 +connect 98 +copy_file_range 519 +creat +create_module 306 +delete_module 308 +dipc 373 +dup 41 +dup2 90 +dup3 487 +epoll_create 407 +epoll_create1 486 +epoll_ctl 408 +epoll_ctl_old +epoll_pwait 474 +epoll_pwait2 551 +epoll_wait 409 +epoll_wait_old +eventfd 478 +eventfd2 485 +exec_with_loader 25 +execv +execve 59 +execveat 513 +exit 1 +exit_group 405 +faccessat 462 +faccessat2 549 +fadvise64 413 +fadvise64_64 +fallocate 480 +fanotify_init 494 +fanotify_mark 495 +fchdir 13 +fchmod 124 +fchmodat 461 +fchown 123 +fchown32 +fchownat 453 +fcntl 92 +fcntl64 +fdatasync 447 +fgetxattr 387 +finit_module 507 +flistxattr 390 +flock 131 +fork 2 +fp_udfiex_crtl +fremovexattr 393 +fsconfig 541 +fsetxattr 384 +fsmount 542 +fsopen 540 +fspick 543 +fstat 91 +fstat64 427 +fstatat64 455 +fstatfs 329 +fstatfs64 529 +fsync 95 +ftruncate 130 +ftruncate64 +futex 394 +futex_time64 +futimesat 454 +get_kernel_syms 309 +get_mempolicy 430 +get_robust_list 467 +get_thread_area +getcpu 473 +getcwd 367 +getdents 305 +getdents64 377 +getdomainname +getdtablesize 89 +getegid 530 +getegid32 +geteuid 531 +geteuid32 +getgid 47 +getgid32 +getgroups 79 +getgroups32 +gethostname 87 +getitimer 361 +getpagesize 64 +getpeername 141 +getpgid 233 +getpgrp 63 +getpid 20 +getpmsg +getppid 532 +getpriority 100 +getrandom 511 +getresgid 372 +getresgid32 +getresuid 344 +getresuid32 +getrlimit 144 +getrusage 364 +getsid 234 +getsockname 150 +getsockopt 118 +gettid 378 +gettimeofday 359 +getuid 24 +getuid32 +getunwind +getxattr 385 +getxgid 47 +getxpid 20 +getxuid 24 +idle +init_module 307 +inotify_add_watch 445 +inotify_init 444 +inotify_init1 489 +inotify_rm_watch 446 +io_cancel 402 +io_destroy 399 +io_getevents 400 +io_pgetevents 523 +io_pgetevents_time64 +io_setup 398 +io_submit 401 +io_uring_enter 536 +io_uring_register 537 +io_uring_setup 535 +ioctl 54 +ioperm +iopl +ioprio_get 443 +ioprio_set 442 +ipc +kcmp 506 +kern_features +kexec_file_load +kexec_load 448 +keyctl 441 +kill 37 +lchown 208 +lchown32 +lgetxattr 386 +link 9 +linkat 458 +listen 106 +listxattr 388 +llistxattr 389 +lookup_dcookie 406 +lremovexattr 392 +lseek 19 +lsetxattr 383 +lstat 68 +lstat64 426 +madvise 75 +mbind 429 +membarrier 517 +memfd_create 512 +memory_ordering +migrate_pages 449 +mincore 375 +mkdir 136 +mkdirat 451 +mknod 14 +mknodat 452 +mlock 314 +mlock2 518 +mlockall 316 +mmap 71 +mmap2 +modify_ldt +mount 302 +mount_setattr 552 +move_mount 539 +move_pages 472 +mprotect 74 +mq_getsetattr 437 +mq_notify 436 +mq_open 432 +mq_timedreceive 435 +mq_timedreceive_time64 +mq_timedsend 434 +mq_timedsend_time64 +mq_unlink 433 +mremap 341 +msgctl 200 +msgget 201 +msgrcv 202 +msgsnd 203 +msync 217 +multiplexer +munlock 315 +munlockall 317 +munmap 73 +name_to_handle_at 497 +nanosleep 340 +newfstatat +nfsservctl 342 +nice +old_adjtimex 303 +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount 321 +olduname +open 45 +open_by_handle_at 498 +open_tree 538 +openat 450 +openat2 547 +or1k_atomic +osf_adjtime 140 +osf_afs_syscall 258 +osf_alt_plock 181 +osf_alt_setsid 188 +osf_alt_sigpending 187 +osf_asynch_daemon 163 +osf_audcntl 252 +osf_audgen 253 +osf_chflags 34 +osf_execve 11 +osf_exportfs 169 +osf_fchflags 35 +osf_fdatasync 261 +osf_fpathconf 248 +osf_fstat 226 +osf_fstatfs 161 +osf_fstatfs64 228 +osf_fuser 243 +osf_getaddressconf 214 +osf_getdirentries 159 +osf_getdomainname 165 +osf_getfh 164 +osf_getfsstat 18 +osf_gethostid 142 +osf_getitimer 86 +osf_getlogin 49 +osf_getmnt 184 +osf_getrusage 117 +osf_getsysinfo 256 +osf_gettimeofday 116 +osf_kloadcall 223 +osf_kmodcall 77 +osf_lstat 225 +osf_memcntl 260 +osf_mincore 78 +osf_mount 21 +osf_mremap 65 +osf_msfs_syscall 240 +osf_msleep 215 +osf_mvalid 213 +osf_mwakeup 216 +osf_naccept 30 +osf_nfssvc 158 +osf_ngetpeername 31 +osf_ngetsockname 32 +osf_nrecvfrom 29 +osf_nrecvmsg 27 +osf_nsendmsg 28 +osf_ntp_adjtime 245 +osf_ntp_gettime 246 +osf_old_creat 8 +osf_old_fstat 62 +osf_old_getpgrp 81 +osf_old_killpg 146 +osf_old_lstat 40 +osf_old_open 5 +osf_old_sigaction 46 +osf_old_sigblock 109 +osf_old_sigreturn 139 +osf_old_sigsetmask 110 +osf_old_sigvec 108 +osf_old_stat 38 +osf_old_vadvise 72 +osf_old_vtrace 115 +osf_old_wait 84 +osf_oldquota 149 +osf_pathconf 247 +osf_pid_block 153 +osf_pid_unblock 154 +osf_plock 107 +osf_priocntlset 237 +osf_profil 44 +osf_proplist_syscall 244 +osf_reboot 55 +osf_revoke 56 +osf_sbrk 69 +osf_security 222 +osf_select 93 +osf_set_program_attributes 43 +osf_set_speculative 239 +osf_sethostid 143 +osf_setitimer 83 +osf_setlogin 50 +osf_setsysinfo 257 +osf_settimeofday 122 +osf_shmat 209 +osf_signal 218 +osf_sigprocmask 48 +osf_sigsendset 238 +osf_sigstack 112 +osf_sigwaitprim 157 +osf_sstk 70 +osf_stat 224 +osf_statfs 160 +osf_statfs64 227 +osf_subsys_info 255 +osf_swapctl 259 +osf_swapon 199 +osf_syscall 0 +osf_sysinfo 241 +osf_table 85 +osf_uadmin 242 +osf_usleep_thread 251 +osf_uswitch 250 +osf_utc_adjtime 220 +osf_utc_gettime 219 +osf_utimes 138 +osf_utsname 207 +osf_wait4 7 +osf_waitid 236 +pause +pciconfig_iobase 376 +pciconfig_read 345 +pciconfig_write 346 +perf_event_open 493 +perfctr +perfmonctl +personality 324 +pidfd_getfd 548 +pidfd_open 544 +pidfd_send_signal 534 +pipe 42 +pipe2 488 +pivot_root 374 +pkey_alloc 525 +pkey_free 526 +pkey_mprotect 524 +poll 94 +ppoll 464 +ppoll_time64 +prctl 348 +pread64 349 +preadv 490 +preadv2 520 +prlimit64 496 +process_madvise 550 +process_vm_readv 504 +process_vm_writev 505 +pselect6 463 +pselect6_time64 +ptrace 26 +pwrite64 350 +pwritev 491 +pwritev2 521 +query_module 347 +quotactl 148 +read 3 +readahead 379 +readdir +readlink 58 +readlinkat 460 +readv 120 +reboot 311 +recv 102 +recvfrom 125 +recvmmsg 479 +recvmmsg_time64 +recvmsg 113 +remap_file_pages 410 +removexattr 391 +rename 128 +renameat 457 +renameat2 510 +request_key 440 +restart_syscall 412 +riscv_flush_icache +rmdir 137 +rseq 527 +rt_sigaction 352 +rt_sigpending 354 +rt_sigprocmask 353 +rt_sigqueueinfo 356 +rt_sigreturn 351 +rt_sigsuspend 357 +rt_sigtimedwait 355 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 492 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 335 +sched_get_priority_min 336 +sched_getaffinity 396 +sched_getattr 509 +sched_getparam 331 +sched_getscheduler 333 +sched_rr_get_interval 337 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 395 +sched_setattr 508 +sched_setparam 330 +sched_setscheduler 332 +sched_yield 334 +seccomp 514 +select 358 +semctl 204 +semget 205 +semop 206 +semtimedop 423 +semtimedop_time64 +send 101 +sendfile 370 +sendfile64 +sendmmsg 503 +sendmsg 114 +sendto 133 +set_mempolicy 431 +set_robust_list 466 +set_thread_area +set_tid_address 411 +setdomainname 166 +setfsgid 326 +setfsgid32 +setfsuid 325 +setfsuid32 +setgid 132 +setgid32 +setgroups 80 +setgroups32 +sethae 301 +sethostname 88 +setitimer 362 +setns 501 +setpgid 39 +setpgrp 82 +setpriority 96 +setregid 127 +setregid32 +setresgid 371 +setresgid32 +setresuid 343 +setresuid32 +setreuid 126 +setreuid32 +setrlimit 145 +setsid 147 +setsockopt 105 +settimeofday 360 +setuid 23 +setuid32 +setxattr 382 +sgetmask +shmat 209 +shmctl 210 +shmdt 211 +shmget 212 +shutdown 134 +sigaction 156 +sigaltstack 235 +signal +signalfd 476 +signalfd4 484 +sigpending 52 +sigprocmask +sigreturn 103 +sigsuspend 111 +socket 97 +socketcall +socketpair 135 +splice 468 +spu_create +spu_run +ssetmask +stat 67 +stat64 425 +statfs 328 +statfs64 528 +statx 522 +stime +subpage_prot +swapcontext +swapoff 304 +swapon 322 +switch_endian +symlink 57 +symlinkat 459 +sync 36 +sync_file_range 469 +sync_file_range2 +syncfs 500 +sys_debug_setcontext +syscall +sysfs 254 +sysinfo 318 +syslog 310 +sysmips +tee 470 +tgkill 424 +time +timer_create 414 +timer_delete 418 +timer_getoverrun 417 +timer_gettime 416 +timer_gettime64 +timer_settime 415 +timer_settime64 +timerfd 477 +timerfd_create 481 +timerfd_gettime 483 +timerfd_gettime64 +timerfd_settime 482 +timerfd_settime64 +times 323 +tkill 381 +truncate 129 +truncate64 +ugetrlimit +umask 60 +umount 22 +umount2 22 +uname 339 +unlink 10 +unlinkat 456 +unshare 465 +uselib 313 +userfaultfd 516 +ustat 327 +utime +utimensat 475 +utimensat_time64 +utimes 363 +utrap_install +vfork 66 +vhangup 76 +vm86 +vm86old +vmsplice 471 +wait4 365 +waitid 438 +waitpid +write 4 +writev 121 diff --git a/src/basic/syscalls-arc.txt b/src/basic/syscalls-arc.txt new file mode 100644 index 000000000..1305f0649 --- /dev/null +++ b/src/basic/syscalls-arc.txt @@ -0,0 +1,594 @@ +_llseek +_newselect +_sysctl +accept 202 +accept4 242 +access +acct 89 +add_key 217 +adjtimex 171 +alarm +arc_gettls 246 +arc_settls 245 +arc_usr_cmpxchg 248 +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush +bind 200 +bpf 280 +brk 214 +cachectl +cacheflush 244 +capget 90 +capset 91 +chdir 49 +chmod +chown +chown32 +chroot 51 +clock_adjtime 266 +clock_adjtime64 405 +clock_getres 114 +clock_getres_time64 406 +clock_gettime 113 +clock_gettime64 403 +clock_nanosleep 115 +clock_nanosleep_time64 407 +clock_settime 112 +clock_settime64 404 +clone 220 +clone2 +clone3 435 +close 57 +close_range 436 +connect 203 +copy_file_range 285 +creat +create_module +delete_module 106 +dipc +dup 23 +dup2 +dup3 24 +epoll_create +epoll_create1 20 +epoll_ctl 21 +epoll_ctl_old +epoll_pwait 22 +epoll_pwait2 441 +epoll_wait +epoll_wait_old +eventfd +eventfd2 19 +exec_with_loader +execv +execve 221 +execveat 281 +exit 93 +exit_group 94 +faccessat 48 +faccessat2 439 +fadvise64 +fadvise64_64 223 +fallocate 47 +fanotify_init 262 +fanotify_mark 263 +fchdir 50 +fchmod 52 +fchmodat 53 +fchown 55 +fchown32 +fchownat 54 +fcntl +fcntl64 25 +fdatasync 83 +fgetxattr 10 +finit_module 273 +flistxattr 13 +flock 32 +fork +fp_udfiex_crtl +fremovexattr 16 +fsconfig 431 +fsetxattr 7 +fsmount 432 +fsopen 430 +fspick 433 +fstat +fstat64 80 +fstatat64 79 +fstatfs +fstatfs64 44 +fsync 82 +ftruncate +ftruncate64 46 +futex 98 +futex_time64 422 +futimesat +get_kernel_syms +get_mempolicy 236 +get_robust_list 100 +get_thread_area +getcpu 168 +getcwd 17 +getdents +getdents64 61 +getdomainname +getdtablesize +getegid 177 +getegid32 +geteuid 175 +geteuid32 +getgid 176 +getgid32 +getgroups 158 +getgroups32 +gethostname +getitimer 102 +getpagesize +getpeername 205 +getpgid 155 +getpgrp +getpid 172 +getpmsg +getppid 173 +getpriority 141 +getrandom 278 +getresgid 150 +getresgid32 +getresuid 148 +getresuid32 +getrlimit 163 +getrusage 165 +getsid 156 +getsockname 204 +getsockopt 209 +gettid 178 +gettimeofday 169 +getuid 174 +getuid32 +getunwind +getxattr 8 +getxgid +getxpid +getxuid +idle +init_module 105 +inotify_add_watch 27 +inotify_init +inotify_init1 26 +inotify_rm_watch 28 +io_cancel 3 +io_destroy 1 +io_getevents 4 +io_pgetevents 292 +io_pgetevents_time64 416 +io_setup 0 +io_submit 2 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 29 +ioperm +iopl +ioprio_get 31 +ioprio_set 30 +ipc +kcmp 272 +kern_features +kexec_file_load 294 +kexec_load 104 +keyctl 219 +kill 129 +lchown +lchown32 +lgetxattr 9 +link +linkat 37 +listen 201 +listxattr 11 +llistxattr 12 +lookup_dcookie 18 +lremovexattr 15 +lseek +lsetxattr 6 +lstat +lstat64 +madvise 233 +mbind 235 +membarrier 283 +memfd_create 279 +memory_ordering +migrate_pages 238 +mincore 232 +mkdir +mkdirat 34 +mknod +mknodat 33 +mlock 228 +mlock2 284 +mlockall 230 +mmap +mmap2 222 +modify_ldt +mount 40 +mount_setattr 442 +move_mount 429 +move_pages 239 +mprotect 226 +mq_getsetattr 185 +mq_notify 184 +mq_open 180 +mq_timedreceive 183 +mq_timedreceive_time64 419 +mq_timedsend 182 +mq_timedsend_time64 418 +mq_unlink 181 +mremap 216 +msgctl 187 +msgget 186 +msgrcv 188 +msgsnd 189 +msync 227 +multiplexer +munlock 229 +munlockall 231 +munmap 215 +name_to_handle_at 264 +nanosleep 101 +newfstatat +nfsservctl 42 +nice +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open +open_by_handle_at 265 +open_tree 428 +openat 56 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 241 +perfctr +perfmonctl +personality 92 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe +pipe2 59 +pivot_root 41 +pkey_alloc 289 +pkey_free 290 +pkey_mprotect 288 +poll +ppoll 73 +ppoll_time64 414 +prctl 167 +pread64 67 +preadv 69 +preadv2 286 +prlimit64 261 +process_madvise 440 +process_vm_readv 270 +process_vm_writev 271 +pselect6 72 +pselect6_time64 413 +ptrace 117 +pwrite64 68 +pwritev 70 +pwritev2 287 +query_module +quotactl 60 +read 63 +readahead 213 +readdir +readlink +readlinkat 78 +readv 65 +reboot 142 +recv +recvfrom 207 +recvmmsg 243 +recvmmsg_time64 417 +recvmsg 212 +remap_file_pages 234 +removexattr 14 +rename +renameat 38 +renameat2 276 +request_key 218 +restart_syscall 128 +riscv_flush_icache +rmdir +rseq 293 +rt_sigaction 134 +rt_sigpending 136 +rt_sigprocmask 135 +rt_sigqueueinfo 138 +rt_sigreturn 139 +rt_sigsuspend 133 +rt_sigtimedwait 137 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 240 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 125 +sched_get_priority_min 126 +sched_getaffinity 123 +sched_getattr 275 +sched_getparam 121 +sched_getscheduler 120 +sched_rr_get_interval 127 +sched_rr_get_interval_time64 423 +sched_set_affinity +sched_setaffinity 122 +sched_setattr 274 +sched_setparam 118 +sched_setscheduler 119 +sched_yield 124 +seccomp 277 +select +semctl 191 +semget 190 +semop 193 +semtimedop 192 +semtimedop_time64 420 +send +sendfile +sendfile64 71 +sendmmsg 269 +sendmsg 211 +sendto 206 +set_mempolicy 237 +set_robust_list 99 +set_thread_area +set_tid_address 96 +setdomainname 162 +setfsgid 152 +setfsgid32 +setfsuid 151 +setfsuid32 +setgid 144 +setgid32 +setgroups 159 +setgroups32 +sethae +sethostname 161 +setitimer 103 +setns 268 +setpgid 154 +setpgrp +setpriority 140 +setregid 143 +setregid32 +setresgid 149 +setresgid32 +setresuid 147 +setresuid32 +setreuid 145 +setreuid32 +setrlimit 164 +setsid 157 +setsockopt 208 +settimeofday 170 +setuid 146 +setuid32 +setxattr 5 +sgetmask +shmat 196 +shmctl 195 +shmdt 197 +shmget 194 +shutdown 210 +sigaction +sigaltstack 132 +signal +signalfd +signalfd4 74 +sigpending +sigprocmask +sigreturn +sigsuspend +socket 198 +socketcall +socketpair 199 +splice 76 +spu_create +spu_run +ssetmask +stat +stat64 +statfs +statfs64 43 +statx 291 +stime +subpage_prot +swapcontext +swapoff 225 +swapon 224 +switch_endian +symlink +symlinkat 36 +sync 81 +sync_file_range 84 +sync_file_range2 +syncfs 267 +sys_debug_setcontext +syscall +sysfs 247 +sysinfo 179 +syslog 116 +sysmips +tee 77 +tgkill 131 +time +timer_create 107 +timer_delete 111 +timer_getoverrun 109 +timer_gettime 108 +timer_gettime64 408 +timer_settime 110 +timer_settime64 409 +timerfd +timerfd_create 85 +timerfd_gettime 87 +timerfd_gettime64 410 +timerfd_settime 86 +timerfd_settime64 411 +times 153 +tkill 130 +truncate +truncate64 45 +ugetrlimit +umask 166 +umount +umount2 39 +uname 160 +unlink +unlinkat 35 +unshare 97 +uselib +userfaultfd 282 +ustat +utime +utimensat 88 +utimensat_time64 412 +utimes +utrap_install +vfork +vhangup 58 +vm86 +vm86old +vmsplice 75 +wait4 260 +waitid 95 +waitpid +write 64 +writev 66 diff --git a/src/basic/syscalls-arm.txt b/src/basic/syscalls-arm.txt new file mode 100644 index 000000000..2e7b238b8 --- /dev/null +++ b/src/basic/syscalls-arm.txt @@ -0,0 +1,594 @@ +_llseek 140 +_newselect 142 +_sysctl 149 +accept 285 +accept4 366 +access 33 +acct 51 +add_key 309 +adjtimex 124 +alarm +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 270 +atomic_barrier +atomic_cmpxchg_32 +bdflush 134 +bind 282 +bpf 386 +brk 45 +cachectl +cacheflush +capget 184 +capset 185 +chdir 12 +chmod 15 +chown 182 +chown32 212 +chroot 61 +clock_adjtime 372 +clock_adjtime64 405 +clock_getres 264 +clock_getres_time64 406 +clock_gettime 263 +clock_gettime64 403 +clock_nanosleep 265 +clock_nanosleep_time64 407 +clock_settime 262 +clock_settime64 404 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 283 +copy_file_range 391 +creat 8 +create_module +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 358 +epoll_create 250 +epoll_create1 357 +epoll_ctl 251 +epoll_ctl_old +epoll_pwait 346 +epoll_pwait2 441 +epoll_wait 252 +epoll_wait_old +eventfd 351 +eventfd2 356 +exec_with_loader +execv +execve 11 +execveat 387 +exit 1 +exit_group 248 +faccessat 334 +faccessat2 439 +fadvise64 +fadvise64_64 +fallocate 352 +fanotify_init 367 +fanotify_mark 368 +fchdir 133 +fchmod 94 +fchmodat 333 +fchown 95 +fchown32 207 +fchownat 325 +fcntl 55 +fcntl64 221 +fdatasync 148 +fgetxattr 231 +finit_module 379 +flistxattr 234 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 237 +fsconfig 431 +fsetxattr 228 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 197 +fstatat64 327 +fstatfs 100 +fstatfs64 267 +fsync 118 +ftruncate 93 +ftruncate64 194 +futex 240 +futex_time64 422 +futimesat 326 +get_kernel_syms +get_mempolicy 320 +get_robust_list 339 +get_thread_area +getcpu 345 +getcwd 183 +getdents 141 +getdents64 217 +getdomainname +getdtablesize +getegid 50 +getegid32 202 +geteuid 49 +geteuid32 201 +getgid 47 +getgid32 200 +getgroups 80 +getgroups32 205 +gethostname +getitimer 105 +getpagesize +getpeername 287 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg +getppid 64 +getpriority 96 +getrandom 384 +getresgid 171 +getresgid32 211 +getresuid 165 +getresuid32 209 +getrlimit +getrusage 77 +getsid 147 +getsockname 286 +getsockopt 295 +gettid 224 +gettimeofday 78 +getuid 24 +getuid32 199 +getunwind +getxattr 229 +getxgid +getxpid +getxuid +idle +init_module 128 +inotify_add_watch 317 +inotify_init 316 +inotify_init1 360 +inotify_rm_watch 318 +io_cancel 247 +io_destroy 244 +io_getevents 245 +io_pgetevents 399 +io_pgetevents_time64 416 +io_setup 243 +io_submit 246 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm +iopl +ioprio_get 315 +ioprio_set 314 +ipc +kcmp 378 +kern_features +kexec_file_load 401 +kexec_load 347 +keyctl 311 +kill 37 +lchown 16 +lchown32 198 +lgetxattr 230 +link 9 +linkat 330 +listen 284 +listxattr 232 +llistxattr 233 +lookup_dcookie 249 +lremovexattr 236 +lseek 19 +lsetxattr 227 +lstat 107 +lstat64 196 +madvise 220 +mbind 319 +membarrier 389 +memfd_create 385 +memory_ordering +migrate_pages 400 +mincore 219 +mkdir 39 +mkdirat 323 +mknod 14 +mknodat 324 +mlock 150 +mlock2 390 +mlockall 152 +mmap +mmap2 192 +modify_ldt +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 344 +mprotect 125 +mq_getsetattr 279 +mq_notify 278 +mq_open 274 +mq_timedreceive 277 +mq_timedreceive_time64 419 +mq_timedsend 276 +mq_timedsend_time64 418 +mq_unlink 275 +mremap 163 +msgctl 304 +msgget 303 +msgrcv 302 +msgsnd 301 +msync 144 +multiplexer +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 370 +nanosleep 162 +newfstatat +nfsservctl 169 +nice 34 +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 5 +open_by_handle_at 371 +open_tree 428 +openat 322 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase 271 +pciconfig_read 272 +pciconfig_write 273 +perf_event_open 364 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 359 +pivot_root 218 +pkey_alloc 395 +pkey_free 396 +pkey_mprotect 394 +poll 168 +ppoll 336 +ppoll_time64 414 +prctl 172 +pread64 180 +preadv 361 +preadv2 392 +prlimit64 369 +process_madvise 440 +process_vm_readv 376 +process_vm_writev 377 +pselect6 335 +pselect6_time64 413 +ptrace 26 +pwrite64 181 +pwritev 362 +pwritev2 393 +query_module +quotactl 131 +read 3 +readahead 225 +readdir +readlink 85 +readlinkat 332 +readv 145 +reboot 88 +recv 291 +recvfrom 292 +recvmmsg 365 +recvmmsg_time64 417 +recvmsg 297 +remap_file_pages 253 +removexattr 235 +rename 38 +renameat 329 +renameat2 382 +request_key 310 +restart_syscall 0 +riscv_flush_icache +rmdir 40 +rseq 398 +rt_sigaction 174 +rt_sigpending 176 +rt_sigprocmask 175 +rt_sigqueueinfo 178 +rt_sigreturn 173 +rt_sigsuspend 179 +rt_sigtimedwait 177 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 363 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 242 +sched_getattr 381 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 423 +sched_set_affinity +sched_setaffinity 241 +sched_setattr 380 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 383 +select +semctl 300 +semget 299 +semop 298 +semtimedop 312 +semtimedop_time64 420 +send 289 +sendfile 187 +sendfile64 239 +sendmmsg 374 +sendmsg 296 +sendto 290 +set_mempolicy 321 +set_robust_list 338 +set_thread_area +set_tid_address 256 +setdomainname 121 +setfsgid 139 +setfsgid32 216 +setfsuid 138 +setfsuid32 215 +setgid 46 +setgid32 214 +setgroups 81 +setgroups32 206 +sethae +sethostname 74 +setitimer 104 +setns 375 +setpgid 57 +setpgrp +setpriority 97 +setregid 71 +setregid32 204 +setresgid 170 +setresgid32 210 +setresuid 164 +setresuid32 208 +setreuid 70 +setreuid32 203 +setrlimit 75 +setsid 66 +setsockopt 294 +settimeofday 79 +setuid 23 +setuid32 213 +setxattr 226 +sgetmask +shmat 305 +shmctl 308 +shmdt 306 +shmget 307 +shutdown 293 +sigaction 67 +sigaltstack 186 +signal +signalfd 349 +signalfd4 355 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 281 +socketcall +socketpair 288 +splice 340 +spu_create +spu_run +ssetmask +stat 106 +stat64 195 +statfs 99 +statfs64 266 +statx 397 +stime +subpage_prot +swapcontext +swapoff 115 +swapon 87 +switch_endian +symlink 83 +symlinkat 331 +sync 36 +sync_file_range +sync_file_range2 341 +syncfs 373 +sys_debug_setcontext +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 342 +tgkill 268 +time +timer_create 257 +timer_delete 261 +timer_getoverrun 260 +timer_gettime 259 +timer_gettime64 408 +timer_settime 258 +timer_settime64 409 +timerfd +timerfd_create 350 +timerfd_gettime 354 +timerfd_gettime64 410 +timerfd_settime 353 +timerfd_settime64 411 +times 43 +tkill 238 +truncate 92 +truncate64 193 +ugetrlimit 191 +umask 60 +umount +umount2 52 +uname 122 +unlink 10 +unlinkat 328 +unshare 337 +uselib 86 +userfaultfd 388 +ustat 62 +utime +utimensat 348 +utimensat_time64 412 +utimes 269 +utrap_install +vfork 190 +vhangup 111 +vm86 +vm86old +vmsplice 343 +wait4 114 +waitid 280 +waitpid +write 4 +writev 146 diff --git a/src/basic/syscalls-arm64.txt b/src/basic/syscalls-arm64.txt new file mode 100644 index 000000000..7fd4be1ed --- /dev/null +++ b/src/basic/syscalls-arm64.txt @@ -0,0 +1,594 @@ +_llseek +_newselect +_sysctl +accept 202 +accept4 242 +access +acct 89 +add_key 217 +adjtimex 171 +alarm +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush +bind 200 +bpf 280 +brk 214 +cachectl +cacheflush +capget 90 +capset 91 +chdir 49 +chmod +chown +chown32 +chroot 51 +clock_adjtime 266 +clock_adjtime64 +clock_getres 114 +clock_getres_time64 +clock_gettime 113 +clock_gettime64 +clock_nanosleep 115 +clock_nanosleep_time64 +clock_settime 112 +clock_settime64 +clone 220 +clone2 +clone3 435 +close 57 +close_range 436 +connect 203 +copy_file_range 285 +creat +create_module +delete_module 106 +dipc +dup 23 +dup2 +dup3 24 +epoll_create +epoll_create1 20 +epoll_ctl 21 +epoll_ctl_old +epoll_pwait 22 +epoll_pwait2 441 +epoll_wait +epoll_wait_old +eventfd +eventfd2 19 +exec_with_loader +execv +execve 221 +execveat 281 +exit 93 +exit_group 94 +faccessat 48 +faccessat2 439 +fadvise64 223 +fadvise64_64 +fallocate 47 +fanotify_init 262 +fanotify_mark 263 +fchdir 50 +fchmod 52 +fchmodat 53 +fchown 55 +fchown32 +fchownat 54 +fcntl 25 +fcntl64 +fdatasync 83 +fgetxattr 10 +finit_module 273 +flistxattr 13 +flock 32 +fork +fp_udfiex_crtl +fremovexattr 16 +fsconfig 431 +fsetxattr 7 +fsmount 432 +fsopen 430 +fspick 433 +fstat 80 +fstat64 +fstatat64 +fstatfs 44 +fstatfs64 +fsync 82 +ftruncate 46 +ftruncate64 +futex 98 +futex_time64 +futimesat +get_kernel_syms +get_mempolicy 236 +get_robust_list 100 +get_thread_area +getcpu 168 +getcwd 17 +getdents +getdents64 61 +getdomainname +getdtablesize +getegid 177 +getegid32 +geteuid 175 +geteuid32 +getgid 176 +getgid32 +getgroups 158 +getgroups32 +gethostname +getitimer 102 +getpagesize +getpeername 205 +getpgid 155 +getpgrp +getpid 172 +getpmsg +getppid 173 +getpriority 141 +getrandom 278 +getresgid 150 +getresgid32 +getresuid 148 +getresuid32 +getrlimit 163 +getrusage 165 +getsid 156 +getsockname 204 +getsockopt 209 +gettid 178 +gettimeofday 169 +getuid 174 +getuid32 +getunwind +getxattr 8 +getxgid +getxpid +getxuid +idle +init_module 105 +inotify_add_watch 27 +inotify_init +inotify_init1 26 +inotify_rm_watch 28 +io_cancel 3 +io_destroy 1 +io_getevents 4 +io_pgetevents 292 +io_pgetevents_time64 +io_setup 0 +io_submit 2 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 29 +ioperm +iopl +ioprio_get 31 +ioprio_set 30 +ipc +kcmp 272 +kern_features +kexec_file_load 294 +kexec_load 104 +keyctl 219 +kill 129 +lchown +lchown32 +lgetxattr 9 +link +linkat 37 +listen 201 +listxattr 11 +llistxattr 12 +lookup_dcookie 18 +lremovexattr 15 +lseek 62 +lsetxattr 6 +lstat +lstat64 +madvise 233 +mbind 235 +membarrier 283 +memfd_create 279 +memory_ordering +migrate_pages 238 +mincore 232 +mkdir +mkdirat 34 +mknod +mknodat 33 +mlock 228 +mlock2 284 +mlockall 230 +mmap 222 +mmap2 +modify_ldt +mount 40 +mount_setattr 442 +move_mount 429 +move_pages 239 +mprotect 226 +mq_getsetattr 185 +mq_notify 184 +mq_open 180 +mq_timedreceive 183 +mq_timedreceive_time64 +mq_timedsend 182 +mq_timedsend_time64 +mq_unlink 181 +mremap 216 +msgctl 187 +msgget 186 +msgrcv 188 +msgsnd 189 +msync 227 +multiplexer +munlock 229 +munlockall 231 +munmap 215 +name_to_handle_at 264 +nanosleep 101 +newfstatat 79 +nfsservctl 42 +nice +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open +open_by_handle_at 265 +open_tree 428 +openat 56 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 241 +perfctr +perfmonctl +personality 92 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe +pipe2 59 +pivot_root 41 +pkey_alloc 289 +pkey_free 290 +pkey_mprotect 288 +poll +ppoll 73 +ppoll_time64 +prctl 167 +pread64 67 +preadv 69 +preadv2 286 +prlimit64 261 +process_madvise 440 +process_vm_readv 270 +process_vm_writev 271 +pselect6 72 +pselect6_time64 +ptrace 117 +pwrite64 68 +pwritev 70 +pwritev2 287 +query_module +quotactl 60 +read 63 +readahead 213 +readdir +readlink +readlinkat 78 +readv 65 +reboot 142 +recv +recvfrom 207 +recvmmsg 243 +recvmmsg_time64 +recvmsg 212 +remap_file_pages 234 +removexattr 14 +rename +renameat 38 +renameat2 276 +request_key 218 +restart_syscall 128 +riscv_flush_icache +rmdir +rseq 293 +rt_sigaction 134 +rt_sigpending 136 +rt_sigprocmask 135 +rt_sigqueueinfo 138 +rt_sigreturn 139 +rt_sigsuspend 133 +rt_sigtimedwait 137 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 240 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 125 +sched_get_priority_min 126 +sched_getaffinity 123 +sched_getattr 275 +sched_getparam 121 +sched_getscheduler 120 +sched_rr_get_interval 127 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 122 +sched_setattr 274 +sched_setparam 118 +sched_setscheduler 119 +sched_yield 124 +seccomp 277 +select +semctl 191 +semget 190 +semop 193 +semtimedop 192 +semtimedop_time64 +send +sendfile 71 +sendfile64 +sendmmsg 269 +sendmsg 211 +sendto 206 +set_mempolicy 237 +set_robust_list 99 +set_thread_area +set_tid_address 96 +setdomainname 162 +setfsgid 152 +setfsgid32 +setfsuid 151 +setfsuid32 +setgid 144 +setgid32 +setgroups 159 +setgroups32 +sethae +sethostname 161 +setitimer 103 +setns 268 +setpgid 154 +setpgrp +setpriority 140 +setregid 143 +setregid32 +setresgid 149 +setresgid32 +setresuid 147 +setresuid32 +setreuid 145 +setreuid32 +setrlimit 164 +setsid 157 +setsockopt 208 +settimeofday 170 +setuid 146 +setuid32 +setxattr 5 +sgetmask +shmat 196 +shmctl 195 +shmdt 197 +shmget 194 +shutdown 210 +sigaction +sigaltstack 132 +signal +signalfd +signalfd4 74 +sigpending +sigprocmask +sigreturn +sigsuspend +socket 198 +socketcall +socketpair 199 +splice 76 +spu_create +spu_run +ssetmask +stat +stat64 +statfs 43 +statfs64 +statx 291 +stime +subpage_prot +swapcontext +swapoff 225 +swapon 224 +switch_endian +symlink +symlinkat 36 +sync 81 +sync_file_range 84 +sync_file_range2 +syncfs 267 +sys_debug_setcontext +syscall +sysfs +sysinfo 179 +syslog 116 +sysmips +tee 77 +tgkill 131 +time +timer_create 107 +timer_delete 111 +timer_getoverrun 109 +timer_gettime 108 +timer_gettime64 +timer_settime 110 +timer_settime64 +timerfd +timerfd_create 85 +timerfd_gettime 87 +timerfd_gettime64 +timerfd_settime 86 +timerfd_settime64 +times 153 +tkill 130 +truncate 45 +truncate64 +ugetrlimit +umask 166 +umount +umount2 39 +uname 160 +unlink +unlinkat 35 +unshare 97 +uselib +userfaultfd 282 +ustat +utime +utimensat 88 +utimensat_time64 +utimes +utrap_install +vfork +vhangup 58 +vm86 +vm86old +vmsplice 75 +wait4 260 +waitid 95 +waitpid +write 64 +writev 66 diff --git a/src/basic/syscalls-i386.txt b/src/basic/syscalls-i386.txt new file mode 100644 index 000000000..281eef070 --- /dev/null +++ b/src/basic/syscalls-i386.txt @@ -0,0 +1,594 @@ +_llseek 140 +_newselect 142 +_sysctl 149 +accept +accept4 364 +access 33 +acct 51 +add_key 286 +adjtimex 124 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl 384 +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 134 +bind 361 +bpf 357 +brk 45 +cachectl +cacheflush +capget 184 +capset 185 +chdir 12 +chmod 15 +chown 182 +chown32 212 +chroot 61 +clock_adjtime 343 +clock_adjtime64 405 +clock_getres 266 +clock_getres_time64 406 +clock_gettime 265 +clock_gettime64 403 +clock_nanosleep 267 +clock_nanosleep_time64 407 +clock_settime 264 +clock_settime64 404 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 362 +copy_file_range 377 +creat 8 +create_module 127 +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 330 +epoll_create 254 +epoll_create1 329 +epoll_ctl 255 +epoll_ctl_old +epoll_pwait 319 +epoll_pwait2 441 +epoll_wait 256 +epoll_wait_old +eventfd 323 +eventfd2 328 +exec_with_loader +execv +execve 11 +execveat 358 +exit 1 +exit_group 252 +faccessat 307 +faccessat2 439 +fadvise64 250 +fadvise64_64 272 +fallocate 324 +fanotify_init 338 +fanotify_mark 339 +fchdir 133 +fchmod 94 +fchmodat 306 +fchown 95 +fchown32 207 +fchownat 298 +fcntl 55 +fcntl64 221 +fdatasync 148 +fgetxattr 231 +finit_module 350 +flistxattr 234 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 237 +fsconfig 431 +fsetxattr 228 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 197 +fstatat64 300 +fstatfs 100 +fstatfs64 269 +fsync 118 +ftruncate 93 +ftruncate64 194 +futex 240 +futex_time64 422 +futimesat 299 +get_kernel_syms 130 +get_mempolicy 275 +get_robust_list 312 +get_thread_area 244 +getcpu 318 +getcwd 183 +getdents 141 +getdents64 220 +getdomainname +getdtablesize +getegid 50 +getegid32 202 +geteuid 49 +geteuid32 201 +getgid 47 +getgid32 200 +getgroups 80 +getgroups32 205 +gethostname +getitimer 105 +getpagesize +getpeername 368 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg 188 +getppid 64 +getpriority 96 +getrandom 355 +getresgid 171 +getresgid32 211 +getresuid 165 +getresuid32 209 +getrlimit 76 +getrusage 77 +getsid 147 +getsockname 367 +getsockopt 365 +gettid 224 +gettimeofday 78 +getuid 24 +getuid32 199 +getunwind +getxattr 229 +getxgid +getxpid +getxuid +idle 112 +init_module 128 +inotify_add_watch 292 +inotify_init 291 +inotify_init1 332 +inotify_rm_watch 293 +io_cancel 249 +io_destroy 246 +io_getevents 247 +io_pgetevents 385 +io_pgetevents_time64 416 +io_setup 245 +io_submit 248 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm 101 +iopl 110 +ioprio_get 290 +ioprio_set 289 +ipc 117 +kcmp 349 +kern_features +kexec_file_load +kexec_load 283 +keyctl 288 +kill 37 +lchown 16 +lchown32 198 +lgetxattr 230 +link 9 +linkat 303 +listen 363 +listxattr 232 +llistxattr 233 +lookup_dcookie 253 +lremovexattr 236 +lseek 19 +lsetxattr 227 +lstat 107 +lstat64 196 +madvise 219 +mbind 274 +membarrier 375 +memfd_create 356 +memory_ordering +migrate_pages 294 +mincore 218 +mkdir 39 +mkdirat 296 +mknod 14 +mknodat 297 +mlock 150 +mlock2 376 +mlockall 152 +mmap 90 +mmap2 192 +modify_ldt 123 +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 317 +mprotect 125 +mq_getsetattr 282 +mq_notify 281 +mq_open 277 +mq_timedreceive 280 +mq_timedreceive_time64 419 +mq_timedsend 279 +mq_timedsend_time64 418 +mq_unlink 278 +mremap 163 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 144 +multiplexer +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 341 +nanosleep 162 +newfstatat +nfsservctl 169 +nice 34 +old_adjtimex +old_getpagesize +oldfstat 28 +oldlstat 84 +oldolduname 59 +oldstat 18 +oldumount +olduname 109 +open 5 +open_by_handle_at 342 +open_tree 428 +openat 295 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 336 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 331 +pivot_root 217 +pkey_alloc 381 +pkey_free 382 +pkey_mprotect 380 +poll 168 +ppoll 309 +ppoll_time64 414 +prctl 172 +pread64 180 +preadv 333 +preadv2 378 +prlimit64 340 +process_madvise 440 +process_vm_readv 347 +process_vm_writev 348 +pselect6 308 +pselect6_time64 413 +ptrace 26 +pwrite64 181 +pwritev 334 +pwritev2 379 +query_module 167 +quotactl 131 +read 3 +readahead 225 +readdir 89 +readlink 85 +readlinkat 305 +readv 145 +reboot 88 +recv +recvfrom 371 +recvmmsg 337 +recvmmsg_time64 417 +recvmsg 372 +remap_file_pages 257 +removexattr 235 +rename 38 +renameat 302 +renameat2 353 +request_key 287 +restart_syscall 0 +riscv_flush_icache +rmdir 40 +rseq 386 +rt_sigaction 174 +rt_sigpending 176 +rt_sigprocmask 175 +rt_sigqueueinfo 178 +rt_sigreturn 173 +rt_sigsuspend 179 +rt_sigtimedwait 177 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 335 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 242 +sched_getattr 352 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 423 +sched_set_affinity +sched_setaffinity 241 +sched_setattr 351 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 354 +select 82 +semctl 394 +semget 393 +semop +semtimedop +semtimedop_time64 420 +send +sendfile 187 +sendfile64 239 +sendmmsg 345 +sendmsg 370 +sendto 369 +set_mempolicy 276 +set_robust_list 311 +set_thread_area 243 +set_tid_address 258 +setdomainname 121 +setfsgid 139 +setfsgid32 216 +setfsuid 138 +setfsuid32 215 +setgid 46 +setgid32 214 +setgroups 81 +setgroups32 206 +sethae +sethostname 74 +setitimer 104 +setns 346 +setpgid 57 +setpgrp +setpriority 97 +setregid 71 +setregid32 204 +setresgid 170 +setresgid32 210 +setresuid 164 +setresuid32 208 +setreuid 70 +setreuid32 203 +setrlimit 75 +setsid 66 +setsockopt 366 +settimeofday 79 +setuid 23 +setuid32 213 +setxattr 226 +sgetmask 68 +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 373 +sigaction 67 +sigaltstack 186 +signal 48 +signalfd 321 +signalfd4 327 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 359 +socketcall 102 +socketpair 360 +splice 313 +spu_create +spu_run +ssetmask 69 +stat 106 +stat64 195 +statfs 99 +statfs64 268 +statx 383 +stime 25 +subpage_prot +swapcontext +swapoff 115 +swapon 87 +switch_endian +symlink 83 +symlinkat 304 +sync 36 +sync_file_range 314 +sync_file_range2 +syncfs 344 +sys_debug_setcontext +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 315 +tgkill 270 +time 13 +timer_create 259 +timer_delete 263 +timer_getoverrun 262 +timer_gettime 261 +timer_gettime64 408 +timer_settime 260 +timer_settime64 409 +timerfd +timerfd_create 322 +timerfd_gettime 326 +timerfd_gettime64 410 +timerfd_settime 325 +timerfd_settime64 411 +times 43 +tkill 238 +truncate 92 +truncate64 193 +ugetrlimit 191 +umask 60 +umount 22 +umount2 52 +uname 122 +unlink 10 +unlinkat 301 +unshare 310 +uselib 86 +userfaultfd 374 +ustat 62 +utime 30 +utimensat 320 +utimensat_time64 412 +utimes 271 +utrap_install +vfork 190 +vhangup 111 +vm86 166 +vm86old 113 +vmsplice 316 +wait4 114 +waitid 284 +waitpid 7 +write 4 +writev 146 diff --git a/src/basic/syscalls-ia64.txt b/src/basic/syscalls-ia64.txt new file mode 100644 index 000000000..44742a2a7 --- /dev/null +++ b/src/basic/syscalls-ia64.txt @@ -0,0 +1,594 @@ +_llseek +_newselect +_sysctl 1150 +accept 1194 +accept4 1334 +access 1049 +acct 1064 +add_key 1271 +adjtimex 1131 +alarm +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 1138 +bind 1191 +bpf 1341 +brk 1060 +cachectl +cacheflush +capget 1185 +capset 1186 +chdir 1034 +chmod 1038 +chown 1039 +chown32 +chroot 1068 +clock_adjtime 1328 +clock_adjtime64 +clock_getres 1255 +clock_getres_time64 +clock_gettime 1254 +clock_gettime64 +clock_nanosleep 1256 +clock_nanosleep_time64 +clock_settime 1253 +clock_settime64 +clone 1128 +clone2 1213 +clone3 +close 1029 +close_range 1460 +connect 1192 +copy_file_range 1347 +creat 1030 +create_module +delete_module 1134 +dipc +dup 1057 +dup2 1070 +dup3 1316 +epoll_create 1243 +epoll_create1 1315 +epoll_ctl 1244 +epoll_ctl_old +epoll_pwait 1305 +epoll_pwait2 1465 +epoll_wait 1245 +epoll_wait_old +eventfd 1309 +eventfd2 1314 +exec_with_loader +execv +execve 1033 +execveat 1342 +exit 1025 +exit_group 1236 +faccessat 1293 +faccessat2 1463 +fadvise64 1234 +fadvise64_64 +fallocate 1303 +fanotify_init 1323 +fanotify_mark 1324 +fchdir 1035 +fchmod 1099 +fchmodat 1292 +fchown 1100 +fchown32 +fchownat 1284 +fcntl 1066 +fcntl64 +fdatasync 1052 +fgetxattr 1222 +finit_module 1335 +flistxattr 1225 +flock 1145 +fork +fp_udfiex_crtl +fremovexattr 1228 +fsconfig 1455 +fsetxattr 1219 +fsmount 1456 +fsopen 1454 +fspick 1457 +fstat 1212 +fstat64 +fstatat64 +fstatfs 1104 +fstatfs64 1257 +fsync 1051 +ftruncate 1098 +ftruncate64 +futex 1230 +futex_time64 +futimesat 1285 +get_kernel_syms +get_mempolicy 1260 +get_robust_list 1299 +get_thread_area +getcpu 1304 +getcwd 1184 +getdents 1144 +getdents64 1214 +getdomainname +getdtablesize +getegid 1063 +getegid32 +geteuid 1047 +geteuid32 +getgid 1062 +getgid32 +getgroups 1077 +getgroups32 +gethostname +getitimer 1119 +getpagesize +getpeername 1196 +getpgid 1079 +getpgrp +getpid 1041 +getpmsg 1188 +getppid 1042 +getpriority 1101 +getrandom 1339 +getresgid 1075 +getresgid32 +getresuid 1073 +getresuid32 +getrlimit 1085 +getrusage 1086 +getsid 1082 +getsockname 1195 +getsockopt 1204 +gettid 1105 +gettimeofday 1087 +getuid 1046 +getuid32 +getunwind 1215 +getxattr 1220 +getxgid +getxpid +getxuid +idle +init_module 1133 +inotify_add_watch 1278 +inotify_init 1277 +inotify_init1 1318 +inotify_rm_watch 1279 +io_cancel 1242 +io_destroy 1239 +io_getevents 1240 +io_pgetevents 1351 +io_pgetevents_time64 +io_setup 1238 +io_submit 1241 +io_uring_enter 1450 +io_uring_register 1451 +io_uring_setup 1449 +ioctl 1065 +ioperm +iopl +ioprio_get 1275 +ioprio_set 1274 +ipc +kcmp 1345 +kern_features +kexec_file_load +kexec_load 1268 +keyctl 1273 +kill 1053 +lchown 1124 +lchown32 +lgetxattr 1221 +link 1031 +linkat 1289 +listen 1193 +listxattr 1223 +llistxattr 1224 +lookup_dcookie 1237 +lremovexattr 1227 +lseek 1040 +lsetxattr 1218 +lstat 1211 +lstat64 +madvise 1209 +mbind 1259 +membarrier 1344 +memfd_create 1340 +memory_ordering +migrate_pages 1280 +mincore 1208 +mkdir 1055 +mkdirat 1282 +mknod 1037 +mknodat 1283 +mlock 1153 +mlock2 1346 +mlockall 1154 +mmap 1151 +mmap2 1172 +modify_ldt +mount 1043 +mount_setattr 1466 +move_mount 1453 +move_pages 1276 +mprotect 1155 +mq_getsetattr 1267 +mq_notify 1266 +mq_open 1262 +mq_timedreceive 1265 +mq_timedreceive_time64 +mq_timedsend 1264 +mq_timedsend_time64 +mq_unlink 1263 +mremap 1156 +msgctl 1112 +msgget 1109 +msgrcv 1111 +msgsnd 1110 +msync 1157 +multiplexer +munlock 1158 +munlockall 1159 +munmap 1152 +name_to_handle_at 1326 +nanosleep 1168 +newfstatat 1286 +nfsservctl 1169 +nice +old_adjtimex +old_getpagesize 1171 +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 1028 +open_by_handle_at 1327 +open_tree 1452 +openat 1281 +openat2 1461 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause +pciconfig_iobase +pciconfig_read 1173 +pciconfig_write 1174 +perf_event_open 1352 +perfctr +perfmonctl 1175 +personality 1140 +pidfd_getfd 1462 +pidfd_open 1458 +pidfd_send_signal 1448 +pipe 1058 +pipe2 1317 +pivot_root 1207 +pkey_alloc 1355 +pkey_free 1356 +pkey_mprotect 1354 +poll 1090 +ppoll 1295 +ppoll_time64 +prctl 1170 +pread64 1148 +preadv 1319 +preadv2 1348 +prlimit64 1325 +process_madvise 1464 +process_vm_readv 1332 +process_vm_writev 1333 +pselect6 1294 +pselect6_time64 +ptrace 1048 +pwrite64 1149 +pwritev 1320 +pwritev2 1349 +query_module +quotactl 1137 +read 1026 +readahead 1216 +readdir +readlink 1092 +readlinkat 1291 +readv 1146 +reboot 1096 +recv 1200 +recvfrom 1201 +recvmmsg 1322 +recvmmsg_time64 +recvmsg 1206 +remap_file_pages 1125 +removexattr 1226 +rename 1054 +renameat 1288 +renameat2 1338 +request_key 1272 +restart_syscall 1246 +riscv_flush_icache +rmdir 1056 +rseq 1357 +rt_sigaction 1177 +rt_sigpending 1178 +rt_sigprocmask 1179 +rt_sigqueueinfo 1180 +rt_sigreturn 1181 +rt_sigsuspend 1182 +rt_sigtimedwait 1183 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 1321 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 1165 +sched_get_priority_min 1166 +sched_getaffinity 1232 +sched_getattr 1337 +sched_getparam 1160 +sched_getscheduler 1162 +sched_rr_get_interval 1167 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 1231 +sched_setattr 1336 +sched_setparam 1161 +sched_setscheduler 1163 +sched_yield 1164 +seccomp 1353 +select 1089 +semctl 1108 +semget 1106 +semop 1107 +semtimedop 1247 +semtimedop_time64 +send 1198 +sendfile 1187 +sendfile64 +sendmmsg 1331 +sendmsg 1205 +sendto 1199 +set_mempolicy 1261 +set_robust_list 1298 +set_thread_area +set_tid_address 1233 +setdomainname 1129 +setfsgid 1143 +setfsgid32 +setfsuid 1142 +setfsuid32 +setgid 1061 +setgid32 +setgroups 1078 +setgroups32 +sethae +sethostname 1083 +setitimer 1118 +setns 1330 +setpgid 1080 +setpgrp +setpriority 1102 +setregid 1072 +setregid32 +setresgid 1076 +setresgid32 +setresuid 1074 +setresuid32 +setreuid 1071 +setreuid32 +setrlimit 1084 +setsid 1081 +setsockopt 1203 +settimeofday 1088 +setuid 1045 +setuid32 +setxattr 1217 +sgetmask +shmat 1114 +shmctl 1116 +shmdt 1115 +shmget 1113 +shutdown 1202 +sigaction +sigaltstack 1176 +signal +signalfd 1307 +signalfd4 1313 +sigpending +sigprocmask +sigreturn +sigsuspend +socket 1190 +socketcall +socketpair 1197 +splice 1297 +spu_create +spu_run +ssetmask +stat 1210 +stat64 +statfs 1103 +statfs64 1258 +statx 1350 +stime +subpage_prot +swapcontext +swapoff 1095 +swapon 1094 +switch_endian +symlink 1091 +symlinkat 1290 +sync 1050 +sync_file_range 1300 +sync_file_range2 +syncfs 1329 +sys_debug_setcontext +syscall +sysfs 1139 +sysinfo 1127 +syslog 1117 +sysmips +tee 1301 +tgkill 1235 +time +timer_create 1248 +timer_delete 1252 +timer_getoverrun 1251 +timer_gettime 1250 +timer_gettime64 +timer_settime 1249 +timer_settime64 +timerfd 1308 +timerfd_create 1310 +timerfd_gettime 1312 +timerfd_gettime64 +timerfd_settime 1311 +timerfd_settime64 +times 1059 +tkill 1229 +truncate 1097 +truncate64 +ugetrlimit +umask 1067 +umount 1044 +umount2 1044 +uname 1130 +unlink 1032 +unlinkat 1287 +unshare 1296 +uselib 1093 +userfaultfd 1343 +ustat 1069 +utime +utimensat 1306 +utimensat_time64 +utimes 1036 +utrap_install +vfork +vhangup 1123 +vm86 +vm86old +vmsplice 1302 +wait4 1126 +waitid 1270 +waitpid +write 1027 +writev 1147 diff --git a/src/basic/syscalls-m68k.txt b/src/basic/syscalls-m68k.txt new file mode 100644 index 000000000..06c34dd8f --- /dev/null +++ b/src/basic/syscalls-m68k.txt @@ -0,0 +1,594 @@ +_llseek 140 +_newselect 142 +_sysctl 149 +accept +accept4 361 +access 33 +acct 51 +add_key 279 +adjtimex 124 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier 336 +atomic_cmpxchg_32 335 +bdflush 134 +bind 358 +bpf 354 +brk 45 +cachectl +cacheflush 123 +capget 184 +capset 185 +chdir 12 +chmod 15 +chown 16 +chown32 198 +chroot 61 +clock_adjtime 342 +clock_adjtime64 405 +clock_getres 261 +clock_getres_time64 406 +clock_gettime 260 +clock_gettime64 403 +clock_nanosleep 262 +clock_nanosleep_time64 407 +clock_settime 259 +clock_settime64 404 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 359 +copy_file_range 376 +creat 8 +create_module 127 +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 326 +epoll_create 249 +epoll_create1 325 +epoll_ctl 250 +epoll_ctl_old +epoll_pwait 315 +epoll_pwait2 441 +epoll_wait 251 +epoll_wait_old +eventfd 319 +eventfd2 324 +exec_with_loader +execv +execve 11 +execveat 355 +exit 1 +exit_group 247 +faccessat 300 +faccessat2 439 +fadvise64 246 +fadvise64_64 267 +fallocate 320 +fanotify_init 337 +fanotify_mark 338 +fchdir 133 +fchmod 94 +fchmodat 299 +fchown 95 +fchown32 207 +fchownat 291 +fcntl 55 +fcntl64 239 +fdatasync 148 +fgetxattr 228 +finit_module 348 +flistxattr 231 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 234 +fsconfig 431 +fsetxattr 225 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 197 +fstatat64 293 +fstatfs 100 +fstatfs64 264 +fsync 118 +ftruncate 93 +ftruncate64 194 +futex 235 +futex_time64 422 +futimesat 292 +get_kernel_syms 130 +get_mempolicy 269 +get_robust_list 305 +get_thread_area 333 +getcpu 314 +getcwd 183 +getdents 141 +getdents64 220 +getdomainname +getdtablesize +getegid 50 +getegid32 202 +geteuid 49 +geteuid32 201 +getgid 47 +getgid32 200 +getgroups 80 +getgroups32 205 +gethostname +getitimer 105 +getpagesize 166 +getpeername 365 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg 188 +getppid 64 +getpriority 96 +getrandom 352 +getresgid 171 +getresgid32 211 +getresuid 165 +getresuid32 209 +getrlimit 76 +getrusage 77 +getsid 147 +getsockname 364 +getsockopt 362 +gettid 221 +gettimeofday 78 +getuid 24 +getuid32 199 +getunwind +getxattr 226 +getxgid +getxpid +getxuid +idle +init_module 128 +inotify_add_watch 285 +inotify_init 284 +inotify_init1 328 +inotify_rm_watch 286 +io_cancel 245 +io_destroy 242 +io_getevents 243 +io_pgetevents +io_pgetevents_time64 416 +io_setup 241 +io_submit 244 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm +iopl +ioprio_get 283 +ioprio_set 282 +ipc 117 +kcmp 347 +kern_features +kexec_file_load +kexec_load 313 +keyctl 281 +kill 37 +lchown 182 +lchown32 212 +lgetxattr 227 +link 9 +linkat 296 +listen 360 +listxattr 229 +llistxattr 230 +lookup_dcookie 248 +lremovexattr 233 +lseek 19 +lsetxattr 224 +lstat 107 +lstat64 196 +madvise 238 +mbind 268 +membarrier 374 +memfd_create 353 +memory_ordering +migrate_pages 287 +mincore 237 +mkdir 39 +mkdirat 289 +mknod 14 +mknodat 290 +mlock 150 +mlock2 375 +mlockall 152 +mmap 90 +mmap2 192 +modify_ldt +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 310 +mprotect 125 +mq_getsetattr 276 +mq_notify 275 +mq_open 271 +mq_timedreceive 274 +mq_timedreceive_time64 419 +mq_timedsend 273 +mq_timedsend_time64 418 +mq_unlink 272 +mremap 163 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 144 +multiplexer +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 340 +nanosleep 162 +newfstatat +nfsservctl 169 +nice 34 +old_adjtimex +old_getpagesize +oldfstat 28 +oldlstat 84 +oldolduname +oldstat 18 +oldumount +olduname +open 5 +open_by_handle_at 341 +open_tree 428 +openat 288 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 332 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 327 +pivot_root 217 +pkey_alloc 382 +pkey_free 383 +pkey_mprotect 381 +poll 168 +ppoll 302 +ppoll_time64 414 +prctl 172 +pread64 180 +preadv 329 +preadv2 377 +prlimit64 339 +process_madvise 440 +process_vm_readv 345 +process_vm_writev 346 +pselect6 301 +pselect6_time64 413 +ptrace 26 +pwrite64 181 +pwritev 330 +pwritev2 378 +query_module 167 +quotactl 131 +read 3 +readahead 240 +readdir 89 +readlink 85 +readlinkat 298 +readv 145 +reboot 88 +recv +recvfrom 368 +recvmmsg 371 +recvmmsg_time64 417 +recvmsg 369 +remap_file_pages 252 +removexattr 232 +rename 38 +renameat 295 +renameat2 351 +request_key 280 +restart_syscall 0 +riscv_flush_icache +rmdir 40 +rseq 384 +rt_sigaction 174 +rt_sigpending 176 +rt_sigprocmask 175 +rt_sigqueueinfo 178 +rt_sigreturn 173 +rt_sigsuspend 179 +rt_sigtimedwait 177 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 331 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 312 +sched_getattr 350 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 423 +sched_set_affinity +sched_setaffinity 311 +sched_setattr 349 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 380 +select 82 +semctl 394 +semget 393 +semop +semtimedop +semtimedop_time64 420 +send +sendfile 187 +sendfile64 236 +sendmmsg 372 +sendmsg 367 +sendto 366 +set_mempolicy 270 +set_robust_list 304 +set_thread_area 334 +set_tid_address 253 +setdomainname 121 +setfsgid 139 +setfsgid32 216 +setfsuid 138 +setfsuid32 215 +setgid 46 +setgid32 214 +setgroups 81 +setgroups32 206 +sethae +sethostname 74 +setitimer 104 +setns 344 +setpgid 57 +setpgrp +setpriority 97 +setregid 71 +setregid32 204 +setresgid 170 +setresgid32 210 +setresuid 164 +setresuid32 208 +setreuid 70 +setreuid32 203 +setrlimit 75 +setsid 66 +setsockopt 363 +settimeofday 79 +setuid 23 +setuid32 213 +setxattr 223 +sgetmask 68 +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 370 +sigaction 67 +sigaltstack 186 +signal 48 +signalfd 317 +signalfd4 323 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 356 +socketcall 102 +socketpair 357 +splice 306 +spu_create +spu_run +ssetmask 69 +stat 106 +stat64 195 +statfs 99 +statfs64 263 +statx 379 +stime 25 +subpage_prot +swapcontext +swapoff 115 +swapon 87 +switch_endian +symlink 83 +symlinkat 297 +sync 36 +sync_file_range 307 +sync_file_range2 +syncfs 343 +sys_debug_setcontext +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 308 +tgkill 265 +time 13 +timer_create 254 +timer_delete 258 +timer_getoverrun 257 +timer_gettime 256 +timer_gettime64 408 +timer_settime 255 +timer_settime64 409 +timerfd +timerfd_create 318 +timerfd_gettime 322 +timerfd_gettime64 410 +timerfd_settime 321 +timerfd_settime64 411 +times 43 +tkill 222 +truncate 92 +truncate64 193 +ugetrlimit 191 +umask 60 +umount 22 +umount2 52 +uname 122 +unlink 10 +unlinkat 294 +unshare 303 +uselib 86 +userfaultfd 373 +ustat 62 +utime 30 +utimensat 316 +utimensat_time64 412 +utimes 266 +utrap_install +vfork 190 +vhangup 111 +vm86 +vm86old +vmsplice 309 +wait4 114 +waitid 277 +waitpid 7 +write 4 +writev 146 diff --git a/src/basic/syscalls-mips64.txt b/src/basic/syscalls-mips64.txt new file mode 100644 index 000000000..8b5f32152 --- /dev/null +++ b/src/basic/syscalls-mips64.txt @@ -0,0 +1,594 @@ +_llseek +_newselect 5022 +_sysctl 5152 +accept 5042 +accept4 5293 +access 5020 +acct 5158 +add_key 5239 +adjtimex 5154 +alarm 5037 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush +bind 5048 +bpf 5315 +brk 5012 +cachectl 5198 +cacheflush 5197 +capget 5123 +capset 5124 +chdir 5078 +chmod 5088 +chown 5090 +chown32 +chroot 5156 +clock_adjtime 5300 +clock_adjtime64 +clock_getres 5223 +clock_getres_time64 +clock_gettime 5222 +clock_gettime64 +clock_nanosleep 5224 +clock_nanosleep_time64 +clock_settime 5221 +clock_settime64 +clone 5055 +clone2 +clone3 5435 +close 5003 +close_range 5436 +connect 5041 +copy_file_range 5320 +creat 5083 +create_module 5167 +delete_module 5169 +dipc +dup 5031 +dup2 5032 +dup3 5286 +epoll_create 5207 +epoll_create1 5285 +epoll_ctl 5208 +epoll_ctl_old +epoll_pwait 5272 +epoll_pwait2 5441 +epoll_wait 5209 +epoll_wait_old +eventfd 5278 +eventfd2 5284 +exec_with_loader +execv +execve 5057 +execveat 5316 +exit 5058 +exit_group 5205 +faccessat 5259 +faccessat2 5439 +fadvise64 5215 +fadvise64_64 +fallocate 5279 +fanotify_init 5295 +fanotify_mark 5296 +fchdir 5079 +fchmod 5089 +fchmodat 5258 +fchown 5091 +fchown32 +fchownat 5250 +fcntl 5070 +fcntl64 +fdatasync 5073 +fgetxattr 5185 +finit_module 5307 +flistxattr 5188 +flock 5071 +fork 5056 +fp_udfiex_crtl +fremovexattr 5191 +fsconfig 5431 +fsetxattr 5182 +fsmount 5432 +fsopen 5430 +fspick 5433 +fstat 5005 +fstat64 +fstatat64 +fstatfs 5135 +fstatfs64 +fsync 5072 +ftruncate 5075 +ftruncate64 +futex 5194 +futex_time64 +futimesat 5251 +get_kernel_syms 5170 +get_mempolicy 5228 +get_robust_list 5269 +get_thread_area +getcpu 5271 +getcwd 5077 +getdents 5076 +getdents64 5308 +getdomainname +getdtablesize +getegid 5106 +getegid32 +geteuid 5105 +geteuid32 +getgid 5102 +getgid32 +getgroups 5113 +getgroups32 +gethostname +getitimer 5035 +getpagesize +getpeername 5051 +getpgid 5119 +getpgrp 5109 +getpid 5038 +getpmsg 5174 +getppid 5108 +getpriority 5137 +getrandom 5313 +getresgid 5118 +getresgid32 +getresuid 5116 +getresuid32 +getrlimit 5095 +getrusage 5096 +getsid 5122 +getsockname 5050 +getsockopt 5054 +gettid 5178 +gettimeofday 5094 +getuid 5100 +getuid32 +getunwind +getxattr 5183 +getxgid +getxpid +getxuid +idle +init_module 5168 +inotify_add_watch 5244 +inotify_init 5243 +inotify_init1 5288 +inotify_rm_watch 5245 +io_cancel 5204 +io_destroy 5201 +io_getevents 5202 +io_pgetevents 5328 +io_pgetevents_time64 +io_setup 5200 +io_submit 5203 +io_uring_enter 5426 +io_uring_register 5427 +io_uring_setup 5425 +ioctl 5015 +ioperm +iopl +ioprio_get 5274 +ioprio_set 5273 +ipc +kcmp 5306 +kern_features +kexec_file_load +kexec_load 5270 +keyctl 5241 +kill 5060 +lchown 5092 +lchown32 +lgetxattr 5184 +link 5084 +linkat 5255 +listen 5049 +listxattr 5186 +llistxattr 5187 +lookup_dcookie 5206 +lremovexattr 5190 +lseek 5008 +lsetxattr 5181 +lstat 5006 +lstat64 +madvise 5027 +mbind 5227 +membarrier 5318 +memfd_create 5314 +memory_ordering +migrate_pages 5246 +mincore 5026 +mkdir 5081 +mkdirat 5248 +mknod 5131 +mknodat 5249 +mlock 5146 +mlock2 5319 +mlockall 5148 +mmap 5009 +mmap2 +modify_ldt +mount 5160 +mount_setattr 5442 +move_mount 5429 +move_pages 5267 +mprotect 5010 +mq_getsetattr 5235 +mq_notify 5234 +mq_open 5230 +mq_timedreceive 5233 +mq_timedreceive_time64 +mq_timedsend 5232 +mq_timedsend_time64 +mq_unlink 5231 +mremap 5024 +msgctl 5069 +msgget 5066 +msgrcv 5068 +msgsnd 5067 +msync 5025 +multiplexer +munlock 5147 +munlockall 5149 +munmap 5011 +name_to_handle_at 5298 +nanosleep 5034 +newfstatat 5252 +nfsservctl 5173 +nice +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 5002 +open_by_handle_at 5299 +open_tree 5428 +openat 5247 +openat2 5437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 5033 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 5292 +perfctr +perfmonctl +personality 5132 +pidfd_getfd 5438 +pidfd_open 5434 +pidfd_send_signal 5424 +pipe 5021 +pipe2 5287 +pivot_root 5151 +pkey_alloc 5324 +pkey_free 5325 +pkey_mprotect 5323 +poll 5007 +ppoll 5261 +ppoll_time64 +prctl 5153 +pread64 5016 +preadv 5289 +preadv2 5321 +prlimit64 5297 +process_madvise 5440 +process_vm_readv 5304 +process_vm_writev 5305 +pselect6 5260 +pselect6_time64 +ptrace 5099 +pwrite64 5017 +pwritev 5290 +pwritev2 5322 +query_module 5171 +quotactl 5172 +read 5000 +readahead 5179 +readdir +readlink 5087 +readlinkat 5257 +readv 5018 +reboot 5164 +recv +recvfrom 5044 +recvmmsg 5294 +recvmmsg_time64 +recvmsg 5046 +remap_file_pages 5210 +removexattr 5189 +rename 5080 +renameat 5254 +renameat2 5311 +request_key 5240 +restart_syscall 5213 +riscv_flush_icache +rmdir 5082 +rseq 5327 +rt_sigaction 5013 +rt_sigpending 5125 +rt_sigprocmask 5014 +rt_sigqueueinfo 5127 +rt_sigreturn 5211 +rt_sigsuspend 5128 +rt_sigtimedwait 5126 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 5291 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 5143 +sched_get_priority_min 5144 +sched_getaffinity 5196 +sched_getattr 5310 +sched_getparam 5140 +sched_getscheduler 5142 +sched_rr_get_interval 5145 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 5195 +sched_setattr 5309 +sched_setparam 5139 +sched_setscheduler 5141 +sched_yield 5023 +seccomp 5312 +select +semctl 5064 +semget 5062 +semop 5063 +semtimedop 5214 +semtimedop_time64 +send +sendfile 5039 +sendfile64 +sendmmsg 5302 +sendmsg 5045 +sendto 5043 +set_mempolicy 5229 +set_robust_list 5268 +set_thread_area 5242 +set_tid_address 5212 +setdomainname 5166 +setfsgid 5121 +setfsgid32 +setfsuid 5120 +setfsuid32 +setgid 5104 +setgid32 +setgroups 5114 +setgroups32 +sethae +sethostname 5165 +setitimer 5036 +setns 5303 +setpgid 5107 +setpgrp +setpriority 5138 +setregid 5112 +setregid32 +setresgid 5117 +setresgid32 +setresuid 5115 +setresuid32 +setreuid 5111 +setreuid32 +setrlimit 5155 +setsid 5110 +setsockopt 5053 +settimeofday 5159 +setuid 5103 +setuid32 +setxattr 5180 +sgetmask +shmat 5029 +shmctl 5030 +shmdt 5065 +shmget 5028 +shutdown 5047 +sigaction +sigaltstack 5129 +signal +signalfd 5276 +signalfd4 5283 +sigpending +sigprocmask +sigreturn +sigsuspend +socket 5040 +socketcall +socketpair 5052 +splice 5263 +spu_create +spu_run +ssetmask +stat 5004 +stat64 +statfs 5134 +statfs64 +statx 5326 +stime +subpage_prot +swapcontext +swapoff 5163 +swapon 5162 +switch_endian +symlink 5086 +symlinkat 5256 +sync 5157 +sync_file_range 5264 +sync_file_range2 +syncfs 5301 +sys_debug_setcontext +syscall +sysfs 5136 +sysinfo 5097 +syslog 5101 +sysmips 5199 +tee 5265 +tgkill 5225 +time +timer_create 5216 +timer_delete 5220 +timer_getoverrun 5219 +timer_gettime 5218 +timer_gettime64 +timer_settime 5217 +timer_settime64 +timerfd 5277 +timerfd_create 5280 +timerfd_gettime 5281 +timerfd_gettime64 +timerfd_settime 5282 +timerfd_settime64 +times 5098 +tkill 5192 +truncate 5074 +truncate64 +ugetrlimit +umask 5093 +umount +umount2 5161 +uname 5061 +unlink 5085 +unlinkat 5253 +unshare 5262 +uselib +userfaultfd 5317 +ustat 5133 +utime 5130 +utimensat 5275 +utimensat_time64 +utimes 5226 +utrap_install +vfork +vhangup 5150 +vm86 +vm86old +vmsplice 5266 +wait4 5059 +waitid 5237 +waitpid +write 5001 +writev 5019 diff --git a/src/basic/syscalls-mips64n32.txt b/src/basic/syscalls-mips64n32.txt new file mode 100644 index 000000000..51ed6fb63 --- /dev/null +++ b/src/basic/syscalls-mips64n32.txt @@ -0,0 +1,594 @@ +_llseek +_newselect 6022 +_sysctl 6152 +accept 6042 +accept4 6297 +access 6020 +acct 6158 +add_key 6243 +adjtimex 6154 +alarm 6037 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush +bind 6048 +bpf 6319 +brk 6012 +cachectl 6198 +cacheflush 6197 +capget 6123 +capset 6124 +chdir 6078 +chmod 6088 +chown 6090 +chown32 +chroot 6156 +clock_adjtime 6305 +clock_adjtime64 6405 +clock_getres 6227 +clock_getres_time64 6406 +clock_gettime 6226 +clock_gettime64 6403 +clock_nanosleep 6228 +clock_nanosleep_time64 6407 +clock_settime 6225 +clock_settime64 6404 +clone 6055 +clone2 +clone3 6435 +close 6003 +close_range 6436 +connect 6041 +copy_file_range 6324 +creat 6083 +create_module 6167 +delete_module 6169 +dipc +dup 6031 +dup2 6032 +dup3 6290 +epoll_create 6207 +epoll_create1 6289 +epoll_ctl 6208 +epoll_ctl_old +epoll_pwait 6276 +epoll_pwait2 6441 +epoll_wait 6209 +epoll_wait_old +eventfd 6282 +eventfd2 6288 +exec_with_loader +execv +execve 6057 +execveat 6320 +exit 6058 +exit_group 6205 +faccessat 6263 +faccessat2 6439 +fadvise64 6216 +fadvise64_64 +fallocate 6283 +fanotify_init 6300 +fanotify_mark 6301 +fchdir 6079 +fchmod 6089 +fchmodat 6262 +fchown 6091 +fchown32 +fchownat 6254 +fcntl 6070 +fcntl64 6212 +fdatasync 6073 +fgetxattr 6185 +finit_module 6312 +flistxattr 6188 +flock 6071 +fork 6056 +fp_udfiex_crtl +fremovexattr 6191 +fsconfig 6431 +fsetxattr 6182 +fsmount 6432 +fsopen 6430 +fspick 6433 +fstat 6005 +fstat64 +fstatat64 +fstatfs 6135 +fstatfs64 6218 +fsync 6072 +ftruncate 6075 +ftruncate64 +futex 6194 +futex_time64 6422 +futimesat 6255 +get_kernel_syms 6170 +get_mempolicy 6232 +get_robust_list 6273 +get_thread_area +getcpu 6275 +getcwd 6077 +getdents 6076 +getdents64 6299 +getdomainname +getdtablesize +getegid 6106 +getegid32 +geteuid 6105 +geteuid32 +getgid 6102 +getgid32 +getgroups 6113 +getgroups32 +gethostname +getitimer 6035 +getpagesize +getpeername 6051 +getpgid 6119 +getpgrp 6109 +getpid 6038 +getpmsg 6174 +getppid 6108 +getpriority 6137 +getrandom 6317 +getresgid 6118 +getresgid32 +getresuid 6116 +getresuid32 +getrlimit 6095 +getrusage 6096 +getsid 6122 +getsockname 6050 +getsockopt 6054 +gettid 6178 +gettimeofday 6094 +getuid 6100 +getuid32 +getunwind +getxattr 6183 +getxgid +getxpid +getxuid +idle +init_module 6168 +inotify_add_watch 6248 +inotify_init 6247 +inotify_init1 6292 +inotify_rm_watch 6249 +io_cancel 6204 +io_destroy 6201 +io_getevents 6202 +io_pgetevents 6332 +io_pgetevents_time64 6416 +io_setup 6200 +io_submit 6203 +io_uring_enter 6426 +io_uring_register 6427 +io_uring_setup 6425 +ioctl 6015 +ioperm +iopl +ioprio_get 6278 +ioprio_set 6277 +ipc +kcmp 6311 +kern_features +kexec_file_load +kexec_load 6274 +keyctl 6245 +kill 6060 +lchown 6092 +lchown32 +lgetxattr 6184 +link 6084 +linkat 6259 +listen 6049 +listxattr 6186 +llistxattr 6187 +lookup_dcookie 6206 +lremovexattr 6190 +lseek 6008 +lsetxattr 6181 +lstat 6006 +lstat64 +madvise 6027 +mbind 6231 +membarrier 6322 +memfd_create 6318 +memory_ordering +migrate_pages 6250 +mincore 6026 +mkdir 6081 +mkdirat 6252 +mknod 6131 +mknodat 6253 +mlock 6146 +mlock2 6323 +mlockall 6148 +mmap 6009 +mmap2 +modify_ldt +mount 6160 +mount_setattr 6442 +move_mount 6429 +move_pages 6271 +mprotect 6010 +mq_getsetattr 6239 +mq_notify 6238 +mq_open 6234 +mq_timedreceive 6237 +mq_timedreceive_time64 6419 +mq_timedsend 6236 +mq_timedsend_time64 6418 +mq_unlink 6235 +mremap 6024 +msgctl 6069 +msgget 6066 +msgrcv 6068 +msgsnd 6067 +msync 6025 +multiplexer +munlock 6147 +munlockall 6149 +munmap 6011 +name_to_handle_at 6303 +nanosleep 6034 +newfstatat 6256 +nfsservctl 6173 +nice +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 6002 +open_by_handle_at 6304 +open_tree 6428 +openat 6251 +openat2 6437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 6033 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 6296 +perfctr +perfmonctl +personality 6132 +pidfd_getfd 6438 +pidfd_open 6434 +pidfd_send_signal 6424 +pipe 6021 +pipe2 6291 +pivot_root 6151 +pkey_alloc 6328 +pkey_free 6329 +pkey_mprotect 6327 +poll 6007 +ppoll 6265 +ppoll_time64 6414 +prctl 6153 +pread64 6016 +preadv 6293 +preadv2 6325 +prlimit64 6302 +process_madvise 6440 +process_vm_readv 6309 +process_vm_writev 6310 +pselect6 6264 +pselect6_time64 6413 +ptrace 6099 +pwrite64 6017 +pwritev 6294 +pwritev2 6326 +query_module 6171 +quotactl 6172 +read 6000 +readahead 6179 +readdir +readlink 6087 +readlinkat 6261 +readv 6018 +reboot 6164 +recv +recvfrom 6044 +recvmmsg 6298 +recvmmsg_time64 6417 +recvmsg 6046 +remap_file_pages 6210 +removexattr 6189 +rename 6080 +renameat 6258 +renameat2 6315 +request_key 6244 +restart_syscall 6214 +riscv_flush_icache +rmdir 6082 +rseq 6331 +rt_sigaction 6013 +rt_sigpending 6125 +rt_sigprocmask 6014 +rt_sigqueueinfo 6127 +rt_sigreturn 6211 +rt_sigsuspend 6128 +rt_sigtimedwait 6126 +rt_sigtimedwait_time64 6421 +rt_tgsigqueueinfo 6295 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 6143 +sched_get_priority_min 6144 +sched_getaffinity 6196 +sched_getattr 6314 +sched_getparam 6140 +sched_getscheduler 6142 +sched_rr_get_interval 6145 +sched_rr_get_interval_time64 6423 +sched_set_affinity +sched_setaffinity 6195 +sched_setattr 6313 +sched_setparam 6139 +sched_setscheduler 6141 +sched_yield 6023 +seccomp 6316 +select +semctl 6064 +semget 6062 +semop 6063 +semtimedop 6215 +semtimedop_time64 6420 +send +sendfile 6039 +sendfile64 6219 +sendmmsg 6307 +sendmsg 6045 +sendto 6043 +set_mempolicy 6233 +set_robust_list 6272 +set_thread_area 6246 +set_tid_address 6213 +setdomainname 6166 +setfsgid 6121 +setfsgid32 +setfsuid 6120 +setfsuid32 +setgid 6104 +setgid32 +setgroups 6114 +setgroups32 +sethae +sethostname 6165 +setitimer 6036 +setns 6308 +setpgid 6107 +setpgrp +setpriority 6138 +setregid 6112 +setregid32 +setresgid 6117 +setresgid32 +setresuid 6115 +setresuid32 +setreuid 6111 +setreuid32 +setrlimit 6155 +setsid 6110 +setsockopt 6053 +settimeofday 6159 +setuid 6103 +setuid32 +setxattr 6180 +sgetmask +shmat 6029 +shmctl 6030 +shmdt 6065 +shmget 6028 +shutdown 6047 +sigaction +sigaltstack 6129 +signal +signalfd 6280 +signalfd4 6287 +sigpending +sigprocmask +sigreturn +sigsuspend +socket 6040 +socketcall +socketpair 6052 +splice 6267 +spu_create +spu_run +ssetmask +stat 6004 +stat64 +statfs 6134 +statfs64 6217 +statx 6330 +stime +subpage_prot +swapcontext +swapoff 6163 +swapon 6162 +switch_endian +symlink 6086 +symlinkat 6260 +sync 6157 +sync_file_range 6268 +sync_file_range2 +syncfs 6306 +sys_debug_setcontext +syscall +sysfs 6136 +sysinfo 6097 +syslog 6101 +sysmips 6199 +tee 6269 +tgkill 6229 +time +timer_create 6220 +timer_delete 6224 +timer_getoverrun 6223 +timer_gettime 6222 +timer_gettime64 6408 +timer_settime 6221 +timer_settime64 6409 +timerfd 6281 +timerfd_create 6284 +timerfd_gettime 6285 +timerfd_gettime64 6410 +timerfd_settime 6286 +timerfd_settime64 6411 +times 6098 +tkill 6192 +truncate 6074 +truncate64 +ugetrlimit +umask 6093 +umount +umount2 6161 +uname 6061 +unlink 6085 +unlinkat 6257 +unshare 6266 +uselib +userfaultfd 6321 +ustat 6133 +utime 6130 +utimensat 6279 +utimensat_time64 6412 +utimes 6230 +utrap_install +vfork +vhangup 6150 +vm86 +vm86old +vmsplice 6270 +wait4 6059 +waitid 6241 +waitpid +write 6001 +writev 6019 diff --git a/src/basic/syscalls-mipso32.txt b/src/basic/syscalls-mipso32.txt new file mode 100644 index 000000000..0e977111e --- /dev/null +++ b/src/basic/syscalls-mipso32.txt @@ -0,0 +1,594 @@ +_llseek 4140 +_newselect 4142 +_sysctl 4153 +accept 4168 +accept4 4334 +access 4033 +acct 4051 +add_key 4280 +adjtimex 4124 +alarm 4027 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 4134 +bind 4169 +bpf 4355 +brk 4045 +cachectl 4148 +cacheflush 4147 +capget 4204 +capset 4205 +chdir 4012 +chmod 4015 +chown 4202 +chown32 +chroot 4061 +clock_adjtime 4341 +clock_adjtime64 4405 +clock_getres 4264 +clock_getres_time64 4406 +clock_gettime 4263 +clock_gettime64 4403 +clock_nanosleep 4265 +clock_nanosleep_time64 4407 +clock_settime 4262 +clock_settime64 4404 +clone 4120 +clone2 +clone3 4435 +close 4006 +close_range 4436 +connect 4170 +copy_file_range 4360 +creat 4008 +create_module 4127 +delete_module 4129 +dipc +dup 4041 +dup2 4063 +dup3 4327 +epoll_create 4248 +epoll_create1 4326 +epoll_ctl 4249 +epoll_ctl_old +epoll_pwait 4313 +epoll_pwait2 4441 +epoll_wait 4250 +epoll_wait_old +eventfd 4319 +eventfd2 4325 +exec_with_loader +execv +execve 4011 +execveat 4356 +exit 4001 +exit_group 4246 +faccessat 4300 +faccessat2 4439 +fadvise64 4254 +fadvise64_64 +fallocate 4320 +fanotify_init 4336 +fanotify_mark 4337 +fchdir 4133 +fchmod 4094 +fchmodat 4299 +fchown 4095 +fchown32 +fchownat 4291 +fcntl 4055 +fcntl64 4220 +fdatasync 4152 +fgetxattr 4229 +finit_module 4348 +flistxattr 4232 +flock 4143 +fork 4002 +fp_udfiex_crtl +fremovexattr 4235 +fsconfig 4431 +fsetxattr 4226 +fsmount 4432 +fsopen 4430 +fspick 4433 +fstat 4108 +fstat64 4215 +fstatat64 4293 +fstatfs 4100 +fstatfs64 4256 +fsync 4118 +ftruncate 4093 +ftruncate64 4212 +futex 4238 +futex_time64 4422 +futimesat 4292 +get_kernel_syms 4130 +get_mempolicy 4269 +get_robust_list 4310 +get_thread_area +getcpu 4312 +getcwd 4203 +getdents 4141 +getdents64 4219 +getdomainname +getdtablesize +getegid 4050 +getegid32 +geteuid 4049 +geteuid32 +getgid 4047 +getgid32 +getgroups 4080 +getgroups32 +gethostname +getitimer 4105 +getpagesize +getpeername 4171 +getpgid 4132 +getpgrp 4065 +getpid 4020 +getpmsg 4208 +getppid 4064 +getpriority 4096 +getrandom 4353 +getresgid 4191 +getresgid32 +getresuid 4186 +getresuid32 +getrlimit 4076 +getrusage 4077 +getsid 4151 +getsockname 4172 +getsockopt 4173 +gettid 4222 +gettimeofday 4078 +getuid 4024 +getuid32 +getunwind +getxattr 4227 +getxgid +getxpid +getxuid +idle 4112 +init_module 4128 +inotify_add_watch 4285 +inotify_init 4284 +inotify_init1 4329 +inotify_rm_watch 4286 +io_cancel 4245 +io_destroy 4242 +io_getevents 4243 +io_pgetevents 4368 +io_pgetevents_time64 4416 +io_setup 4241 +io_submit 4244 +io_uring_enter 4426 +io_uring_register 4427 +io_uring_setup 4425 +ioctl 4054 +ioperm 4101 +iopl 4110 +ioprio_get 4315 +ioprio_set 4314 +ipc 4117 +kcmp 4347 +kern_features +kexec_file_load +kexec_load 4311 +keyctl 4282 +kill 4037 +lchown 4016 +lchown32 +lgetxattr 4228 +link 4009 +linkat 4296 +listen 4174 +listxattr 4230 +llistxattr 4231 +lookup_dcookie 4247 +lremovexattr 4234 +lseek 4019 +lsetxattr 4225 +lstat 4107 +lstat64 4214 +madvise 4218 +mbind 4268 +membarrier 4358 +memfd_create 4354 +memory_ordering +migrate_pages 4287 +mincore 4217 +mkdir 4039 +mkdirat 4289 +mknod 4014 +mknodat 4290 +mlock 4154 +mlock2 4359 +mlockall 4156 +mmap 4090 +mmap2 4210 +modify_ldt 4123 +mount 4021 +mount_setattr 4442 +move_mount 4429 +move_pages 4308 +mprotect 4125 +mq_getsetattr 4276 +mq_notify 4275 +mq_open 4271 +mq_timedreceive 4274 +mq_timedreceive_time64 4419 +mq_timedsend 4273 +mq_timedsend_time64 4418 +mq_unlink 4272 +mremap 4167 +msgctl 4402 +msgget 4399 +msgrcv 4401 +msgsnd 4400 +msync 4144 +multiplexer +munlock 4155 +munlockall 4157 +munmap 4091 +name_to_handle_at 4339 +nanosleep 4166 +newfstatat +nfsservctl 4189 +nice 4034 +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 4005 +open_by_handle_at 4340 +open_tree 4428 +openat 4288 +openat2 4437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 4029 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 4333 +perfctr +perfmonctl +personality 4136 +pidfd_getfd 4438 +pidfd_open 4434 +pidfd_send_signal 4424 +pipe 4042 +pipe2 4328 +pivot_root 4216 +pkey_alloc 4364 +pkey_free 4365 +pkey_mprotect 4363 +poll 4188 +ppoll 4302 +ppoll_time64 4414 +prctl 4192 +pread64 4200 +preadv 4330 +preadv2 4361 +prlimit64 4338 +process_madvise 4440 +process_vm_readv 4345 +process_vm_writev 4346 +pselect6 4301 +pselect6_time64 4413 +ptrace 4026 +pwrite64 4201 +pwritev 4331 +pwritev2 4362 +query_module 4187 +quotactl 4131 +read 4003 +readahead 4223 +readdir 4089 +readlink 4085 +readlinkat 4298 +readv 4145 +reboot 4088 +recv 4175 +recvfrom 4176 +recvmmsg 4335 +recvmmsg_time64 4417 +recvmsg 4177 +remap_file_pages 4251 +removexattr 4233 +rename 4038 +renameat 4295 +renameat2 4351 +request_key 4281 +restart_syscall 4253 +riscv_flush_icache +rmdir 4040 +rseq 4367 +rt_sigaction 4194 +rt_sigpending 4196 +rt_sigprocmask 4195 +rt_sigqueueinfo 4198 +rt_sigreturn 4193 +rt_sigsuspend 4199 +rt_sigtimedwait 4197 +rt_sigtimedwait_time64 4421 +rt_tgsigqueueinfo 4332 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 4163 +sched_get_priority_min 4164 +sched_getaffinity 4240 +sched_getattr 4350 +sched_getparam 4159 +sched_getscheduler 4161 +sched_rr_get_interval 4165 +sched_rr_get_interval_time64 4423 +sched_set_affinity +sched_setaffinity 4239 +sched_setattr 4349 +sched_setparam 4158 +sched_setscheduler 4160 +sched_yield 4162 +seccomp 4352 +select +semctl 4394 +semget 4393 +semop +semtimedop +semtimedop_time64 4420 +send 4178 +sendfile 4207 +sendfile64 4237 +sendmmsg 4343 +sendmsg 4179 +sendto 4180 +set_mempolicy 4270 +set_robust_list 4309 +set_thread_area 4283 +set_tid_address 4252 +setdomainname 4121 +setfsgid 4139 +setfsgid32 +setfsuid 4138 +setfsuid32 +setgid 4046 +setgid32 +setgroups 4081 +setgroups32 +sethae +sethostname 4074 +setitimer 4104 +setns 4344 +setpgid 4057 +setpgrp +setpriority 4097 +setregid 4071 +setregid32 +setresgid 4190 +setresgid32 +setresuid 4185 +setresuid32 +setreuid 4070 +setreuid32 +setrlimit 4075 +setsid 4066 +setsockopt 4181 +settimeofday 4079 +setuid 4023 +setuid32 +setxattr 4224 +sgetmask 4068 +shmat 4397 +shmctl 4396 +shmdt 4398 +shmget 4395 +shutdown 4182 +sigaction 4067 +sigaltstack 4206 +signal 4048 +signalfd 4317 +signalfd4 4324 +sigpending 4073 +sigprocmask 4126 +sigreturn 4119 +sigsuspend 4072 +socket 4183 +socketcall 4102 +socketpair 4184 +splice 4304 +spu_create +spu_run +ssetmask 4069 +stat 4106 +stat64 4213 +statfs 4099 +statfs64 4255 +statx 4366 +stime 4025 +subpage_prot +swapcontext +swapoff 4115 +swapon 4087 +switch_endian +symlink 4083 +symlinkat 4297 +sync 4036 +sync_file_range 4305 +sync_file_range2 +syncfs 4342 +sys_debug_setcontext +syscall 4000 +sysfs 4135 +sysinfo 4116 +syslog 4103 +sysmips 4149 +tee 4306 +tgkill 4266 +time 4013 +timer_create 4257 +timer_delete 4261 +timer_getoverrun 4260 +timer_gettime 4259 +timer_gettime64 4408 +timer_settime 4258 +timer_settime64 4409 +timerfd 4318 +timerfd_create 4321 +timerfd_gettime 4322 +timerfd_gettime64 4410 +timerfd_settime 4323 +timerfd_settime64 4411 +times 4043 +tkill 4236 +truncate 4092 +truncate64 4211 +ugetrlimit +umask 4060 +umount 4022 +umount2 4052 +uname 4122 +unlink 4010 +unlinkat 4294 +unshare 4303 +uselib 4086 +userfaultfd 4357 +ustat 4062 +utime 4030 +utimensat 4316 +utimensat_time64 4412 +utimes 4267 +utrap_install +vfork +vhangup 4111 +vm86 4113 +vm86old +vmsplice 4307 +wait4 4114 +waitid 4278 +waitpid 4007 +write 4004 +writev 4146 diff --git a/src/basic/syscalls-powerpc.txt b/src/basic/syscalls-powerpc.txt new file mode 100644 index 000000000..3df924989 --- /dev/null +++ b/src/basic/syscalls-powerpc.txt @@ -0,0 +1,594 @@ +_llseek 140 +_newselect 142 +_sysctl 149 +accept 330 +accept4 344 +access 33 +acct 51 +add_key 269 +adjtimex 124 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 134 +bind 327 +bpf 361 +brk 45 +cachectl +cacheflush +capget 183 +capset 184 +chdir 12 +chmod 15 +chown 181 +chown32 +chroot 61 +clock_adjtime 347 +clock_adjtime64 405 +clock_getres 247 +clock_getres_time64 406 +clock_gettime 246 +clock_gettime64 403 +clock_nanosleep 248 +clock_nanosleep_time64 407 +clock_settime 245 +clock_settime64 404 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 328 +copy_file_range 379 +creat 8 +create_module 127 +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 316 +epoll_create 236 +epoll_create1 315 +epoll_ctl 237 +epoll_ctl_old +epoll_pwait 303 +epoll_pwait2 441 +epoll_wait 238 +epoll_wait_old +eventfd 307 +eventfd2 314 +exec_with_loader +execv +execve 11 +execveat 362 +exit 1 +exit_group 234 +faccessat 298 +faccessat2 439 +fadvise64 233 +fadvise64_64 254 +fallocate 309 +fanotify_init 323 +fanotify_mark 324 +fchdir 133 +fchmod 94 +fchmodat 297 +fchown 95 +fchown32 +fchownat 289 +fcntl 55 +fcntl64 204 +fdatasync 148 +fgetxattr 214 +finit_module 353 +flistxattr 217 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 220 +fsconfig 431 +fsetxattr 211 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 197 +fstatat64 291 +fstatfs 100 +fstatfs64 253 +fsync 118 +ftruncate 93 +ftruncate64 194 +futex 221 +futex_time64 422 +futimesat 290 +get_kernel_syms 130 +get_mempolicy 260 +get_robust_list 299 +get_thread_area +getcpu 302 +getcwd 182 +getdents 141 +getdents64 202 +getdomainname +getdtablesize +getegid 50 +getegid32 +geteuid 49 +geteuid32 +getgid 47 +getgid32 +getgroups 80 +getgroups32 +gethostname +getitimer 105 +getpagesize +getpeername 332 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg 187 +getppid 64 +getpriority 96 +getrandom 359 +getresgid 170 +getresgid32 +getresuid 165 +getresuid32 +getrlimit 76 +getrusage 77 +getsid 147 +getsockname 331 +getsockopt 340 +gettid 207 +gettimeofday 78 +getuid 24 +getuid32 +getunwind +getxattr 212 +getxgid +getxpid +getxuid +idle 112 +init_module 128 +inotify_add_watch 276 +inotify_init 275 +inotify_init1 318 +inotify_rm_watch 277 +io_cancel 231 +io_destroy 228 +io_getevents 229 +io_pgetevents 388 +io_pgetevents_time64 416 +io_setup 227 +io_submit 230 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm 101 +iopl 110 +ioprio_get 274 +ioprio_set 273 +ipc 117 +kcmp 354 +kern_features +kexec_file_load 382 +kexec_load 268 +keyctl 271 +kill 37 +lchown 16 +lchown32 +lgetxattr 213 +link 9 +linkat 294 +listen 329 +listxattr 215 +llistxattr 216 +lookup_dcookie 235 +lremovexattr 219 +lseek 19 +lsetxattr 210 +lstat 107 +lstat64 196 +madvise 205 +mbind 259 +membarrier 365 +memfd_create 360 +memory_ordering +migrate_pages 258 +mincore 206 +mkdir 39 +mkdirat 287 +mknod 14 +mknodat 288 +mlock 150 +mlock2 378 +mlockall 152 +mmap 90 +mmap2 192 +modify_ldt 123 +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 301 +mprotect 125 +mq_getsetattr 267 +mq_notify 266 +mq_open 262 +mq_timedreceive 265 +mq_timedreceive_time64 419 +mq_timedsend 264 +mq_timedsend_time64 418 +mq_unlink 263 +mremap 163 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 144 +multiplexer 201 +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 345 +nanosleep 162 +newfstatat +nfsservctl 168 +nice 34 +old_adjtimex +old_getpagesize +oldfstat 28 +oldlstat 84 +oldolduname 59 +oldstat 18 +oldumount +olduname 109 +open 5 +open_by_handle_at 346 +open_tree 428 +openat 286 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase 200 +pciconfig_read 198 +pciconfig_write 199 +perf_event_open 319 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 317 +pivot_root 203 +pkey_alloc 384 +pkey_free 385 +pkey_mprotect 386 +poll 167 +ppoll 281 +ppoll_time64 414 +prctl 171 +pread64 179 +preadv 320 +preadv2 380 +prlimit64 325 +process_madvise 440 +process_vm_readv 351 +process_vm_writev 352 +pselect6 280 +pselect6_time64 413 +ptrace 26 +pwrite64 180 +pwritev 321 +pwritev2 381 +query_module 166 +quotactl 131 +read 3 +readahead 191 +readdir 89 +readlink 85 +readlinkat 296 +readv 145 +reboot 88 +recv 336 +recvfrom 337 +recvmmsg 343 +recvmmsg_time64 417 +recvmsg 342 +remap_file_pages 239 +removexattr 218 +rename 38 +renameat 293 +renameat2 357 +request_key 270 +restart_syscall 0 +riscv_flush_icache +rmdir 40 +rseq 387 +rt_sigaction 173 +rt_sigpending 175 +rt_sigprocmask 174 +rt_sigqueueinfo 177 +rt_sigreturn 172 +rt_sigsuspend 178 +rt_sigtimedwait 176 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 322 +rtas 255 +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 223 +sched_getattr 356 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 423 +sched_set_affinity +sched_setaffinity 222 +sched_setattr 355 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 358 +select 82 +semctl 394 +semget 393 +semop +semtimedop +semtimedop_time64 420 +send 334 +sendfile 186 +sendfile64 226 +sendmmsg 349 +sendmsg 341 +sendto 335 +set_mempolicy 261 +set_robust_list 300 +set_thread_area +set_tid_address 232 +setdomainname 121 +setfsgid 139 +setfsgid32 +setfsuid 138 +setfsuid32 +setgid 46 +setgid32 +setgroups 81 +setgroups32 +sethae +sethostname 74 +setitimer 104 +setns 350 +setpgid 57 +setpgrp +setpriority 97 +setregid 71 +setregid32 +setresgid 169 +setresgid32 +setresuid 164 +setresuid32 +setreuid 70 +setreuid32 +setrlimit 75 +setsid 66 +setsockopt 339 +settimeofday 79 +setuid 23 +setuid32 +setxattr 209 +sgetmask 68 +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 338 +sigaction 67 +sigaltstack 185 +signal 48 +signalfd 305 +signalfd4 313 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 326 +socketcall 102 +socketpair 333 +splice 283 +spu_create 279 +spu_run 278 +ssetmask 69 +stat 106 +stat64 195 +statfs 99 +statfs64 252 +statx 383 +stime 25 +subpage_prot 310 +swapcontext 249 +swapoff 115 +swapon 87 +switch_endian 363 +symlink 83 +symlinkat 295 +sync 36 +sync_file_range +sync_file_range2 308 +syncfs 348 +sys_debug_setcontext 256 +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 284 +tgkill 250 +time 13 +timer_create 240 +timer_delete 244 +timer_getoverrun 243 +timer_gettime 242 +timer_gettime64 408 +timer_settime 241 +timer_settime64 409 +timerfd +timerfd_create 306 +timerfd_gettime 312 +timerfd_gettime64 410 +timerfd_settime 311 +timerfd_settime64 411 +times 43 +tkill 208 +truncate 92 +truncate64 193 +ugetrlimit 190 +umask 60 +umount 22 +umount2 52 +uname 122 +unlink 10 +unlinkat 292 +unshare 282 +uselib 86 +userfaultfd 364 +ustat 62 +utime 30 +utimensat 304 +utimensat_time64 412 +utimes 251 +utrap_install +vfork 189 +vhangup 111 +vm86 113 +vm86old +vmsplice 285 +wait4 114 +waitid 272 +waitpid 7 +write 4 +writev 146 diff --git a/src/basic/syscalls-powerpc64.txt b/src/basic/syscalls-powerpc64.txt new file mode 100644 index 000000000..492b2c078 --- /dev/null +++ b/src/basic/syscalls-powerpc64.txt @@ -0,0 +1,594 @@ +_llseek 140 +_newselect 142 +_sysctl 149 +accept 330 +accept4 344 +access 33 +acct 51 +add_key 269 +adjtimex 124 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 134 +bind 327 +bpf 361 +brk 45 +cachectl +cacheflush +capget 183 +capset 184 +chdir 12 +chmod 15 +chown 181 +chown32 +chroot 61 +clock_adjtime 347 +clock_adjtime64 +clock_getres 247 +clock_getres_time64 +clock_gettime 246 +clock_gettime64 +clock_nanosleep 248 +clock_nanosleep_time64 +clock_settime 245 +clock_settime64 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 328 +copy_file_range 379 +creat 8 +create_module 127 +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 316 +epoll_create 236 +epoll_create1 315 +epoll_ctl 237 +epoll_ctl_old +epoll_pwait 303 +epoll_pwait2 441 +epoll_wait 238 +epoll_wait_old +eventfd 307 +eventfd2 314 +exec_with_loader +execv +execve 11 +execveat 362 +exit 1 +exit_group 234 +faccessat 298 +faccessat2 439 +fadvise64 233 +fadvise64_64 +fallocate 309 +fanotify_init 323 +fanotify_mark 324 +fchdir 133 +fchmod 94 +fchmodat 297 +fchown 95 +fchown32 +fchownat 289 +fcntl 55 +fcntl64 +fdatasync 148 +fgetxattr 214 +finit_module 353 +flistxattr 217 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 220 +fsconfig 431 +fsetxattr 211 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 +fstatat64 +fstatfs 100 +fstatfs64 253 +fsync 118 +ftruncate 93 +ftruncate64 +futex 221 +futex_time64 +futimesat 290 +get_kernel_syms 130 +get_mempolicy 260 +get_robust_list 299 +get_thread_area +getcpu 302 +getcwd 182 +getdents 141 +getdents64 202 +getdomainname +getdtablesize +getegid 50 +getegid32 +geteuid 49 +geteuid32 +getgid 47 +getgid32 +getgroups 80 +getgroups32 +gethostname +getitimer 105 +getpagesize +getpeername 332 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg 187 +getppid 64 +getpriority 96 +getrandom 359 +getresgid 170 +getresgid32 +getresuid 165 +getresuid32 +getrlimit 76 +getrusage 77 +getsid 147 +getsockname 331 +getsockopt 340 +gettid 207 +gettimeofday 78 +getuid 24 +getuid32 +getunwind +getxattr 212 +getxgid +getxpid +getxuid +idle 112 +init_module 128 +inotify_add_watch 276 +inotify_init 275 +inotify_init1 318 +inotify_rm_watch 277 +io_cancel 231 +io_destroy 228 +io_getevents 229 +io_pgetevents 388 +io_pgetevents_time64 +io_setup 227 +io_submit 230 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm 101 +iopl 110 +ioprio_get 274 +ioprio_set 273 +ipc 117 +kcmp 354 +kern_features +kexec_file_load 382 +kexec_load 268 +keyctl 271 +kill 37 +lchown 16 +lchown32 +lgetxattr 213 +link 9 +linkat 294 +listen 329 +listxattr 215 +llistxattr 216 +lookup_dcookie 235 +lremovexattr 219 +lseek 19 +lsetxattr 210 +lstat 107 +lstat64 +madvise 205 +mbind 259 +membarrier 365 +memfd_create 360 +memory_ordering +migrate_pages 258 +mincore 206 +mkdir 39 +mkdirat 287 +mknod 14 +mknodat 288 +mlock 150 +mlock2 378 +mlockall 152 +mmap 90 +mmap2 +modify_ldt 123 +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 301 +mprotect 125 +mq_getsetattr 267 +mq_notify 266 +mq_open 262 +mq_timedreceive 265 +mq_timedreceive_time64 +mq_timedsend 264 +mq_timedsend_time64 +mq_unlink 263 +mremap 163 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 144 +multiplexer 201 +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 345 +nanosleep 162 +newfstatat 291 +nfsservctl 168 +nice 34 +old_adjtimex +old_getpagesize +oldfstat 28 +oldlstat 84 +oldolduname 59 +oldstat 18 +oldumount +olduname 109 +open 5 +open_by_handle_at 346 +open_tree 428 +openat 286 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase 200 +pciconfig_read 198 +pciconfig_write 199 +perf_event_open 319 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 317 +pivot_root 203 +pkey_alloc 384 +pkey_free 385 +pkey_mprotect 386 +poll 167 +ppoll 281 +ppoll_time64 +prctl 171 +pread64 179 +preadv 320 +preadv2 380 +prlimit64 325 +process_madvise 440 +process_vm_readv 351 +process_vm_writev 352 +pselect6 280 +pselect6_time64 +ptrace 26 +pwrite64 180 +pwritev 321 +pwritev2 381 +query_module 166 +quotactl 131 +read 3 +readahead 191 +readdir 89 +readlink 85 +readlinkat 296 +readv 145 +reboot 88 +recv 336 +recvfrom 337 +recvmmsg 343 +recvmmsg_time64 +recvmsg 342 +remap_file_pages 239 +removexattr 218 +rename 38 +renameat 293 +renameat2 357 +request_key 270 +restart_syscall 0 +riscv_flush_icache +rmdir 40 +rseq 387 +rt_sigaction 173 +rt_sigpending 175 +rt_sigprocmask 174 +rt_sigqueueinfo 177 +rt_sigreturn 172 +rt_sigsuspend 178 +rt_sigtimedwait 176 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 322 +rtas 255 +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 223 +sched_getattr 356 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 222 +sched_setattr 355 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 358 +select 82 +semctl 394 +semget 393 +semop +semtimedop 392 +semtimedop_time64 +send 334 +sendfile 186 +sendfile64 +sendmmsg 349 +sendmsg 341 +sendto 335 +set_mempolicy 261 +set_robust_list 300 +set_thread_area +set_tid_address 232 +setdomainname 121 +setfsgid 139 +setfsgid32 +setfsuid 138 +setfsuid32 +setgid 46 +setgid32 +setgroups 81 +setgroups32 +sethae +sethostname 74 +setitimer 104 +setns 350 +setpgid 57 +setpgrp +setpriority 97 +setregid 71 +setregid32 +setresgid 169 +setresgid32 +setresuid 164 +setresuid32 +setreuid 70 +setreuid32 +setrlimit 75 +setsid 66 +setsockopt 339 +settimeofday 79 +setuid 23 +setuid32 +setxattr 209 +sgetmask 68 +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 338 +sigaction 67 +sigaltstack 185 +signal 48 +signalfd 305 +signalfd4 313 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 326 +socketcall 102 +socketpair 333 +splice 283 +spu_create 279 +spu_run 278 +ssetmask 69 +stat 106 +stat64 +statfs 99 +statfs64 252 +statx 383 +stime 25 +subpage_prot 310 +swapcontext 249 +swapoff 115 +swapon 87 +switch_endian 363 +symlink 83 +symlinkat 295 +sync 36 +sync_file_range +sync_file_range2 308 +syncfs 348 +sys_debug_setcontext 256 +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 284 +tgkill 250 +time 13 +timer_create 240 +timer_delete 244 +timer_getoverrun 243 +timer_gettime 242 +timer_gettime64 +timer_settime 241 +timer_settime64 +timerfd +timerfd_create 306 +timerfd_gettime 312 +timerfd_gettime64 +timerfd_settime 311 +timerfd_settime64 +times 43 +tkill 208 +truncate 92 +truncate64 +ugetrlimit 190 +umask 60 +umount 22 +umount2 52 +uname 122 +unlink 10 +unlinkat 292 +unshare 282 +uselib 86 +userfaultfd 364 +ustat 62 +utime 30 +utimensat 304 +utimensat_time64 +utimes 251 +utrap_install +vfork 189 +vhangup 111 +vm86 113 +vm86old +vmsplice 285 +wait4 114 +waitid 272 +waitpid 7 +write 4 +writev 146 diff --git a/src/basic/syscalls-s390.txt b/src/basic/syscalls-s390.txt new file mode 100644 index 000000000..a70ced38a --- /dev/null +++ b/src/basic/syscalls-s390.txt @@ -0,0 +1,594 @@ +_llseek 140 +_newselect 142 +_sysctl 149 +accept +accept4 364 +access 33 +acct 51 +add_key 278 +adjtimex 124 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 134 +bind 361 +bpf 351 +brk 45 +cachectl +cacheflush +capget 184 +capset 185 +chdir 12 +chmod 15 +chown 182 +chown32 212 +chroot 61 +clock_adjtime 337 +clock_adjtime64 405 +clock_getres 261 +clock_getres_time64 406 +clock_gettime 260 +clock_gettime64 403 +clock_nanosleep 262 +clock_nanosleep_time64 407 +clock_settime 259 +clock_settime64 404 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 362 +copy_file_range 375 +creat 8 +create_module 127 +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 326 +epoll_create 249 +epoll_create1 327 +epoll_ctl 250 +epoll_ctl_old +epoll_pwait 312 +epoll_pwait2 441 +epoll_wait 251 +epoll_wait_old +eventfd 318 +eventfd2 323 +exec_with_loader +execv +execve 11 +execveat 354 +exit 1 +exit_group 248 +faccessat 300 +faccessat2 439 +fadvise64 253 +fadvise64_64 264 +fallocate 314 +fanotify_init 332 +fanotify_mark 333 +fchdir 133 +fchmod 94 +fchmodat 299 +fchown 95 +fchown32 207 +fchownat 291 +fcntl 55 +fcntl64 221 +fdatasync 148 +fgetxattr 229 +finit_module 344 +flistxattr 232 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 235 +fsconfig 431 +fsetxattr 226 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 197 +fstatat64 293 +fstatfs 100 +fstatfs64 266 +fsync 118 +ftruncate 93 +ftruncate64 194 +futex 238 +futex_time64 422 +futimesat 292 +get_kernel_syms 130 +get_mempolicy 269 +get_robust_list 305 +get_thread_area +getcpu 311 +getcwd 183 +getdents 141 +getdents64 220 +getdomainname +getdtablesize +getegid 50 +getegid32 202 +geteuid 49 +geteuid32 201 +getgid 47 +getgid32 200 +getgroups 80 +getgroups32 205 +gethostname +getitimer 105 +getpagesize +getpeername 368 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg 188 +getppid 64 +getpriority 96 +getrandom 349 +getresgid 171 +getresgid32 211 +getresuid 165 +getresuid32 209 +getrlimit 76 +getrusage 77 +getsid 147 +getsockname 367 +getsockopt 365 +gettid 236 +gettimeofday 78 +getuid 24 +getuid32 199 +getunwind +getxattr 227 +getxgid +getxpid +getxuid +idle 112 +init_module 128 +inotify_add_watch 285 +inotify_init 284 +inotify_init1 324 +inotify_rm_watch 286 +io_cancel 247 +io_destroy 244 +io_getevents 245 +io_pgetevents 382 +io_pgetevents_time64 416 +io_setup 243 +io_submit 246 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm 101 +iopl +ioprio_get 283 +ioprio_set 282 +ipc 117 +kcmp 343 +kern_features +kexec_file_load 381 +kexec_load 277 +keyctl 280 +kill 37 +lchown 16 +lchown32 198 +lgetxattr 228 +link 9 +linkat 296 +listen 363 +listxattr 230 +llistxattr 231 +lookup_dcookie 110 +lremovexattr 234 +lseek 19 +lsetxattr 225 +lstat 107 +lstat64 196 +madvise 219 +mbind 268 +membarrier 356 +memfd_create 350 +memory_ordering +migrate_pages 287 +mincore 218 +mkdir 39 +mkdirat 289 +mknod 14 +mknodat 290 +mlock 150 +mlock2 374 +mlockall 152 +mmap 90 +mmap2 192 +modify_ldt +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 310 +mprotect 125 +mq_getsetattr 276 +mq_notify 275 +mq_open 271 +mq_timedreceive 274 +mq_timedreceive_time64 419 +mq_timedsend 273 +mq_timedsend_time64 418 +mq_unlink 272 +mremap 163 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 144 +multiplexer +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 335 +nanosleep 162 +newfstatat +nfsservctl 169 +nice 34 +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 5 +open_by_handle_at 336 +open_tree 428 +openat 288 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 331 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 325 +pivot_root 217 +pkey_alloc 385 +pkey_free 386 +pkey_mprotect 384 +poll 168 +ppoll 302 +ppoll_time64 414 +prctl 172 +pread64 180 +preadv 328 +preadv2 376 +prlimit64 334 +process_madvise 440 +process_vm_readv 340 +process_vm_writev 341 +pselect6 301 +pselect6_time64 413 +ptrace 26 +pwrite64 181 +pwritev 329 +pwritev2 377 +query_module 167 +quotactl 131 +read 3 +readahead 222 +readdir 89 +readlink 85 +readlinkat 298 +readv 145 +reboot 88 +recv +recvfrom 371 +recvmmsg 357 +recvmmsg_time64 417 +recvmsg 372 +remap_file_pages 267 +removexattr 233 +rename 38 +renameat 295 +renameat2 347 +request_key 279 +restart_syscall 7 +riscv_flush_icache +rmdir 40 +rseq 383 +rt_sigaction 174 +rt_sigpending 176 +rt_sigprocmask 175 +rt_sigqueueinfo 178 +rt_sigreturn 173 +rt_sigsuspend 179 +rt_sigtimedwait 177 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 330 +rtas +s390_guarded_storage 378 +s390_pci_mmio_read 353 +s390_pci_mmio_write 352 +s390_runtime_instr 342 +s390_sthyi 380 +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 240 +sched_getattr 346 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 423 +sched_set_affinity +sched_setaffinity 239 +sched_setattr 345 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 348 +select +semctl 394 +semget 393 +semop +semtimedop +semtimedop_time64 420 +send +sendfile 187 +sendfile64 223 +sendmmsg 358 +sendmsg 370 +sendto 369 +set_mempolicy 270 +set_robust_list 304 +set_thread_area +set_tid_address 252 +setdomainname 121 +setfsgid 139 +setfsgid32 216 +setfsuid 138 +setfsuid32 215 +setgid 46 +setgid32 214 +setgroups 81 +setgroups32 206 +sethae +sethostname 74 +setitimer 104 +setns 339 +setpgid 57 +setpgrp +setpriority 97 +setregid 71 +setregid32 204 +setresgid 170 +setresgid32 210 +setresuid 164 +setresuid32 208 +setreuid 70 +setreuid32 203 +setrlimit 75 +setsid 66 +setsockopt 366 +settimeofday 79 +setuid 23 +setuid32 213 +setxattr 224 +sgetmask +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 373 +sigaction 67 +sigaltstack 186 +signal 48 +signalfd 316 +signalfd4 322 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 359 +socketcall 102 +socketpair 360 +splice 306 +spu_create +spu_run +ssetmask +stat 106 +stat64 195 +statfs 99 +statfs64 265 +statx 379 +stime 25 +subpage_prot +swapcontext +swapoff 115 +swapon 87 +switch_endian +symlink 83 +symlinkat 297 +sync 36 +sync_file_range 307 +sync_file_range2 +syncfs 338 +sys_debug_setcontext +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 308 +tgkill 241 +time 13 +timer_create 254 +timer_delete 258 +timer_getoverrun 257 +timer_gettime 256 +timer_gettime64 408 +timer_settime 255 +timer_settime64 409 +timerfd 317 +timerfd_create 319 +timerfd_gettime 321 +timerfd_gettime64 410 +timerfd_settime 320 +timerfd_settime64 411 +times 43 +tkill 237 +truncate 92 +truncate64 193 +ugetrlimit 191 +umask 60 +umount 22 +umount2 52 +uname 122 +unlink 10 +unlinkat 294 +unshare 303 +uselib 86 +userfaultfd 355 +ustat 62 +utime 30 +utimensat 315 +utimensat_time64 412 +utimes 313 +utrap_install +vfork 190 +vhangup 111 +vm86 +vm86old +vmsplice 309 +wait4 114 +waitid 281 +waitpid +write 4 +writev 146 diff --git a/src/basic/syscalls-s390x.txt b/src/basic/syscalls-s390x.txt new file mode 100644 index 000000000..2374cd393 --- /dev/null +++ b/src/basic/syscalls-s390x.txt @@ -0,0 +1,594 @@ +_llseek +_newselect +_sysctl 149 +accept +accept4 364 +access 33 +acct 51 +add_key 278 +adjtimex 124 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 134 +bind 361 +bpf 351 +brk 45 +cachectl +cacheflush +capget 184 +capset 185 +chdir 12 +chmod 15 +chown 212 +chown32 +chroot 61 +clock_adjtime 337 +clock_adjtime64 +clock_getres 261 +clock_getres_time64 +clock_gettime 260 +clock_gettime64 +clock_nanosleep 262 +clock_nanosleep_time64 +clock_settime 259 +clock_settime64 +clone 120 +clone2 +clone3 435 +close 6 +close_range 436 +connect 362 +copy_file_range 375 +creat 8 +create_module 127 +delete_module 129 +dipc +dup 41 +dup2 63 +dup3 326 +epoll_create 249 +epoll_create1 327 +epoll_ctl 250 +epoll_ctl_old +epoll_pwait 312 +epoll_pwait2 441 +epoll_wait 251 +epoll_wait_old +eventfd 318 +eventfd2 323 +exec_with_loader +execv +execve 11 +execveat 354 +exit 1 +exit_group 248 +faccessat 300 +faccessat2 439 +fadvise64 253 +fadvise64_64 +fallocate 314 +fanotify_init 332 +fanotify_mark 333 +fchdir 133 +fchmod 94 +fchmodat 299 +fchown 207 +fchown32 +fchownat 291 +fcntl 55 +fcntl64 +fdatasync 148 +fgetxattr 229 +finit_module 344 +flistxattr 232 +flock 143 +fork 2 +fp_udfiex_crtl +fremovexattr 235 +fsconfig 431 +fsetxattr 226 +fsmount 432 +fsopen 430 +fspick 433 +fstat 108 +fstat64 +fstatat64 +fstatfs 100 +fstatfs64 266 +fsync 118 +ftruncate 93 +ftruncate64 +futex 238 +futex_time64 +futimesat 292 +get_kernel_syms 130 +get_mempolicy 269 +get_robust_list 305 +get_thread_area +getcpu 311 +getcwd 183 +getdents 141 +getdents64 220 +getdomainname +getdtablesize +getegid 202 +getegid32 +geteuid 201 +geteuid32 +getgid 200 +getgid32 +getgroups 205 +getgroups32 +gethostname +getitimer 105 +getpagesize +getpeername 368 +getpgid 132 +getpgrp 65 +getpid 20 +getpmsg 188 +getppid 64 +getpriority 96 +getrandom 349 +getresgid 211 +getresgid32 +getresuid 209 +getresuid32 +getrlimit 191 +getrusage 77 +getsid 147 +getsockname 367 +getsockopt 365 +gettid 236 +gettimeofday 78 +getuid 199 +getuid32 +getunwind +getxattr 227 +getxgid +getxpid +getxuid +idle 112 +init_module 128 +inotify_add_watch 285 +inotify_init 284 +inotify_init1 324 +inotify_rm_watch 286 +io_cancel 247 +io_destroy 244 +io_getevents 245 +io_pgetevents 382 +io_pgetevents_time64 +io_setup 243 +io_submit 246 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm +iopl +ioprio_get 283 +ioprio_set 282 +ipc 117 +kcmp 343 +kern_features +kexec_file_load 381 +kexec_load 277 +keyctl 280 +kill 37 +lchown 198 +lchown32 +lgetxattr 228 +link 9 +linkat 296 +listen 363 +listxattr 230 +llistxattr 231 +lookup_dcookie 110 +lremovexattr 234 +lseek 19 +lsetxattr 225 +lstat 107 +lstat64 +madvise 219 +mbind 268 +membarrier 356 +memfd_create 350 +memory_ordering +migrate_pages 287 +mincore 218 +mkdir 39 +mkdirat 289 +mknod 14 +mknodat 290 +mlock 150 +mlock2 374 +mlockall 152 +mmap 90 +mmap2 +modify_ldt +mount 21 +mount_setattr 442 +move_mount 429 +move_pages 310 +mprotect 125 +mq_getsetattr 276 +mq_notify 275 +mq_open 271 +mq_timedreceive 274 +mq_timedreceive_time64 +mq_timedsend 273 +mq_timedsend_time64 +mq_unlink 272 +mremap 163 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 144 +multiplexer +munlock 151 +munlockall 153 +munmap 91 +name_to_handle_at 335 +nanosleep 162 +newfstatat 293 +nfsservctl 169 +nice 34 +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 5 +open_by_handle_at 336 +open_tree 428 +openat 288 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 331 +perfctr +perfmonctl +personality 136 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 325 +pivot_root 217 +pkey_alloc 385 +pkey_free 386 +pkey_mprotect 384 +poll 168 +ppoll 302 +ppoll_time64 +prctl 172 +pread64 180 +preadv 328 +preadv2 376 +prlimit64 334 +process_madvise 440 +process_vm_readv 340 +process_vm_writev 341 +pselect6 301 +pselect6_time64 +ptrace 26 +pwrite64 181 +pwritev 329 +pwritev2 377 +query_module 167 +quotactl 131 +read 3 +readahead 222 +readdir 89 +readlink 85 +readlinkat 298 +readv 145 +reboot 88 +recv +recvfrom 371 +recvmmsg 357 +recvmmsg_time64 +recvmsg 372 +remap_file_pages 267 +removexattr 233 +rename 38 +renameat 295 +renameat2 347 +request_key 279 +restart_syscall 7 +riscv_flush_icache +rmdir 40 +rseq 383 +rt_sigaction 174 +rt_sigpending 176 +rt_sigprocmask 175 +rt_sigqueueinfo 178 +rt_sigreturn 173 +rt_sigsuspend 179 +rt_sigtimedwait 177 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 330 +rtas +s390_guarded_storage 378 +s390_pci_mmio_read 353 +s390_pci_mmio_write 352 +s390_runtime_instr 342 +s390_sthyi 380 +sched_get_affinity +sched_get_priority_max 159 +sched_get_priority_min 160 +sched_getaffinity 240 +sched_getattr 346 +sched_getparam 155 +sched_getscheduler 157 +sched_rr_get_interval 161 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 239 +sched_setattr 345 +sched_setparam 154 +sched_setscheduler 156 +sched_yield 158 +seccomp 348 +select 142 +semctl 394 +semget 393 +semop +semtimedop 392 +semtimedop_time64 +send +sendfile 187 +sendfile64 +sendmmsg 358 +sendmsg 370 +sendto 369 +set_mempolicy 270 +set_robust_list 304 +set_thread_area +set_tid_address 252 +setdomainname 121 +setfsgid 216 +setfsgid32 +setfsuid 215 +setfsuid32 +setgid 214 +setgid32 +setgroups 206 +setgroups32 +sethae +sethostname 74 +setitimer 104 +setns 339 +setpgid 57 +setpgrp +setpriority 97 +setregid 204 +setregid32 +setresgid 210 +setresgid32 +setresuid 208 +setresuid32 +setreuid 203 +setreuid32 +setrlimit 75 +setsid 66 +setsockopt 366 +settimeofday 79 +setuid 213 +setuid32 +setxattr 224 +sgetmask +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 373 +sigaction 67 +sigaltstack 186 +signal 48 +signalfd 316 +signalfd4 322 +sigpending 73 +sigprocmask 126 +sigreturn 119 +sigsuspend 72 +socket 359 +socketcall 102 +socketpair 360 +splice 306 +spu_create +spu_run +ssetmask +stat 106 +stat64 +statfs 99 +statfs64 265 +statx 379 +stime +subpage_prot +swapcontext +swapoff 115 +swapon 87 +switch_endian +symlink 83 +symlinkat 297 +sync 36 +sync_file_range 307 +sync_file_range2 +syncfs 338 +sys_debug_setcontext +syscall +sysfs 135 +sysinfo 116 +syslog 103 +sysmips +tee 308 +tgkill 241 +time +timer_create 254 +timer_delete 258 +timer_getoverrun 257 +timer_gettime 256 +timer_gettime64 +timer_settime 255 +timer_settime64 +timerfd 317 +timerfd_create 319 +timerfd_gettime 321 +timerfd_gettime64 +timerfd_settime 320 +timerfd_settime64 +times 43 +tkill 237 +truncate 92 +truncate64 +ugetrlimit +umask 60 +umount 22 +umount2 52 +uname 122 +unlink 10 +unlinkat 294 +unshare 303 +uselib 86 +userfaultfd 355 +ustat 62 +utime 30 +utimensat 315 +utimensat_time64 +utimes 313 +utrap_install +vfork 190 +vhangup 111 +vm86 +vm86old +vmsplice 309 +wait4 114 +waitid 281 +waitpid +write 4 +writev 146 diff --git a/src/basic/syscalls-sparc.txt b/src/basic/syscalls-sparc.txt new file mode 100644 index 000000000..46ed8b5c7 --- /dev/null +++ b/src/basic/syscalls-sparc.txt @@ -0,0 +1,594 @@ +_llseek 236 +_newselect 230 +_sysctl 251 +accept 99 +accept4 323 +access 33 +acct 51 +add_key 281 +adjtimex 219 +alarm 27 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush 225 +bind 353 +bpf 349 +brk 17 +cachectl +cacheflush +capget 21 +capset 22 +chdir 12 +chmod 15 +chown 13 +chown32 35 +chroot 61 +clock_adjtime 334 +clock_adjtime64 405 +clock_getres 258 +clock_getres_time64 406 +clock_gettime 257 +clock_gettime64 403 +clock_nanosleep 259 +clock_nanosleep_time64 407 +clock_settime 256 +clock_settime64 404 +clone 217 +clone2 +clone3 +close 6 +close_range 436 +connect 98 +copy_file_range 357 +creat 8 +create_module 221 +delete_module 222 +dipc +dup 41 +dup2 90 +dup3 320 +epoll_create 193 +epoll_create1 319 +epoll_ctl 194 +epoll_ctl_old +epoll_pwait 309 +epoll_pwait2 441 +epoll_wait 195 +epoll_wait_old +eventfd 313 +eventfd2 318 +exec_with_loader +execv 11 +execve 59 +execveat 350 +exit 1 +exit_group 188 +faccessat 296 +faccessat2 439 +fadvise64 209 +fadvise64_64 210 +fallocate 314 +fanotify_init 329 +fanotify_mark 330 +fchdir 176 +fchmod 124 +fchmodat 295 +fchown 123 +fchown32 32 +fchownat 287 +fcntl 92 +fcntl64 155 +fdatasync 253 +fgetxattr 177 +finit_module 342 +flistxattr 180 +flock 131 +fork 2 +fp_udfiex_crtl +fremovexattr 186 +fsconfig 431 +fsetxattr 171 +fsmount 432 +fsopen 430 +fspick 433 +fstat 62 +fstat64 63 +fstatat64 289 +fstatfs 158 +fstatfs64 235 +fsync 95 +ftruncate 130 +ftruncate64 84 +futex 142 +futex_time64 422 +futimesat 288 +get_kernel_syms 223 +get_mempolicy 304 +get_robust_list 301 +get_thread_area +getcpu 308 +getcwd 119 +getdents 174 +getdents64 154 +getdomainname 162 +getdtablesize +getegid 50 +getegid32 70 +geteuid 49 +geteuid32 69 +getgid 47 +getgid32 53 +getgroups 79 +getgroups32 115 +gethostname +getitimer 86 +getpagesize 64 +getpeername 141 +getpgid 224 +getpgrp 81 +getpid 20 +getpmsg +getppid 197 +getpriority 100 +getrandom 347 +getresgid +getresgid32 111 +getresuid +getresuid32 109 +getrlimit 144 +getrusage 117 +getsid 252 +getsockname 150 +getsockopt 118 +gettid 143 +gettimeofday 116 +getuid 24 +getuid32 44 +getunwind +getxattr 172 +getxgid +getxpid +getxuid +idle +init_module 190 +inotify_add_watch 152 +inotify_init 151 +inotify_init1 322 +inotify_rm_watch 156 +io_cancel 271 +io_destroy 269 +io_getevents 272 +io_pgetevents 361 +io_pgetevents_time64 416 +io_setup 268 +io_submit 270 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 54 +ioperm +iopl +ioprio_get 218 +ioprio_set 196 +ipc 215 +kcmp 341 +kern_features 340 +kexec_file_load +kexec_load 306 +keyctl 283 +kill 37 +lchown 16 +lchown32 31 +lgetxattr 173 +link 9 +linkat 292 +listen 354 +listxattr 178 +llistxattr 179 +lookup_dcookie 208 +lremovexattr 182 +lseek 19 +lsetxattr 170 +lstat 40 +lstat64 132 +madvise 75 +mbind 303 +membarrier 351 +memfd_create 348 +memory_ordering +migrate_pages 302 +mincore 78 +mkdir 136 +mkdirat 285 +mknod 14 +mknodat 286 +mlock 237 +mlock2 356 +mlockall 239 +mmap 71 +mmap2 56 +modify_ldt +mount 167 +mount_setattr 442 +move_mount 429 +move_pages 307 +mprotect 74 +mq_getsetattr 278 +mq_notify 277 +mq_open 273 +mq_timedreceive 276 +mq_timedreceive_time64 419 +mq_timedsend 275 +mq_timedsend_time64 418 +mq_unlink 274 +mremap 250 +msgctl 402 +msgget 399 +msgrcv 401 +msgsnd 400 +msync 65 +multiplexer +munlock 238 +munlockall 240 +munmap 73 +name_to_handle_at 332 +nanosleep 249 +newfstatat +nfsservctl 254 +nice 34 +old_adjtimex +old_getpagesize +oldfstat +oldlstat 202 +oldolduname +oldstat +oldumount +olduname +open 5 +open_by_handle_at 333 +open_tree 428 +openat 284 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 29 +pciconfig_iobase +pciconfig_read 148 +pciconfig_write 149 +perf_event_open 327 +perfctr 18 +perfmonctl +personality 191 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 42 +pipe2 321 +pivot_root 146 +pkey_alloc 363 +pkey_free 364 +pkey_mprotect 362 +poll 153 +ppoll 298 +ppoll_time64 414 +prctl 147 +pread64 67 +preadv 324 +preadv2 358 +prlimit64 331 +process_madvise 440 +process_vm_readv 338 +process_vm_writev 339 +pselect6 297 +pselect6_time64 413 +ptrace 26 +pwrite64 68 +pwritev 325 +pwritev2 359 +query_module 184 +quotactl 165 +read 3 +readahead 205 +readdir 204 +readlink 58 +readlinkat 294 +readv 120 +reboot 55 +recv +recvfrom 125 +recvmmsg 328 +recvmmsg_time64 417 +recvmsg 113 +remap_file_pages 192 +removexattr 181 +rename 128 +renameat 291 +renameat2 345 +request_key 282 +restart_syscall 0 +riscv_flush_icache +rmdir 137 +rseq 365 +rt_sigaction 102 +rt_sigpending 104 +rt_sigprocmask 103 +rt_sigqueueinfo 106 +rt_sigreturn 101 +rt_sigsuspend 107 +rt_sigtimedwait 105 +rt_sigtimedwait_time64 421 +rt_tgsigqueueinfo 326 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity 161 +sched_get_priority_max 246 +sched_get_priority_min 247 +sched_getaffinity 260 +sched_getattr 344 +sched_getparam 242 +sched_getscheduler 244 +sched_rr_get_interval 248 +sched_rr_get_interval_time64 423 +sched_set_affinity 160 +sched_setaffinity 261 +sched_setattr 343 +sched_setparam 241 +sched_setscheduler 243 +sched_yield 245 +seccomp 346 +select 93 +semctl 394 +semget 393 +semop +semtimedop +semtimedop_time64 420 +send +sendfile 39 +sendfile64 140 +sendmmsg 336 +sendmsg 114 +sendto 133 +set_mempolicy 305 +set_robust_list 300 +set_thread_area +set_tid_address 166 +setdomainname 163 +setfsgid 229 +setfsgid32 94 +setfsuid 228 +setfsuid32 91 +setgid 46 +setgid32 89 +setgroups 80 +setgroups32 82 +sethae +sethostname 88 +setitimer 83 +setns 337 +setpgid 185 +setpgrp +setpriority 96 +setregid 127 +setregid32 112 +setresgid +setresgid32 110 +setresuid +setresuid32 108 +setreuid 126 +setreuid32 72 +setrlimit 145 +setsid 175 +setsockopt 355 +settimeofday 122 +setuid 23 +setuid32 87 +setxattr 169 +sgetmask 199 +shmat 397 +shmctl 396 +shmdt 398 +shmget 395 +shutdown 134 +sigaction 198 +sigaltstack 28 +signal 48 +signalfd 311 +signalfd4 317 +sigpending 183 +sigprocmask 220 +sigreturn 216 +sigsuspend 201 +socket 97 +socketcall 206 +socketpair 135 +splice 232 +spu_create +spu_run +ssetmask 200 +stat 38 +stat64 139 +statfs 157 +statfs64 234 +statx 360 +stime 233 +subpage_prot +swapcontext +swapoff 213 +swapon 85 +switch_endian +symlink 57 +symlinkat 293 +sync 36 +sync_file_range 255 +sync_file_range2 +syncfs 335 +sys_debug_setcontext +syscall +sysfs 226 +sysinfo 214 +syslog 207 +sysmips +tee 280 +tgkill 211 +time 231 +timer_create 266 +timer_delete 265 +timer_getoverrun 264 +timer_gettime 263 +timer_gettime64 408 +timer_settime 262 +timer_settime64 409 +timerfd +timerfd_create 312 +timerfd_gettime 316 +timerfd_gettime64 410 +timerfd_settime 315 +timerfd_settime64 411 +times 43 +tkill 187 +truncate 129 +truncate64 77 +ugetrlimit +umask 60 +umount 159 +umount2 45 +uname 189 +unlink 10 +unlinkat 290 +unshare 299 +uselib 203 +userfaultfd 352 +ustat 168 +utime 30 +utimensat 310 +utimensat_time64 412 +utimes 138 +utrap_install +vfork 66 +vhangup 76 +vm86 +vm86old +vmsplice 25 +wait4 7 +waitid 279 +waitpid 212 +write 4 +writev 121 diff --git a/src/basic/syscalls-x86_64.txt b/src/basic/syscalls-x86_64.txt new file mode 100644 index 000000000..8a947ee8e --- /dev/null +++ b/src/basic/syscalls-x86_64.txt @@ -0,0 +1,594 @@ +_llseek +_newselect +_sysctl 156 +accept 43 +accept4 288 +access 21 +acct 163 +add_key 248 +adjtimex 159 +alarm 37 +arc_gettls +arc_settls +arc_usr_cmpxchg +arch_prctl 158 +arm_fadvise64_64 +atomic_barrier +atomic_cmpxchg_32 +bdflush +bind 49 +bpf 321 +brk 12 +cachectl +cacheflush +capget 125 +capset 126 +chdir 80 +chmod 90 +chown 92 +chown32 +chroot 161 +clock_adjtime 305 +clock_adjtime64 +clock_getres 229 +clock_getres_time64 +clock_gettime 228 +clock_gettime64 +clock_nanosleep 230 +clock_nanosleep_time64 +clock_settime 227 +clock_settime64 +clone 56 +clone2 +clone3 435 +close 3 +close_range 436 +connect 42 +copy_file_range 326 +creat 85 +create_module 174 +delete_module 176 +dipc +dup 32 +dup2 33 +dup3 292 +epoll_create 213 +epoll_create1 291 +epoll_ctl 233 +epoll_ctl_old 214 +epoll_pwait 281 +epoll_pwait2 441 +epoll_wait 232 +epoll_wait_old 215 +eventfd 284 +eventfd2 290 +exec_with_loader +execv +execve 59 +execveat 322 +exit 60 +exit_group 231 +faccessat 269 +faccessat2 439 +fadvise64 221 +fadvise64_64 +fallocate 285 +fanotify_init 300 +fanotify_mark 301 +fchdir 81 +fchmod 91 +fchmodat 268 +fchown 93 +fchown32 +fchownat 260 +fcntl 72 +fcntl64 +fdatasync 75 +fgetxattr 193 +finit_module 313 +flistxattr 196 +flock 73 +fork 57 +fp_udfiex_crtl +fremovexattr 199 +fsconfig 431 +fsetxattr 190 +fsmount 432 +fsopen 430 +fspick 433 +fstat 5 +fstat64 +fstatat64 +fstatfs 138 +fstatfs64 +fsync 74 +ftruncate 77 +ftruncate64 +futex 202 +futex_time64 +futimesat 261 +get_kernel_syms 177 +get_mempolicy 239 +get_robust_list 274 +get_thread_area 211 +getcpu 309 +getcwd 79 +getdents 78 +getdents64 217 +getdomainname +getdtablesize +getegid 108 +getegid32 +geteuid 107 +geteuid32 +getgid 104 +getgid32 +getgroups 115 +getgroups32 +gethostname +getitimer 36 +getpagesize +getpeername 52 +getpgid 121 +getpgrp 111 +getpid 39 +getpmsg 181 +getppid 110 +getpriority 140 +getrandom 318 +getresgid 120 +getresgid32 +getresuid 118 +getresuid32 +getrlimit 97 +getrusage 98 +getsid 124 +getsockname 51 +getsockopt 55 +gettid 186 +gettimeofday 96 +getuid 102 +getuid32 +getunwind +getxattr 191 +getxgid +getxpid +getxuid +idle +init_module 175 +inotify_add_watch 254 +inotify_init 253 +inotify_init1 294 +inotify_rm_watch 255 +io_cancel 210 +io_destroy 207 +io_getevents 208 +io_pgetevents 333 +io_pgetevents_time64 +io_setup 206 +io_submit 209 +io_uring_enter 426 +io_uring_register 427 +io_uring_setup 425 +ioctl 16 +ioperm 173 +iopl 172 +ioprio_get 252 +ioprio_set 251 +ipc +kcmp 312 +kern_features +kexec_file_load 320 +kexec_load 246 +keyctl 250 +kill 62 +lchown 94 +lchown32 +lgetxattr 192 +link 86 +linkat 265 +listen 50 +listxattr 194 +llistxattr 195 +lookup_dcookie 212 +lremovexattr 198 +lseek 8 +lsetxattr 189 +lstat 6 +lstat64 +madvise 28 +mbind 237 +membarrier 324 +memfd_create 319 +memory_ordering +migrate_pages 256 +mincore 27 +mkdir 83 +mkdirat 258 +mknod 133 +mknodat 259 +mlock 149 +mlock2 325 +mlockall 151 +mmap 9 +mmap2 +modify_ldt 154 +mount 165 +mount_setattr 442 +move_mount 429 +move_pages 279 +mprotect 10 +mq_getsetattr 245 +mq_notify 244 +mq_open 240 +mq_timedreceive 243 +mq_timedreceive_time64 +mq_timedsend 242 +mq_timedsend_time64 +mq_unlink 241 +mremap 25 +msgctl 71 +msgget 68 +msgrcv 70 +msgsnd 69 +msync 26 +multiplexer +munlock 150 +munlockall 152 +munmap 11 +name_to_handle_at 303 +nanosleep 35 +newfstatat 262 +nfsservctl 180 +nice +old_adjtimex +old_getpagesize +oldfstat +oldlstat +oldolduname +oldstat +oldumount +olduname +open 2 +open_by_handle_at 304 +open_tree 428 +openat 257 +openat2 437 +or1k_atomic +osf_adjtime +osf_afs_syscall +osf_alt_plock +osf_alt_setsid +osf_alt_sigpending +osf_asynch_daemon +osf_audcntl +osf_audgen +osf_chflags +osf_execve +osf_exportfs +osf_fchflags +osf_fdatasync +osf_fpathconf +osf_fstat +osf_fstatfs +osf_fstatfs64 +osf_fuser +osf_getaddressconf +osf_getdirentries +osf_getdomainname +osf_getfh +osf_getfsstat +osf_gethostid +osf_getitimer +osf_getlogin +osf_getmnt +osf_getrusage +osf_getsysinfo +osf_gettimeofday +osf_kloadcall +osf_kmodcall +osf_lstat +osf_memcntl +osf_mincore +osf_mount +osf_mremap +osf_msfs_syscall +osf_msleep +osf_mvalid +osf_mwakeup +osf_naccept +osf_nfssvc +osf_ngetpeername +osf_ngetsockname +osf_nrecvfrom +osf_nrecvmsg +osf_nsendmsg +osf_ntp_adjtime +osf_ntp_gettime +osf_old_creat +osf_old_fstat +osf_old_getpgrp +osf_old_killpg +osf_old_lstat +osf_old_open +osf_old_sigaction +osf_old_sigblock +osf_old_sigreturn +osf_old_sigsetmask +osf_old_sigvec +osf_old_stat +osf_old_vadvise +osf_old_vtrace +osf_old_wait +osf_oldquota +osf_pathconf +osf_pid_block +osf_pid_unblock +osf_plock +osf_priocntlset +osf_profil +osf_proplist_syscall +osf_reboot +osf_revoke +osf_sbrk +osf_security +osf_select +osf_set_program_attributes +osf_set_speculative +osf_sethostid +osf_setitimer +osf_setlogin +osf_setsysinfo +osf_settimeofday +osf_shmat +osf_signal +osf_sigprocmask +osf_sigsendset +osf_sigstack +osf_sigwaitprim +osf_sstk +osf_stat +osf_statfs +osf_statfs64 +osf_subsys_info +osf_swapctl +osf_swapon +osf_syscall +osf_sysinfo +osf_table +osf_uadmin +osf_usleep_thread +osf_uswitch +osf_utc_adjtime +osf_utc_gettime +osf_utimes +osf_utsname +osf_wait4 +osf_waitid +pause 34 +pciconfig_iobase +pciconfig_read +pciconfig_write +perf_event_open 298 +perfctr +perfmonctl +personality 135 +pidfd_getfd 438 +pidfd_open 434 +pidfd_send_signal 424 +pipe 22 +pipe2 293 +pivot_root 155 +pkey_alloc 330 +pkey_free 331 +pkey_mprotect 329 +poll 7 +ppoll 271 +ppoll_time64 +prctl 157 +pread64 17 +preadv 295 +preadv2 327 +prlimit64 302 +process_madvise 440 +process_vm_readv 310 +process_vm_writev 311 +pselect6 270 +pselect6_time64 +ptrace 101 +pwrite64 18 +pwritev 296 +pwritev2 328 +query_module 178 +quotactl 179 +read 0 +readahead 187 +readdir +readlink 89 +readlinkat 267 +readv 19 +reboot 169 +recv +recvfrom 45 +recvmmsg 299 +recvmmsg_time64 +recvmsg 47 +remap_file_pages 216 +removexattr 197 +rename 82 +renameat 264 +renameat2 316 +request_key 249 +restart_syscall 219 +riscv_flush_icache +rmdir 84 +rseq 334 +rt_sigaction 13 +rt_sigpending 127 +rt_sigprocmask 14 +rt_sigqueueinfo 129 +rt_sigreturn 15 +rt_sigsuspend 130 +rt_sigtimedwait 128 +rt_sigtimedwait_time64 +rt_tgsigqueueinfo 297 +rtas +s390_guarded_storage +s390_pci_mmio_read +s390_pci_mmio_write +s390_runtime_instr +s390_sthyi +sched_get_affinity +sched_get_priority_max 146 +sched_get_priority_min 147 +sched_getaffinity 204 +sched_getattr 315 +sched_getparam 143 +sched_getscheduler 145 +sched_rr_get_interval 148 +sched_rr_get_interval_time64 +sched_set_affinity +sched_setaffinity 203 +sched_setattr 314 +sched_setparam 142 +sched_setscheduler 144 +sched_yield 24 +seccomp 317 +select 23 +semctl 66 +semget 64 +semop 65 +semtimedop 220 +semtimedop_time64 +send +sendfile 40 +sendfile64 +sendmmsg 307 +sendmsg 46 +sendto 44 +set_mempolicy 238 +set_robust_list 273 +set_thread_area 205 +set_tid_address 218 +setdomainname 171 +setfsgid 123 +setfsgid32 +setfsuid 122 +setfsuid32 +setgid 106 +setgid32 +setgroups 116 +setgroups32 +sethae +sethostname 170 +setitimer 38 +setns 308 +setpgid 109 +setpgrp +setpriority 141 +setregid 114 +setregid32 +setresgid 119 +setresgid32 +setresuid 117 +setresuid32 +setreuid 113 +setreuid32 +setrlimit 160 +setsid 112 +setsockopt 54 +settimeofday 164 +setuid 105 +setuid32 +setxattr 188 +sgetmask +shmat 30 +shmctl 31 +shmdt 67 +shmget 29 +shutdown 48 +sigaction +sigaltstack 131 +signal +signalfd 282 +signalfd4 289 +sigpending +sigprocmask +sigreturn +sigsuspend +socket 41 +socketcall +socketpair 53 +splice 275 +spu_create +spu_run +ssetmask +stat 4 +stat64 +statfs 137 +statfs64 +statx 332 +stime +subpage_prot +swapcontext +swapoff 168 +swapon 167 +switch_endian +symlink 88 +symlinkat 266 +sync 162 +sync_file_range 277 +sync_file_range2 +syncfs 306 +sys_debug_setcontext +syscall +sysfs 139 +sysinfo 99 +syslog 103 +sysmips +tee 276 +tgkill 234 +time 201 +timer_create 222 +timer_delete 226 +timer_getoverrun 225 +timer_gettime 224 +timer_gettime64 +timer_settime 223 +timer_settime64 +timerfd +timerfd_create 283 +timerfd_gettime 287 +timerfd_gettime64 +timerfd_settime 286 +timerfd_settime64 +times 100 +tkill 200 +truncate 76 +truncate64 +ugetrlimit +umask 95 +umount +umount2 166 +uname 63 +unlink 87 +unlinkat 263 +unshare 272 +uselib 134 +userfaultfd 323 +ustat 136 +utime 132 +utimensat 280 +utimensat_time64 +utimes 235 +utrap_install +vfork 58 +vhangup 153 +vm86 +vm86old +vmsplice 278 +wait4 61 +waitid 247 +waitpid +write 1 +writev 20 diff --git a/src/shared/sysctl-util.c b/src/basic/sysctl-util.c similarity index 94% rename from src/shared/sysctl-util.c rename to src/basic/sysctl-util.c index 670c33108..c96b5cd77 100644 --- a/src/shared/sysctl-util.c +++ b/src/basic/sysctl-util.c @@ -96,14 +96,14 @@ int sysctl_write_ip_property(int af, const char *ifname, const char *property, c return write_string_file(p, value, WRITE_STRING_FILE_VERIFY_ON_FAILURE | WRITE_STRING_FILE_DISABLE_BUFFER); } -int sysctl_read(const char *property, char **content) { +int sysctl_read(const char *property, char **ret) { char *p; assert(property); - assert(content); + assert(ret); p = strjoina("/proc/sys/", property); - return read_full_file(p, content, NULL); + return read_full_virtual_file(p, ret, NULL); } int sysctl_read_ip_property(int af, const char *ifname, const char *property, char **ret) { @@ -118,10 +118,11 @@ int sysctl_read_ip_property(int af, const char *ifname, const char *property, ch ifname ? "/conf/" : "", strempty(ifname), property[0] == '/' ? "" : "/", property); - r = read_one_line_file(p, &value); + r = read_full_virtual_file(p, &value, NULL); if (r < 0) return r; + truncate_nl(value); if (ret) *ret = TAKE_PTR(value); diff --git a/src/shared/sysctl-util.h b/src/basic/sysctl-util.h similarity index 100% rename from src/shared/sysctl-util.h rename to src/basic/sysctl-util.h diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c index 4eb9eba97..0371922e3 100644 --- a/src/basic/syslog-util.c +++ b/src/basic/syslog-util.c @@ -57,26 +57,26 @@ int syslog_parse_priority(const char **p, int *priority, bool with_facility) { } static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = { - [LOG_FAC(LOG_KERN)] = "kern", - [LOG_FAC(LOG_USER)] = "user", - [LOG_FAC(LOG_MAIL)] = "mail", - [LOG_FAC(LOG_DAEMON)] = "daemon", - [LOG_FAC(LOG_AUTH)] = "auth", - [LOG_FAC(LOG_SYSLOG)] = "syslog", - [LOG_FAC(LOG_LPR)] = "lpr", - [LOG_FAC(LOG_NEWS)] = "news", - [LOG_FAC(LOG_UUCP)] = "uucp", - [LOG_FAC(LOG_CRON)] = "cron", + [LOG_FAC(LOG_KERN)] = "kern", + [LOG_FAC(LOG_USER)] = "user", + [LOG_FAC(LOG_MAIL)] = "mail", + [LOG_FAC(LOG_DAEMON)] = "daemon", + [LOG_FAC(LOG_AUTH)] = "auth", + [LOG_FAC(LOG_SYSLOG)] = "syslog", + [LOG_FAC(LOG_LPR)] = "lpr", + [LOG_FAC(LOG_NEWS)] = "news", + [LOG_FAC(LOG_UUCP)] = "uucp", + [LOG_FAC(LOG_CRON)] = "cron", [LOG_FAC(LOG_AUTHPRIV)] = "authpriv", - [LOG_FAC(LOG_FTP)] = "ftp", - [LOG_FAC(LOG_LOCAL0)] = "local0", - [LOG_FAC(LOG_LOCAL1)] = "local1", - [LOG_FAC(LOG_LOCAL2)] = "local2", - [LOG_FAC(LOG_LOCAL3)] = "local3", - [LOG_FAC(LOG_LOCAL4)] = "local4", - [LOG_FAC(LOG_LOCAL5)] = "local5", - [LOG_FAC(LOG_LOCAL6)] = "local6", - [LOG_FAC(LOG_LOCAL7)] = "local7" + [LOG_FAC(LOG_FTP)] = "ftp", + [LOG_FAC(LOG_LOCAL0)] = "local0", + [LOG_FAC(LOG_LOCAL1)] = "local1", + [LOG_FAC(LOG_LOCAL2)] = "local2", + [LOG_FAC(LOG_LOCAL3)] = "local3", + [LOG_FAC(LOG_LOCAL4)] = "local4", + [LOG_FAC(LOG_LOCAL5)] = "local5", + [LOG_FAC(LOG_LOCAL6)] = "local6", + [LOG_FAC(LOG_LOCAL7)] = "local7", }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_facility_unshifted, int, LOG_FAC(~0)); @@ -86,14 +86,14 @@ bool log_facility_unshifted_is_valid(int facility) { } static const char *const log_level_table[] = { - [LOG_EMERG] = "emerg", - [LOG_ALERT] = "alert", - [LOG_CRIT] = "crit", - [LOG_ERR] = "err", + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", [LOG_WARNING] = "warning", - [LOG_NOTICE] = "notice", - [LOG_INFO] = "info", - [LOG_DEBUG] = "debug" + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug", }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(log_level, int, LOG_DEBUG); diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index e00e9e875..1a3f9ccb3 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -41,13 +41,14 @@ #include "strv.h" #include "terminal-util.h" #include "time-util.h" +#include "user-util.h" #include "util.h" static volatile unsigned cached_columns = 0; static volatile unsigned cached_lines = 0; static volatile int cached_on_tty = -1; -static volatile int cached_colors_enabled = -1; +static volatile int cached_color_mode = _COLOR_INVALID; static volatile int cached_underline_enabled = -1; int chvt(int vt) { @@ -164,8 +165,7 @@ int ask_char(char *ret, const char *replies, const char *fmt, ...) { char c; bool need_nl = true; - if (colors_enabled()) - fputs(ANSI_HIGHLIGHT, stdout); + fputs(ansi_highlight(), stdout); putchar('\r'); @@ -173,8 +173,7 @@ int ask_char(char *ret, const char *replies, const char *fmt, ...) { vprintf(fmt, ap); va_end(ap); - if (colors_enabled()) - fputs(ANSI_NORMAL, stdout); + fputs(ansi_normal(), stdout); fflush(stdout); @@ -213,15 +212,13 @@ int ask_string(char **ret, const char *text, ...) { assert(ret); assert(text); - if (colors_enabled()) - fputs(ANSI_HIGHLIGHT, stdout); + fputs(ansi_highlight(), stdout); va_start(ap, text); vprintf(text, ap); va_end(ap); - if (colors_enabled()) - fputs(ANSI_NORMAL, stdout); + fputs(ansi_normal(), stdout); fflush(stdout); @@ -444,11 +441,11 @@ int acquire_terminal( assert(ts != USEC_INFINITY); - n = now(CLOCK_MONOTONIC); - if (ts + timeout < n) + n = usec_sub_unsigned(now(CLOCK_MONOTONIC), ts); + if (n >= timeout) return -ETIMEDOUT; - r = fd_wait_for_event(notify, POLLIN, ts + timeout - n); + r = fd_wait_for_event(notify, POLLIN, usec_sub_unsigned(timeout, n)); if (r < 0) return r; if (r == 0) @@ -867,7 +864,7 @@ void reset_terminal_feature_caches(void) { cached_columns = 0; cached_lines = 0; - cached_colors_enabled = -1; + cached_color_mode = _COLOR_INVALID; cached_underline_enabled = -1; cached_on_tty = -1; } @@ -1206,38 +1203,62 @@ bool terminal_is_dumb(void) { return getenv_terminal_is_dumb(); } -bool colors_enabled(void) { +static ColorMode parse_systemd_colors(void) { + const char *e; + int r; - /* Returns true if colors are considered supported on our stdout. For that we check $SYSTEMD_COLORS first - * (which is the explicit way to turn colors on/off). If that didn't work we turn colors off unless we are on a - * TTY. And if we are on a TTY we turn it off if $TERM is set to "dumb". There's one special tweak though: if - * we are PID 1 then we do not check whether we are connected to a TTY, because we don't keep /dev/console open - * continuously due to fear of SAK, and hence things are a bit weird. */ + e = getenv("SYSTEMD_COLORS"); + if (!e) + return _COLOR_INVALID; + if (streq(e, "16")) + return COLOR_16; + if (streq(e, "256")) + return COLOR_256; + r = parse_boolean(e); + if (r >= 0) + return r > 0 ? COLOR_ON : COLOR_OFF; + return _COLOR_INVALID; +} - if (cached_colors_enabled < 0) { - int val; +ColorMode get_color_mode(void) { - val = getenv_bool("SYSTEMD_COLORS"); - if (val >= 0) - cached_colors_enabled = val; + /* Returns the mode used to choose output colors. The possible modes are COLOR_OFF for no colors, + * COLOR_16 for only the base 16 ANSI colors, COLOR_256 for more colors and COLOR_ON for unrestricted + * color output. For that we check $SYSTEMD_COLORS first (which is the explicit way to + * change the mode). If that didn't work we turn colors off unless we are on a TTY. And if we are on a TTY + * we turn it off if $TERM is set to "dumb". There's one special tweak though: if we are PID 1 then we do not + * check whether we are connected to a TTY, because we don't keep /dev/console open continuously due to fear + * of SAK, and hence things are a bit weird. */ + ColorMode m; + if (cached_color_mode < 0) { + m = parse_systemd_colors(); + if (m >= 0) + cached_color_mode = m; else if (getenv("NO_COLOR")) /* We only check for the presence of the variable; value is ignored. */ - cached_colors_enabled = false; + cached_color_mode = COLOR_OFF; else if (getpid_cached() == 1) - /* PID1 outputs to the console without holding it open all the time */ - cached_colors_enabled = !getenv_terminal_is_dumb(); + /* PID1 outputs to the console without holding it open all the time. + * + * Note that the Linux console can only display 16 colors. We still enable 256 color + * mode even for PID1 output though (which typically goes to the Linux console), + * since the Linux console is able to parse the 256 color sequences and automatically + * map them to the closest color in the 16 color palette (since kernel 3.16). Doing + * 256 colors is nice for people who invoke systemd in a container or via a serial + * link or such, and use a true 256 color terminal to do so. */ + cached_color_mode = getenv_terminal_is_dumb() ? COLOR_OFF : COLOR_256; else - cached_colors_enabled = !terminal_is_dumb(); + cached_color_mode = terminal_is_dumb() ? COLOR_OFF : COLOR_256; } - return cached_colors_enabled; + return cached_color_mode; } bool dev_console_colors_enabled(void) { _cleanup_free_ char *s = NULL; - int b; + ColorMode m; /* Returns true if we assume that color is supported on /dev/console. * @@ -1246,9 +1267,9 @@ bool dev_console_colors_enabled(void) { * line. If we find $TERM set we assume color if it's not set to "dumb", similarly to how regular * colors_enabled() operates. */ - b = getenv_bool("SYSTEMD_COLORS"); - if (b >= 0) - return b; + m = parse_systemd_colors(); + if (m >= 0) + return m; if (getenv("NO_COLOR")) return false; @@ -1321,7 +1342,7 @@ int vt_restore(int fd) { q = -errno; } - r = fchmod_and_chown(fd, TTY_MODE, 0, (gid_t) -1); + r = fchmod_and_chown(fd, TTY_MODE, 0, GID_INVALID); if (r < 0) { log_debug_errno(r, "Failed to chmod()/chown() VT, ignoring: %m"); if (q >= 0) @@ -1353,34 +1374,34 @@ void get_log_colors(int priority, const char **on, const char **off, const char if (priority <= LOG_ERR) { if (on) - *on = ANSI_HIGHLIGHT_RED; + *on = ansi_highlight_red(); if (off) - *off = ANSI_NORMAL; + *off = ansi_normal(); if (highlight) - *highlight = ANSI_HIGHLIGHT; + *highlight = ansi_highlight(); } else if (priority <= LOG_WARNING) { if (on) - *on = ANSI_HIGHLIGHT_YELLOW; + *on = ansi_highlight_yellow(); if (off) - *off = ANSI_NORMAL; + *off = ansi_normal(); if (highlight) - *highlight = ANSI_HIGHLIGHT; + *highlight = ansi_highlight(); } else if (priority <= LOG_NOTICE) { if (on) - *on = ANSI_HIGHLIGHT; + *on = ansi_highlight(); if (off) - *off = ANSI_NORMAL; + *off = ansi_normal(); if (highlight) - *highlight = ANSI_HIGHLIGHT_RED; + *highlight = ansi_highlight_red(); } else if (priority >= LOG_DEBUG) { if (on) - *on = ANSI_GREY; + *on = ansi_grey(); if (off) - *off = ANSI_NORMAL; + *off = ansi_normal(); if (highlight) - *highlight = ANSI_HIGHLIGHT_RED; + *highlight = ansi_highlight_red(); } } diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index 5cb1e138f..d327627b2 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -61,6 +61,10 @@ #define ANSI_HIGHLIGHT "\x1B[0;1;39m" #define ANSI_HIGHLIGHT_UNDERLINE "\x1B[0;1;4m" +/* Fallback colors: 256 -> 16 */ +#define ANSI_HIGHLIGHT_GREY_FALLBACK "\x1B[0;1;90m" +#define ANSI_HIGHLIGHT_YELLOW_FALLBACK "\x1B[0;1;33m" + /* Reset/clear ANSI styles */ #define ANSI_NORMAL "\x1B[0m" @@ -93,6 +97,23 @@ typedef enum AcquireTerminalFlags { ACQUIRE_TERMINAL_PERMISSIVE = 1 << 2, } AcquireTerminalFlags; +/* Limits the use of ANSI colors to a subset. */ +typedef enum ColorMode { + /* No colors, monochrome output. */ + COLOR_OFF = 0, + + /* All colors, no restrictions. */ + COLOR_ON = 1, + + /* Only the base 16 colors. */ + COLOR_16 = 16, + + /* Only 256 colors. */ + COLOR_256 = 256, + + _COLOR_INVALID = -EINVAL, +} ColorMode; + int acquire_terminal(const char *name, AcquireTerminalFlags flags, usec_t timeout); int release_terminal(void); @@ -127,19 +148,44 @@ void reset_terminal_feature_caches(void); bool on_tty(void); bool terminal_is_dumb(void); -bool colors_enabled(void); +ColorMode get_color_mode(void); bool underline_enabled(void); bool dev_console_colors_enabled(void); +static inline bool colors_enabled(void) { + + /* Returns true if colors are considered supported on our stdout. */ + return get_color_mode() != COLOR_OFF; +} + #define DEFINE_ANSI_FUNC(name, NAME) \ static inline const char *ansi_##name(void) { \ return colors_enabled() ? ANSI_##NAME : ""; \ } -#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME, REPLACEMENT) \ - static inline const char *ansi_##name(void) { \ - return underline_enabled() ? ANSI_##NAME : \ - colors_enabled() ? ANSI_##REPLACEMENT : ""; \ +#define DEFINE_ANSI_FUNC_256(name, NAME, FALLBACK) \ + static inline const char *ansi_##name(void) { \ + switch (get_color_mode()) { \ + case COLOR_OFF: return ""; \ + case COLOR_16: return ANSI_##FALLBACK; \ + default : return ANSI_##NAME; \ + } \ + } + +#define DEFINE_ANSI_FUNC_UNDERLINE(name, NAME) \ + static inline const char *ansi_##name(void) { \ + return underline_enabled() ? ANSI_##NAME ANSI_UNDERLINE : \ + colors_enabled() ? ANSI_##NAME : ""; \ + } + + +#define DEFINE_ANSI_FUNC_UNDERLINE_256(name, NAME, FALLBACK) \ + static inline const char *ansi_##name(void) { \ + switch (get_color_mode()) { \ + case COLOR_OFF: return ""; \ + case COLOR_16: return underline_enabled() ? ANSI_##FALLBACK ANSI_UNDERLINE : ANSI_##FALLBACK; \ + default : return underline_enabled() ? ANSI_##NAME ANSI_UNDERLINE: ANSI_##NAME; \ + } \ } DEFINE_ANSI_FUNC(normal, NORMAL); @@ -152,7 +198,7 @@ DEFINE_ANSI_FUNC(blue, BLUE); DEFINE_ANSI_FUNC(magenta, MAGENTA); DEFINE_ANSI_FUNC(cyan, CYAN); DEFINE_ANSI_FUNC(white, WHITE); -DEFINE_ANSI_FUNC(grey, GREY); +DEFINE_ANSI_FUNC_256(grey, GREY, BRIGHT_BLACK); DEFINE_ANSI_FUNC(bright_black, BRIGHT_BLACK); DEFINE_ANSI_FUNC(bright_red, BRIGHT_RED); @@ -163,29 +209,30 @@ DEFINE_ANSI_FUNC(bright_magenta, BRIGHT_MAGENTA); DEFINE_ANSI_FUNC(bright_cyan, BRIGHT_CYAN); DEFINE_ANSI_FUNC(bright_white, BRIGHT_WHITE); -DEFINE_ANSI_FUNC(highlight_black, HIGHLIGHT_BLACK); -DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED); -DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN); -DEFINE_ANSI_FUNC(highlight_yellow, HIGHLIGHT_YELLOW); -DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE); -DEFINE_ANSI_FUNC(highlight_magenta, HIGHLIGHT_MAGENTA); -DEFINE_ANSI_FUNC(highlight_cyan, HIGHLIGHT_CYAN); -DEFINE_ANSI_FUNC(highlight_grey, HIGHLIGHT_GREY); -DEFINE_ANSI_FUNC(highlight_white, HIGHLIGHT_WHITE); +DEFINE_ANSI_FUNC(highlight_black, HIGHLIGHT_BLACK); +DEFINE_ANSI_FUNC(highlight_red, HIGHLIGHT_RED); +DEFINE_ANSI_FUNC(highlight_green, HIGHLIGHT_GREEN); +DEFINE_ANSI_FUNC_256(highlight_yellow, HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK); +DEFINE_ANSI_FUNC_256(highlight_yellow4, HIGHLIGHT_YELLOW4, HIGHLIGHT_YELLOW_FALLBACK); +DEFINE_ANSI_FUNC(highlight_blue, HIGHLIGHT_BLUE); +DEFINE_ANSI_FUNC(highlight_magenta, HIGHLIGHT_MAGENTA); +DEFINE_ANSI_FUNC(highlight_cyan, HIGHLIGHT_CYAN); +DEFINE_ANSI_FUNC_256(highlight_grey, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK); +DEFINE_ANSI_FUNC(highlight_white, HIGHLIGHT_WHITE); static inline const char* _ansi_highlight_yellow(void) { return colors_enabled() ? _ANSI_HIGHLIGHT_YELLOW : ""; } -DEFINE_ANSI_FUNC_UNDERLINE(underline, UNDERLINE, NORMAL); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT_UNDERLINE, HIGHLIGHT); -DEFINE_ANSI_FUNC_UNDERLINE(grey_underline, GREY_UNDERLINE, GREY); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED_UNDERLINE, HIGHLIGHT_RED); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN_UNDERLINE, HIGHLIGHT_GREEN); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_yellow_underline, HIGHLIGHT_YELLOW_UNDERLINE, HIGHLIGHT_YELLOW); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE_UNDERLINE, HIGHLIGHT_BLUE); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta_underline, HIGHLIGHT_MAGENTA_UNDERLINE, HIGHLIGHT_MAGENTA); -DEFINE_ANSI_FUNC_UNDERLINE(highlight_grey_underline, HIGHLIGHT_GREY_UNDERLINE, HIGHLIGHT_GREY); +DEFINE_ANSI_FUNC_UNDERLINE(underline, NORMAL); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_underline, HIGHLIGHT); +DEFINE_ANSI_FUNC_UNDERLINE_256(grey_underline, GREY, BRIGHT_BLACK); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_red_underline, HIGHLIGHT_RED); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_green_underline, HIGHLIGHT_GREEN); +DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_yellow_underline, HIGHLIGHT_YELLOW, HIGHLIGHT_YELLOW_FALLBACK); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_blue_underline, HIGHLIGHT_BLUE); +DEFINE_ANSI_FUNC_UNDERLINE(highlight_magenta_underline, HIGHLIGHT_MAGENTA); +DEFINE_ANSI_FUNC_UNDERLINE_256(highlight_grey_underline, HIGHLIGHT_GREY, HIGHLIGHT_GREY_FALLBACK); int get_ctty_devnr(pid_t pid, dev_t *d); int get_ctty(pid_t, dev_t *_devnr, char **r); @@ -206,5 +253,9 @@ int vt_release(int fd, bool restore_vt); void get_log_colors(int priority, const char **on, const char **off, const char **highlight); +static inline const char* ansi_highlight_green_red(bool b) { + return b ? ansi_highlight_green() : ansi_highlight_red(); +} + /* This assumes there is a 'tty' group */ #define TTY_MODE 0620 diff --git a/src/basic/time-util.c b/src/basic/time-util.c index 5318d6378..3c2b25bd2 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -493,7 +493,6 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { { "us", 1 }, }; - size_t i; char *p = buf; bool something = false; @@ -514,7 +513,7 @@ char *format_timespan(char *buf, size_t l, usec_t t, usec_t accuracy) { /* The result of this function can be parsed with parse_sec */ - for (i = 0; i < ELEMENTSOF(table); i++) { + for (size_t i = 0; i < ELEMENTSOF(table); i++) { int k = 0; size_t n; bool done = false; @@ -962,9 +961,8 @@ static const char* extract_multiplier(const char *p, usec_t *multiplier) { { "us", 1ULL }, { "µs", 1ULL }, }; - size_t i; - for (i = 0; i < ELEMENTSOF(table); i++) { + for (size_t i = 0; i < ELEMENTSOF(table); i++) { char *e; e = startswith(p, table[i].suffix); @@ -1606,7 +1604,7 @@ TimestampStyle timestamp_style_from_string(const char *s) { return t; if (streq_ptr(s, "µs")) return TIMESTAMP_US; - if (streq_ptr(s, "µs+uts")) + if (streq_ptr(s, "µs+utc")) return TIMESTAMP_US_UTC; return t; } diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 89ee8b4a9..d716074fb 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -35,7 +35,7 @@ typedef enum TimestampStyle { TIMESTAMP_UTC, TIMESTAMP_US_UTC, _TIMESTAMP_STYLE_MAX, - _TIMESTAMP_STYLE_INVALID = -1, + _TIMESTAMP_STYLE_INVALID = -EINVAL, } TimestampStyle; #define USEC_INFINITY ((usec_t) UINT64_MAX) @@ -155,16 +155,14 @@ usec_t jiffies_to_usec(uint32_t jiffies); bool in_utc_timezone(void); static inline usec_t usec_add(usec_t a, usec_t b) { - usec_t c; /* Adds two time values, and makes sure USEC_INFINITY as input results as USEC_INFINITY in output, and doesn't * overflow. */ - c = a + b; - if (c < a || c < b) /* overflow check */ + if (a > USEC_INFINITY - b) /* overflow check */ return USEC_INFINITY; - return c; + return a + b; } static inline usec_t usec_sub_unsigned(usec_t timestamp, usec_t delta) { diff --git a/src/basic/tmpfile-util.c b/src/basic/tmpfile-util.c index 49c343773..5ee71d015 100644 --- a/src/basic/tmpfile-util.c +++ b/src/basic/tmpfile-util.c @@ -94,16 +94,11 @@ int fmkostemp_safe(char *pattern, const char *mode, FILE **ret_f) { } int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { - const char *fn; - char *t; + _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL; + int r; assert(ret); - if (isempty(p)) - return -EINVAL; - if (path_equal(p, "/")) - return -EINVAL; - /* * Turns this: * /foo/bar/waldo @@ -112,35 +107,41 @@ int tempfn_xxxxxx(const char *p, const char *extra, char **ret) { * /foo/bar/.#waldoXXXXXX */ - fn = basename(p); - if (!filename_is_valid(fn)) - return -EINVAL; + r = path_extract_directory(p, &d); + if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */ + return r; - extra = strempty(extra); + r = path_extract_filename(p, &fn); + if (r < 0) + return r; - t = new(char, strlen(p) + 2 + strlen(extra) + 6 + 1); - if (!t) + nf = strjoin(".#", strempty(extra), fn, "XXXXXX"); + if (!nf) return -ENOMEM; - strcpy(stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn), "XXXXXX"); + if (!filename_is_valid(nf)) /* New name is not valid? (Maybe because too long?) Refuse. */ + return -EINVAL; + + if (d) { + char *j; + + j = path_join(d, nf); + if (!j) + return -ENOMEM; + + *ret = path_simplify(j, false); + } else + *ret = TAKE_PTR(nf); - *ret = path_simplify(t, false); return 0; } int tempfn_random(const char *p, const char *extra, char **ret) { - const char *fn; - char *t, *x; - uint64_t u; - unsigned i; + _cleanup_free_ char *d = NULL, *fn = NULL, *nf = NULL; + int r; assert(ret); - if (isempty(p)) - return -EINVAL; - if (path_equal(p, "/")) - return -EINVAL; - /* * Turns this: * /foo/bar/waldo @@ -149,34 +150,40 @@ int tempfn_random(const char *p, const char *extra, char **ret) { * /foo/bar/.#waldobaa2a261115984a9 */ - fn = basename(p); - if (!filename_is_valid(fn)) - return -EINVAL; + r = path_extract_directory(p, &d); + if (r < 0 && r != -EDESTADDRREQ) /* EDESTADDRREQ → No directory specified, just a filename */ + return r; - extra = strempty(extra); + r = path_extract_filename(p, &fn); + if (r < 0) + return r; - t = new(char, strlen(p) + 2 + strlen(extra) + 16 + 1); - if (!t) + if (asprintf(&nf, ".#%s%s%016" PRIx64, + strempty(extra), + fn, + random_u64()) < 0) return -ENOMEM; - x = stpcpy(stpcpy(stpcpy(mempcpy(t, p, fn - p), ".#"), extra), fn); + if (!filename_is_valid(nf)) /* Not valid? (maybe because too long now?) — refuse early */ + return -EINVAL; - u = random_u64(); - for (i = 0; i < 16; i++) { - *(x++) = hexchar(u & 0xF); - u >>= 4; - } + if (d) { + char *j; - *x = 0; + j = path_join(d, nf); + if (!j) + return -ENOMEM; + + *ret = path_simplify(j, false); + } else + *ret = TAKE_PTR(nf); - *ret = path_simplify(t, false); return 0; } int tempfn_random_child(const char *p, const char *extra, char **ret) { char *t, *x; uint64_t u; - unsigned i; int r; assert(ret); @@ -205,7 +212,7 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) { x = stpcpy(stpcpy(stpcpy(t, p), "/.#"), extra); u = random_u64(); - for (i = 0; i < 16; i++) { + for (unsigned i = 0; i < 16; i++) { *(x++) = hexchar(u & 0xF); u >>= 4; } diff --git a/src/basic/unit-def.c b/src/basic/unit-def.c index 145399c96..6fbb947f0 100644 --- a/src/basic/unit-def.c +++ b/src/basic/unit-def.c @@ -117,6 +117,13 @@ static const char* const freezer_state_table[_FREEZER_STATE_MAX] = { DEFINE_STRING_TABLE_LOOKUP(freezer_state, FreezerState); +static const char* const unit_marker_table[_UNIT_MARKER_MAX] = { + [UNIT_MARKER_NEEDS_RELOAD] = "needs-reload", + [UNIT_MARKER_NEEDS_RESTART] = "needs-restart", +}; + +DEFINE_STRING_TABLE_LOOKUP(unit_marker, UnitMarker); + static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = { [AUTOMOUNT_DEAD] = "dead", [AUTOMOUNT_WAITING] = "waiting", @@ -287,3 +294,24 @@ static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess); + +SpecialGlyph unit_active_state_to_glyph(UnitActiveState state) { + switch (state) { + case UNIT_ACTIVE: + return SPECIAL_GLYPH_BLACK_CIRCLE; + case UNIT_RELOADING: + return SPECIAL_GLYPH_CIRCLE_ARROW; + case UNIT_INACTIVE: + return SPECIAL_GLYPH_WHITE_CIRCLE; + case UNIT_FAILED: + return SPECIAL_GLYPH_MULTIPLICATION_SIGN; + case UNIT_ACTIVATING: + case UNIT_DEACTIVATING: + return SPECIAL_GLYPH_BLACK_CIRCLE; + case UNIT_MAINTENANCE: + return SPECIAL_GLYPH_WHITE_CIRCLE; + + default: + return SPECIAL_GLYPH_BLACK_CIRCLE; + } +} diff --git a/src/basic/unit-def.h b/src/basic/unit-def.h index 8535fbe06..508b4c504 100644 --- a/src/basic/unit-def.h +++ b/src/basic/unit-def.h @@ -3,6 +3,7 @@ #include +#include "locale-util.h" #include "macro.h" /* The enum order is used to order unit jobs in the job queue @@ -21,7 +22,7 @@ typedef enum UnitType { UNIT_SLICE, UNIT_SCOPE, _UNIT_TYPE_MAX, - _UNIT_TYPE_INVALID = -1 + _UNIT_TYPE_INVALID = -EINVAL, } UnitType; typedef enum UnitLoadState { @@ -33,7 +34,7 @@ typedef enum UnitLoadState { UNIT_MERGED, UNIT_MASKED, _UNIT_LOAD_STATE_MAX, - _UNIT_LOAD_STATE_INVALID = -1 + _UNIT_LOAD_STATE_INVALID = -EINVAL, } UnitLoadState; typedef enum UnitActiveState { @@ -45,7 +46,7 @@ typedef enum UnitActiveState { UNIT_DEACTIVATING, UNIT_MAINTENANCE, _UNIT_ACTIVE_STATE_MAX, - _UNIT_ACTIVE_STATE_INVALID = -1 + _UNIT_ACTIVE_STATE_INVALID = -EINVAL, } UnitActiveState; typedef enum FreezerState { @@ -54,16 +55,23 @@ typedef enum FreezerState { FREEZER_FROZEN, FREEZER_THAWING, _FREEZER_STATE_MAX, - _FREEZER_STATE_INVALID = -1 + _FREEZER_STATE_INVALID = -EINVAL, } FreezerState; +typedef enum UnitMarker { + UNIT_MARKER_NEEDS_RELOAD, + UNIT_MARKER_NEEDS_RESTART, + _UNIT_MARKER_MAX, + _UNIT_MARKER_INVALID = -EINVAL, +} UnitMarker; + typedef enum AutomountState { AUTOMOUNT_DEAD, AUTOMOUNT_WAITING, AUTOMOUNT_RUNNING, AUTOMOUNT_FAILED, _AUTOMOUNT_STATE_MAX, - _AUTOMOUNT_STATE_INVALID = -1 + _AUTOMOUNT_STATE_INVALID = -EINVAL, } AutomountState; /* We simply watch devices, we cannot plug/unplug them. That @@ -73,7 +81,7 @@ typedef enum DeviceState { DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */ DEVICE_PLUGGED, /* announced by udev */ _DEVICE_STATE_MAX, - _DEVICE_STATE_INVALID = -1 + _DEVICE_STATE_INVALID = -EINVAL, } DeviceState; typedef enum MountState { @@ -90,7 +98,7 @@ typedef enum MountState { MOUNT_FAILED, MOUNT_CLEANING, _MOUNT_STATE_MAX, - _MOUNT_STATE_INVALID = -1 + _MOUNT_STATE_INVALID = -EINVAL, } MountState; typedef enum PathState { @@ -99,7 +107,7 @@ typedef enum PathState { PATH_RUNNING, PATH_FAILED, _PATH_STATE_MAX, - _PATH_STATE_INVALID = -1 + _PATH_STATE_INVALID = -EINVAL, } PathState; typedef enum ScopeState { @@ -110,7 +118,7 @@ typedef enum ScopeState { SCOPE_STOP_SIGKILL, SCOPE_FAILED, _SCOPE_STATE_MAX, - _SCOPE_STATE_INVALID = -1 + _SCOPE_STATE_INVALID = -EINVAL, } ScopeState; typedef enum ServiceState { @@ -134,14 +142,14 @@ typedef enum ServiceState { SERVICE_AUTO_RESTART, SERVICE_CLEANING, _SERVICE_STATE_MAX, - _SERVICE_STATE_INVALID = -1 + _SERVICE_STATE_INVALID = -EINVAL, } ServiceState; typedef enum SliceState { SLICE_DEAD, SLICE_ACTIVE, _SLICE_STATE_MAX, - _SLICE_STATE_INVALID = -1 + _SLICE_STATE_INVALID = -EINVAL, } SliceState; typedef enum SocketState { @@ -160,7 +168,7 @@ typedef enum SocketState { SOCKET_FAILED, SOCKET_CLEANING, _SOCKET_STATE_MAX, - _SOCKET_STATE_INVALID = -1 + _SOCKET_STATE_INVALID = -EINVAL, } SocketState; typedef enum SwapState { @@ -174,14 +182,14 @@ typedef enum SwapState { SWAP_FAILED, SWAP_CLEANING, _SWAP_STATE_MAX, - _SWAP_STATE_INVALID = -1 + _SWAP_STATE_INVALID = -EINVAL, } SwapState; typedef enum TargetState { TARGET_DEAD, TARGET_ACTIVE, _TARGET_STATE_MAX, - _TARGET_STATE_INVALID = -1 + _TARGET_STATE_INVALID = -EINVAL, } TargetState; typedef enum TimerState { @@ -191,7 +199,7 @@ typedef enum TimerState { TIMER_ELAPSED, TIMER_FAILED, _TIMER_STATE_MAX, - _TIMER_STATE_INVALID = -1 + _TIMER_STATE_INVALID = -EINVAL, } TimerState; typedef enum UnitDependency { @@ -236,7 +244,7 @@ typedef enum UnitDependency { UNIT_REFERENCED_BY, _UNIT_DEPENDENCY_MAX, - _UNIT_DEPENDENCY_INVALID = -1 + _UNIT_DEPENDENCY_INVALID = -EINVAL, } UnitDependency; typedef enum NotifyAccess { @@ -245,7 +253,7 @@ typedef enum NotifyAccess { NOTIFY_MAIN, NOTIFY_EXEC, _NOTIFY_ACCESS_MAX, - _NOTIFY_ACCESS_INVALID = -1 + _NOTIFY_ACCESS_INVALID = -EINVAL, } NotifyAccess; char *unit_dbus_path_from_name(const char *name); @@ -266,6 +274,9 @@ UnitActiveState unit_active_state_from_string(const char *s) _pure_; const char *freezer_state_to_string(FreezerState i) _const_; FreezerState freezer_state_from_string(const char *s) _pure_; +const char *unit_marker_to_string(UnitMarker m) _const_; +UnitMarker unit_marker_from_string(const char *s) _pure_; + const char* automount_state_to_string(AutomountState i) _const_; AutomountState automount_state_from_string(const char *s) _pure_; @@ -304,3 +315,5 @@ UnitDependency unit_dependency_from_string(const char *s) _pure_; const char* notify_access_to_string(NotifyAccess i) _const_; NotifyAccess notify_access_from_string(const char *s) _pure_; + +SpecialGlyph unit_active_state_to_glyph(UnitActiveState state); diff --git a/src/shared/unit-file.c b/src/basic/unit-file.c similarity index 97% rename from src/shared/unit-file.c rename to src/basic/unit-file.c index 4c307199e..50e6eccbf 100644 --- a/src/shared/unit-file.c +++ b/src/basic/unit-file.c @@ -243,7 +243,7 @@ int unit_file_build_name_map( Set **path_cache) { /* Build two mappings: any name → main unit (i.e. the end result of symlink resolution), unit name → - * all aliases (i.e. the entry for a given key is a a list of all names which point to this key). The + * all aliases (i.e. the entry for a given key is a list of all names which point to this key). The * key is included in the value iff we saw a file or symlink with that name. In other words, if we * have a key, but it is not present in the value for itself, there was an alias pointing to it, but * the unit itself is not loadable. @@ -262,7 +262,7 @@ int unit_file_build_name_map( * If yes, do nothing. */ if (cache_timestamp_hash && lookup_paths_timestamp_hash_same(lp, *cache_timestamp_hash, ×tamp_hash)) - return 0; + return 0; /* The timestamp hash is now set based on the mtimes from before when we start reading files. * If anything is modified concurrently, we'll consider the cache outdated. */ @@ -354,10 +354,16 @@ int unit_file_build_name_map( /* Check if the symlink goes outside of our search path. * If yes, it's a linked unit file or mask, and we don't care about the target name. - * Let's just store the link destination directly. + * Let's just store the link source directly. * If not, let's verify that it's a good symlink. */ char *tail = path_startswith_strv(simplified, lp->search_path); - if (tail) { + if (!tail) { + log_debug("%s: linked unit file: %s → %s", + __func__, filename, simplified); + + dst = filename; + } else { + bool self_alias; dst = basename(simplified); @@ -380,10 +386,6 @@ int unit_file_build_name_map( } log_debug("%s: alias: %s/%s → %s", __func__, *dir, de->d_name, dst); - } else { - dst = simplified; - - log_debug("%s: linked unit file: %s/%s → %s", __func__, *dir, de->d_name, dst); } } else { @@ -511,7 +513,7 @@ int unit_file_find_fragment( r = unit_name_template(unit_name, &template); if (r < 0) - return log_error_errno(r, "Failed to determine template name: %m"); + return log_debug_errno(r, "Failed to determine template name: %m"); r = unit_ids_map_get(unit_ids_map, template, &fragment); if (r < 0 && !IN_SET(r, -ENOENT, -ENXIO)) @@ -580,7 +582,6 @@ static const char * const rlmap_initrd[] = { const char* runlevel_to_target(const char *word) { const char * const *rlmap_ptr; - size_t i; if (!word) return NULL; @@ -593,7 +594,7 @@ const char* runlevel_to_target(const char *word) { rlmap_ptr = in_initrd() ? rlmap_initrd : rlmap; - for (i = 0; rlmap_ptr[i]; i += 2) + for (size_t i = 0; rlmap_ptr[i]; i += 2) if (streq(word, rlmap_ptr[i])) return rlmap_ptr[i+1]; diff --git a/src/shared/unit-file.h b/src/basic/unit-file.h similarity index 95% rename from src/shared/unit-file.h rename to src/basic/unit-file.h index 5463b0ab1..cc731a9e0 100644 --- a/src/shared/unit-file.h +++ b/src/basic/unit-file.h @@ -26,7 +26,7 @@ enum UnitFileState { UNIT_FILE_TRANSIENT, UNIT_FILE_BAD, _UNIT_FILE_STATE_MAX, - _UNIT_FILE_STATE_INVALID = -1 + _UNIT_FILE_STATE_INVALID = -EINVAL, }; enum UnitFileScope { @@ -34,7 +34,7 @@ enum UnitFileScope { UNIT_FILE_GLOBAL, UNIT_FILE_USER, _UNIT_FILE_SCOPE_MAX, - _UNIT_FILE_SCOPE_INVALID = -1 + _UNIT_FILE_SCOPE_INVALID = -EINVAL, }; bool unit_type_may_alias(UnitType type) _const_; diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index c1529bbee..532f8fa04 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -252,7 +252,7 @@ int unit_name_build(const char *prefix, const char *instance, const char *suffix type = unit_type_from_string(suffix + 1); if (type < 0) - return -EINVAL; + return type; return unit_name_build_from_type(prefix, instance, type, ret); } diff --git a/src/basic/unit-name.h b/src/basic/unit-name.h index c25672fad..19d70abea 100644 --- a/src/basic/unit-name.h +++ b/src/basic/unit-name.h @@ -13,7 +13,7 @@ typedef enum UnitNameFlags { UNIT_NAME_TEMPLATE = 1 << 1, /* Allow foo@.service */ UNIT_NAME_INSTANCE = 1 << 2, /* Allow foo@bar.service */ UNIT_NAME_ANY = UNIT_NAME_PLAIN|UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE, - _UNIT_NAME_INVALID = -1, + _UNIT_NAME_INVALID = -EINVAL, } UnitNameFlags; bool unit_name_is_valid(const char *n, UnitNameFlags flags) _pure_; diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 933a398e7..0ea4e409f 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -836,7 +836,7 @@ bool valid_user_group_name(const char *u, ValidUserFlags flags) { if (l > (size_t) sz) return false; - if (l > FILENAME_MAX) + if (l > NAME_MAX) /* must fit in a filename */ return false; if (l > UT_NAMESIZE - 1) return false; @@ -882,7 +882,7 @@ char *mangle_gecos(const char *d) { continue; } - len = utf8_encoded_valid_unichar(i, (size_t) -1); + len = utf8_encoded_valid_unichar(i, SIZE_MAX); if (len < 0) { *i = ' '; continue; diff --git a/src/basic/utf8.c b/src/basic/utf8.c index 59663c035..46c3a463b 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -81,7 +81,7 @@ static size_t utf8_encoded_expected_len(uint8_t c) { /* decode one unicode char */ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) { char32_t unichar; - size_t len, i; + size_t len; assert(str); @@ -110,7 +110,7 @@ int utf8_encoded_to_unichar(const char *str, char32_t *ret_unichar) { return -EINVAL; } - for (i = 1; i < len; i++) { + for (size_t i = 1; i < len; i++) { if (((char32_t)str[i] & 0xc0) != 0x80) return -EINVAL; @@ -156,14 +156,14 @@ char *utf8_is_valid_n(const char *str, size_t len_bytes) { assert(str); - for (const char *p = str; len_bytes != (size_t) -1 ? (size_t) (p - str) < len_bytes : *p != '\0'; ) { + for (const char *p = str; len_bytes != SIZE_MAX ? (size_t) (p - str) < len_bytes : *p != '\0'; ) { int len; - if (_unlikely_(*p == '\0') && len_bytes != (size_t) -1) + if (_unlikely_(*p == '\0') && len_bytes != SIZE_MAX) return NULL; /* embedded NUL */ len = utf8_encoded_valid_unichar(p, - len_bytes != (size_t) -1 ? len_bytes - (p - str) : (size_t) -1); + len_bytes != SIZE_MAX ? len_bytes - (p - str) : SIZE_MAX); if (_unlikely_(len < 0)) return NULL; /* invalid character */ @@ -185,7 +185,7 @@ char *utf8_escape_invalid(const char *str) { while (*str) { int len; - len = utf8_encoded_valid_unichar(str, (size_t) -1); + len = utf8_encoded_valid_unichar(str, SIZE_MAX); if (len > 0) { s = mempcpy(s, str, len); str += len; @@ -233,7 +233,7 @@ char *utf8_escape_non_printable_full(const char *str, size_t console_width) { if (!*str) /* done! */ goto finish; - len = utf8_encoded_valid_unichar(str, (size_t) -1); + len = utf8_encoded_valid_unichar(str, SIZE_MAX); if (len > 0) { if (utf8_is_printable(str, len)) { int w; @@ -302,14 +302,12 @@ char *ascii_is_valid(const char *str) { } char *ascii_is_valid_n(const char *str, size_t len) { - size_t i; - /* Very similar to ascii_is_valid(), but checks exactly len * bytes and rejects any NULs in that range. */ assert(str); - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) if ((unsigned char) str[i] >= 128 || str[i] == 0) return NULL; @@ -436,7 +434,6 @@ size_t utf16_encode_unichar(char16_t *out, char32_t c) { char16_t *utf8_to_utf16(const char *s, size_t length) { char16_t *n, *p; - size_t i; int r; assert(s); @@ -447,7 +444,7 @@ char16_t *utf8_to_utf16(const char *s, size_t length) { p = n; - for (i = 0; i < length;) { + for (size_t i = 0; i < length;) { char32_t unichar; size_t e; @@ -505,13 +502,13 @@ static int utf8_unichar_to_encoded_len(char32_t unichar) { /* validate one encoded unicode char and return its length */ int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) { char32_t unichar; - size_t len, i; + size_t len; int r; assert(str); assert(length > 0); - /* We read until NUL, at most length bytes. (size_t) -1 may be used to disable the length check. */ + /* We read until NUL, at most length bytes. SIZE_MAX may be used to disable the length check. */ len = utf8_encoded_expected_len(str[0]); if (len == 0) @@ -526,7 +523,7 @@ int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) { return 1; /* check if expected encoded chars are available */ - for (i = 0; i < len; i++) + for (size_t i = 0; i < len; i++) if ((str[i] & 0x80) != 0x80) return -EINVAL; @@ -548,14 +545,14 @@ int utf8_encoded_valid_unichar(const char *str, size_t length /* bytes */) { size_t utf8_n_codepoints(const char *str) { size_t n = 0; - /* Returns the number of UTF-8 codepoints in this string, or (size_t) -1 if the string is not valid UTF-8. */ + /* Returns the number of UTF-8 codepoints in this string, or SIZE_MAX if the string is not valid UTF-8. */ while (*str != 0) { int k; - k = utf8_encoded_valid_unichar(str, (size_t) -1); + k = utf8_encoded_valid_unichar(str, SIZE_MAX); if (k < 0) - return (size_t) -1; + return SIZE_MAX; str += k; n++; @@ -575,7 +572,7 @@ size_t utf8_console_width(const char *str) { w = utf8_char_console_width(str); if (w < 0) - return (size_t) -1; + return SIZE_MAX; n += w; str = utf8_next_char(str); diff --git a/src/basic/utf8.h b/src/basic/utf8.h index a6ea942c6..219ca8918 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -16,7 +16,7 @@ bool unichar_is_valid(char32_t c); char *utf8_is_valid_n(const char *str, size_t len_bytes) _pure_; static inline char *utf8_is_valid(const char *s) { - return utf8_is_valid_n(s, (size_t) -1); + return utf8_is_valid_n(s, SIZE_MAX); } char *ascii_is_valid(const char *s) _pure_; char *ascii_is_valid_n(const char *str, size_t len); @@ -27,7 +27,7 @@ bool utf8_is_printable_newline(const char* str, size_t length, bool allow_newlin char *utf8_escape_invalid(const char *s); char *utf8_escape_non_printable_full(const char *str, size_t console_width); static inline char *utf8_escape_non_printable(const char *str) { - return utf8_escape_non_printable_full(str, (size_t) -1); + return utf8_escape_non_printable_full(str, SIZE_MAX); } size_t utf8_encode_unichar(char *out_utf8, char32_t g); diff --git a/src/basic/util.c b/src/basic/util.c index f98ecf385..955b18bd2 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -52,13 +52,14 @@ int prot_from_flags(int flags) { } bool in_initrd(void) { - struct statfs s; int r; + const char *e; + bool lenient = false; if (saved_in_initrd >= 0) return saved_in_initrd; - /* We make two checks here: + /* We have two checks here: * * 1. the flag file /etc/initrd-release must exist * 2. the root file system must be a memory file system @@ -66,18 +67,46 @@ bool in_initrd(void) { * The second check is extra paranoia, since misdetecting an * initrd can have bad consequences due the initrd * emptying when transititioning to the main systemd. + * + * If env var $SYSTEMD_IN_INITRD is not set or set to "auto", + * both checks are used. If it's set to "lenient", only check + * 1 is used. If set to a boolean value, then the boolean + * value is returned. */ - r = getenv_bool_secure("SYSTEMD_IN_INITRD"); - if (r < 0 && r != -ENXIO) - log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m"); + e = secure_getenv("SYSTEMD_IN_INITRD"); + if (e) { + if (streq(e, "lenient")) + lenient = true; + else if (!streq(e, "auto")) { + r = parse_boolean(e); + if (r >= 0) { + saved_in_initrd = r > 0; + return saved_in_initrd; + } + log_debug_errno(r, "Failed to parse $SYSTEMD_IN_INITRD, ignoring: %m"); + } + } + + if (!lenient) { + r = path_is_temporary_fs("/"); + if (r < 0) + log_debug_errno(r, "Couldn't determine if / is a temporary file system: %m"); - if (r >= 0) saved_in_initrd = r > 0; - else - saved_in_initrd = access("/etc/initrd-release", F_OK) >= 0 && - statfs("/", &s) >= 0 && - is_temporary_fs(&s); + } + + r = access("/etc/initrd-release", F_OK); + if (r >= 0) { + if (saved_in_initrd == 0) + log_debug("/etc/initrd-release exists, but it's not an initrd."); + else + saved_in_initrd = 1; + } else { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to test if /etc/initrd-release exists: %m"); + saved_in_initrd = 0; + } return saved_in_initrd; } @@ -165,7 +194,7 @@ int container_get_leader(const char *machine, pid_t *pid) { return 0; } - if (!machine_name_is_valid(machine)) + if (!hostname_is_valid(machine, 0)) return -EINVAL; p = strjoina("/run/systemd/machines/", machine); @@ -193,73 +222,11 @@ int container_get_leader(const char *machine, pid_t *pid) { } int version(void) { - puts("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n" - SYSTEMD_FEATURES); + printf("systemd " STRINGIFY(PROJECT_VERSION) " (" GIT_VERSION ")\n%s\n", + systemd_features); return 0; } -/* This is a direct translation of str_verscmp from boot.c */ -static bool is_digit(int c) { - return c >= '0' && c <= '9'; -} - -static int c_order(int c) { - if (c == 0 || is_digit(c)) - return 0; - - if ((c >= 'a') && (c <= 'z')) - return c; - - return c + 0x10000; -} - -int str_verscmp(const char *s1, const char *s2) { - const char *os1, *os2; - - assert(s1); - assert(s2); - - os1 = s1; - os2 = s2; - - while (*s1 || *s2) { - int first; - - while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) { - int order; - - order = c_order(*s1) - c_order(*s2); - if (order != 0) - return order; - s1++; - s2++; - } - - while (*s1 == '0') - s1++; - while (*s2 == '0') - s2++; - - first = 0; - while (is_digit(*s1) && is_digit(*s2)) { - if (first == 0) - first = *s1 - *s2; - s1++; - s2++; - } - - if (is_digit(*s1)) - return 1; - if (is_digit(*s2)) - return -1; - - if (first != 0) - return first; - } - - return strcmp(os1, os2); -} - /* Turn off core dumps but only if we're running outside of a container. */ void disable_coredumps(void) { int r; diff --git a/src/basic/util.h b/src/basic/util.h index 942d773ff..b6c51c036 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -63,6 +63,4 @@ int container_get_leader(const char *machine, pid_t *pid); int version(void); -int str_verscmp(const char *s1, const char *s2); - void disable_coredumps(void); diff --git a/src/basic/virt.c b/src/basic/virt.c index 7d78a402b..335f59d6f 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -9,6 +9,7 @@ #include #include "alloc-util.h" +#include "cgroup-util.h" #include "dirent-util.h" #include "env-util.h" #include "fd-util.h" @@ -159,10 +160,9 @@ static int detect_vm_dmi(void) { /* https://wiki.freebsd.org/bhyve */ { "BHYVE", VIRTUALIZATION_BHYVE }, }; - unsigned i; int r; - for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { + for (size_t i = 0; i < ELEMENTSOF(dmi_vendors); i++) { _cleanup_free_ char *s = NULL; unsigned j; @@ -454,11 +454,103 @@ static const char *const container_table[_VIRTUALIZATION_MAX] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(container, int); +static int running_in_cgroupns(void) { + int r; + + if (!cg_ns_supported()) + return false; + + r = cg_all_unified(); + if (r < 0) + return r; + + if (r) { + /* cgroup v2 */ + + r = access("/sys/fs/cgroup/cgroup.events", F_OK); + if (r < 0) { + if (errno != ENOENT) + return -errno; + /* All kernel versions have cgroup.events in nested cgroups. */ + return false; + } + + /* There's no cgroup.type in the root cgroup, and future kernel versions + * are unlikely to add it since cgroup.type is something that makes no sense + * whatsoever in the root cgroup. */ + r = access("/sys/fs/cgroup/cgroup.type", F_OK); + if (r == 0) + return true; + if (r < 0 && errno != ENOENT) + return -errno; + + /* On older kernel versions, there's no cgroup.type */ + r = access("/sys/kernel/cgroup/features", F_OK); + if (r < 0) { + if (errno != ENOENT) + return -errno; + /* This is an old kernel that we know for sure has cgroup.events + * only in nested cgroups. */ + return true; + } + + /* This is a recent kernel, and cgroup.type doesn't exist, so we must be + * in the root cgroup. */ + return false; + } else { + /* cgroup v1 */ + + /* If systemd controller is not mounted, do not even bother. */ + r = access("/sys/fs/cgroup/systemd", F_OK); + if (r < 0) { + if (errno != ENOENT) + return -errno; + return false; + } + + /* release_agent only exists in the root cgroup. */ + r = access("/sys/fs/cgroup/systemd/release_agent", F_OK); + if (r < 0) { + if (errno != ENOENT) + return -errno; + return true; + } + + return false; + } +} + +static int detect_container_files(void) { + unsigned i; + + static const struct { + const char *file_path; + int id; + } container_file_table[] = { + /* https://github.com/containers/podman/issues/6192 */ + /* https://github.com/containers/podman/issues/3586#issuecomment-661918679 */ + { "/run/.containerenv", VIRTUALIZATION_PODMAN }, + /* https://github.com/moby/moby/issues/18355 */ + /* Docker must be the last in this table, see below. */ + { "/.dockerenv", VIRTUALIZATION_DOCKER }, + }; + + for (i = 0; i < ELEMENTSOF(container_file_table); i++) { + if (access(container_file_table[i].file_path, F_OK) >= 0) + return container_file_table[i].id; + + if (errno != ENOENT) + log_debug_errno(errno, + "Checking if %s exists failed, ignoring: %m", + container_file_table[i].file_path); + } + + return VIRTUALIZATION_NONE; +} + int detect_container(void) { static thread_local int cached_found = _VIRTUALIZATION_INVALID; - _cleanup_free_ char *m = NULL; - _cleanup_free_ char *o = NULL; - _cleanup_free_ char *p = NULL; + _cleanup_free_ char *m = NULL, *o = NULL, *p = NULL; const char *e = NULL; int r; @@ -466,16 +558,23 @@ int detect_container(void) { return cached_found; /* /proc/vz exists in container and outside of the container, /proc/bc only outside of the container. */ - if (access("/proc/vz", F_OK) >= 0 && - access("/proc/bc", F_OK) < 0) { - r = VIRTUALIZATION_OPENVZ; - goto finish; + if (access("/proc/vz", F_OK) < 0) { + if (errno != ENOENT) + log_debug_errno(errno, "Failed to check if /proc/vz exists, ignoring: %m"); + } else if (access("/proc/bc", F_OK) < 0) { + if (errno == ENOENT) { + r = VIRTUALIZATION_OPENVZ; + goto finish; + } + + log_debug_errno(errno, "Failed to check if /proc/bc exists, ignoring: %m"); } /* "Official" way of detecting WSL https://github.com/Microsoft/WSL/issues/423#issuecomment-221627364 */ r = read_one_line_file("/proc/sys/kernel/osrelease", &o); - if (r >= 0 && - (strstr(o, "Microsoft") || strstr(o, "WSL"))) { + if (r < 0) + log_debug_errno(r, "Failed to read /proc/sys/kernel/osrelease, ignoring: %m"); + else if (strstr(o, "Microsoft") || strstr(o, "WSL")) { r = VIRTUALIZATION_WSL; goto finish; } @@ -484,21 +583,30 @@ int detect_container(void) { * invocation without worrying about it being elsewhere. */ r = get_proc_field("/proc/self/status", "TracerPid", WHITESPACE, &p); - if (r == 0 && !streq(p, "0")) { + if (r < 0) + log_debug_errno(r, "Failed to read our own trace PID, ignoring: %m"); + else if (!streq(p, "0")) { pid_t ptrace_pid; + r = parse_pid(p, &ptrace_pid); - if (r == 0) { - const char *pf = procfs_file_alloca(ptrace_pid, "comm"); + if (r < 0) + log_debug_errno(r, "Failed to parse our own tracer PID, ignoring: %m"); + else { _cleanup_free_ char *ptrace_comm = NULL; + const char *pf; + + pf = procfs_file_alloca(ptrace_pid, "comm"); r = read_one_line_file(pf, &ptrace_comm); - if (r >= 0 && startswith(ptrace_comm, "proot")) { + if (r < 0) + log_debug_errno(r, "Failed to read %s, ignoring: %m", pf); + else if (startswith(ptrace_comm, "proot")) { r = VIRTUALIZATION_PROOT; goto finish; } } } - /* The container manager might have placed this in the /run/host hierarchy for us, which is best + /* The container manager might have placed this in the /run/host/ hierarchy for us, which is best * because we can be consumed just like that, without special privileges. */ r = read_one_line_file("/run/host/container-manager", &m); if (r > 0) { @@ -506,7 +614,7 @@ int detect_container(void) { goto translate_name; } if (!IN_SET(r, -ENOENT, 0)) - return log_debug_errno(r, "Failed to read /run/systemd/container-manager: %m"); + return log_debug_errno(r, "Failed to read /run/host/container-manager: %m"); if (getpid_cached() == 1) { /* If we are PID 1 we can just check our own environment variable, and that's authoritative. @@ -517,7 +625,7 @@ int detect_container(void) { */ e = getenv("container"); if (!e) - goto check_sched; + goto check_files; if (isempty(e)) { r = VIRTUALIZATION_NONE; goto finish; @@ -545,29 +653,36 @@ int detect_container(void) { if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */ log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m"); - /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. If the PID - * shown there is not 1, we know we are in a PID namespace and hence a container. */ - check_sched: - r = read_one_line_file("/proc/1/sched", &m); - if (r >= 0) { - const char *t; +check_files: + /* Check for existence of some well-known files. We only do this after checking + * for other specific container managers, otherwise we risk mistaking another + * container manager for Docker: the /.dockerenv file could inadvertently end up + * in a file system image. */ + r = detect_container_files(); + if (r) + goto finish; - t = strrchr(m, '('); - if (!t) - return -EIO; + r = running_in_cgroupns(); + if (r > 0) { + r = VIRTUALIZATION_CONTAINER_OTHER; + goto finish; + } + if (r < 0) + log_debug_errno(r, "Failed to detect cgroup namespace: %m"); - if (!startswith(t, "(1,")) { - r = VIRTUALIZATION_CONTAINER_OTHER; - goto finish; - } - } else if (r != -ENOENT) - return r; - - /* If that didn't work, give up, assume no container manager. */ + /* If none of that worked, give up, assume no container manager. */ r = VIRTUALIZATION_NONE; goto finish; translate_name: + if (streq(e, "oci")) { + /* Some images hardcode container=oci, but OCI is not a specific container manager. + * Try to detect one based on well-known files. */ + r = detect_container_files(); + if (!r) + r = VIRTUALIZATION_CONTAINER_OTHER; + goto finish; + } r = container_from_string(e); if (r < 0) r = VIRTUALIZATION_CONTAINER_OTHER; @@ -671,6 +786,131 @@ int running_in_chroot(void) { return r == 0; } +#if defined(__i386__) || defined(__x86_64__) +struct cpuid_table_entry { + uint32_t flag_bit; + const char *name; +}; + +static const struct cpuid_table_entry leaf1_edx[] = { + { 0, "fpu" }, + { 1, "vme" }, + { 2, "de" }, + { 3, "pse" }, + { 4, "tsc" }, + { 5, "msr" }, + { 6, "pae" }, + { 7, "mce" }, + { 8, "cx8" }, + { 9, "apic" }, + { 11, "sep" }, + { 12, "mtrr" }, + { 13, "pge" }, + { 14, "mca" }, + { 15, "cmov" }, + { 16, "pat" }, + { 17, "pse36" }, + { 19, "clflush" }, + { 23, "mmx" }, + { 24, "fxsr" }, + { 25, "sse" }, + { 26, "sse2" }, + { 28, "ht" }, +}; + +static const struct cpuid_table_entry leaf1_ecx[] = { + { 0, "pni" }, + { 1, "pclmul" }, + { 3, "monitor" }, + { 9, "ssse3" }, + { 12, "fma3" }, + { 13, "cx16" }, + { 19, "sse4_1" }, + { 20, "sse4_2" }, + { 22, "movbe" }, + { 23, "popcnt" }, + { 25, "aes" }, + { 26, "xsave" }, + { 27, "osxsave" }, + { 28, "avx" }, + { 29, "f16c" }, + { 30, "rdrand" }, +}; + +static const struct cpuid_table_entry leaf7_ebx[] = { + { 3, "bmi1" }, + { 5, "avx2" }, + { 8, "bmi2" }, + { 18, "rdseed" }, + { 19, "adx" }, + { 29, "sha_ni" }, +}; + +static const struct cpuid_table_entry leaf81_edx[] = { + { 11, "syscall" }, + { 27, "rdtscp" }, + { 29, "lm" }, +}; + +static const struct cpuid_table_entry leaf81_ecx[] = { + { 0, "lahf_lm" }, + { 5, "abm" }, +}; + +static const struct cpuid_table_entry leaf87_edx[] = { + { 8, "constant_tsc" }, +}; + +static bool given_flag_in_set(const char *flag, const struct cpuid_table_entry *set, size_t set_size, uint32_t val) { + for (size_t i = 0; i < set_size; i++) { + if ((UINT32_C(1) << set[i].flag_bit) & val && + streq(flag, set[i].name)) + return true; + } + return false; +} + +static bool real_has_cpu_with_flag(const char *flag) { + uint32_t eax, ebx, ecx, edx; + + if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) { + if (given_flag_in_set(flag, leaf1_ecx, ELEMENTSOF(leaf1_ecx), ecx)) + return true; + + if (given_flag_in_set(flag, leaf1_edx, ELEMENTSOF(leaf1_edx), edx)) + return true; + } + + if (__get_cpuid(7, &eax, &ebx, &ecx, &edx)) { + if (given_flag_in_set(flag, leaf7_ebx, ELEMENTSOF(leaf7_ebx), ebx)) + return true; + } + + if (__get_cpuid(0x80000001U, &eax, &ebx, &ecx, &edx)) { + if (given_flag_in_set(flag, leaf81_ecx, ELEMENTSOF(leaf81_ecx), ecx)) + return true; + + if (given_flag_in_set(flag, leaf81_edx, ELEMENTSOF(leaf81_edx), edx)) + return true; + } + + if (__get_cpuid(0x80000007U, &eax, &ebx, &ecx, &edx)) + if (given_flag_in_set(flag, leaf87_edx, ELEMENTSOF(leaf87_edx), edx)) + return true; + + return false; +} +#endif + +bool has_cpu_with_flag(const char *flag) { + /* CPUID is an x86 specific interface. Assume on all others that no CPUs have those flags. */ +#if defined(__i386__) || defined(__x86_64__) + return real_has_cpu_with_flag(flag); +#else + return false; +#endif +} + static const char *const virtualization_table[_VIRTUALIZATION_MAX] = { [VIRTUALIZATION_NONE] = "none", [VIRTUALIZATION_KVM] = "kvm", diff --git a/src/basic/virt.h b/src/basic/virt.h index 42d63d513..378c7c4d2 100644 --- a/src/basic/virt.h +++ b/src/basic/virt.h @@ -41,7 +41,7 @@ enum { VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER, _VIRTUALIZATION_MAX, - _VIRTUALIZATION_INVALID = -1 + _VIRTUALIZATION_INVALID = -EINVAL, }; static inline bool VIRTUALIZATION_IS_VM(int x) { @@ -61,3 +61,4 @@ int running_in_chroot(void); const char *virtualization_to_string(int v) _const_; int virtualization_from_string(const char *s) _pure_; +bool has_cpu_with_flag(const char *flag); diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index b9a0dc54c..c175ce1fb 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -147,7 +147,7 @@ static int parse_crtime(le64_t le, usec_t *usec) { assert(usec); u = le64toh(le); - if (IN_SET(u, 0, (uint64_t) -1)) + if (IN_SET(u, 0, UINT64_MAX)) return -EIO; *usec = (usec_t) u; diff --git a/src/binfmt/binfmt.c b/src/binfmt/binfmt.c index 43ed2f385..f6b72e0ba 100644 --- a/src/binfmt/binfmt.c +++ b/src/binfmt/binfmt.c @@ -118,10 +118,9 @@ static int help(void) { " --cat-config Show configuration files\n" " --no-pager Do not pipe output into a pager\n" " --unregister Unregister all existing entries\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -191,7 +190,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/boot/bless-boot.c b/src/boot/bless-boot.c index cd34f88bb..bd6f64915 100644 --- a/src/boot/bless-boot.c +++ b/src/boot/bless-boot.c @@ -42,12 +42,11 @@ static int help(int argc, char *argv[], void *userdata) { " -h --help Show this help\n" " --version Print version\n" " --path=PATH Path to the $BOOT partition (may be used multiple times)\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } diff --git a/src/boot/boot-check-no-failures.c b/src/boot/boot-check-no-failures.c index 92f3cd4ed..cb4f758cb 100644 --- a/src/boot/boot-check-no-failures.c +++ b/src/boot/boot-check-no-failures.c @@ -27,12 +27,11 @@ static int help(void) { "\n%sVerify system operational state.%s\n\n" " -h --help Show this help\n" " --version Print version\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 511b0105f..04cc7664e 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -471,7 +471,7 @@ static int compare_version(const char *a, const char *b) { b += strcspn(b, " "); b += strspn(b, " "); - return strverscmp(a, b); + return strverscmp_improved(a, b); } static int version_check(int fd_from, const char *from, int fd_to, const char *to) { @@ -541,7 +541,7 @@ static int copy_file_with_version_check(const char *from, const char *to, bool f return log_error_errno(errno, "Failed to open \"%s\" for writing: %m", t); } - r = copy_bytes(fd_from, fd_to, (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(fd_from, fd_to, UINT64_MAX, COPY_REFLINK); if (r < 0) { (void) unlink(t); return log_error_errno(r, "Failed to copy data from \"%s\" to \"%s\": %m", from, t); @@ -1043,12 +1043,13 @@ static int help(int argc, char *argv[], void *userdata) { " --no-pager Do not pipe output into a pager\n" " --graceful Don't fail when the ESP cannot be found or EFI\n" " variables cannot be written\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - , ansi_underline(), ansi_normal() - , ansi_highlight(), ansi_normal() - ); + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); return 0; } @@ -1152,8 +1153,8 @@ static void read_loader_efi_var(const char *name, char **var) { static void print_yes_no_line(bool first, bool good, const char *name) { printf("%s%s%s%s %s\n", first ? " Features: " : " ", - good ? ansi_highlight_green() : ansi_highlight_red(), - good ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK), + ansi_highlight_green_red(good), + special_glyph_check_mark(good), ansi_normal(), name); } @@ -1232,6 +1233,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal()); printf(" Secure Boot: %sd\n", enable_disable(is_efi_secure_boot())); printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user"); + printf(" TPM2 Support: %s\n", yes_no(efi_has_tpm2())); k = efi_get_reboot_to_firmware(); if (k > 0) @@ -1257,7 +1259,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { print_yes_no_line(false, have_bootloader_esp_uuid, "Boot loader sets ESP partition information"); if (have_bootloader_esp_uuid && !sd_id128_equal(esp_uuid, bootloader_esp_uuid)) - printf("WARNING: The boot loader reports different ESP UUID then detected!\n"); + printf("WARNING: The boot loader reports a different ESP UUID than detected!\n"); if (stub) printf(" Stub: %s\n", stub); diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c index 938e5645f..35248db00 100644 --- a/src/boot/efi/boot.c +++ b/src/boot/efi/boot.c @@ -7,12 +7,13 @@ #include "console.h" #include "crc32.h" #include "disk.h" +#include "efi-loader-features.h" #include "graphics.h" #include "linux.h" -#include "loader-features.h" #include "measure.h" #include "pe.h" #include "random-seed.h" +#include "secure-boot.h" #include "shim.h" #include "util.h" @@ -23,8 +24,6 @@ /* magic string to find in the binary image */ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-boot " GIT_VERSION " ####"; -static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; - enum loader_type { LOADER_UNDEFINED, LOADER_EFI, @@ -119,17 +118,17 @@ static BOOLEAN line_edit( while (!exit) { EFI_STATUS err; UINT64 key; - UINTN i; + UINTN j; - i = len - first; - if (i >= x_max-1) - i = x_max-1; - CopyMem(print, line + first, i * sizeof(CHAR16)); - while (clear > 0 && i < x_max-1) { + j = len - first; + if (j >= x_max-1) + j = x_max-1; + CopyMem(print, line + first, j * sizeof(CHAR16)); + while (clear > 0 && j < x_max-1) { clear--; - print[i++] = ' '; + print[j++] = ' '; } - print[i] = '\0'; + print[j] = '\0'; uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_pos); uefi_call_wrapper(ST->ConOut->OutputString, 2, ST->ConOut, print); @@ -213,12 +212,14 @@ static BOOLEAN line_edit( case KEYPRESS(EFI_ALT_PRESSED, 0, 'd'): /* kill-word */ clear = 0; - for (i = first + cursor; i < len && line[i] == ' '; i++) + + UINTN k; + for (k = first + cursor; k < len && line[k] == ' '; k++) clear++; - for (; i < len && line[i] != ' '; i++) + for (; k < len && line[k] != ' '; k++) clear++; - for (i = first + cursor; i + clear < len; i++) + for (UINTN i = first + cursor; i + clear < len; i++) line[i] = line[i + clear]; len -= clear; line[len] = '\0'; @@ -243,7 +244,7 @@ static BOOLEAN line_edit( } uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, cursor, y_pos); - for (i = first + cursor; i + clear < len; i++) + for (UINTN i = first + cursor; i + clear < len; i++) line[i] = line[i + clear]; len -= clear; line[len] = '\0'; @@ -256,7 +257,7 @@ static BOOLEAN line_edit( continue; if (first + cursor == len) continue; - for (i = first + cursor; i < len; i++) + for (UINTN i = first + cursor; i < len; i++) line[i] = line[i+1]; clear = 1; len--; @@ -285,7 +286,7 @@ static BOOLEAN line_edit( continue; if (first == 0 && cursor == 0) continue; - for (i = first + cursor-1; i < len; i++) + for (UINTN i = first + cursor-1; i < len; i++) line[i] = line[i+1]; clear = 1; len--; @@ -313,7 +314,7 @@ static BOOLEAN line_edit( case KEYPRESS(0, 0, 0x80) ... KEYPRESS(0, 0, 0xffff): if (len+1 == size) continue; - for (i = len; i > first + cursor; i--) + for (UINTN i = len; i > first + cursor; i--) line[i] = line[i-1]; line[first + cursor] = KEYCHAR(key); len++; @@ -331,25 +332,23 @@ static BOOLEAN line_edit( } static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) { - UINTN i; - if (key == 0) return -1; /* select entry by number key */ if (key >= '1' && key <= '9') { - i = key - '0'; + UINTN i = key - '0'; if (i > config->entry_count) i = config->entry_count; return i-1; } /* find matching key in config entries */ - for (i = start; i < config->entry_count; i++) + for (UINTN i = start; i < config->entry_count; i++) if (config->entries[i]->key == key) return i; - for (i = 0; i < start; i++) + for (UINTN i = 0; i < start; i++) if (config->entries[i]->key == key) return i; @@ -357,11 +356,11 @@ static UINTN entry_lookup_key(Config *config, UINTN start, CHAR16 key) { } static VOID print_status(Config *config, CHAR16 *loaded_image_path) { - UINT64 key; - UINTN i; - _cleanup_freepool_ CHAR8 *bootvar = NULL, *modevar = NULL, *indvar = NULL; + UINT64 key, indvar; + UINTN timeout; + BOOLEAN modevar; _cleanup_freepool_ CHAR16 *partstr = NULL, *defaultstr = NULL; - UINTN x, y, size; + UINTN x, y; uefi_call_wrapper(ST->ConOut->SetAttribute, 2, ST->ConOut, EFI_LIGHTGRAY|EFI_BACKGROUND_BLACK); uefi_call_wrapper(ST->ConOut->ClearScreen, 1, ST->ConOut); @@ -376,17 +375,16 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { if (uefi_call_wrapper(ST->ConOut->QueryMode, 4, ST->ConOut, ST->ConOut->Mode->Mode, &x, &y) == EFI_SUCCESS) Print(L"console size: %d x %d\n", x, y); - if (efivar_get_raw(&global_guid, L"SecureBoot", &bootvar, &size) == EFI_SUCCESS) - Print(L"SecureBoot: %s\n", yes_no(*bootvar > 0)); + Print(L"SecureBoot: %s\n", yes_no(secure_boot_enabled())); - if (efivar_get_raw(&global_guid, L"SetupMode", &modevar, &size) == EFI_SUCCESS) - Print(L"SetupMode: %s\n", *modevar > 0 ? L"setup" : L"user"); + if (efivar_get_boolean_u8(EFI_GLOBAL_GUID, L"SetupMode", &modevar) == EFI_SUCCESS) + Print(L"SetupMode: %s\n", modevar ? L"setup" : L"user"); if (shim_loaded()) Print(L"Shim: present\n"); - if (efivar_get_raw(&global_guid, L"OsIndicationsSupported", &indvar, &size) == EFI_SUCCESS) - Print(L"OsIndicationsSupported: %d\n", (UINT64)*indvar); + if (efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &indvar) == EFI_SUCCESS) + Print(L"OsIndicationsSupported: %d\n", indvar); Print(L"\n--- press key ---\n\n"); console_key_read(&key, TRUE); @@ -423,20 +421,20 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { Print(L"entry EFI var idx: %d\n", config->idx_default_efivar); Print(L"\n"); - if (efivar_get_int(L"LoaderConfigTimeout", &i) == EFI_SUCCESS) - Print(L"LoaderConfigTimeout: %u\n", i); + if (efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeout", &timeout) == EFI_SUCCESS) + Print(L"LoaderConfigTimeout: %u\n", timeout); if (config->entry_oneshot) Print(L"LoaderEntryOneShot: %s\n", config->entry_oneshot); - if (efivar_get(L"LoaderDevicePartUUID", &partstr) == EFI_SUCCESS) + if (efivar_get(LOADER_GUID, L"LoaderDevicePartUUID", &partstr) == EFI_SUCCESS) Print(L"LoaderDevicePartUUID: %s\n", partstr); - if (efivar_get(L"LoaderEntryDefault", &defaultstr) == EFI_SUCCESS) + if (efivar_get(LOADER_GUID, L"LoaderEntryDefault", &defaultstr) == EFI_SUCCESS) Print(L"LoaderEntryDefault: %s\n", defaultstr); Print(L"\n--- press key ---\n\n"); console_key_read(&key, TRUE); - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { ConfigEntry *entry; if (key == KEYPRESS(0, SCAN_ESC, 0) || key == KEYPRESS(0, 0, 'q')) @@ -472,7 +470,7 @@ static VOID print_status(Config *config, CHAR16 *loaded_image_path) { if (entry->call) Print(L"internal call yes\n"); - if (entry->tries_left != (UINTN) -1) + if (entry->tries_left != UINTN_MAX) Print(L"counting boots yes\n" "tries done %u\n" "tries left %u\n" @@ -503,7 +501,6 @@ static BOOLEAN menu_run( UINTN idx_last; BOOLEAN refresh; BOOLEAN highlight; - UINTN i; UINTN line_width; CHAR16 **lines; UINTN x_start; @@ -564,7 +561,7 @@ static BOOLEAN menu_run( /* length of the longest entry */ line_width = 5; - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { UINTN entry_len; entry_len = StrLen(config->entries[i]->title_show); @@ -583,14 +580,14 @@ static BOOLEAN menu_run( /* menu entries title lines */ lines = AllocatePool(sizeof(CHAR16 *) * config->entry_count); - for (i = 0; i < config->entry_count; i++) { - UINTN j, k; + for (UINTN i = 0; i < config->entry_count; i++) { + UINTN j; lines[i] = AllocatePool(((x_max+1) * sizeof(CHAR16))); for (j = 0; j < x_start; j++) lines[i][j] = ' '; - for (k = 0; config->entries[i]->title_show[k] != '\0' && j < x_max; j++, k++) + for (UINTN k = 0; config->entries[i]->title_show[k] != '\0' && j < x_max; j++, k++) lines[i][j] = config->entries[i]->title_show[k]; for (; j < x_max; j++) @@ -600,15 +597,15 @@ static BOOLEAN menu_run( status = NULL; clearline = AllocatePool((x_max+1) * sizeof(CHAR16)); - for (i = 0; i < x_max; i++) + for (UINTN i = 0; i < x_max; i++) clearline[i] = ' '; - clearline[i] = 0; + clearline[x_max] = 0; while (!exit) { UINT64 key; if (refresh) { - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { if (i < idx_first || i > idx_last) continue; uefi_call_wrapper(ST->ConOut->SetCursorPosition, 3, ST->ConOut, 0, y_start + i - idx_first); @@ -764,12 +761,16 @@ static BOOLEAN menu_run( case KEYPRESS(0, 0, 'd'): if (config->idx_default_efivar != (INTN)idx_highlight) { /* store the selected entry in a persistent EFI variable */ - efivar_set(L"LoaderEntryDefault", config->entries[idx_highlight]->id, TRUE); + efivar_set( + LOADER_GUID, + L"LoaderEntryDefault", + config->entries[idx_highlight]->id, + EFI_VARIABLE_NON_VOLATILE); config->idx_default_efivar = idx_highlight; status = StrDuplicate(L"Default boot entry selected."); } else { /* clear the default entry EFI variable */ - efivar_set(L"LoaderEntryDefault", NULL, TRUE); + efivar_set(LOADER_GUID, L"LoaderEntryDefault", NULL, EFI_VARIABLE_NON_VOLATILE); config->idx_default_efivar = -1; status = StrDuplicate(L"Default boot entry cleared."); } @@ -780,14 +781,19 @@ static BOOLEAN menu_run( case KEYPRESS(0, 0, 'T'): if (config->timeout_sec_efivar > 0) { config->timeout_sec_efivar--; - efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE); + efivar_set_uint_string( + LOADER_GUID, + L"LoaderConfigTimeout", + config->timeout_sec_efivar, + EFI_VARIABLE_NON_VOLATILE); if (config->timeout_sec_efivar > 0) status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar); else status = StrDuplicate(L"Menu disabled. Hold down key at bootup to show menu."); } else if (config->timeout_sec_efivar <= 0){ config->timeout_sec_efivar = -1; - efivar_set(L"LoaderConfigTimeout", NULL, TRUE); + efivar_set( + LOADER_GUID, L"LoaderConfigTimeout", NULL, EFI_VARIABLE_NON_VOLATILE); if (config->timeout_sec_config > 0) status = PoolPrint(L"Menu timeout of %d sec is defined by configuration file.", config->timeout_sec_config); @@ -801,7 +807,11 @@ static BOOLEAN menu_run( if (config->timeout_sec_efivar == -1 && config->timeout_sec_config == 0) config->timeout_sec_efivar++; config->timeout_sec_efivar++; - efivar_set_int(L"LoaderConfigTimeout", config->timeout_sec_efivar, TRUE); + efivar_set_uint_string( + LOADER_GUID, + L"LoaderConfigTimeout", + config->timeout_sec_efivar, + EFI_VARIABLE_NON_VOLATILE); if (config->timeout_sec_efivar > 0) status = PoolPrint(L"Menu timeout set to %d sec.", config->timeout_sec_efivar); @@ -863,7 +873,7 @@ static BOOLEAN menu_run( *chosen_entry = config->entries[idx_highlight]; - for (i = 0; i < config->entry_count; i++) + for (UINTN i = 0; i < config->entry_count; i++) FreePool(lines[i]); FreePool(lines); FreePool(clearline); @@ -904,63 +914,6 @@ static VOID config_entry_free(ConfigEntry *entry) { FreePool(entry); } -static BOOLEAN is_digit(CHAR16 c) { - return (c >= '0') && (c <= '9'); -} - -static UINTN c_order(CHAR16 c) { - if (c == '\0') - return 0; - if (is_digit(c)) - return 0; - else if ((c >= 'a') && (c <= 'z')) - return c; - else - return c + 0x10000; -} - -static INTN str_verscmp(CHAR16 *s1, CHAR16 *s2) { - CHAR16 *os1 = s1; - CHAR16 *os2 = s2; - - while (*s1 || *s2) { - INTN first; - - while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) { - INTN order; - - order = c_order(*s1) - c_order(*s2); - if (order != 0) - return order; - s1++; - s2++; - } - - while (*s1 == '0') - s1++; - while (*s2 == '0') - s2++; - - first = 0; - while (is_digit(*s1) && is_digit(*s2)) { - if (first == 0) - first = *s1 - *s2; - s1++; - s2++; - } - - if (is_digit(*s1)) - return 1; - if (is_digit(*s2)) - return -1; - - if (first != 0) - return first; - } - - return StrCmp(os1, os2); -} - static CHAR8 *line_get_key_value( CHAR8 *content, CHAR8 *sep, @@ -1124,7 +1077,7 @@ static VOID config_entry_parse_tries( CHAR16 *file, CHAR16 *suffix) { - UINTN left = (UINTN) -1, done = (UINTN) -1, factor = 1, i, next_left, next_done; + UINTN left = UINTN_MAX, done = UINTN_MAX, factor = 1, i, next_left, next_done; _cleanup_freepool_ CHAR16 *prefix = NULL; /* @@ -1161,46 +1114,46 @@ static VOID config_entry_parse_tries( switch (file[i]) { case '+': - if (left == (UINTN) -1) /* didn't read at least one digit for 'left'? */ + if (left == UINTN_MAX) /* didn't read at least one digit for 'left'? */ return; - if (done == (UINTN) -1) /* no 'done' counter? If so, it's equivalent to 0 */ + if (done == UINTN_MAX) /* no 'done' counter? If so, it's equivalent to 0 */ done = 0; goto good; case '-': - if (left == (UINTN) -1) /* didn't parse any digit yet? */ + if (left == UINTN_MAX) /* didn't parse any digit yet? */ return; - if (done != (UINTN) -1) /* already encountered a dash earlier? */ + if (done != UINTN_MAX) /* already encountered a dash earlier? */ return; /* So we encountered a dash. This means this counter is of the form +LEFT-DONE. Let's assign * what we already parsed to 'done', and start fresh for the 'left' part. */ done = left; - left = (UINTN) -1; + left = UINTN_MAX; factor = 1; break; case '0'...'9': { UINTN new_factor; - if (left == (UINTN) -1) + if (left == UINTN_MAX) left = file[i] - '0'; else { UINTN new_left, digit; digit = file[i] - '0'; - if (digit > (UINTN) -1 / factor) /* overflow check */ + if (digit > UINTN_MAX / factor) /* overflow check */ return; new_left = left + digit * factor; if (new_left < left) /* overflow check */ return; - if (new_left == (UINTN) -1) /* don't allow us to be confused */ + if (new_left == UINTN_MAX) /* don't allow us to be confused */ return; } @@ -1244,7 +1197,7 @@ static VOID config_entry_bump_counters( UINTN file_info_size, a, b; EFI_STATUS r; - if (entry->tries_left == (UINTN) -1) + if (entry->tries_left == UINTN_MAX) return; if (!entry->path || !entry->current_name || !entry->next_name) @@ -1293,7 +1246,7 @@ static VOID config_entry_bump_counters( /* Let's tell the OS that we renamed this file, so that it knows what to rename to the counter-less name on * success */ new_path = PoolPrint(L"%s\\%s", entry->path, entry->next_name); - efivar_set(L"LoaderBootCountPath", new_path, FALSE); + efivar_set(LOADER_GUID, L"LoaderBootCountPath", new_path, 0); /* If the file we just renamed is the loader path, then let's update that. */ if (StrCmp(entry->loader, old_path) == 0) { @@ -1322,8 +1275,8 @@ static VOID config_entry_add_from_file( entry = AllocatePool(sizeof(ConfigEntry)); *entry = (ConfigEntry) { - .tries_done = (UINTN) -1, - .tries_left = (UINTN) -1, + .tries_done = UINTN_MAX, + .tries_left = UINTN_MAX, }; while ((line = line_get_key_value(content, (CHAR8 *)" \t", &pos, &key, &value))) { @@ -1458,17 +1411,17 @@ static VOID config_load_defaults(Config *config, EFI_FILE *root_dir) { if (!EFI_ERROR(err)) config_defaults_load_from_file(config, content); - err = efivar_get_int(L"LoaderConfigTimeout", &sec); + err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeout", &sec); if (!EFI_ERROR(err)) { config->timeout_sec_efivar = sec > INTN_MAX ? INTN_MAX : sec; config->timeout_sec = sec; } else config->timeout_sec_efivar = -1; - err = efivar_get_int(L"LoaderConfigTimeoutOneShot", &sec); + err = efivar_get_uint_string(LOADER_GUID, L"LoaderConfigTimeoutOneShot", &sec); if (!EFI_ERROR(err)) { /* Unset variable now, after all it's "one shot". */ - (void) efivar_set(L"LoaderConfigTimeoutOneShot", NULL, TRUE); + (void) efivar_set(LOADER_GUID, L"LoaderConfigTimeoutOneShot", NULL, EFI_VARIABLE_NON_VOLATILE); config->timeout_sec = sec; config->force_menu = TRUE; /* force the menu when this is set */ @@ -1491,7 +1444,6 @@ static VOID config_load_entries( UINTN bufsize; EFI_FILE_INFO *f; _cleanup_freepool_ CHAR8 *content = NULL; - UINTN len; bufsize = sizeof(buf); err = uefi_call_wrapper(entries_dir->Read, 3, entries_dir, &bufsize, buf); @@ -1504,12 +1456,9 @@ static VOID config_load_entries( if (f->Attribute & EFI_FILE_DIRECTORY) continue; - len = StrLen(f->FileName); - if (len < 6) + if (!endswith_no_case(f->FileName, L".conf")) continue; - if (StriCmp(f->FileName + len - 5, L".conf") != 0) - continue; - if (StrnCmp(f->FileName, L"auto-", 5) == 0) + if (startswith(f->FileName, L"auto-")) continue; err = file_read(entries_dir, f->FileName, 0, 0, &content, NULL); @@ -1529,12 +1478,12 @@ static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) { if (a->tries_left == 0 && b->tries_left != 0) return -1; - r = str_verscmp(a->id, b->id); + r = strverscmp_improved(a->id, b->id); if (r != 0) return r; - if (a->tries_left == (UINTN) -1 || - b->tries_left == (UINTN) -1) + if (a->tries_left == UINTN_MAX || + b->tries_left == UINTN_MAX) return 0; /* If both items have boot counting, and otherwise are identical, put the entry with more tries left last */ @@ -1553,14 +1502,11 @@ static INTN config_entry_compare(ConfigEntry *a, ConfigEntry *b) { } static VOID config_sort_entries(Config *config) { - UINTN i; - - for (i = 1; i < config->entry_count; i++) { + for (UINTN i = 1; i < config->entry_count; i++) { BOOLEAN more; - UINTN k; more = FALSE; - for (k = 0; k < config->entry_count - i; k++) { + for (UINTN k = 0; k < config->entry_count - i; k++) { ConfigEntry *entry; if (config_entry_compare(config->entries[k], config->entries[k+1]) <= 0) @@ -1577,9 +1523,7 @@ static VOID config_sort_entries(Config *config) { } static INTN config_entry_find(Config *config, CHAR16 *id) { - UINTN i; - - for (i = 0; i < config->entry_count; i++) + for (UINTN i = 0; i < config->entry_count; i++) if (StrCmp(config->entries[i]->id, id) == 0) return (INTN) i; @@ -1595,11 +1539,11 @@ static VOID config_default_entry_select(Config *config) { * The EFI variable to specify a boot entry for the next, and only the * next reboot. The variable is always cleared directly after it is read. */ - err = efivar_get(L"LoaderEntryOneShot", &entry_oneshot); + err = efivar_get(LOADER_GUID, L"LoaderEntryOneShot", &entry_oneshot); if (!EFI_ERROR(err)) { config->entry_oneshot = StrDuplicate(entry_oneshot); - efivar_set(L"LoaderEntryOneShot", NULL, TRUE); + efivar_set(LOADER_GUID, L"LoaderEntryOneShot", NULL, EFI_VARIABLE_NON_VOLATILE); i = config_entry_find(config, entry_oneshot); if (i >= 0) { @@ -1614,7 +1558,7 @@ static VOID config_default_entry_select(Config *config) { * the 'd' key in the loader selection menu, the entry is marked with * an '*'. */ - err = efivar_get(L"LoaderEntryDefault", &entry_default); + err = efivar_get(LOADER_GUID, L"LoaderEntryDefault", &entry_default); if (!EFI_ERROR(err)) { i = config_entry_find(config, entry_default); @@ -1660,13 +1604,12 @@ static VOID config_default_entry_select(Config *config) { static BOOLEAN find_nonunique(ConfigEntry **entries, UINTN entry_count) { BOOLEAN non_unique = FALSE; - UINTN i, k; - for (i = 0; i < entry_count; i++) + for (UINTN i = 0; i < entry_count; i++) entries[i]->non_unique = FALSE; - for (i = 0; i < entry_count; i++) - for (k = 0; k < entry_count; k++) { + for (UINTN i = 0; i < entry_count; i++) + for (UINTN k = 0; k < entry_count; k++) { if (i == k) continue; if (StrCmp(entries[i]->title_show, entries[k]->title_show) != 0) @@ -1680,10 +1623,8 @@ static BOOLEAN find_nonunique(ConfigEntry **entries, UINTN entry_count) { /* generate a unique title, avoiding non-distinguishable menu entries */ static VOID config_title_generate(Config *config) { - UINTN i; - /* set title */ - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { CHAR16 *title; FreePool(config->entries[i]->title_show); @@ -1697,7 +1638,7 @@ static VOID config_title_generate(Config *config) { return; /* add version to non-unique titles */ - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { CHAR16 *s; if (!config->entries[i]->non_unique) @@ -1714,7 +1655,7 @@ static VOID config_title_generate(Config *config) { return; /* add machine-id to non-unique titles */ - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { CHAR16 *s; _cleanup_freepool_ CHAR16 *m = NULL; @@ -1734,7 +1675,7 @@ static VOID config_title_generate(Config *config) { return; /* add file name to non-unique titles */ - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { CHAR16 *s; if (!config->entries[i]->non_unique) @@ -1760,8 +1701,8 @@ static BOOLEAN config_entry_add_call( .title = StrDuplicate(title), .call = call, .no_autoselect = TRUE, - .tries_done = (UINTN) -1, - .tries_left = (UINTN) -1, + .tries_done = UINTN_MAX, + .tries_left = UINTN_MAX, }; config_add_entry(config, entry); @@ -1789,8 +1730,8 @@ static ConfigEntry *config_entry_add_loader( .loader = StrDuplicate(loader), .id = StrDuplicate(id), .key = key, - .tries_done = (UINTN) -1, - .tries_left = (UINTN) -1, + .tries_done = UINTN_MAX, + .tries_left = UINTN_MAX, }; StrLwr(entry->id); @@ -1826,14 +1767,10 @@ static BOOLEAN config_entry_add_loader_auto( /* look for systemd-boot magic string */ err = file_read(root_dir, loader, 0, 100*1024, &content, &len); - if (!EFI_ERROR(err)) { - CHAR8 *start = content; - CHAR8 *last = content + len - sizeof(magic) - 1; - - for (; start <= last; start++) + if (!EFI_ERROR(err)) + for (CHAR8 *start = content; start <= content + len - sizeof(magic) - 1; start++) if (start[0] == magic[0] && CompareMem(start, magic, sizeof(magic) - 1) == 0) return FALSE; - } } /* check existence */ @@ -1862,9 +1799,7 @@ static VOID config_entry_add_osx(Config *config) { err = LibLocateHandle(ByProtocol, &FileSystemProtocol, NULL, &handle_count, &handles); if (!EFI_ERROR(err)) { - UINTN i; - - for (i = 0; i < handle_count; i++) { + for (UINTN i = 0; i < handle_count; i++) { EFI_FILE *root; BOOLEAN found; @@ -1906,7 +1841,6 @@ static VOID config_entry_add_linux( UINTN szs[ELEMENTSOF(sections)-1] = {}; UINTN addrs[ELEMENTSOF(sections)-1] = {}; CHAR8 *content = NULL; - UINTN len; CHAR8 *line; UINTN pos = 0; CHAR8 *key, *value; @@ -1926,12 +1860,9 @@ static VOID config_entry_add_linux( continue; if (f->Attribute & EFI_FILE_DIRECTORY) continue; - len = StrLen(f->FileName); - if (len < 5) + if (!endswith_no_case(f->FileName, L".efi")) continue; - if (StriCmp(f->FileName + len - 4, L".efi") != 0) - continue; - if (StrnCmp(f->FileName, L"auto-", 5) == 0) + if (startswith(f->FileName, L"auto-")) continue; /* look for .osrel and .cmdline sections in the .efi binary */ @@ -1988,8 +1919,8 @@ static VOID config_entry_add_linux( path = PoolPrint(L"\\EFI\\Linux\\%s", f->FileName); entry = config_entry_add_loader(config, device, LOADER_LINUX, f->FileName, 'l', - os_name_pretty ? : (os_name ? : os_id), path, - os_version ? : (os_version_id ? : os_build_id)); + os_name_pretty ?: os_name, path, + os_version ?: (os_version_id ? : os_build_id)); FreePool(content); content = NULL; @@ -2020,12 +1951,10 @@ static VOID config_entry_add_linux( uefi_call_wrapper(linux_dir->Close, 1, linux_dir); } -/* Note that this is in GUID format, i.e. the first 32bit, and the following pair of 16bit are byteswapped. */ -static const UINT8 xbootldr_guid[16] = { - 0xff, 0xc2, 0x13, 0xbc, 0xe6, 0x59, 0x62, 0x42, 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 -}; +#define XBOOTLDR_GUID \ + &(const EFI_GUID) { 0xbc13c2ff, 0x59e6, 0x4262, { 0xa3, 0x52, 0xb2, 0x75, 0xfd, 0x6f, 0x71, 0x72 } } -EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) { +static EFI_DEVICE_PATH *path_parent(EFI_DEVICE_PATH *path, EFI_DEVICE_PATH *node) { EFI_DEVICE_PATH *parent; UINTN len; @@ -2041,10 +1970,10 @@ static VOID config_load_xbootldr( Config *config, EFI_HANDLE *device) { - EFI_DEVICE_PATH *partition_path, *node, *disk_path, *copy; - UINT32 found_partition_number = (UINT32) -1; - UINT64 found_partition_start = (UINT64) -1; - UINT64 found_partition_size = (UINT64) -1; + EFI_DEVICE_PATH *partition_path, *disk_path, *copy; + UINT32 found_partition_number = UINT32_MAX; + UINT64 found_partition_start = UINT64_MAX; + UINT64 found_partition_size = UINT64_MAX; UINT8 found_partition_signature[16] = {}; EFI_HANDLE new_device; EFI_FILE *root_dir; @@ -2054,11 +1983,10 @@ static VOID config_load_xbootldr( if (!partition_path) return; - for (node = partition_path; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) { + for (EFI_DEVICE_PATH *node = partition_path; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) { EFI_HANDLE disk_handle; EFI_BLOCK_IO *block_io; EFI_DEVICE_PATH *p; - UINTN nr; /* First, Let's look for the SCSI/SATA/USB/… device path node, i.e. one above the media * devices */ @@ -2085,7 +2013,7 @@ static VOID config_load_xbootldr( continue; /* Try both copies of the GPT header, in case one is corrupted */ - for (nr = 0; nr < 2; nr++) { + for (UINTN nr = 0; nr < 2; nr++) { _cleanup_freepool_ EFI_PARTITION_ENTRY* entries = NULL; union { EFI_PARTITION_TABLE_HEADER gpt_header; @@ -2093,7 +2021,7 @@ static VOID config_load_xbootldr( } gpt_header_buffer; const EFI_PARTITION_TABLE_HEADER *h = &gpt_header_buffer.gpt_header; UINT64 where; - UINTN i, sz; + UINTN sz; UINT32 c; if (nr == 0) @@ -2125,7 +2053,7 @@ static VOID config_load_xbootldr( continue; /* Calculate CRC check */ - c = ~crc32_exclude_offset((UINT32) -1, + c = ~crc32_exclude_offset(UINT32_MAX, (const UINT8*) &gpt_header_buffer, h->Header.HeaderSize, OFFSETOF(EFI_PARTITION_TABLE_HEADER, Header.CRC32), @@ -2159,16 +2087,16 @@ static VOID config_load_xbootldr( continue; /* Calculate CRC of entries array, too */ - c = ~crc32((UINT32) -1, entries, sz); + c = ~crc32(UINT32_MAX, entries, sz); if (c != h->PartitionEntryArrayCRC32) continue; - for (i = 0; i < h->NumberOfPartitionEntries; i++) { + for (UINTN i = 0; i < h->NumberOfPartitionEntries; i++) { EFI_PARTITION_ENTRY *entry; entry = (EFI_PARTITION_ENTRY*) ((UINT8*) entries + h->SizeOfPartitionEntry * i); - if (CompareMem(&entry->PartitionTypeGUID, xbootldr_guid, 16) == 0) { + if (CompareMem(&entry->PartitionTypeGUID, XBOOTLDR_GUID, 16) == 0) { UINT64 end; /* Let's use memcpy(), in case the structs are not aligned (they really should be though) */ @@ -2197,7 +2125,7 @@ found: copy = DuplicateDevicePath(partition_path); /* Patch in the data we found */ - for (node = copy; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) { + for (EFI_DEVICE_PATH *node = copy; !IsDevicePathEnd(node); node = NextDevicePathNode(node)) { HARDDRIVE_DEVICE_PATH *hd; if (DevicePathType(node) != MEDIA_DEVICE_PATH) @@ -2282,7 +2210,7 @@ static EFI_STATUS image_start( #endif } - efivar_set_time_usec(L"LoaderTimeExecUSec", 0); + efivar_set_time_usec(LOADER_GUID, L"LoaderTimeExecUSec", 0); err = uefi_call_wrapper(BS->StartImage, 3, image, NULL, NULL); out_unload: uefi_call_wrapper(BS->UnloadImage, 1, image); @@ -2290,18 +2218,16 @@ out_unload: } static EFI_STATUS reboot_into_firmware(VOID) { - _cleanup_freepool_ CHAR8 *b = NULL; - UINTN size; - UINT64 osind; + UINT64 old, new; EFI_STATUS err; - osind = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; + new = EFI_OS_INDICATIONS_BOOT_TO_FW_UI; - err = efivar_get_raw(&global_guid, L"OsIndications", &b, &size); + err = efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", &old); if (!EFI_ERROR(err)) - osind |= (UINT64)*b; + new |= old; - err = efivar_set_raw(&global_guid, L"OsIndications", &osind, sizeof(UINT64), TRUE); + err = efivar_set_uint64_le(EFI_GLOBAL_GUID, L"OsIndications", new, EFI_VARIABLE_NON_VOLATILE); if (EFI_ERROR(err)) return err; @@ -2312,9 +2238,7 @@ static EFI_STATUS reboot_into_firmware(VOID) { } static VOID config_free(Config *config) { - UINTN i; - - for (i = 0; i < config->entry_count; i++) + for (UINTN i = 0; i < config->entry_count; i++) config_entry_free(config->entries[i]); FreePool(config->entries); FreePool(config->entry_default_pattern); @@ -2324,15 +2248,15 @@ static VOID config_free(Config *config) { static VOID config_write_entries_to_variable(Config *config) { _cleanup_freepool_ CHAR16 *buffer = NULL; - UINTN i, sz = 0; + UINTN sz = 0; CHAR16 *p; - for (i = 0; i < config->entry_count; i++) + for (UINTN i = 0; i < config->entry_count; i++) sz += StrLen(config->entries[i]->id) + 1; p = buffer = AllocatePool(sz * sizeof(CHAR16)); - for (i = 0; i < config->entry_count; i++) { + for (UINTN i = 0; i < config->entry_count; i++) { UINTN l; l = StrLen(config->entries[i]->id) + 1; @@ -2342,7 +2266,7 @@ static VOID config_write_entries_to_variable(Config *config) { } /* Store the full list of discovered entries. */ - (void) efivar_set_raw(&loader_guid, L"LoaderEntries", buffer, (UINT8*) p - (UINT8*) buffer, FALSE); + (void) efivar_set_raw(LOADER_GUID, L"LoaderEntries", buffer, (UINT8 *) p - (UINT8 *) buffer, 0); } EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { @@ -2357,8 +2281,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { 0; _cleanup_freepool_ CHAR16 *infostr = NULL, *typestr = NULL; - CHAR8 *b; - UINTN size; + UINT64 osind = 0; EFI_LOADED_IMAGE *loaded_image; EFI_FILE *root_dir; CHAR16 *loaded_image_path; @@ -2370,16 +2293,16 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { InitializeLib(image, sys_table); init_usec = time_usec(); - efivar_set_time_usec(L"LoaderTimeInitUSec", init_usec); - efivar_set(L"LoaderInfo", L"systemd-boot " GIT_VERSION, FALSE); + efivar_set_time_usec(LOADER_GUID, L"LoaderTimeInitUSec", init_usec); + efivar_set(LOADER_GUID, L"LoaderInfo", L"systemd-boot " GIT_VERSION, 0); infostr = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - efivar_set(L"LoaderFirmwareInfo", infostr, FALSE); + efivar_set(LOADER_GUID, L"LoaderFirmwareInfo", infostr, 0); typestr = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - efivar_set(L"LoaderFirmwareType", typestr, FALSE); + efivar_set(LOADER_GUID, L"LoaderFirmwareType", typestr, 0); - (void) efivar_set_raw(&loader_guid, L"LoaderFeatures", &loader_features, sizeof(loader_features), FALSE); + (void) efivar_set_uint64_le(LOADER_GUID, L"LoaderFeatures", loader_features, 0); err = uefi_call_wrapper(BS->OpenProtocol, 6, image, &LoadedImageProtocol, (VOID **)&loaded_image, image, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL); @@ -2391,7 +2314,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { /* export the device path this image is started from */ if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS) - efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); + efivar_set(LOADER_GUID, L"LoaderDevicePartUUID", uuid, 0); root_dir = LibOpenRoot(loaded_image->DeviceHandle); if (!root_dir) { @@ -2411,7 +2334,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { /* the filesystem path to this image, to prevent adding ourselves to the menu */ loaded_image_path = DevicePathToStr(loaded_image->FilePath); - efivar_set(L"LoaderImageIdentifier", loaded_image_path, FALSE); + efivar_set(LOADER_GUID, L"LoaderImageIdentifier", loaded_image_path, 0); config_load_defaults(&config, root_dir); @@ -2436,15 +2359,12 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { L"auto-efi-default", '\0', L"EFI Default Loader", L"\\EFI\\Boot\\boot" EFI_MACHINE_TYPE_NAME ".efi"); config_entry_add_osx(&config); - if (config.auto_firmware && efivar_get_raw(&global_guid, L"OsIndicationsSupported", &b, &size) == EFI_SUCCESS) { - UINT64 osind = (UINT64)*b; - + if (config.auto_firmware && efivar_get_uint64_le(EFI_GLOBAL_GUID, L"OsIndicationsSupported", &osind) == EFI_SUCCESS) { if (osind & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) config_entry_add_call(&config, L"auto-reboot-to-firmware-setup", L"Reboot Into Firmware Interface", reboot_into_firmware); - FreePool(b); } if (config.entry_count == 0) { @@ -2497,7 +2417,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { entry = config.entries[config.idx_default]; if (menu) { - efivar_set_time_usec(L"LoaderTimeMenuUSec", 0); + efivar_set_time_usec(LOADER_GUID, L"LoaderTimeMenuUSec", 0); uefi_call_wrapper(BS->SetWatchdogTimer, 4, 0, 0x10000, 0, NULL); if (!menu_run(&config, &entry, loaded_image_path)) break; @@ -2512,7 +2432,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { config_entry_bump_counters(entry, root_dir); /* Export the selected boot entry to the system */ - (VOID) efivar_set(L"LoaderEntrySelected", entry->id, FALSE); + (VOID) efivar_set(LOADER_GUID, L"LoaderEntrySelected", entry->id, 0); /* Optionally, read a random seed off the ESP and pass it to the OS */ (VOID) process_random_seed(root_dir, config.random_seed_mode); diff --git a/src/boot/efi/console.c b/src/boot/efi/console.c index 2dd4543d5..83619d214 100644 --- a/src/boot/efi/console.c +++ b/src/boot/efi/console.c @@ -9,65 +9,9 @@ #define SYSTEM_FONT_WIDTH 8 #define SYSTEM_FONT_HEIGHT 19 -#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ - { 0xdd9e7534, 0x7762, 0x4698, { 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa } } - -struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; - -typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - BOOLEAN ExtendedVerification -); - -typedef UINT8 EFI_KEY_TOGGLE_STATE; - -typedef struct { - UINT32 KeyShiftState; - EFI_KEY_TOGGLE_STATE KeyToggleState; -} EFI_KEY_STATE; - -typedef struct { - EFI_INPUT_KEY Key; - EFI_KEY_STATE KeyState; -} EFI_KEY_DATA; - -typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - EFI_KEY_DATA *KeyData -); - -typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - EFI_KEY_TOGGLE_STATE *KeyToggleState -); - -typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)( - EFI_KEY_DATA *KeyData -); - -typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - EFI_KEY_DATA KeyData, - EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, - VOID **NotifyHandle -); - -typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)( - struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, - VOID *NotificationHandle -); - -typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { - EFI_INPUT_RESET_EX Reset; - EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx; - EFI_EVENT WaitForKeyEx; - EFI_SET_STATE SetState; - EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify; - EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify; -} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; +#define EFI_SIMPLE_TEXT_INPUT_EX_GUID &(EFI_GUID) EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) { - EFI_GUID EfiSimpleTextInputExProtocolGuid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; static EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *TextInputEx; static BOOLEAN checked; UINTN index; @@ -75,7 +19,7 @@ EFI_STATUS console_key_read(UINT64 *key, BOOLEAN wait) { EFI_STATUS err; if (!checked) { - err = LibLocateProtocol(&EfiSimpleTextInputExProtocolGuid, (VOID **)&TextInputEx); + err = LibLocateProtocol(EFI_SIMPLE_TEXT_INPUT_EX_GUID, (VOID **)&TextInputEx); if (EFI_ERROR(err)) TextInputEx = NULL; diff --git a/src/boot/efi/console.h b/src/boot/efi/console.h index 41df3a406..2c69af552 100644 --- a/src/boot/efi/console.h +++ b/src/boot/efi/console.h @@ -1,11 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#define EFI_SHIFT_STATE_VALID 0x80000000 -#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 -#define EFI_LEFT_CONTROL_PRESSED 0x00000008 -#define EFI_RIGHT_ALT_PRESSED 0x00000010 -#define EFI_LEFT_ALT_PRESSED 0x00000020 +#include "missing_efi.h" #define EFI_CONTROL_PRESSED (EFI_RIGHT_CONTROL_PRESSED|EFI_LEFT_CONTROL_PRESSED) #define EFI_ALT_PRESSED (EFI_RIGHT_ALT_PRESSED|EFI_LEFT_ALT_PRESSED) diff --git a/src/boot/efi/crc32.c b/src/boot/efi/crc32.c index 5dfd3db26..c9e5501ff 100644 --- a/src/boot/efi/crc32.c +++ b/src/boot/efi/crc32.c @@ -128,9 +128,8 @@ UINT32 crc32_exclude_offset( const UINT8 *p = buf; UINT32 crc = seed; - UINTN i; - for (i = 0; i < len; i++) { + for (UINTN i = 0; i < len; i++) { UINT8 x = *p++; if (i >= exclude_off && i < exclude_off + exclude_len) diff --git a/src/boot/efi/disk.c b/src/boot/efi/disk.c index 89508f86d..122f08dd5 100644 --- a/src/boot/efi/disk.c +++ b/src/boot/efi/disk.c @@ -3,6 +3,7 @@ #include #include +#include "disk.h" #include "util.h" EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[static 37]) { @@ -12,10 +13,9 @@ EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[static 37]) { device_path = DevicePathFromHandle(handle); if (device_path) { _cleanup_freepool_ EFI_DEVICE_PATH *paths = NULL; - EFI_DEVICE_PATH *path; paths = UnpackDevicePath(device_path); - for (path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) { + for (EFI_DEVICE_PATH *path = paths; !IsDevicePathEnd(path); path = NextDevicePathNode(path)) { HARDDRIVE_DEVICE_PATH *drive; if (DevicePathType(path) != MEDIA_DEVICE_PATH) diff --git a/src/boot/efi/disk.h b/src/boot/efi/disk.h index 551a9ae63..8e10bb727 100644 --- a/src/boot/efi/disk.h +++ b/src/boot/efi/disk.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + EFI_STATUS disk_get_part_uuid(EFI_HANDLE *handle, CHAR16 uuid[static 37]); diff --git a/src/boot/efi/graphics.c b/src/boot/efi/graphics.c index f36ecb35b..ddfe68cc7 100644 --- a/src/boot/efi/graphics.c +++ b/src/boot/efi/graphics.c @@ -10,9 +10,10 @@ #include "graphics.h" #include "util.h" +#define EFI_CONSOLE_CONTROL_GUID \ + &(EFI_GUID) { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } } + EFI_STATUS graphics_mode(BOOLEAN on) { - #define EFI_CONSOLE_CONTROL_PROTOCOL_GUID \ - { 0xf42f7782, 0x12e, 0x4c12, { 0x99, 0x56, 0x49, 0xf9, 0x43, 0x4, 0xf7, 0x21 } }; struct _EFI_CONSOLE_CONTROL_PROTOCOL; @@ -45,7 +46,6 @@ EFI_STATUS graphics_mode(BOOLEAN on) { EFI_CONSOLE_CONTROL_PROTOCOL_LOCK_STD_IN LockStdIn; } EFI_CONSOLE_CONTROL_PROTOCOL; - EFI_GUID ConsoleControlProtocolGuid = EFI_CONSOLE_CONTROL_PROTOCOL_GUID; EFI_CONSOLE_CONTROL_PROTOCOL *ConsoleControl = NULL; EFI_CONSOLE_CONTROL_SCREEN_MODE new; EFI_CONSOLE_CONTROL_SCREEN_MODE current; @@ -53,7 +53,7 @@ EFI_STATUS graphics_mode(BOOLEAN on) { BOOLEAN stdin_locked; EFI_STATUS err; - err = LibLocateProtocol(&ConsoleControlProtocolGuid, (VOID **)&ConsoleControl); + err = LibLocateProtocol(EFI_CONSOLE_CONTROL_GUID, (VOID **)&ConsoleControl); if (EFI_ERROR(err)) /* console control protocol is nonstandard and might not exist. */ return err == EFI_NOT_FOUND ? EFI_SUCCESS : err; diff --git a/src/boot/efi/graphics.h b/src/boot/efi/graphics.h index 116aae28c..96f25d809 100644 --- a/src/boot/efi/graphics.h +++ b/src/boot/efi/graphics.h @@ -5,4 +5,6 @@ */ #pragma once +#include + EFI_STATUS graphics_mode(BOOLEAN on); diff --git a/src/boot/efi/linux.h b/src/boot/efi/linux.h index b92c27c8b..09be2de27 100644 --- a/src/boot/efi/linux.h +++ b/src/boot/efi/linux.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #define SETUP_MAGIC 0x53726448 /* "HdrS" */ struct setup_header { diff --git a/src/boot/efi/measure.c b/src/boot/efi/measure.c index ff876a6c5..c272d0855 100644 --- a/src/boot/efi/measure.c +++ b/src/boot/efi/measure.c @@ -4,9 +4,11 @@ #include #include + #include "measure.h" -#define EFI_TCG_PROTOCOL_GUID { 0xf541796d, 0xa62e, 0x4954, {0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd} } +#define EFI_TCG_GUID \ + &(EFI_GUID) { 0xf541796d, 0xa62e, 0x4954, { 0xa7, 0x75, 0x95, 0x84, 0xf6, 0x1b, 0x9c, 0xdd } } typedef struct _TCG_VERSION { UINT8 Major; @@ -100,7 +102,8 @@ typedef struct _EFI_TCG { EFI_TCG_HASH_LOG_EXTEND_EVENT HashLogExtendEvent; } EFI_TCG; -#define EFI_TCG2_PROTOCOL_GUID {0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f }} +#define EFI_TCG2_GUID \ + &(EFI_GUID) { 0x607f766c, 0x7455, 0x42be, { 0x93, 0x0b, 0xe4, 0xd7, 0x6d, 0xb2, 0x72, 0x0f } } typedef struct tdEFI_TCG2_PROTOCOL EFI_TCG2_PROTOCOL; @@ -238,7 +241,6 @@ static EFI_STATUS tpm2_measure_to_pcr_and_event_log(const EFI_TCG2 *tcg, UINT32 } static EFI_TCG * tcg1_interface_check(void) { - EFI_GUID tpm_guid = EFI_TCG_PROTOCOL_GUID; EFI_STATUS status; EFI_TCG *tcg; TCG_BOOT_SERVICE_CAPABILITY capability; @@ -246,7 +248,7 @@ static EFI_TCG * tcg1_interface_check(void) { EFI_PHYSICAL_ADDRESS event_log_location; EFI_PHYSICAL_ADDRESS event_log_last_entry; - status = LibLocateProtocol(&tpm_guid, (void **) &tcg); + status = LibLocateProtocol(EFI_TCG_GUID, (void **) &tcg); if (EFI_ERROR(status)) return NULL; @@ -267,12 +269,11 @@ static EFI_TCG * tcg1_interface_check(void) { } static EFI_TCG2 * tcg2_interface_check(void) { - EFI_GUID tpm2_guid = EFI_TCG2_PROTOCOL_GUID; EFI_STATUS status; EFI_TCG2 *tcg; EFI_TCG2_BOOT_SERVICE_CAPABILITY capability; - status = LibLocateProtocol(&tpm2_guid, (void **) &tcg); + status = LibLocateProtocol(EFI_TCG2_GUID, (void **) &tcg); if (EFI_ERROR(status)) return NULL; diff --git a/src/boot/efi/measure.h b/src/boot/efi/measure.h index 19e148d92..e2873adae 100644 --- a/src/boot/efi/measure.h +++ b/src/boot/efi/measure.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + EFI_STATUS tpm_log_event(UINT32 pcrindex, const EFI_PHYSICAL_ADDRESS buffer, UINTN buffer_size, const CHAR16 *description); diff --git a/src/boot/efi/meson.build b/src/boot/efi/meson.build index 24177f938..2a37b0a9a 100644 --- a/src/boot/efi/meson.build +++ b/src/boot/efi/meson.build @@ -21,6 +21,7 @@ common_sources = ''' graphics.c measure.c pe.c + secure-boot.c util.c '''.split() @@ -44,10 +45,15 @@ if conf.get('ENABLE_EFI') == 1 and get_option('gnu-efi') != 'false' if efi_cc.length() == 0 efi_cc = cc.cmd_array() endif - efi_ld = get_option('efi-ld') - if efi_ld == '' - efi_ld = find_program('ld', required: true) + + efi_ld = find_program(get_option('efi-ld'), required: true) + efi_ld_name = efi_ld.path().split('/')[-1] + if efi_ld_name == 'lld' or efi_ld_name == 'ld.lld' + # LLVM/LLD does not support PE/COFF relocations + # https://lists.llvm.org/pipermail/llvm-dev/2021-March/149234.html + error('LLVM/lld does not support PE/COFF relocations. Use different linker for EFI image.') endif + efi_incdir = get_option('efi-includedir') gnu_efi_path_arch = '' @@ -133,8 +139,8 @@ endif if have_gnu_efi compile_args = ['-Wall', '-Wextra', - '-std=gnu90', - '-nostdinc', + '-std=gnu99', + '-nostdlib', '-fpic', '-fshort-wchar', '-ffreestanding', @@ -144,6 +150,8 @@ if have_gnu_efi '-Wno-missing-field-initializers', '-isystem', efi_incdir, '-isystem', join_paths(efi_incdir, gnu_efi_path_arch), + '-I', fundamental_path, + '-DSD_BOOT', '-include', efi_config_h, '-include', version_h] if efi_arch == 'x86_64' @@ -193,17 +201,17 @@ if have_gnu_efi systemd_boot_objects = [] stub_objects = [] - foreach file : common_sources + systemd_boot_sources + stub_sources - o_file = custom_target(file + '.o', + foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources + o_file = custom_target(file.split('/')[-1] + '.o', input : file, - output : file + '.o', + output : file.split('/')[-1] + '.o', command : efi_cc + ['-c', '@INPUT@', '-o', '@OUTPUT@'] + compile_args, - depend_files : efi_headers) - if (common_sources + systemd_boot_sources).contains(file) + depend_files : efi_headers + fundamental_headers) + if (fundamental_source_paths + common_sources + systemd_boot_sources).contains(file) systemd_boot_objects += o_file endif - if (common_sources + stub_sources).contains(file) + if (fundamental_source_paths + common_sources + stub_sources).contains(file) stub_objects += o_file endif endforeach diff --git a/src/boot/efi/missing_efi.h b/src/boot/efi/missing_efi.h index 1b838af2a..b98393134 100644 --- a/src/boot/efi/missing_efi.h +++ b/src/boot/efi/missing_efi.h @@ -53,3 +53,70 @@ typedef struct _EFI_RNG_PROTOCOL { } EFI_RNG_PROTOCOL; #endif + +#ifndef EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID + +#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \ + { 0xdd9e7534, 0x7762, 0x4698, {0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa} } + +#define EFI_SHIFT_STATE_VALID 0x80000000 +#define EFI_RIGHT_CONTROL_PRESSED 0x00000004 +#define EFI_LEFT_CONTROL_PRESSED 0x00000008 +#define EFI_RIGHT_ALT_PRESSED 0x00000010 +#define EFI_LEFT_ALT_PRESSED 0x00000020 + +struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; + +typedef EFI_STATUS (EFIAPI *EFI_INPUT_RESET_EX)( + struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + BOOLEAN ExtendedVerification +); + +typedef UINT8 EFI_KEY_TOGGLE_STATE; + +typedef struct { + UINT32 KeyShiftState; + EFI_KEY_TOGGLE_STATE KeyToggleState; +} EFI_KEY_STATE; + +typedef struct { + EFI_INPUT_KEY Key; + EFI_KEY_STATE KeyState; +} EFI_KEY_DATA; + +typedef EFI_STATUS (EFIAPI *EFI_INPUT_READ_KEY_EX)( + struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + EFI_KEY_DATA *KeyData +); + +typedef EFI_STATUS (EFIAPI *EFI_SET_STATE)( + struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + EFI_KEY_TOGGLE_STATE *KeyToggleState +); + +typedef EFI_STATUS (EFIAPI *EFI_KEY_NOTIFY_FUNCTION)( + EFI_KEY_DATA *KeyData +); + +typedef EFI_STATUS (EFIAPI *EFI_REGISTER_KEYSTROKE_NOTIFY)( + struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + EFI_KEY_DATA KeyData, + EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction, + VOID **NotifyHandle +); + +typedef EFI_STATUS (EFIAPI *EFI_UNREGISTER_KEYSTROKE_NOTIFY)( + struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This, + VOID *NotificationHandle +); + +typedef struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL { + EFI_INPUT_RESET_EX Reset; + EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx; + EFI_EVENT WaitForKeyEx; + EFI_SET_STATE SetState; + EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify; + EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify; +} EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL; + +#endif diff --git a/src/boot/efi/no-undefined-symbols.sh b/src/boot/efi/no-undefined-symbols.sh index 84cbd5b42..b9541c312 100755 --- a/src/boot/efi/no-undefined-symbols.sh +++ b/src/boot/efi/no-undefined-symbols.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu if nm -D -u "$1" | grep ' U '; then diff --git a/src/boot/efi/pe.c b/src/boot/efi/pe.c index f99ecd0ed..cb3583807 100644 --- a/src/boot/efi/pe.c +++ b/src/boot/efi/pe.c @@ -62,7 +62,6 @@ struct PeSectionHeader { EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes) { struct DosFileHeader *dos; struct PeHeader *pe; - UINTN i; UINTN offset; dos = (struct DosFileHeader *)base; @@ -85,12 +84,11 @@ EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs offset = dos->ExeHeader + sizeof(*pe) + pe->FileHeader.SizeOfOptionalHeader; - for (i = 0; i < pe->FileHeader.NumberOfSections; i++) { + for (UINTN i = 0; i < pe->FileHeader.NumberOfSections; i++) { struct PeSectionHeader *sect; - UINTN j; sect = (struct PeSectionHeader *)&base[offset]; - for (j = 0; sections[j]; j++) { + for (UINTN j = 0; sections[j]; j++) { if (CompareMem(sect->Name, sections[j], strlena(sections[j])) != 0) continue; diff --git a/src/boot/efi/pe.h b/src/boot/efi/pe.h index 3e97d43f6..06a0fcd70 100644 --- a/src/boot/efi/pe.h +++ b/src/boot/efi/pe.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + EFI_STATUS pe_memory_locate_sections(CHAR8 *base, CHAR8 **sections, UINTN *addrs, UINTN *offsets, UINTN *sizes); EFI_STATUS pe_file_locate_sections(EFI_FILE *dir, CHAR16 *path, diff --git a/src/boot/efi/random-seed.c b/src/boot/efi/random-seed.c index eda9260ae..6de520c0c 100644 --- a/src/boot/efi/random-seed.c +++ b/src/boot/efi/random-seed.c @@ -5,14 +5,14 @@ #include "missing_efi.h" #include "random-seed.h" +#include "secure-boot.h" #include "sha256.h" #include "util.h" -#include "shim.h" #define RANDOM_MAX_SIZE_MIN (32U) #define RANDOM_MAX_SIZE_MAX (32U*1024U) -static const EFI_GUID rng_protocol_guid = EFI_RNG_PROTOCOL_GUID; +#define EFI_RNG_GUID &(EFI_GUID) EFI_RNG_PROTOCOL_GUID /* SHA256 gives us 256/8=32 bytes */ #define HASH_VALUE_SIZE 32 @@ -24,7 +24,7 @@ static EFI_STATUS acquire_rng(UINTN size, VOID **ret) { /* Try to acquire the specified number of bytes from the UEFI RNG */ - err = LibLocateProtocol((EFI_GUID*) &rng_protocol_guid, (VOID**) &rng); + err = LibLocateProtocol(EFI_RNG_GUID, (VOID**) &rng); if (EFI_ERROR(err)) return err; if (!rng) @@ -86,7 +86,6 @@ static EFI_STATUS hash_many( VOID **ret) { _cleanup_freepool_ VOID *output = NULL; - UINTN i; /* Hashes the specified parameters in counter mode, generating n hash values, with the counter in the * range counter_start…counter_start+n-1. */ @@ -95,7 +94,7 @@ static EFI_STATUS hash_many( if (!output) return log_oom(); - for (i = 0; i < n; i++) + for (UINTN i = 0; i < n; i++) hash_once(old_seed, rng, size, system_token, system_token_size, counter_start + i, @@ -142,12 +141,12 @@ static EFI_STATUS mangle_random_seed( return EFI_SUCCESS; } -EFI_STATUS acquire_system_token(VOID **ret, UINTN *ret_size) { +static EFI_STATUS acquire_system_token(VOID **ret, UINTN *ret_size) { _cleanup_freepool_ CHAR8 *data = NULL; EFI_STATUS err; UINTN size; - err = efivar_get_raw(&loader_guid, L"LoaderSystemToken", &data, &size); + err = efivar_get_raw(LOADER_GUID, L"LoaderSystemToken", &data, &size); if (EFI_ERROR(err)) { if (err != EFI_NOT_FOUND) Print(L"Failed to read LoaderSystemToken EFI variable: %r", err); @@ -201,9 +200,7 @@ static VOID validate_sha256(void) { 0xaf, 0xac, 0x45, 0x03, 0x7a, 0xfe, 0xe9, 0xd1 }}, }; - UINTN i; - - for (i = 0; i < ELEMENTSOF(array); i++) { + for (UINTN i = 0; i < ELEMENTSOF(array); i++) { struct sha256_ctx hash; uint8_t result[HASH_VALUE_SIZE]; @@ -318,7 +315,7 @@ EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode) { } /* We are good to go */ - err = efivar_set_raw(&loader_guid, L"LoaderRandomSeed", for_kernel, size, FALSE); + err = efivar_set_raw(LOADER_GUID, L"LoaderRandomSeed", for_kernel, size, 0); if (EFI_ERROR(err)) { Print(L"Failed to write random seed to EFI variable: %r\n", err); return err; diff --git a/src/boot/efi/random-seed.h b/src/boot/efi/random-seed.h index 0f443e6a8..f14da800e 100644 --- a/src/boot/efi/random-seed.h +++ b/src/boot/efi/random-seed.h @@ -2,13 +2,14 @@ #pragma once #include +#include typedef enum RandomSeedMode { RANDOM_SEED_OFF, RANDOM_SEED_WITH_SYSTEM_TOKEN, RANDOM_SEED_ALWAYS, _RANDOM_SEED_MODE_MAX, - _RANDOM_SEED_MODE_INVALID = -1, + _RANDOM_SEED_MODE_INVALID = -EINVAL, } RandomSeedMode; EFI_STATUS process_random_seed(EFI_FILE *root_dir, RandomSeedMode mode); diff --git a/src/boot/efi/secure-boot.c b/src/boot/efi/secure-boot.c new file mode 100644 index 000000000..cacf3b6a7 --- /dev/null +++ b/src/boot/efi/secure-boot.c @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "secure-boot.h" +#include "util.h" + +BOOLEAN secure_boot_enabled(void) { + BOOLEAN secure; + EFI_STATUS err; + + err = efivar_get_boolean_u8(EFI_GLOBAL_GUID, L"SecureBoot", &secure); + + return !EFI_ERROR(err) && secure; +} diff --git a/src/core/hostname-setup.h b/src/boot/efi/secure-boot.h similarity index 54% rename from src/core/hostname-setup.h rename to src/boot/efi/secure-boot.h index 7fd0a0274..d06a7deaa 100644 --- a/src/core/hostname-setup.h +++ b/src/boot/efi/secure-boot.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -int hostname_setup(void); +#include + +BOOLEAN secure_boot_enabled(void); diff --git a/src/boot/efi/sha256.c b/src/boot/efi/sha256.c index f23066d0a..774f0eeb6 100644 --- a/src/boot/efi/sha256.c +++ b/src/boot/efi/sha256.c @@ -94,7 +94,7 @@ void sha256_init_ctx(struct sha256_ctx *ctx) { void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { /* Take yet unprocessed bytes into account. */ UINT32 bytes = ctx->buflen; - UINTN pad, i; + UINTN pad; /* Now count remaining bytes. */ ctx->total64 += bytes; @@ -111,7 +111,7 @@ void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { sha256_process_block (ctx->buffer, bytes + pad + 8, ctx); /* Put result from CTX in first 32 bytes following RESBUF. */ - for (i = 0; i < 8; ++i) + for (UINTN i = 0; i < 8; ++i) ((UINT32 *) resbuf)[i] = SWAP (ctx->H[i]); return resbuf; @@ -214,7 +214,6 @@ static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ct UINT32 f_save = f; UINT32 g_save = g; UINT32 h_save = h; - UINTN t; /* Operators defined in FIPS 180-2:4.1.2. */ #define Ch(x, y, z) ((x & y) ^ (~x & z)) @@ -229,15 +228,15 @@ static void sha256_process_block(const void *buffer, UINTN len, struct sha256_ct #define CYCLIC(w, s) ((w >> s) | (w << (32 - s))) /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ - for (t = 0; t < 16; ++t) { + for (UINTN t = 0; t < 16; ++t) { W[t] = SWAP (*words); ++words; } - for (t = 16; t < 64; ++t) + for (UINTN t = 16; t < 64; ++t) W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16]; /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ - for (t = 0; t < 64; ++t) { + for (UINTN t = 0; t < 64; ++t) { UINT32 T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t]; UINT32 T2 = S0 (a) + Maj (a, b, c); h = g; diff --git a/src/boot/efi/shim.c b/src/boot/efi/shim.c index 3dc10089c..48602627b 100644 --- a/src/boot/efi/shim.c +++ b/src/boot/efi/shim.c @@ -30,17 +30,18 @@ struct ShimLock { EFI_STATUS __sysv_abi__ (*read_header) (VOID *data, UINT32 datasize, VOID *context); }; -static const EFI_GUID simple_fs_guid = SIMPLE_FILE_SYSTEM_PROTOCOL; -static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; - -static const EFI_GUID security_protocol_guid = { 0xa46423e3, 0x4617, 0x49f1, {0xb9, 0xff, 0xd1, 0xbf, 0xa9, 0x11, 0x58, 0x39 } }; -static const EFI_GUID security2_protocol_guid = { 0x94ab2f58, 0x1438, 0x4ef1, {0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } }; -static const EFI_GUID shim_lock_guid = { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }; +#define SIMPLE_FS_GUID &(EFI_GUID) SIMPLE_FILE_SYSTEM_PROTOCOL +#define SECURITY_PROTOCOL_GUID \ + &(EFI_GUID) { 0xa46423e3, 0x4617, 0x49f1, { 0xb9, 0xff, 0xd1, 0xbf, 0xa9, 0x11, 0x58, 0x39 } } +#define SECURITY_PROTOCOL2_GUID \ + &(EFI_GUID) { 0x94ab2f58, 0x1438, 0x4ef1, { 0x91, 0x52, 0x18, 0x94, 0x1a, 0x3a, 0x0e, 0x68 } } +#define SHIM_LOCK_GUID \ + &(EFI_GUID) { 0x605dab50, 0xe046, 0x4300, { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } } BOOLEAN shim_loaded(void) { struct ShimLock *shim_lock; - return uefi_call_wrapper(BS->LocateProtocol, 3, (EFI_GUID*) &shim_lock_guid, NULL, (VOID**) &shim_lock) == EFI_SUCCESS; + return uefi_call_wrapper(BS->LocateProtocol, 3, SHIM_LOCK_GUID, NULL, (VOID**) &shim_lock) == EFI_SUCCESS; } static BOOLEAN shim_validate(VOID *data, UINT32 size) { @@ -49,7 +50,7 @@ static BOOLEAN shim_validate(VOID *data, UINT32 size) { if (!data) return FALSE; - if (uefi_call_wrapper(BS->LocateProtocol, 3, (EFI_GUID*) &shim_lock_guid, NULL, (VOID**) &shim_lock) != EFI_SUCCESS) + if (uefi_call_wrapper(BS->LocateProtocol, 3, SHIM_LOCK_GUID, NULL, (VOID**) &shim_lock) != EFI_SUCCESS) return FALSE; if (!shim_lock) @@ -58,16 +59,6 @@ static BOOLEAN shim_validate(VOID *data, UINT32 size) { return shim_lock->shim_verify(data, size) == EFI_SUCCESS; } -BOOLEAN secure_boot_enabled(void) { - _cleanup_freepool_ CHAR8 *b = NULL; - UINTN size; - - if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) - return *b > 0; - - return FALSE; -} - /* * See the UEFI Platform Initialization manual (Vol2: DXE) for this */ @@ -157,7 +148,7 @@ static EFIAPI EFI_STATUS security_policy_authentication (const EFI_SECURITY_PROT dev_path = DuplicateDevicePath((EFI_DEVICE_PATH*) device_path_const); - status = uefi_call_wrapper(BS->LocateDevicePath, 3, (EFI_GUID*) &simple_fs_guid, &dev_path, &h); + status = uefi_call_wrapper(BS->LocateDevicePath, 3, SIMPLE_FS_GUID, &dev_path, &h); if (status != EFI_SUCCESS) return status; @@ -191,9 +182,9 @@ EFI_STATUS security_policy_install(void) { * to fail, since SECURITY2 was introduced in PI 1.2.1. * Use security2_protocol == NULL as indicator. */ - uefi_call_wrapper(BS->LocateProtocol, 3, (EFI_GUID*) &security2_protocol_guid, NULL, (VOID**) &security2_protocol); + uefi_call_wrapper(BS->LocateProtocol, 3, SECURITY_PROTOCOL2_GUID, NULL, (VOID**) &security2_protocol); - status = uefi_call_wrapper(BS->LocateProtocol, 3, (EFI_GUID*) &security_protocol_guid, NULL, (VOID**) &security_protocol); + status = uefi_call_wrapper(BS->LocateProtocol, 3, SECURITY_PROTOCOL_GUID, NULL, (VOID**) &security_protocol); /* This one is mandatory, so there's a serious problem */ if (status != EFI_SUCCESS) return status; diff --git a/src/boot/efi/shim.h b/src/boot/efi/shim.h index 72ecf2ed9..d682994b9 100644 --- a/src/boot/efi/shim.h +++ b/src/boot/efi/shim.h @@ -9,8 +9,8 @@ */ #pragma once +#include + BOOLEAN shim_loaded(void); -BOOLEAN secure_boot_enabled(void); - EFI_STATUS security_policy_install(void); diff --git a/src/boot/efi/splash.c b/src/boot/efi/splash.c index e166fec57..5e085ec45 100644 --- a/src/boot/efi/splash.c +++ b/src/boot/efi/splash.c @@ -37,7 +37,7 @@ struct bmp_map { UINT8 reserved; } __attribute__((packed)); -EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib, +static EFI_STATUS bmp_parse_header(UINT8 *bmp, UINTN size, struct bmp_dib **ret_dib, struct bmp_map **ret_map, UINT8 **pixmap) { struct bmp_file *file; struct bmp_dib *dib; @@ -147,26 +147,22 @@ static VOID pixel_blend(UINT32 *dst, const UINT32 source) { *dst = (rb | g); } -EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, +static EFI_STATUS bmp_to_blt(EFI_GRAPHICS_OUTPUT_BLT_PIXEL *buf, struct bmp_dib *dib, struct bmp_map *map, UINT8 *pixmap) { UINT8 *in; - UINTN y; /* transform and copy pixels */ in = pixmap; - for (y = 0; y < dib->y; y++) { + for (UINTN y = 0; y < dib->y; y++) { EFI_GRAPHICS_OUTPUT_BLT_PIXEL *out; UINTN row_size; - UINTN x; out = &buf[(dib->y - y - 1) * dib->x]; - for (x = 0; x < dib->x; x++, in++, out++) { + for (UINTN x = 0; x < dib->x; x++, in++, out++) { switch (dib->depth) { case 1: { - UINTN i; - - for (i = 0; i < 8 && x < dib->x; i++) { + for (UINTN i = 0; i < 8 && x < dib->x; i++) { out->Red = map[((*in) >> (7 - i)) & 1].red; out->Green = map[((*in) >> (7 - i)) & 1].green; out->Blue = map[((*in) >> (7 - i)) & 1].blue; diff --git a/src/boot/efi/splash.h b/src/boot/efi/splash.h index 0ba45a037..b9f74ffbf 100644 --- a/src/boot/efi/splash.h +++ b/src/boot/efi/splash.h @@ -1,4 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + EFI_STATUS graphics_splash(UINT8 *content, UINTN len, const EFI_GRAPHICS_OUTPUT_BLT_PIXEL *background); diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c index a09f47c71..1d9a5f07a 100644 --- a/src/boot/efi/stub.c +++ b/src/boot/efi/stub.c @@ -8,19 +8,15 @@ #include "linux.h" #include "measure.h" #include "pe.h" +#include "secure-boot.h" #include "splash.h" #include "util.h" /* magic string to find in the binary image */ static const char __attribute__((used)) magic[] = "#### LoaderInfo: systemd-stub " GIT_VERSION " ####"; -static const EFI_GUID global_guid = EFI_GLOBAL_VARIABLE; - EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { EFI_LOADED_IMAGE *loaded_image; - _cleanup_freepool_ CHAR8 *b = NULL; - UINTN size; - BOOLEAN secure = FALSE; CHAR8 *sections[] = { (CHAR8 *)".cmdline", (CHAR8 *)".linux", @@ -46,10 +42,6 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { return err; } - if (efivar_get_raw(&global_guid, L"SecureBoot", &b, &size) == EFI_SUCCESS) - if (*b > 0) - secure = TRUE; - err = pe_memory_locate_sections(loaded_image->ImageBase, sections, addrs, offs, szs); if (EFI_ERROR(err)) { Print(L"Unable to locate embedded .linux section: %r ", err); @@ -58,20 +50,20 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { } if (szs[0] > 0) - cmdline = (CHAR8 *)(loaded_image->ImageBase + addrs[0]); + cmdline = (CHAR8 *)(loaded_image->ImageBase) + addrs[0]; cmdline_len = szs[0]; /* if we are not in secure boot mode, or none was provided, accept a custom command line and replace the built-in one */ - if ((!secure || cmdline_len == 0) && loaded_image->LoadOptionsSize > 0 && *(CHAR16 *)loaded_image->LoadOptions > 0x1F) { + if ((!secure_boot_enabled() || cmdline_len == 0) && loaded_image->LoadOptionsSize > 0 && + *(CHAR16 *) loaded_image->LoadOptions > 0x1F) { CHAR16 *options; CHAR8 *line; - UINTN i; options = (CHAR16 *)loaded_image->LoadOptions; cmdline_len = (loaded_image->LoadOptionsSize / sizeof(CHAR16)) * sizeof(CHAR8); line = AllocatePool(cmdline_len); - for (i = 0; i < cmdline_len; i++) + for (UINTN i = 0; i < cmdline_len; i++) line[i] = options[i]; cmdline = line; @@ -88,37 +80,43 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) { } /* Export the device path this image is started from, if it's not set yet */ - if (efivar_get_raw(&loader_guid, L"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS) + if (efivar_get_raw(LOADER_GUID, L"LoaderDevicePartUUID", NULL, NULL) != EFI_SUCCESS) if (disk_get_part_uuid(loaded_image->DeviceHandle, uuid) == EFI_SUCCESS) - efivar_set(L"LoaderDevicePartUUID", uuid, FALSE); + efivar_set(LOADER_GUID, L"LoaderDevicePartUUID", uuid, 0); - /* if LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from UEFI */ - if (efivar_get_raw(&loader_guid, L"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS) { + /* If LoaderImageIdentifier is not set, assume the image with this stub was loaded directly from the + * UEFI firmware without any boot loader, and hence set the LoaderImageIdentifier ourselves. Note + * that some boot chain loaders neither set LoaderImageIdentifier nor make FilePath available to us, + * in which case there's simple nothing to set for us. (The UEFI spec doesn't really say who's wrong + * here, i.e. whether FilePath may be NULL or not, hence handle this gracefully and check if FilePath + * is non-NULL explicitly.) */ + if (efivar_get_raw(LOADER_GUID, L"LoaderImageIdentifier", NULL, NULL) != EFI_SUCCESS && + loaded_image->FilePath) { _cleanup_freepool_ CHAR16 *s; s = DevicePathToStr(loaded_image->FilePath); - efivar_set(L"LoaderImageIdentifier", s, FALSE); + efivar_set(LOADER_GUID, L"LoaderImageIdentifier", s, 0); } /* if LoaderFirmwareInfo is not set, let's set it */ - if (efivar_get_raw(&loader_guid, L"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) { + if (efivar_get_raw(LOADER_GUID, L"LoaderFirmwareInfo", NULL, NULL) != EFI_SUCCESS) { _cleanup_freepool_ CHAR16 *s; s = PoolPrint(L"%s %d.%02d", ST->FirmwareVendor, ST->FirmwareRevision >> 16, ST->FirmwareRevision & 0xffff); - efivar_set(L"LoaderFirmwareInfo", s, FALSE); + efivar_set(LOADER_GUID, L"LoaderFirmwareInfo", s, 0); } /* ditto for LoaderFirmwareType */ - if (efivar_get_raw(&loader_guid, L"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) { + if (efivar_get_raw(LOADER_GUID, L"LoaderFirmwareType", NULL, NULL) != EFI_SUCCESS) { _cleanup_freepool_ CHAR16 *s; s = PoolPrint(L"UEFI %d.%02d", ST->Hdr.Revision >> 16, ST->Hdr.Revision & 0xffff); - efivar_set(L"LoaderFirmwareType", s, FALSE); + efivar_set(LOADER_GUID, L"LoaderFirmwareType", s, 0); } /* add StubInfo */ - if (efivar_get_raw(&loader_guid, L"StubInfo", NULL, NULL) != EFI_SUCCESS) - efivar_set(L"StubInfo", L"systemd-stub " GIT_VERSION, FALSE); + if (efivar_get_raw(LOADER_GUID, L"StubInfo", NULL, NULL) != EFI_SUCCESS) + efivar_set(LOADER_GUID, L"StubInfo", L"systemd-stub " GIT_VERSION, 0); if (szs[3] > 0) graphics_splash((UINT8 *)((UINTN)loaded_image->ImageBase + addrs[3]), szs[3], NULL); diff --git a/src/boot/efi/util.c b/src/boot/efi/util.c index 2712c2d3f..06fbd500e 100644 --- a/src/boot/efi/util.c +++ b/src/boot/efi/util.c @@ -5,13 +5,6 @@ #include "util.h" -/* - * Allocated random UUID, intended to be shared across tools that implement - * the (ESP)\loader\entries\-.conf convention and the - * associated EFI variables. - */ -const EFI_GUID loader_guid = { 0x4a67b082, 0x0a4c, 0x41cf, {0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f} }; - #ifdef __x86_64__ UINT64 ticks_read(VOID) { UINT64 a, d; @@ -82,34 +75,55 @@ EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b) { return EFI_INVALID_PARAMETER; } -EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, BOOLEAN persistent) { - UINT32 flags; - - flags = EFI_VARIABLE_BOOTSERVICE_ACCESS|EFI_VARIABLE_RUNTIME_ACCESS; - if (persistent) - flags |= EFI_VARIABLE_NON_VOLATILE; - +EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, UINT32 flags) { + flags |= EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS; return uefi_call_wrapper(RT->SetVariable, 5, (CHAR16*) name, (EFI_GUID *)vendor, flags, size, (VOID*) buf); } -EFI_STATUS efivar_set(const CHAR16 *name, const CHAR16 *value, BOOLEAN persistent) { - return efivar_set_raw(&loader_guid, name, value, value ? (StrLen(value)+1) * sizeof(CHAR16) : 0, persistent); +EFI_STATUS efivar_set(const EFI_GUID *vendor, const CHAR16 *name, const CHAR16 *value, UINT32 flags) { + return efivar_set_raw(vendor, name, value, value ? (StrLen(value) + 1) * sizeof(CHAR16) : 0, flags); } -EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent) { +EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, CHAR16 *name, UINTN i, UINT32 flags) { CHAR16 str[32]; SPrint(str, 32, L"%u", i); - return efivar_set(name, str, persistent); + return efivar_set(vendor, name, str, flags); } -EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value) { +EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, CHAR16 *name, UINT32 value, UINT32 flags) { + UINT8 buf[4]; + + buf[0] = (UINT8)(value >> 0U & 0xFF); + buf[1] = (UINT8)(value >> 8U & 0xFF); + buf[2] = (UINT8)(value >> 16U & 0xFF); + buf[3] = (UINT8)(value >> 24U & 0xFF); + + return efivar_set_raw(vendor, name, buf, sizeof(buf), flags); +} + +EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, CHAR16 *name, UINT64 value, UINT32 flags) { + UINT8 buf[8]; + + buf[0] = (UINT8)(value >> 0U & 0xFF); + buf[1] = (UINT8)(value >> 8U & 0xFF); + buf[2] = (UINT8)(value >> 16U & 0xFF); + buf[3] = (UINT8)(value >> 24U & 0xFF); + buf[4] = (UINT8)(value >> 32U & 0xFF); + buf[5] = (UINT8)(value >> 40U & 0xFF); + buf[6] = (UINT8)(value >> 48U & 0xFF); + buf[7] = (UINT8)(value >> 56U & 0xFF); + + return efivar_set_raw(vendor, name, buf, sizeof(buf), flags); +} + +EFI_STATUS efivar_get(const EFI_GUID *vendor, const CHAR16 *name, CHAR16 **value) { _cleanup_freepool_ CHAR8 *buf = NULL; EFI_STATUS err; CHAR16 *val; UINTN size; - err = efivar_get_raw(&loader_guid, name, &buf, &size); + err = efivar_get_raw(vendor, name, &buf, &size); if (EFI_ERROR(err)) return err; @@ -138,17 +152,52 @@ EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value) { return EFI_SUCCESS; } -EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i) { +EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UINTN *i) { _cleanup_freepool_ CHAR16 *val = NULL; EFI_STATUS err; - err = efivar_get(name, &val); + err = efivar_get(vendor, name, &val); if (!EFI_ERROR(err) && i) *i = Atoi(val); return err; } +EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const CHAR16 *name, UINT32 *ret) { + _cleanup_freepool_ CHAR8 *buf = NULL; + UINTN size; + EFI_STATUS err; + + err = efivar_get_raw(vendor, name, &buf, &size); + if (!EFI_ERROR(err) && ret) { + if (size != sizeof(UINT32)) + return EFI_BUFFER_TOO_SMALL; + + *ret = (UINT32) buf[0] << 0U | (UINT32) buf[1] << 8U | (UINT32) buf[2] << 16U | + (UINT32) buf[3] << 24U; + } + + return err; +} + +EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT64 *ret) { + _cleanup_freepool_ CHAR8 *buf = NULL; + UINTN size; + EFI_STATUS err; + + err = efivar_get_raw(vendor, name, &buf, &size); + if (!EFI_ERROR(err) && ret) { + if (size != sizeof(UINT64)) + return EFI_BUFFER_TOO_SMALL; + + *ret = (UINT64) buf[0] << 0U | (UINT64) buf[1] << 8U | (UINT64) buf[2] << 16U | + (UINT64) buf[3] << 24U | (UINT64) buf[4] << 32U | (UINT64) buf[5] << 40U | + (UINT64) buf[6] << 48U | (UINT64) buf[7] << 56U; + } + + return err; +} + EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size) { _cleanup_freepool_ CHAR8 *buf = NULL; UINTN l; @@ -172,7 +221,19 @@ EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **bu return err; } -VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) { +EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const CHAR16 *name, BOOLEAN *ret) { + _cleanup_freepool_ CHAR8 *b = NULL; + UINTN size; + EFI_STATUS err; + + err = efivar_get_raw(vendor, name, &b, &size); + if (!EFI_ERROR(err)) + *ret = *b > 0; + + return err; +} + +VOID efivar_set_time_usec(const EFI_GUID *vendor, CHAR16 *name, UINT64 usec) { CHAR16 str[32]; if (usec == 0) @@ -181,13 +242,12 @@ VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec) { return; SPrint(str, 32, L"%ld", usec); - efivar_set(name, str, FALSE); + efivar_set(vendor, name, str, 0); } static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) { CHAR16 unichar; UINTN len; - UINTN i; if (!(stra[0] & 0x80)) len = 1; @@ -225,7 +285,7 @@ static INTN utf8_to_16(CHAR8 *stra, CHAR16 *c) { break; } - for (i = 1; i < len; i++) { + for (UINTN i = 1; i < len; i++) { if ((stra[i] & 0xc0) != 0x80) return -1; unichar <<= 6; diff --git a/src/boot/efi/util.h b/src/boot/efi/util.h index 916519cdf..f3c97186e 100644 --- a/src/boot/efi/util.h +++ b/src/boot/efi/util.h @@ -4,31 +4,33 @@ #include #include -#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0])) +#include "string-util-fundamental.h" + #define OFFSETOF(x,y) __builtin_offsetof(x,y) static inline UINTN ALIGN_TO(UINTN l, UINTN ali) { return ((l + ali - 1) & ~(ali - 1)); } -static inline const CHAR16 *yes_no(BOOLEAN b) { - return b ? L"yes" : L"no"; -} - EFI_STATUS parse_boolean(const CHAR8 *v, BOOLEAN *b); UINT64 ticks_read(void); UINT64 ticks_freq(void); UINT64 time_usec(void); -EFI_STATUS efivar_set(const CHAR16 *name, const CHAR16 *value, BOOLEAN persistent); -EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, BOOLEAN persistent); -EFI_STATUS efivar_set_int(CHAR16 *name, UINTN i, BOOLEAN persistent); -VOID efivar_set_time_usec(CHAR16 *name, UINT64 usec); +EFI_STATUS efivar_set(const EFI_GUID *vendor, const CHAR16 *name, const CHAR16 *value, UINT32 flags); +EFI_STATUS efivar_set_raw(const EFI_GUID *vendor, const CHAR16 *name, const VOID *buf, UINTN size, UINT32 flags); +EFI_STATUS efivar_set_uint_string(const EFI_GUID *vendor, CHAR16 *name, UINTN i, UINT32 flags); +EFI_STATUS efivar_set_uint32_le(const EFI_GUID *vendor, CHAR16 *NAME, UINT32 value, UINT32 flags); +EFI_STATUS efivar_set_uint64_le(const EFI_GUID *vendor, CHAR16 *name, UINT64 value, UINT32 flags); +VOID efivar_set_time_usec(const EFI_GUID *vendor, CHAR16 *name, UINT64 usec); -EFI_STATUS efivar_get(const CHAR16 *name, CHAR16 **value); +EFI_STATUS efivar_get(const EFI_GUID *vendor, const CHAR16 *name, CHAR16 **value); EFI_STATUS efivar_get_raw(const EFI_GUID *vendor, const CHAR16 *name, CHAR8 **buffer, UINTN *size); -EFI_STATUS efivar_get_int(const CHAR16 *name, UINTN *i); +EFI_STATUS efivar_get_uint_string(const EFI_GUID *vendor, const CHAR16 *name, UINTN *i); +EFI_STATUS efivar_get_uint32_le(const EFI_GUID *vendor, const CHAR16 *name, UINT32 *ret); +EFI_STATUS efivar_get_uint64_le(const EFI_GUID *vendor, const CHAR16 *name, UINT64 *ret); +EFI_STATUS efivar_get_boolean_u8(const EFI_GUID *vendor, const CHAR16 *name, BOOLEAN *ret); CHAR8 *strchra(CHAR8 *s, CHAR8 c); CHAR16 *stra_to_path(CHAR8 *stra); @@ -45,7 +47,6 @@ static inline void FreePoolp(void *p) { FreePool(q); } -#define _cleanup_(x) __attribute__((__cleanup__(x))) #define _cleanup_freepool_ _cleanup_(FreePoolp) static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) { @@ -55,16 +56,22 @@ static inline void FileHandleClosep(EFI_FILE_HANDLE *handle) { uefi_call_wrapper((*handle)->Close, 1, *handle); } -extern const EFI_GUID loader_guid; +/* + * Allocated random UUID, intended to be shared across tools that implement + * the (ESP)\loader\entries\-.conf convention and the + * associated EFI variables. + */ +#define LOADER_GUID \ + &(const EFI_GUID) { 0x4a67b082, 0x0a4c, 0x41cf, { 0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f } } +#define EFI_GLOBAL_GUID &(const EFI_GUID) EFI_GLOBAL_VARIABLE #define UINTN_MAX (~(UINTN)0) #define INTN_MAX ((INTN)(UINTN_MAX>>1)) - -#define TAKE_PTR(ptr) \ - ({ \ - typeof(ptr) _ptr_ = (ptr); \ - (ptr) = NULL; \ - _ptr_; \ - }) +#ifndef UINT32_MAX +#define UINT32_MAX ((UINT32) -1) +#endif +#ifndef UINT64_MAX +#define UINT64_MAX ((UINT64) -1) +#endif EFI_STATUS log_oom(void); diff --git a/src/busctl/busctl-introspect.c b/src/busctl/busctl-introspect.c index 7a5d57f8c..89b32f4c7 100644 --- a/src/busctl/busctl-introspect.c +++ b/src/busctl/busctl-introspect.c @@ -406,10 +406,10 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth if (argument_type) { if (!argument_direction || streq(argument_direction, "in")) { - if (!strextend(&context->member_signature, argument_type, NULL)) + if (!strextend(&context->member_signature, argument_type)) return log_oom(); } else if (streq(argument_direction, "out")) { - if (!strextend(&context->member_result, argument_type, NULL)) + if (!strextend(&context->member_result, argument_type)) return log_oom(); } else log_error("Unexpected method direction value '%s'.", argument_direction); @@ -541,7 +541,7 @@ static int parse_xml_node(Context *context, const char *prefix, unsigned n_depth if (argument_type) { if (!argument_direction || streq(argument_direction, "out")) { - if (!strextend(&context->member_signature, argument_type, NULL)) + if (!strextend(&context->member_signature, argument_type)) return log_oom(); } else log_error("Unexpected signal direction value '%s'.", argument_direction); diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c index 06a15ddd8..cbc24bc25 100644 --- a/src/busctl/busctl.c +++ b/src/busctl/busctl.c @@ -21,6 +21,7 @@ #include "log.h" #include "main-func.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -31,11 +32,7 @@ #include "user-util.h" #include "verbs.h" -static enum { - JSON_OFF, - JSON_SHORT, - JSON_PRETTY, -} arg_json = JSON_OFF; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static PagerFlags arg_pager_flags = 0; static bool arg_legend = true; static bool arg_full = false; @@ -67,7 +64,6 @@ STATIC_DESTRUCTOR_REGISTER(arg_matches, strv_freep); #define NAME_IS_ACTIVATABLE INT_TO_PTR(2) static int json_transform_message(sd_bus_message *m, JsonVariant **ret); -static void json_dump_with_flags(JsonVariant *v, FILE *f); static int acquire_bus(bool set_monitor, sd_bus **ret) { _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; @@ -121,7 +117,7 @@ static int acquire_bus(bool set_monitor, sd_bus **ret) { break; case BUS_TRANSPORT_MACHINE: - r = bus_set_address_system_machine(bus, arg_host); + r = bus_set_address_machine(bus, arg_user, arg_host); break; default: @@ -215,7 +211,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) { if (r < 0) return log_error_errno(r, "Failed to set empty string: %m"); - r = table_set_sort(table, (size_t) COLUMN_NAME, (size_t) -1); + r = table_set_sort(table, (size_t) COLUMN_NAME); if (r < 0) return log_error_errno(r, "Failed to set sort column: %m"); @@ -228,8 +224,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) { (size_t) COLUMN_UNIT, (size_t) COLUMN_SESSION, (size_t) COLUMN_DESCRIPTION, - (size_t) COLUMN_MACHINE, - (size_t) -1); + (size_t) COLUMN_MACHINE); else r = table_set_display(table, (size_t) COLUMN_NAME, (size_t) COLUMN_PID, @@ -238,14 +233,11 @@ static int list_bus_names(int argc, char **argv, void *userdata) { (size_t) COLUMN_CONNECTION, (size_t) COLUMN_UNIT, (size_t) COLUMN_SESSION, - (size_t) COLUMN_DESCRIPTION, - (size_t) -1); + (size_t) COLUMN_DESCRIPTION); if (r < 0) return log_error_errno(r, "Failed to set columns to display: %m"); - table_set_header(table, arg_legend); - HASHMAP_FOREACH_KEY(v, k, names) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; @@ -362,17 +354,7 @@ static int list_bus_names(int argc, char **argv, void *userdata) { return log_error_errno(r, "Failed to fill line: %m"); } - (void) pager_open(arg_pager_flags); - - if (arg_json) - r = table_print_json(table, stdout, - (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) | JSON_FORMAT_COLOR_AUTO); - else - r = table_print(table, stdout); - if (r < 0) - return table_log_print_error(r); - - return 0; + return table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); } static void print_subtree(const char *prefix, const char *path, char **l) { @@ -459,7 +441,7 @@ static int find_nodes(sd_bus *bus, const char *service, const char *path, Set *p r = sd_bus_call_method(bus, service, path, "org.freedesktop.DBus.Introspectable", "Introspect", - &error, &reply, ""); + &error, &reply, NULL); if (r < 0) { printf("%sFailed to introspect object %s of service %s: %s%s\n", ansi_highlight_red(), @@ -796,24 +778,22 @@ static int member_compare_funcp(Member * const *a, Member * const *b) { return member_compare_func(*a, *b); } -static void member_free(Member *m) { +static Member* member_free(Member *m) { if (!m) - return; + return NULL; free(m->interface); free(m->name); free(m->signature); free(m->result); free(m->value); - free(m); + return mfree(m); } - DEFINE_TRIVIAL_CLEANUP_FUNC(Member*, member_free); -static void member_set_free(Set *s) { - set_free_with_destructor(s, member_free); +static Set* member_set_free(Set *s) { + return set_free_with_destructor(s, member_free); } - DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, member_set_free); static int on_interface(const char *interface, uint64_t flags, void *userdata) { @@ -998,7 +978,7 @@ static int introspect(int argc, char **argv, void *userdata) { r = sd_bus_call_method(bus, argv[1], argv[2], "org.freedesktop.DBus.Introspectable", "Introspect", - &error, &reply_xml, ""); + &error, &reply_xml, NULL); if (r < 0) return log_error_errno(r, "Failed to introspect object %s of service %s: %s", argv[2], argv[1], bus_error_message(&error, r)); @@ -1194,6 +1174,7 @@ static int message_json(sd_bus_message *m, FILE *f) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL; char e[2]; int r; + usec_t ts; r = json_transform_message(m, &v); if (r < 0) @@ -1202,6 +1183,10 @@ static int message_json(sd_bus_message *m, FILE *f) { e[0] = m->header->endian; e[1] = 0; + ts = m->realtime; + if (ts == 0) + ts = now(CLOCK_REALTIME); + r = json_build(&w, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("type", JSON_BUILD_STRING(bus_message_type_to_string(m->header->type))), JSON_BUILD_PAIR("endian", JSON_BUILD_STRING(e)), @@ -1209,6 +1194,7 @@ static int message_json(sd_bus_message *m, FILE *f) { JSON_BUILD_PAIR("version", JSON_BUILD_INTEGER(m->header->version)), JSON_BUILD_PAIR("cookie", JSON_BUILD_INTEGER(BUS_MESSAGE_COOKIE(m))), JSON_BUILD_PAIR_CONDITION(m->reply_cookie != 0, "reply_cookie", JSON_BUILD_INTEGER(m->reply_cookie)), + JSON_BUILD_PAIR("timestamp-realtime", JSON_BUILD_UNSIGNED(ts)), JSON_BUILD_PAIR_CONDITION(m->sender, "sender", JSON_BUILD_STRING(m->sender)), JSON_BUILD_PAIR_CONDITION(m->destination, "destination", JSON_BUILD_STRING(m->destination)), JSON_BUILD_PAIR_CONDITION(m->path, "path", JSON_BUILD_STRING(m->path)), @@ -1222,7 +1208,7 @@ static int message_json(sd_bus_message *m, FILE *f) { if (r < 0) return log_error_errno(r, "Failed to build JSON object: %m"); - json_dump_with_flags(w, f); + json_variant_dump(w, arg_json_format_flags, f, NULL); return 0; } @@ -1342,14 +1328,14 @@ static int monitor(int argc, char **argv, int (*dump)(sd_bus_message *m, FILE *f if (r > 0) continue; - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) return log_error_errno(r, "Failed to wait for bus: %m"); } } static int verb_monitor(int argc, char **argv, void *userdata) { - return monitor(argc, argv, arg_json != JSON_OFF ? message_json : message_dump); + return monitor(argc, argv, (arg_json_format_flags & JSON_FORMAT_OFF) ? message_dump : message_json); } static int verb_capture(int argc, char **argv, void *userdata) { @@ -2000,14 +1986,6 @@ static int json_transform_message(sd_bus_message *m, JsonVariant **ret) { return 0; } -static void json_dump_with_flags(JsonVariant *v, FILE *f) { - - json_variant_dump(v, - (arg_json == JSON_PRETTY ? JSON_FORMAT_PRETTY : JSON_FORMAT_NEWLINE) | - JSON_FORMAT_COLOR_AUTO, - f, NULL); -} - static int call(int argc, char **argv, void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -2066,17 +2044,17 @@ static int call(int argc, char **argv, void *userdata) { if (r == 0 && !arg_quiet) { - if (arg_json != JSON_OFF) { + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; - if (arg_json != JSON_SHORT) + if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) (void) pager_open(arg_pager_flags); r = json_transform_message(reply, &v); if (r < 0) return r; - json_dump_with_flags(v, stdout); + json_variant_dump(v, arg_json_format_flags, NULL, NULL); } else if (arg_verbose) { (void) pager_open(arg_pager_flags); @@ -2175,17 +2153,17 @@ static int get_property(int argc, char **argv, void *userdata) { if (r < 0) return bus_log_parse_error(r); - if (arg_json != JSON_OFF) { + if (!FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; - if (arg_json != JSON_SHORT) + if (arg_json_format_flags & (JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) (void) pager_open(arg_pager_flags); r = json_transform_variant(reply, contents, &v); if (r < 0) return r; - json_dump_with_flags(v, stdout); + json_variant_dump(v, arg_json_format_flags, NULL, NULL); } else if (arg_verbose) { (void) pager_open(arg_pager_flags); @@ -2265,6 +2243,8 @@ static int help(void) { if (r < 0) return log_oom(); + (void) pager_open(arg_pager_flags); + printf("%s [OPTIONS...] COMMAND ...\n\n" "%sIntrospect the D-Bus IPC bus.%s\n" "\nCommands:\n" @@ -2314,12 +2294,11 @@ static int help(void) { " --watch-bind=BOOL Wait for bus AF_UNIX socket to be bound in the file\n" " system\n" " --destination=SERVICE Destination service of a signal\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -2490,27 +2469,22 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_EXPECT_REPLY: - r = parse_boolean(optarg); + r = parse_boolean_argument("--expect-reply=", optarg, &arg_expect_reply); if (r < 0) - return log_error_errno(r, "Failed to parse --expect-reply= parameter '%s': %m", optarg); - - arg_expect_reply = r; + return r; break; case ARG_AUTO_START: - r = parse_boolean(optarg); + r = parse_boolean_argument("--auto-start=", optarg, &arg_auto_start); if (r < 0) - return log_error_errno(r, "Failed to parse --auto-start= parameter '%s': %m", optarg); - - arg_auto_start = r; + return r; break; case ARG_ALLOW_INTERACTIVE_AUTHORIZATION: - r = parse_boolean(optarg); + r = parse_boolean_argument("--allow-interactive-authorization=", optarg, + &arg_allow_interactive_authorization); if (r < 0) - return log_error_errno(r, "Failed to parse --allow-interactive-authorization= parameter '%s': %m", optarg); - - arg_allow_interactive_authorization = r; + return r; break; case ARG_TIMEOUT: @@ -2521,41 +2495,25 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_AUGMENT_CREDS: - r = parse_boolean(optarg); + r = parse_boolean_argument("--augment-creds=", optarg, &arg_augment_creds); if (r < 0) - return log_error_errno(r, "Failed to parse --augment-creds= parameter '%s': %m", optarg); - - arg_augment_creds = r; + return r; break; case ARG_WATCH_BIND: - r = parse_boolean(optarg); + r = parse_boolean_argument("--watch-bind=", optarg, &arg_watch_bind); if (r < 0) - return log_error_errno(r, "Failed to parse --watch-bind= parameter '%s': %m", optarg); - - arg_watch_bind = r; + return r; break; case 'j': - if (on_tty()) - arg_json = JSON_PRETTY; - else - arg_json = JSON_SHORT; + arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO; break; case ARG_JSON: - if (streq(optarg, "short")) - arg_json = JSON_SHORT; - else if (streq(optarg, "pretty")) - arg_json = JSON_PRETTY; - else if (streq(optarg, "help")) { - fputs("short\n" - "pretty\n", stdout); - return 0; - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown JSON out mode: %s", - optarg); + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; break; @@ -2595,7 +2553,7 @@ static int busctl_main(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/busctl/meson.build b/src/busctl/meson.build new file mode 100644 index 000000000..aacd0b270 --- /dev/null +++ b/src/busctl/meson.build @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +busctl_sources = files( + 'busctl-introspect.c', + 'busctl-introspect.h', + 'busctl.c') diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 693b5047f..6868049c1 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -57,10 +57,9 @@ static int help(void) { " -l --full Do not ellipsize output\n" " -k Include kernel threads in output\n" " -M --machine= Show container\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -164,7 +163,7 @@ static void show_cg_info(const char *controller, const char *path) { static int run(int argc, char *argv[]) { int r, output_flags; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/cgroups-agent/cgroups-agent.c b/src/cgroups-agent/cgroups-agent.c index eeb4ba80f..071cba309 100644 --- a/src/cgroups-agent/cgroups-agent.c +++ b/src/cgroups-agent/cgroups-agent.c @@ -22,7 +22,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - log_setup_service(); + log_setup(); fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0); if (fd < 0) { diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c index e9e7ed273..5424f2c90 100644 --- a/src/cgtop/cgtop.c +++ b/src/cgtop/cgtop.c @@ -19,6 +19,7 @@ #include "hashmap.h" #include "main-func.h" #include "missing_sched.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -55,7 +56,7 @@ typedef struct Group { } Group; static unsigned arg_depth = 3; -static unsigned arg_iterations = (unsigned) -1; +static unsigned arg_iterations = UINT_MAX; static bool arg_batch = false; static bool arg_raw = false; static usec_t arg_delay = 1*USEC_PER_SEC; @@ -722,11 +723,10 @@ static int help(void) { " -b --batch Run in batch mode, accepting no input\n" " --depth=DEPTH Maximum traversal depth (default: %u)\n" " -M --machine= Show container\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , arg_depth - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + arg_depth, + link); return 0; } @@ -868,12 +868,11 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_RECURSIVE: - r = parse_boolean(optarg); + r = parse_boolean_argument("--recursive=", optarg, &arg_recursive); if (r < 0) - return log_error_errno(r, "Failed to parse --recursive= argument '%s': %m", optarg); + return r; - arg_recursive = r; - arg_recursive_unset = r == 0; + arg_recursive_unset = !r; break; case 'M': @@ -916,7 +915,7 @@ static int run(int argc, char *argv[]) { CGroupMask mask; int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) @@ -944,7 +943,7 @@ static int run(int argc, char *argv[]) { signal(SIGWINCH, columns_lines_cache_reset); - if (arg_iterations == (unsigned) -1) + if (arg_iterations == UINT_MAX) arg_iterations = on_tty() ? 0 : 1; while (!quit) { @@ -954,7 +953,7 @@ static int run(int argc, char *argv[]) { t = now(CLOCK_MONOTONIC); - if (t >= last_refresh + arg_delay || immediate_refresh) { + if (t >= usec_add(last_refresh, arg_delay) || immediate_refresh) { r = refresh(root, a, b, iteration++); if (r < 0) @@ -977,9 +976,9 @@ static int run(int argc, char *argv[]) { fflush(stdout); if (arg_batch) - (void) usleep(last_refresh + arg_delay - t); + (void) usleep(usec_add(usec_sub_unsigned(last_refresh, t), arg_delay)); else { - r = read_one_char(stdin, &key, last_refresh + arg_delay - t, NULL); + r = read_one_char(stdin, &key, usec_add(usec_sub_unsigned(last_refresh, t), arg_delay), NULL); if (r == -ETIMEDOUT) continue; if (r < 0) @@ -1054,10 +1053,7 @@ static int run(int argc, char *argv[]) { break; case '+': - if (arg_delay < USEC_PER_SEC) - arg_delay += USEC_PER_MSEC*250; - else - arg_delay += USEC_PER_SEC; + arg_delay = usec_add(arg_delay, arg_delay < USEC_PER_SEC ? USEC_PER_MSEC * 250 : USEC_PER_SEC); fprintf(stdout, "\nIncreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); fflush(stdout); @@ -1067,10 +1063,8 @@ static int run(int argc, char *argv[]) { case '-': if (arg_delay <= USEC_PER_MSEC*500) arg_delay = USEC_PER_MSEC*250; - else if (arg_delay < USEC_PER_MSEC*1250) - arg_delay -= USEC_PER_MSEC*250; else - arg_delay -= USEC_PER_SEC; + arg_delay = usec_sub_unsigned(arg_delay, arg_delay < USEC_PER_MSEC * 1250 ? USEC_PER_MSEC * 250 : USEC_PER_SEC); fprintf(stdout, "\nDecreased delay to %s.", format_timespan(h, sizeof(h), arg_delay, 0)); fflush(stdout); @@ -1080,14 +1074,12 @@ static int run(int argc, char *argv[]) { case '?': case 'h': -#define ON ANSI_HIGHLIGHT -#define OFF ANSI_NORMAL - fprintf(stdout, - "\t<" ON "p" OFF "> By path; <" ON "t" OFF "> By tasks/procs; <" ON "c" OFF "> By CPU; <" ON "m" OFF "> By memory; <" ON "i" OFF "> By I/O\n" - "\t<" ON "+" OFF "> Inc. delay; <" ON "-" OFF "> Dec. delay; <" ON "%%" OFF "> Toggle time; <" ON "SPACE" OFF "> Refresh\n" - "\t<" ON "P" OFF "> Toggle count userspace processes; <" ON "k" OFF "> Toggle count all processes\n" - "\t<" ON "r" OFF "> Count processes recursively; <" ON "q" OFF "> Quit"); + "\t<%1$sp%2$s> By path; <%1$st%2$s> By tasks/procs; <%1$sc%2$s> By CPU; <%1$sm%2$s> By memory; <%1$si%2$s> By I/O\n" + "\t<%1$s+%2$s> Inc. delay; <%1$s-%2$s> Dec. delay; <%1$s%%%2$s> Toggle time; <%1$sSPACE%2$s> Refresh\n" + "\t<%1$sP%2$s> Toggle count userspace processes; <%1$sk%2$s> Toggle count all processes\n" + "\t<%1$sr%2$s> Count processes recursively; <%1$sq%2$s> Quit", + ansi_highlight(), ansi_normal()); fflush(stdout); sleep(3); break; diff --git a/src/core/apparmor-setup.c b/src/core/apparmor-setup.c index e856f5c18..304a3e6aa 100644 --- a/src/core/apparmor-setup.c +++ b/src/core/apparmor-setup.c @@ -16,17 +16,17 @@ #include "strv.h" #if HAVE_APPARMOR -DEFINE_TRIVIAL_CLEANUP_FUNC(aa_policy_cache *, aa_policy_cache_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(aa_features *, aa_features_unref); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(aa_policy_cache *, aa_policy_cache_unref, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(aa_features *, aa_features_unref, NULL); #endif int mac_apparmor_setup(void) { #if HAVE_APPARMOR - int r; _cleanup_(aa_policy_cache_unrefp) aa_policy_cache *policy_cache = NULL; _cleanup_(aa_features_unrefp) aa_features *features = NULL; const char *current_file; _cleanup_free_ char *current_profile = NULL, *cache_dir_path = NULL; + int r; if (!mac_apparmor_use()) { log_debug("AppArmor either not supported by the kernel or disabled."); diff --git a/src/core/automount.c b/src/core/automount.c index a84cddbdb..f0fa5c8ca 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -48,13 +48,13 @@ struct expire_data { int ioctl_fd; }; -static void expire_data_free(struct expire_data *data) { +static struct expire_data* expire_data_free(struct expire_data *data) { if (!data) - return; + return NULL; safe_close(data->dev_autofs_fd); safe_close(data->ioctl_fd); - free(data); + return mfree(data); } DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free); @@ -174,19 +174,15 @@ static int automount_verify(Automount *a) { assert(a); assert(UNIT(a)->load_state == UNIT_LOADED); - if (path_equal(a->where, "/")) { - log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing."); - return -ENOEXEC; - } + if (path_equal(a->where, "/")) + return log_unit_error_errno(UNIT(a), SYNTHETIC_ERRNO(ENOEXEC), "Cannot have an automount unit for the root directory. Refusing."); r = unit_name_from_path(a->where, ".automount", &e); if (r < 0) return log_unit_error_errno(UNIT(a), r, "Failed to generate unit name from path: %m"); - if (!unit_has_name(UNIT(a), e)) { - log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing."); - return -ENOEXEC; - } + if (!unit_has_name(UNIT(a), e)) + return log_unit_error_errno(UNIT(a), SYNTHETIC_ERRNO(ENOEXEC), "Where= setting doesn't match unit name. Refusing."); return 0; } @@ -811,10 +807,8 @@ static int automount_start(Unit *u) { assert(a); assert(IN_SET(a->state, AUTOMOUNT_DEAD, AUTOMOUNT_FAILED)); - if (path_is_mount_point(a->where, NULL, 0) > 0) { - log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where); - return -EEXIST; - } + if (path_is_mount_point(a->where, NULL, 0) > 0) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(EEXIST), "Path %s is already a mount point, refusing start.", a->where); r = unit_test_trigger_loaded(u); if (r < 0) diff --git a/src/core/automount.h b/src/core/automount.h index fe668d977..91e6c5766 100644 --- a/src/core/automount.h +++ b/src/core/automount.h @@ -12,7 +12,7 @@ typedef enum AutomountResult { AUTOMOUNT_FAILURE_START_LIMIT_HIT, AUTOMOUNT_FAILURE_MOUNT_START_LIMIT_HIT, _AUTOMOUNT_RESULT_MAX, - _AUTOMOUNT_RESULT_INVALID = -1 + _AUTOMOUNT_RESULT_INVALID = -EINVAL, } AutomountResult; struct Automount { diff --git a/src/core/bpf-firewall.c b/src/core/bpf-firewall.c index 99783aca2..0f588b6ca 100644 --- a/src/core/bpf-firewall.c +++ b/src/core/bpf-firewall.c @@ -686,14 +686,10 @@ int bpf_firewall_install(Unit *u) { supported = bpf_firewall_supported(); if (supported < 0) return supported; - if (supported == BPF_FIREWALL_UNSUPPORTED) { - log_unit_debug(u, "BPF firewalling not supported on this manager, proceeding without."); - return -EOPNOTSUPP; - } - if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE) { - log_unit_debug(u, "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units."); - return -EOPNOTSUPP; - } + if (supported == BPF_FIREWALL_UNSUPPORTED) + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF firewalling not supported on this manager, proceeding without."); + if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && u->type == UNIT_SLICE) + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI is not supported on this manager, not doing BPF firewall on slice units."); if (supported != BPF_FIREWALL_SUPPORTED_WITH_MULTI && (!set_isempty(u->ip_bpf_custom_ingress) || !set_isempty(u->ip_bpf_custom_egress))) return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EOPNOTSUPP), "BPF_F_ALLOW_MULTI not supported on this manager, cannot attach custom BPF programs."); diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 7dc6c20bb..96073b108 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -21,6 +21,7 @@ #include "nulstr-util.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "process-util.h" #include "procfs-util.h" #include "special.h" @@ -131,6 +132,7 @@ void cgroup_context_init(CGroupContext *c) { .moom_swap = MANAGED_OOM_AUTO, .moom_mem_pressure = MANAGED_OOM_AUTO, + .moom_preference = MANAGED_OOM_PREFERENCE_NONE, }; } @@ -417,7 +419,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { "%sDelegate: %s\n" "%sManagedOOMSwap: %s\n" "%sManagedOOMMemoryPressure: %s\n" - "%sManagedOOMMemoryPressureLimitPercent: %d%%\n", + "%sManagedOOMMemoryPressureLimit: " PERMYRIAD_AS_PERCENT_FORMAT_STR "\n" + "%sManagedOOMPreference: %s%%\n", prefix, yes_no(c->cpu_accounting), prefix, yes_no(c->io_accounting), prefix, yes_no(c->blockio_accounting), @@ -450,7 +453,8 @@ void cgroup_context_dump(Unit *u, FILE* f, const char *prefix) { prefix, yes_no(c->delegate), prefix, managed_oom_mode_to_string(c->moom_swap), prefix, managed_oom_mode_to_string(c->moom_mem_pressure), - prefix, c->moom_mem_pressure_limit); + prefix, PERMYRIAD_AS_PERCENT_FORMAT_VAL(UINT32_SCALE_TO_PERMYRIAD(c->moom_mem_pressure_limit)), + prefix, managed_oom_preference_to_string(c->moom_preference)); if (c->delegate) { _cleanup_free_ char *t = NULL; @@ -600,6 +604,41 @@ int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode) UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_low); UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_min); +void cgroup_oomd_xattr_apply(Unit *u, const char *cgroup_path) { + CGroupContext *c; + int r; + + assert(u); + + c = unit_get_cgroup_context(u); + if (!c) + return; + + if (c->moom_preference == MANAGED_OOM_PREFERENCE_OMIT) { + r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, "user.oomd_omit", "1", 1, 0); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to set oomd_omit flag on control group %s, ignoring: %m", cgroup_path); + } + + if (c->moom_preference == MANAGED_OOM_PREFERENCE_AVOID) { + r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, "user.oomd_avoid", "1", 1, 0); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to set oomd_avoid flag on control group %s, ignoring: %m", cgroup_path); + } + + if (c->moom_preference != MANAGED_OOM_PREFERENCE_AVOID) { + r = cg_remove_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, "user.oomd_avoid"); + if (r != -ENODATA) + log_unit_debug_errno(u, r, "Failed to remove oomd_avoid flag on control group %s, ignoring: %m", cgroup_path); + } + + if (c->moom_preference != MANAGED_OOM_PREFERENCE_OMIT) { + r = cg_remove_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup_path, "user.oomd_omit"); + if (r != -ENODATA) + log_unit_debug_errno(u, r, "Failed to remove oomd_omit flag on control group %s, ignoring: %m", cgroup_path); + } +} + static void cgroup_xattr_apply(Unit *u) { char ids[SD_ID128_STRING_MAX]; int r; @@ -630,6 +669,8 @@ static void cgroup_xattr_apply(Unit *u) { if (r != -ENODATA) log_unit_debug_errno(u, r, "Failed to remove delegate flag on control group %s, ignoring: %m", u->cgroup_path); } + + cgroup_oomd_xattr_apply(u, u->cgroup_path); } static int lookup_block_device(const char *p, dev_t *ret) { @@ -1057,6 +1098,23 @@ static int cgroup_apply_devices(Unit *u) { return r; } +static void set_io_weight(Unit *u, const char *controller, uint64_t weight) { + char buf[8+DECIMAL_STR_MAX(uint64_t)+1]; + const char *p; + + p = strjoina(controller, ".weight"); + xsprintf(buf, "default %" PRIu64 "\n", weight); + (void) set_attribute_and_warn(u, controller, p, buf); + + /* FIXME: drop this when distro kernels properly support BFQ through "io.weight" + * See also: https://github.com/systemd/systemd/pull/13335 and + * https://github.com/torvalds/linux/commit/65752aef0a407e1ef17ec78a7fc31ba4e0b360f9. + * The range is 1..1000 apparently. */ + p = strjoina(controller, ".bfq.weight"); + xsprintf(buf, "%" PRIu64 "\n", (weight + 9) / 10); + (void) set_attribute_and_warn(u, controller, p, buf); +} + static void cgroup_context_apply( Unit *u, CGroupMask apply_mask, @@ -1143,7 +1201,6 @@ static void cgroup_context_apply( * controller), and in case of containers we want to leave control of these attributes to the container manager * (and we couldn't access that stuff anyway, even if we tried if proper delegation is used). */ if ((apply_mask & CGROUP_MASK_IO) && !is_local_root) { - char buf[8+DECIMAL_STR_MAX(uint64_t)+1]; bool has_io, has_blockio; uint64_t weight; @@ -1163,13 +1220,7 @@ static void cgroup_context_apply( } else weight = CGROUP_WEIGHT_DEFAULT; - xsprintf(buf, "default %" PRIu64 "\n", weight); - (void) set_attribute_and_warn(u, "io", "io.weight", buf); - - /* FIXME: drop this when distro kernels properly support BFQ through "io.weight" - * See also: https://github.com/systemd/systemd/pull/13335 */ - xsprintf(buf, "%" PRIu64 "\n", weight); - (void) set_attribute_and_warn(u, "io", "io.bfq.weight", buf); + set_io_weight(u, "io", weight); if (has_io) { CGroupIODeviceLatency *latency; @@ -1225,7 +1276,6 @@ static void cgroup_context_apply( /* Applying a 'weight' never makes sense for the host root cgroup, and for containers this should be * left to our container manager, too. */ if (!is_local_root) { - char buf[DECIMAL_STR_MAX(uint64_t)+1]; uint64_t weight; if (has_io) { @@ -1241,13 +1291,7 @@ static void cgroup_context_apply( else weight = CGROUP_BLKIO_WEIGHT_DEFAULT; - xsprintf(buf, "%" PRIu64 "\n", weight); - (void) set_attribute_and_warn(u, "blkio", "blkio.weight", buf); - - /* FIXME: drop this when distro kernels properly support BFQ through "blkio.weight" - * See also: https://github.com/systemd/systemd/pull/13335 */ - xsprintf(buf, "%" PRIu64 "\n", weight); - (void) set_attribute_and_warn(u, "blkio", "blkio.bfq.weight", buf); + set_io_weight(u, "blkio", weight); if (has_io) { CGroupIODeviceWeight *w; @@ -1579,20 +1623,20 @@ CGroupMask unit_get_ancestor_disable_mask(Unit *u) { } CGroupMask unit_get_target_mask(Unit *u) { - CGroupMask mask; + CGroupMask own_mask, mask; - /* This returns the cgroup mask of all controllers to enable - * for a specific cgroup, i.e. everything it needs itself, - * plus all that its children need, plus all that its siblings - * need. This is primarily useful on the legacy cgroup - * hierarchy, where we need to duplicate each cgroup in each + /* This returns the cgroup mask of all controllers to enable for a specific cgroup, i.e. everything + * it needs itself, plus all that its children need, plus all that its siblings need. This is + * primarily useful on the legacy cgroup hierarchy, where we need to duplicate each cgroup in each * hierarchy that shall be enabled for it. */ - mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u); + own_mask = unit_get_own_mask(u); - if (mask & CGROUP_MASK_BPF_FIREWALL & ~u->manager->cgroup_supported) + if (own_mask & CGROUP_MASK_BPF_FIREWALL & ~u->manager->cgroup_supported) emit_bpf_firewall_warning(u); + mask = own_mask | unit_get_members_mask(u) | unit_get_siblings_mask(u); + mask &= u->manager->cgroup_supported; mask &= ~unit_get_ancestor_disable_mask(u); @@ -1836,10 +1880,6 @@ int unit_pick_cgroup_path(Unit *u) { return 0; } -static int cg_v1_errno_to_log_level(int r) { - return r == -EROFS ? LOG_DEBUG : LOG_WARNING; -} - static int unit_update_cgroup( Unit *u, CGroupMask target_mask, @@ -1897,30 +1937,16 @@ static int unit_update_cgroup( * We perform migration also with whole slices for cases when users don't care about leave * granularity. Since delegated_mask is subset of target mask, we won't trim slice subtree containing * delegated units. - * - * If we're in an nspawn container and using legacy cgroups, the controller hierarchies are mounted - * read-only into the container. We skip migration/trim in this scenario since it would fail - * regardless with noisy "Read-only filesystem" warnings. */ if (cg_all_unified() == 0) { r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u); if (r < 0) - log_unit_full_errno( - u, - cg_v1_errno_to_log_level(r), - r, - "Failed to migrate controller cgroups from %s, ignoring: %m", - u->cgroup_path); + log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", u->cgroup_path); is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE); r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice); if (r < 0) - log_unit_full_errno( - u, - cg_v1_errno_to_log_level(r), - r, - "Failed to delete controller cgroups %s, ignoring: %m", - u->cgroup_path); + log_unit_warning_errno(u, r, "Failed to delete controller cgroups %s, ignoring: %m", u->cgroup_path); } /* Set attributes */ @@ -2743,7 +2769,7 @@ int unit_check_oomd_kill(Unit *u) { else if (r == 0) return 0; - r = cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "user.systemd_oomd_kill", &value); + r = cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "user.oomd_kill", &value); if (r < 0 && r != -ENODATA) return r; @@ -3075,7 +3101,7 @@ int manager_setup_cgroup(Manager *m) { /* On the legacy hierarchy we only get notifications via cgroup agents. (Which isn't really reliable, * since it does not generate events when control groups with children run empty. */ - r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH); + r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUPS_AGENT_PATH); if (r < 0) log_warning_errno(r, "Failed to install release agent, ignoring: %m"); else if (r > 0) @@ -3107,7 +3133,7 @@ int manager_setup_cgroup(Manager *m) { (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1"); /* 8. Figure out which controllers are supported */ - r = cg_mask_supported(&m->cgroup_supported); + r = cg_mask_supported_subtree(m->cgroup_root, &m->cgroup_supported); if (r < 0) return log_error_errno(r, "Failed to determine supported controllers: %m"); @@ -3734,12 +3760,6 @@ int unit_cgroup_freezer_action(Unit *u, FreezerAction action) { return 1; } -static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { - [CGROUP_DEVICE_POLICY_AUTO] = "auto", - [CGROUP_DEVICE_POLICY_CLOSED] = "closed", - [CGROUP_DEVICE_POLICY_STRICT] = "strict", -}; - int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) { _cleanup_free_ char *v = NULL; int r; @@ -3768,6 +3788,12 @@ int unit_get_cpuset(Unit *u, CPUSet *cpus, const char *name) { return parse_cpu_set_full(v, cpus, false, NULL, NULL, 0, NULL); } +static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = { + [CGROUP_DEVICE_POLICY_AUTO] = "auto", + [CGROUP_DEVICE_POLICY_CLOSED] = "closed", + [CGROUP_DEVICE_POLICY_STRICT] = "strict", +}; + DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy); static const char* const freezer_action_table[_FREEZER_ACTION_MAX] = { diff --git a/src/core/cgroup.h b/src/core/cgroup.h index 66f3a63b8..fa79ba152 100644 --- a/src/core/cgroup.h +++ b/src/core/cgroup.h @@ -44,7 +44,7 @@ typedef enum CGroupDevicePolicy { CGROUP_DEVICE_POLICY_STRICT, _CGROUP_DEVICE_POLICY_MAX, - _CGROUP_DEVICE_POLICY_INVALID = -1 + _CGROUP_DEVICE_POLICY_INVALID = -EINVAL, } CGroupDevicePolicy; typedef enum FreezerAction { @@ -52,7 +52,7 @@ typedef enum FreezerAction { FREEZER_THAW, _FREEZER_ACTION_MAX, - _FREEZER_ACTION_INVALID = -1, + _FREEZER_ACTION_INVALID = -EINVAL, } FreezerAction; struct CGroupDeviceAllow { @@ -163,7 +163,8 @@ struct CGroupContext { /* Settings for systemd-oomd */ ManagedOOMMode moom_swap; ManagedOOMMode moom_mem_pressure; - int moom_mem_pressure_limit; + uint32_t moom_mem_pressure_limit; /* Normalized to 2^32-1 == 100% */ + ManagedOOMPreference moom_preference; }; /* Used when querying IP accounting data */ @@ -173,7 +174,7 @@ typedef enum CGroupIPAccountingMetric { CGROUP_IP_EGRESS_BYTES, CGROUP_IP_EGRESS_PACKETS, _CGROUP_IP_ACCOUNTING_METRIC_MAX, - _CGROUP_IP_ACCOUNTING_METRIC_INVALID = -1, + _CGROUP_IP_ACCOUNTING_METRIC_INVALID = -EINVAL, } CGroupIPAccountingMetric; /* Used when querying IO accounting data */ @@ -183,7 +184,7 @@ typedef enum CGroupIOAccountingMetric { CGROUP_IO_READ_OPERATIONS, CGROUP_IO_WRITE_OPERATIONS, _CGROUP_IO_ACCOUNTING_METRIC_MAX, - _CGROUP_IO_ACCOUNTING_METRIC_INVALID = -1, + _CGROUP_IO_ACCOUNTING_METRIC_INVALID = -EINVAL, } CGroupIOAccountingMetric; typedef struct Unit Unit; @@ -204,6 +205,8 @@ void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockI int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode); +void cgroup_oomd_xattr_apply(Unit *u, const char *cgroup_path); + CGroupMask unit_get_own_mask(Unit *u); CGroupMask unit_get_delegate_mask(Unit *u); CGroupMask unit_get_members_mask(Unit *u); diff --git a/src/core/core-varlink.c b/src/core/core-varlink.c index dd6c11ab4..b3df8cd89 100644 --- a/src/core/core-varlink.c +++ b/src/core/core-varlink.c @@ -142,7 +142,7 @@ static int vl_method_subscribe_managed_oom_cgroups( /* We only take one subscriber for this method so return an error if there's already an existing one. * This shouldn't happen since systemd-oomd is the only client of this method. */ if (FLAGS_SET(flags, VARLINK_METHOD_MORE) && m->managed_oom_varlink_request) - return varlink_error(m->managed_oom_varlink_request, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL); + return varlink_error(link, VARLINK_ERROR_SUBSCRIPTION_TAKEN, NULL); r = json_build(&arr, JSON_BUILD_EMPTY_ARRAY); if (r < 0) @@ -188,6 +188,7 @@ static int vl_method_subscribe_managed_oom_cgroups( if (!FLAGS_SET(flags, VARLINK_METHOD_MORE)) return varlink_reply(link, v); + assert(!m->managed_oom_varlink_request); m->managed_oom_varlink_request = varlink_ref(link); return varlink_notify(m->managed_oom_varlink_request, v); } @@ -432,7 +433,7 @@ int manager_varlink_init(Manager *m) { if (!MANAGER_IS_SYSTEM(m)) return 0; - r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID); + r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); if (r < 0) return log_error_errno(r, "Failed to allocate varlink server object: %m"); @@ -475,8 +476,7 @@ void manager_varlink_done(Manager *m) { assert(m); /* Send the final message if we still have a subscribe request open. */ - if (m->managed_oom_varlink_request) - m->managed_oom_varlink_request = varlink_close_unref(m->managed_oom_varlink_request); + m->managed_oom_varlink_request = varlink_close_unref(m->managed_oom_varlink_request); m->varlink_server = varlink_server_unref(m->varlink_server); } diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c index 37c581fb2..04d2ba34f 100644 --- a/src/core/dbus-cgroup.c +++ b/src/core/dbus-cgroup.c @@ -16,11 +16,13 @@ #include "fileio.h" #include "limits-util.h" #include "path-util.h" +#include "percent-util.h" BUS_DEFINE_PROPERTY_GET(bus_property_get_tasks_max, "t", TasksMax, tasks_max_resolve); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy); static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_managed_oom_mode, managed_oom_mode, ManagedOOMMode); +static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_managed_oom_preference, managed_oom_preference, ManagedOOMPreference); static int property_get_cgroup_mask( sd_bus *bus, @@ -32,7 +34,6 @@ static int property_get_cgroup_mask( sd_bus_error *error) { CGroupMask *mask = userdata; - CGroupController ctrl; int r; assert(bus); @@ -42,7 +43,7 @@ static int property_get_cgroup_mask( if (r < 0) return r; - for (ctrl = 0; ctrl < _CGROUP_CONTROLLER_MAX; ctrl++) { + for (CGroupController ctrl = 0; ctrl < _CGROUP_CONTROLLER_MAX; ctrl++) { if ((*mask & CGROUP_CONTROLLER_TO_MASK(ctrl)) == 0) continue; @@ -395,7 +396,8 @@ const sd_bus_vtable bus_cgroup_vtable[] = { SD_BUS_PROPERTY("DisableControllers", "as", property_get_cgroup_mask, offsetof(CGroupContext, disable_controllers), 0), SD_BUS_PROPERTY("ManagedOOMSwap", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_swap), 0), SD_BUS_PROPERTY("ManagedOOMMemoryPressure", "s", property_get_managed_oom_mode, offsetof(CGroupContext, moom_mem_pressure), 0), - SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimitPercent", "s", bus_property_get_percent, offsetof(CGroupContext, moom_mem_pressure_limit), 0), + SD_BUS_PROPERTY("ManagedOOMMemoryPressureLimit", "u", NULL, offsetof(CGroupContext, moom_mem_pressure_limit), 0), + SD_BUS_PROPERTY("ManagedOOMPreference", "s", property_get_managed_oom_preference, offsetof(CGroupContext, moom_preference), 0), SD_BUS_VTABLE_END }; @@ -703,10 +705,10 @@ static int bus_cgroup_set_boolean( /* 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 scaled = UINT32_SCALE_TO_PERMYRIAD(raw); \ + unit_write_settingf(u, flags, name, "%.*s=" PERMYRIAD_AS_PERCENT_FORMAT_STR, \ (int)(strlen(name) - strlen("Scale")), name, \ - scaled / 10, scaled % 10); \ + PERMYRIAD_AS_PERCENT_FORMAT_VAL(scaled)); \ } \ \ return 1; \ @@ -1453,7 +1455,7 @@ int bus_cgroup_set_property( p = cgroup_device_policy_from_string(policy); if (p < 0) - return -EINVAL; + return p; if (!UNIT_WRITE_FLAGS_NOOP(flags)) { c->device_policy = p; @@ -1697,20 +1699,49 @@ int bus_cgroup_set_property( return 1; } - if (streq(name, "ManagedOOMMemoryPressureLimitPercent")) { + if (streq(name, "ManagedOOMMemoryPressureLimit")) { + uint32_t v; + if (!UNIT_VTABLE(u)->can_set_managed_oom) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set %s for this unit type", name); - r = bus_set_transient_percent(u, name, &c->moom_mem_pressure_limit, message, flags, error); + r = sd_bus_message_read(message, "u", &v); if (r < 0) return r; + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + c->moom_mem_pressure_limit = v; + unit_write_settingf(u, flags, name, + "ManagedOOMMemoryPressureLimit=" PERMYRIAD_AS_PERCENT_FORMAT_STR, + PERMYRIAD_AS_PERCENT_FORMAT_VAL(UINT32_SCALE_TO_PERMYRIAD(v))); + } + if (c->moom_mem_pressure == MANAGED_OOM_KILL) (void) manager_varlink_send_managed_oom_update(u); return 1; } + if (streq(name, "ManagedOOMPreference")) { + ManagedOOMPreference p; + const char *pref; + + r = sd_bus_message_read(message, "s", &pref); + if (r < 0) + return r; + + p = managed_oom_preference_from_string(pref); + if (p < 0) + return p; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + c->moom_preference = p; + unit_write_settingf(u, flags, name, "ManagedOOMPreference=%s", pref); + } + + return 1; + } + if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB)) return bus_cgroup_set_transient_property(u, c, name, message, flags, error); diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c index 04735354a..4a1585f66 100644 --- a/src/core/dbus-execute.c +++ b/src/core/dbus-execute.c @@ -698,7 +698,6 @@ static int property_get_bind_paths( sd_bus_error *error) { ExecContext *c = userdata; - unsigned i; bool ro; int r; @@ -713,7 +712,7 @@ static int property_get_bind_paths( if (r < 0) return r; - for (i = 0; i < c->n_bind_mounts; i++) { + for (size_t i = 0; i < c->n_bind_mounts; i++) { if (ro != c->bind_mounts[i].read_only) continue; @@ -741,7 +740,6 @@ static int property_get_temporary_filesystems( sd_bus_error *error) { ExecContext *c = userdata; - unsigned i; int r; assert(bus); @@ -753,7 +751,7 @@ static int property_get_temporary_filesystems( if (r < 0) return r; - for (i = 0; i < c->n_temporary_filesystems; i++) { + for (unsigned i = 0; i < c->n_temporary_filesystems; i++) { TemporaryFileSystem *t = c->temporary_filesystems + i; r = sd_bus_message_append( @@ -777,7 +775,6 @@ static int property_get_log_extra_fields( sd_bus_error *error) { ExecContext *c = userdata; - size_t i; int r; assert(bus); @@ -789,7 +786,7 @@ static int property_get_log_extra_fields( if (r < 0) return r; - for (i = 0; i < c->n_log_extra_fields; i++) { + for (size_t i = 0; i < c->n_log_extra_fields; i++) { r = sd_bus_message_append_array(reply, 'y', c->log_extra_fields[i].iov_base, c->log_extra_fields[i].iov_len); if (r < 0) return r; @@ -999,6 +996,60 @@ static int property_get_mount_images( return sd_bus_message_close_container(reply); } +static int property_get_extension_images( + 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; + int r; + + assert(bus); + assert(c); + assert(property); + assert(reply); + + r = sd_bus_message_open_container(reply, 'a', "(sba(ss))"); + if (r < 0) + return r; + + for (size_t i = 0; i < c->n_extension_images; i++) { + MountOptions *m; + + r = sd_bus_message_open_container(reply, SD_BUS_TYPE_STRUCT, "sba(ss)"); + if (r < 0) + return r; + r = sd_bus_message_append( + reply, "sb", + c->extension_images[i].source, + c->extension_images[i].ignore_enoent); + if (r < 0) + return r; + r = sd_bus_message_open_container(reply, 'a', "(ss)"); + if (r < 0) + return r; + LIST_FOREACH(mount_options, m, c->extension_images[i].mount_options) { + r = sd_bus_message_append(reply, "(ss)", + partition_designator_to_string(m->partition_designator), + m->options); + if (r < 0) + return r; + } + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + 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), @@ -1047,6 +1098,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("RootHashSignature", "ay", property_get_root_hash_sig, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootHashSignaturePath", "s", NULL, offsetof(ExecContext, root_hash_sig_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RootVerity", "s", NULL, offsetof(ExecContext, root_verity), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ExtensionImages", "a(sba(ss))", property_get_extension_images, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MountImages", "a(ssba(ss))", property_get_mount_images, 0, 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), @@ -1097,6 +1149,8 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ExecPaths", "as", NULL, offsetof(ExecContext, exec_paths), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("NoExecPaths", "as", NULL, offsetof(ExecContext, no_exec_paths), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1108,6 +1162,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PrivateMounts", "b", bus_property_get_bool, offsetof(ExecContext, private_mounts), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("PrivateIPC", "b", bus_property_get_bool, offsetof(ExecContext, private_ipc), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ProtectHome", "s", property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ProtectSystem", "s", property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1150,6 +1205,7 @@ const sd_bus_vtable bus_exec_vtable[] = { SD_BUS_PROPERTY("ProcSubset", "s", property_get_proc_subset, offsetof(ExecContext, proc_subset), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ProtectHostname", "b", bus_property_get_bool, offsetof(ExecContext, protect_hostname), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NetworkNamespacePath", "s", NULL, offsetof(ExecContext, network_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("IPCNamespacePath", "s", NULL, offsetof(ExecContext, ipc_namespace_path), SD_BUS_VTABLE_PROPERTY_CONST), /* Obsolete/redundant properties: */ SD_BUS_PROPERTY("Capabilities", "s", property_get_empty_string, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), @@ -1497,74 +1553,6 @@ static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(capability, "t", uint64_t, uint6 static BUS_DEFINE_SET_TRANSIENT_TO_STRING_ALLOC(namespace_flag, "t", uint64_t, unsigned long, "%" PRIu64, namespace_flags_to_string); static BUS_DEFINE_SET_TRANSIENT_TO_STRING(mount_flags, "t", uint64_t, unsigned long, "%" PRIu64, mount_propagation_flags_to_string_with_check); -/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */ -static int read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator) { - _cleanup_(mount_options_free_allp) MountOptions *options = NULL; - _cleanup_free_ char *format_str = NULL; - const char *mount_options, *partition; - int r; - - assert(message); - assert(ret_options); - assert(ret_format_str); - assert(separator); - - r = sd_bus_message_enter_container(message, 'a', "(ss)"); - if (r < 0) - return r; - - while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) { - _cleanup_free_ char *previous = NULL, *escaped = NULL; - _cleanup_free_ MountOptions *o = NULL; - PartitionDesignator partition_designator; - - if (chars_intersect(mount_options, WHITESPACE)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, - "Invalid mount options string, contains whitespace character(s): %s", mount_options); - - partition_designator = partition_designator_from_string(partition); - if (partition_designator < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition); - - /* Need to store them in the unit with the escapes, so that they can be parsed again */ - escaped = shell_escape(mount_options, ":"); - if (!escaped) - return -ENOMEM; - - previous = TAKE_PTR(format_str); - format_str = strjoin(previous, previous ? separator : "", partition, ":", escaped); - if (!format_str) - return -ENOMEM; - - o = new(MountOptions, 1); - if (!o) - return -ENOMEM; - *o = (MountOptions) { - .partition_designator = partition_designator, - .options = strdup(mount_options), - }; - if (!o->options) - return -ENOMEM; - LIST_APPEND(mount_options, options, TAKE_PTR(o)); - } - if (r < 0) - return r; - - r = sd_bus_message_exit_container(message); - if (r < 0) - return r; - - if (!LIST_IS_EMPTY(options)) { - char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str); - if (!final) - return -ENOMEM; - free_and_replace(*ret_format_str, final); - LIST_JOIN(mount_options, *ret_options, options); - } - - return 0; -} - int bus_exec_context_set_transient_property( Unit *u, ExecContext *c, @@ -1599,7 +1587,7 @@ int bus_exec_context_set_transient_property( _cleanup_(mount_options_free_allp) MountOptions *options = NULL; _cleanup_free_ char *format_str = NULL; - r = read_mount_options(message, error, &options, &format_str, " "); + r = bus_read_mount_options(message, error, &options, &format_str, " "); if (r < 0) return r; @@ -1767,6 +1755,9 @@ int bus_exec_context_set_transient_property( if (streq(name, "PrivateNetwork")) return bus_set_transient_bool(u, name, &c->private_network, message, flags, error); + if (streq(name, "PrivateIPC")) + return bus_set_transient_bool(u, name, &c->private_ipc, message, flags, error); + if (streq(name, "PrivateUsers")) return bus_set_transient_bool(u, name, &c->private_users, message, flags, error); @@ -1887,6 +1878,9 @@ int bus_exec_context_set_transient_property( if (streq(name, "NetworkNamespacePath")) return bus_set_transient_path(u, name, &c->network_namespace_path, message, flags, error); + if (streq(name, "IPCNamespacePath")) + return bus_set_transient_path(u, name, &c->ipc_namespace_path, message, flags, error); + if (streq(name, "SupplementaryGroups")) { _cleanup_strv_free_ char **l = NULL; char **p; @@ -1983,11 +1977,7 @@ int bus_exec_context_set_transient_property( sc->data = TAKE_PTR(copy); sc->size = sz; - r = hashmap_ensure_allocated(&c->set_credentials, &exec_set_credential_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(c->set_credentials, sc->id, sc); + r = hashmap_ensure_put(&c->set_credentials, &exec_set_credential_hash_ops, sc->id, sc); if (r < 0) return r; @@ -2262,6 +2252,9 @@ int bus_exec_context_set_transient_property( if (r < 0) return r; + if (allow_list && e >= 0) + return -EINVAL; + r = seccomp_parse_syscall_filter(n, e, c->syscall_filter, @@ -2325,15 +2318,8 @@ int bus_exec_context_set_transient_property( } STRV_FOREACH(s, l) { - _cleanup_free_ char *n = NULL; - int e; - - r = parse_syscall_and_errno(*s, &n, &e); - if (r < 0) - return r; - - r = seccomp_parse_syscall_filter(n, - 0, /* errno not used */ + r = seccomp_parse_syscall_filter(*s, + -1, /* errno not used */ c->syscall_log, SECCOMP_PARSE_LOG | SECCOMP_PARSE_PERMISSIVE | invert_flag | @@ -2727,8 +2713,8 @@ int bus_exec_context_set_transient_property( } else if (STR_IN_SET(name, "StandardInputFile", - "StandardOutputFile", "StandardOutputFileToAppend", - "StandardErrorFile", "StandardErrorFileToAppend")) { + "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate", + "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate")) { const char *s; r = sd_bus_message_read(message, "s", &s); @@ -2752,7 +2738,7 @@ int bus_exec_context_set_transient_property( c->std_input = EXEC_INPUT_FILE; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardInput=file:%s", s); - } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend")) { + } else if (STR_IN_SET(name, "StandardOutputFile", "StandardOutputFileToAppend", "StandardOutputFileToTruncate")) { r = free_and_strdup(&c->stdio_file[STDOUT_FILENO], empty_to_null(s)); if (r < 0) return r; @@ -2760,13 +2746,16 @@ int bus_exec_context_set_transient_property( if (streq(name, "StandardOutputFile")) { c->std_output = EXEC_OUTPUT_FILE; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=file:%s", s); - } else { - assert(streq(name, "StandardOutputFileToAppend")); + } else if (streq(name, "StandardOutputFileToAppend")) { c->std_output = EXEC_OUTPUT_FILE_APPEND; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=append:%s", s); + } else { + assert(streq(name, "StandardOutputFileToTruncate")); + c->std_output = EXEC_OUTPUT_FILE_TRUNCATE; + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardOutput=truncate:%s", s); } } else { - assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend")); + assert(STR_IN_SET(name, "StandardErrorFile", "StandardErrorFileToAppend", "StandardErrorFileToTruncate")); r = free_and_strdup(&c->stdio_file[STDERR_FILENO], empty_to_null(s)); if (r < 0) @@ -2775,10 +2764,13 @@ int bus_exec_context_set_transient_property( if (streq(name, "StandardErrorFile")) { c->std_error = EXEC_OUTPUT_FILE; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=file:%s", s); - } else { - assert(streq(name, "StandardErrorFileToAppend")); + } else if (streq(name, "StandardErrorFileToAppend")) { c->std_error = EXEC_OUTPUT_FILE_APPEND; unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=append:%s", s); + } else { + assert(streq(name, "StandardErrorFileToTruncate")); + c->std_error = EXEC_OUTPUT_FILE_TRUNCATE; + unit_write_settingf(u, flags|UNIT_ESCAPE_SPECIFIERS, name, "StandardError=truncate:%s", s); } } } @@ -3050,7 +3042,7 @@ int bus_exec_context_set_transient_property( return 1; } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories", - "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) { + "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", "ExecPaths", "NoExecPaths")) { _cleanup_strv_free_ char **l = NULL; char ***dirs; char **p; @@ -3076,6 +3068,10 @@ int bus_exec_context_set_transient_property( dirs = &c->read_write_paths; else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths")) dirs = &c->read_only_paths; + else if (streq(name, "ExecPaths")) + dirs = &c->exec_paths; + else if (streq(name, "NoExecPaths")) + dirs = &c->no_exec_paths; else /* "InaccessiblePaths" */ dirs = &c->inaccessible_paths; @@ -3309,7 +3305,7 @@ int bus_exec_context_set_transient_property( if (r < 0) return r; - if (rl == (uint64_t) -1) + if (rl == UINT64_MAX) x = RLIM_INFINITY; else { x = (rlim_t) rl; @@ -3405,7 +3401,7 @@ int bus_exec_context_set_transient_property( return -ENOMEM; free_and_replace(format_str, tuple); - r = read_mount_options(message, error, &options, &format_str, ":"); + r = bus_read_mount_options(message, error, &options, &format_str, ":"); if (r < 0) return r; @@ -3419,6 +3415,7 @@ int bus_exec_context_set_transient_property( .destination = destination, .mount_options = options, .ignore_enoent = permissive, + .type = MOUNT_IMAGE_DISCRETE, }); if (r < 0) return r; @@ -3452,6 +3449,95 @@ int bus_exec_context_set_transient_property( mount_images = mount_image_free_many(mount_images, &n_mount_images); + return 1; + } else if (streq(name, "ExtensionImages")) { + _cleanup_free_ char *format_str = NULL; + MountImage *extension_images = NULL; + size_t n_extension_images = 0; + + r = sd_bus_message_enter_container(message, 'a', "(sba(ss))"); + if (r < 0) + return r; + + for (;;) { + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + _cleanup_free_ char *source_escaped = NULL; + char *source, *tuple; + int permissive; + + r = sd_bus_message_enter_container(message, 'r', "sba(ss)"); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "sb", &source, &permissive); + if (r <= 0) + break; + + if (!path_is_absolute(source)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not absolute.", source); + if (!path_is_normalized(source)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path %s is not normalized.", source); + + /* Need to store them in the unit with the escapes, so that they can be parsed again */ + source_escaped = shell_escape(source, ":"); + if (!source_escaped) + return -ENOMEM; + + tuple = strjoin(format_str, + format_str ? " " : "", + permissive ? "-" : "", + source_escaped); + if (!tuple) + return -ENOMEM; + free_and_replace(format_str, tuple); + + r = bus_read_mount_options(message, error, &options, &format_str, ":"); + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + r = mount_image_add(&extension_images, &n_extension_images, + &(MountImage) { + .source = source, + .mount_options = options, + .ignore_enoent = permissive, + .type = MOUNT_IMAGE_EXTENSION, + }); + if (r < 0) + return r; + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (n_extension_images == 0) { + c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images); + + unit_write_settingf(u, flags, name, "%s=", name); + } else { + for (size_t i = 0; i < n_extension_images; ++i) { + r = mount_image_add(&c->extension_images, &c->n_extension_images, &extension_images[i]); + if (r < 0) + return r; + } + + unit_write_settingf(u, flags|UNIT_ESCAPE_C|UNIT_ESCAPE_SPECIFIERS, + name, + "%s=%s", + name, + format_str); + } + } + + extension_images = mount_image_free_many(extension_images, &n_extension_images); + return 1; } diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c index 1526b316c..3334b977b 100644 --- a/src/core/dbus-job.c +++ b/src/core/dbus-job.c @@ -71,7 +71,7 @@ int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ Job **list = NULL; Job *j = userdata; - int r, i, n; + int r, n; if (strstr(sd_bus_message_get_member(message), "After")) n = job_get_after(j, &list); @@ -88,7 +88,7 @@ int bus_job_method_get_waiting_jobs(sd_bus_message *message, void *userdata, sd_ if (r < 0) return r; - for (i = 0; i < n; i ++) { + for (int i = 0; i < n; i ++) { _cleanup_free_ char *unit_path = NULL, *job_path = NULL; job_path = job_dbus_path(list[i]); diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c index b37ed7c86..e33896f97 100644 --- a/src/core/dbus-manager.c +++ b/src/core/dbus-manager.c @@ -16,6 +16,7 @@ #include "dbus-job.h" #include "dbus-manager.h" #include "dbus-scope.h" +#include "dbus-service.h" #include "dbus-unit.h" #include "dbus.h" #include "env-util.h" @@ -37,8 +38,8 @@ #include "virt.h" #include "watchdog.h" -/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state there, and if - * we can't we'll fail badly. */ +/* Require 16MiB free in /run/systemd for reloading/reexecing. After all we need to serialize our state + * there, and if we can't we'll fail badly. */ #define RELOAD_DISK_SPACE_MIN (UINT64_C(16) * UINT64_C(1024) * UINT64_C(1024)) static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) { @@ -49,7 +50,7 @@ static UnitFileFlags unit_file_bools_to_flags(bool runtime, bool force) { BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_oom_policy, oom_policy, OOMPolicy); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_version, "s", GIT_VERSION); -static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_features, "s", SYSTEMD_FEATURES); +static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_features, "s", systemd_features); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_architecture, "s", architecture_to_string(uname_architecture())); static BUS_DEFINE_PROPERTY_GET2(property_get_system_state, "s", Manager, manager_state, manager_state_to_string); static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_timer_slack_nsec, "t", (uint64_t) prctl(PR_GET_TIMERSLACK)); @@ -362,8 +363,8 @@ static int bus_get_unit_by_name(Manager *m, sd_bus_message *message, const char assert(message); assert(ret_unit); - /* More or less a wrapper around manager_get_unit() that generates nice errors and has one trick up its sleeve: - * if the name is specified empty we use the client's unit. */ + /* More or less a wrapper around manager_get_unit() that generates nice errors and has one trick up + * its sleeve: if the name is specified empty we use the client's unit. */ if (isempty(name)) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; @@ -519,7 +520,8 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd u = manager_get_unit_by_pid(m, pid); if (!u) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client " PID_FMT " not member of any unit.", pid); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, + "Client " PID_FMT " not member of any unit.", pid); } else { u = hashmap_get(m->units_by_invocation_id, &id); if (!u) @@ -530,8 +532,9 @@ static int method_get_unit_by_invocation_id(sd_bus_message *message, void *userd if (r < 0) return r; - /* So here's a special trick: the bus path we return actually references the unit by its invocation ID instead - * of the unit name. This means it stays valid only as long as the invocation ID stays the same. */ + /* So here's a special trick: the bus path we return actually references the unit by its invocation + * ID instead of the unit name. This means it stays valid only as long as the invocation ID stays the + * same. */ path = unit_dbus_path_invocation_id(u); if (!path) return -ENOMEM; @@ -551,7 +554,9 @@ static int method_get_unit_by_control_group(sd_bus_message *message, void *userd u = manager_get_unit_by_cgroup(m, cgroup); if (!u) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Control group '%s' is not valid or not managed by this instance", cgroup); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, + "Control group '%s' is not valid or not managed by this instance", + cgroup); return reply_unit_path(u, message, error); } @@ -725,6 +730,16 @@ static int method_set_unit_properties(sd_bus_message *message, void *userdata, s return method_generic_unit_operation(message, userdata, error, bus_unit_method_set_properties, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED); } +static int method_bind_mount_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { + /* Only add mounts on fully loaded units */ + return method_generic_unit_operation(message, userdata, error, bus_service_method_bind_mount, GENERIC_UNIT_VALIDATE_LOADED); +} + +static int method_mount_image_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { + /* Only add mounts on fully loaded units */ + return method_generic_unit_operation(message, userdata, error, bus_service_method_mount_image, GENERIC_UNIT_VALIDATE_LOADED); +} + static int method_ref_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) { /* Only allow reffing of fully loaded units, and make sure reffing a unit loads it. */ return method_generic_unit_operation(message, userdata, error, bus_unit_method_ref, GENERIC_UNIT_LOAD|GENERIC_UNIT_VALIDATE_LOADED); @@ -840,17 +855,21 @@ static int transient_unit_from_message( t = unit_name_to_type(name); if (t < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or type."); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid unit name or type."); if (!unit_vtable[t]->can_transient) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t)); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Unit type %s does not support transient units.", + unit_type_to_string(t)); r = manager_load_unit(m, name, NULL, error, &u); if (r < 0) return r; if (!unit_is_pristine(u)) - return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name); + return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, + "Unit %s already exists.", name); /* OK, the unit failed to load and is unreferenced, now let's * fill in the transient data instead */ @@ -1424,7 +1443,8 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Reboot is only supported for system managers."); m->objective = MANAGER_REBOOT; @@ -1443,7 +1463,8 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Powering off is only supported for system managers."); m->objective = MANAGER_POWEROFF; @@ -1462,7 +1483,8 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Halt is only supported for system managers."); m->objective = MANAGER_HALT; @@ -1481,7 +1503,8 @@ static int method_kexec(sd_bus_message *message, void *userdata, sd_bus_error *e return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "KExec is only supported for system managers."); m->objective = MANAGER_KEXEC; @@ -1506,7 +1529,7 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er if (available < RELOAD_DISK_SPACE_MIN) { char fb_available[FORMAT_BYTES_MAX], fb_need[FORMAT_BYTES_MAX]; - log_warning("Dangerously low amount of free space on /run/systemd, root switching operation might not complete successfully. " + log_warning("Dangerously low amount of free space on /run/systemd, root switching might fail.\n" "Currently, %s are free, but %s are suggested. Proceeding anyway.", format_bytes(fb_available, sizeof(fb_available), available), format_bytes(fb_need, sizeof(fb_need), RELOAD_DISK_SPACE_MIN)); @@ -1517,41 +1540,53 @@ static int method_switch_root(sd_bus_message *message, void *userdata, sd_bus_er return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Root switching is only supported by system manager."); r = sd_bus_message_read(message, "ss", &root, &init); if (r < 0) return r; if (isempty(root)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory may not be the empty string."); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "New root directory may not be the empty string."); if (!path_is_absolute(root)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root path '%s' is not absolute.", root); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "New root path '%s' is not absolute.", root); if (path_equal(root, "/")) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New root directory cannot be the old root directory."); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "New root directory cannot be the old root directory."); /* Safety check */ if (isempty(init)) { r = path_is_os_tree(root); if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to determine whether root path '%s' contains an OS tree: %m", root); + return sd_bus_error_set_errnof(error, r, + "Failed to determine whether root path '%s' contains an OS tree: %m", + root); if (r == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", root); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Specified switch root path '%s' does not seem to be an OS tree. os-release file is missing.", + root); } else { _cleanup_free_ char *chased = NULL; if (!path_is_absolute(init)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Path to init binary '%s' not absolute.", init); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Path to init binary '%s' not absolute.", init); r = chase_symlinks(init, root, CHASE_PREFIX_ROOT|CHASE_TRAIL_SLASH, &chased, NULL); if (r < 0) - return sd_bus_error_set_errnof(error, r, "Could not resolve init executable %s: %m", init); + return sd_bus_error_set_errnof(error, r, + "Could not resolve init executable %s: %m", init); if (laccess(chased, X_OK) < 0) { if (errno == EACCES) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Init binary %s is not executable.", init); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Init binary %s is not executable.", init); - return sd_bus_error_set_errnof(error, r, "Could not check whether init binary %s is executable: %m", init); + return sd_bus_error_set_errnof(error, r, + "Could not check whether init binary %s is executable: %m", init); } } @@ -1621,7 +1656,8 @@ static int method_unset_environment(sd_bus_message *message, void *userdata, sd_ return r; if (!strv_env_name_or_assignment_is_valid(minus)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid environment variable names or assignments"); r = bus_verify_set_environment_async(m, message, error); if (r < 0) @@ -1657,9 +1693,11 @@ static int method_unset_and_set_environment(sd_bus_message *message, void *userd return r; if (!strv_env_name_or_assignment_is_valid(minus)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid environment variable names or assignments"); if (!strv_env_is_valid(plus)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid environment assignments"); r = bus_verify_set_environment_async(m, message, error); if (r < 0) @@ -1712,13 +1750,16 @@ static int method_lookup_dynamic_user_by_name(sd_bus_message *message, void *use return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Dynamic users are only supported in the system instance."); if (!valid_user_group_name(name, VALID_USER_RELAX)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User name invalid: %s", name); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "User name invalid: %s", name); r = dynamic_user_lookup_name(m, name, &uid); if (r == -ESRCH) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, "Dynamic user %s does not exist.", name); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, + "Dynamic user %s does not exist.", name); if (r < 0) return r; @@ -1740,13 +1781,16 @@ static int method_lookup_dynamic_user_by_uid(sd_bus_message *message, void *user return r; if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Dynamic users are only supported in the system instance."); if (!uid_is_valid(uid)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "User ID invalid: " UID_FMT, uid); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "User ID invalid: " UID_FMT, uid); r = dynamic_user_lookup_uid(m, uid, &name); if (r == -ESRCH) - return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, "Dynamic user ID " UID_FMT " does not exist.", uid); + return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_DYNAMIC_USER, + "Dynamic user ID " UID_FMT " does not exist.", uid); if (r < 0) return r; @@ -1765,7 +1809,8 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_ assert_cc(sizeof(uid_t) == sizeof(uint32_t)); if (!MANAGER_IS_SYSTEM(m)) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Dynamic users are only supported in the system instance."); + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, + "Dynamic users are only supported in the system instance."); r = sd_bus_message_new_method_return(message, &reply); if (r < 0) @@ -1782,7 +1827,8 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_ if (r == -EAGAIN) /* not realized yet? */ continue; if (r < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to look up a dynamic user."); + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, + "Failed to look up a dynamic user."); r = sd_bus_message_append(reply, "(us)", uid, d->name); if (r < 0) @@ -1796,6 +1842,75 @@ static int method_get_dynamic_users(sd_bus_message *message, void *userdata, sd_ return sd_bus_send(NULL, reply, NULL); } +static int method_enqueue_marked_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) { + Manager *m = userdata; + int r; + + assert(message); + assert(m); + + r = mac_selinux_access_check(message, "start", error); + if (r < 0) + return r; + + r = bus_verify_manage_units_async(m, message, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + + log_info("Queuing reload/restart jobs for marked units…"); + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + r = sd_bus_message_new_method_return(message, &reply); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "o"); + if (r < 0) + return r; + + Unit *u; + char *k; + int ret = 0; + HASHMAP_FOREACH_KEY(u, k, m->units) { + /* ignore aliases */ + if (u->id != k) + continue; + + BusUnitQueueFlags flags; + if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RESTART)) + flags = 0; + else if (FLAGS_SET(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD)) + flags = BUS_UNIT_QUEUE_RELOAD_IF_POSSIBLE; + else + continue; + + r = mac_selinux_unit_access_check(u, message, "start", error); + if (r >= 0) + r = bus_unit_queue_job_one(message, u, + JOB_TRY_RESTART, JOB_FAIL, flags, + reply, error); + if (r < 0) { + if (ERRNO_IS_RESOURCE(r)) + return r; + if (ret >= 0) + ret = r; + sd_bus_error_free(error); + } + } + + if (ret < 0) + return sd_bus_error_set_errnof(error, ret, + "Failed to enqueue some jobs, see logs for details: %m"); + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + static int list_unit_files_by_patterns(sd_bus_message *message, void *userdata, sd_bus_error *error, char **states, char **patterns) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; Manager *m = userdata; @@ -1921,7 +2036,10 @@ static int send_unit_files_changed(sd_bus *bus, void *userdata) { assert(bus); - r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged"); + r = sd_bus_message_new_signal(bus, &message, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "UnitFilesChanged"); if (r < 0) return r; @@ -1940,14 +2058,13 @@ static int install_error( UnitFileChange *changes, size_t n_changes) { - size_t i; int r; - for (i = 0; i < n_changes; i++) + for (size_t i = 0; i < n_changes; i++) - switch(changes[i].type) { + switch(changes[i].type_or_errno) { - case 0 ... INT_MAX: + case 0 ... _UNIT_FILE_CHANGE_TYPE_MAX: /* not errors */ continue; case -EEXIST: @@ -1989,7 +2106,8 @@ static int install_error( goto found; default: - r = sd_bus_error_set_errnof(error, changes[i].type, "File %s: %m", changes[i].path); + assert(changes[i].type_or_errno < 0); /* other errors */ + r = sd_bus_error_set_errnof(error, changes[i].type_or_errno, "File %s: %m", changes[i].path); goto found; } @@ -2010,7 +2128,6 @@ static int reply_unit_file_changes_and_free( _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; bool bad = false, good = false; - size_t i; int r; if (unit_file_changes_have_modification(changes, n_changes)) { @@ -2033,16 +2150,16 @@ static int reply_unit_file_changes_and_free( if (r < 0) goto fail; - for (i = 0; i < n_changes; i++) { + for (size_t i = 0; i < n_changes; i++) { - if (changes[i].type < 0) { + if (changes[i].type_or_errno < 0) { bad = true; continue; } r = sd_bus_message_append( reply, "(sss)", - unit_file_change_type_to_string(changes[i].type), + unit_file_change_type_to_string(changes[i].type_or_errno), changes[i].path, changes[i].source); if (r < 0) @@ -2051,8 +2168,8 @@ static int reply_unit_file_changes_and_free( good = true; } - /* If there was a failed change, and no successful change, then return the first failure as proper method call - * error. */ + /* If there was a failed change, and no successful change, then return the first failure as proper + * method call error. */ if (bad && !good) return install_error(error, 0, changes, n_changes); @@ -2426,7 +2543,7 @@ static int method_get_unit_file_links(sd_bus_message *message, void *userdata, s return log_error_errno(r, "Failed to get file links for %s: %m", name); for (i = 0; i < n_changes; i++) - if (changes[i].type == UNIT_FILE_UNLINK) { + if (changes[i].type_or_errno == UNIT_FILE_UNLINK) { r = sd_bus_message_append(reply, "s", changes[i].path); if (r < 0) return r; @@ -2477,7 +2594,8 @@ static int method_abandon_scope(sd_bus_message *message, void *userdata, sd_bus_ return r; if (u->type != UNIT_SCOPE) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit '%s' is not a scope unit, refusing.", name); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Unit '%s' is not a scope unit, refusing.", name); return bus_scope_method_abandon(message, u, error); } @@ -2498,7 +2616,8 @@ static int method_set_show_status(sd_bus_message *message, void *userdata, sd_bu 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); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid show status '%s'", t); } manager_override_show_status(m, mode, "bus"); @@ -2545,7 +2664,7 @@ const sd_bus_vtable bus_manager_vtable[] = { SD_BUS_PROPERTY("ShowStatus", "b", property_get_show_status, 0, 0), SD_BUS_PROPERTY("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.search_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("DefaultStandardOutput", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_output), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("DefaultStandardError", "s", bus_property_get_exec_output, offsetof(Manager, default_std_error), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", property_get_runtime_watchdog, property_set_runtime_watchdog, 0, 0), SD_BUS_WRITABLE_PROPERTY("RebootWatchdogUSec", "t", property_get_reboot_watchdog, property_set_reboot_watchdog, 0, 0), /* The following item is an obsolete alias */ @@ -2760,6 +2879,27 @@ const sd_bus_vtable bus_manager_vtable[] = { NULL,, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("BindMountUnit", + "sssbb", + SD_BUS_PARAM(name) + SD_BUS_PARAM(source) + SD_BUS_PARAM(destination) + SD_BUS_PARAM(read_only) + SD_BUS_PARAM(mkdir), + NULL,, + method_bind_mount_unit, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("MountImageUnit", + "sssbba(ss)", + SD_BUS_PARAM(name) + SD_BUS_PARAM(source) + SD_BUS_PARAM(destination) + SD_BUS_PARAM(read_only) + SD_BUS_PARAM(mkdir) + SD_BUS_PARAM(options), + NULL,, + method_mount_image_unit, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("RefUnit", "s", SD_BUS_PARAM(name), @@ -2977,6 +3117,12 @@ const sd_bus_vtable bus_manager_vtable[] = { NULL,, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("EnqueueMarkedJobs", + NULL,, + "ao", + SD_BUS_PARAM(jobs), + method_enqueue_marked_jobs, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("ListUnitFiles", NULL,, "a(ss)", @@ -3230,7 +3376,11 @@ static int send_finished(sd_bus *bus, void *userdata) { assert(bus); assert(times); - r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished"); + r = sd_bus_message_new_signal(bus, + &message, + "/org/freedesktop/systemd1", + "org.freedesktop.systemd1.Manager", + "StartupFinished"); if (r < 0) return r; diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c index 64f9d4ab3..f7cdb51eb 100644 --- a/src/core/dbus-service.c +++ b/src/core/dbus-service.c @@ -11,11 +11,15 @@ #include "dbus-manager.h" #include "dbus-service.h" #include "dbus-util.h" +#include "execute.h" #include "exit-status.h" #include "fd-util.h" #include "fileio.h" +#include "locale-util.h" +#include "mount-util.h" #include "parse-util.h" #include "path-util.h" +#include "selinux-access.h" #include "service.h" #include "signal-util.h" #include "string-util.h" @@ -91,6 +95,100 @@ static int property_get_exit_status_set( return sd_bus_message_close_container(reply); } +static int bus_service_method_mount(sd_bus_message *message, void *userdata, sd_bus_error *error, bool is_image) { + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + const char *dest, *src, *propagate_directory; + int read_only, make_file_or_directory; + Unit *u = userdata; + ExecContext *c; + pid_t unit_pid; + int r; + + assert(message); + assert(u); + + if (!MANAGER_IS_SYSTEM(u->manager)) + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Adding bind mounts at runtime is only supported for system managers."); + + r = mac_selinux_unit_access_check(u, message, "start", error); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_file_or_directory); + if (r < 0) + return r; + + if (!path_is_absolute(src) || !path_is_normalized(src)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized."); + + if (!is_image && isempty(dest)) + dest = src; + else if (!path_is_absolute(dest) || !path_is_normalized(dest)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized."); + + if (is_image) { + r = bus_read_mount_options(message, error, &options, NULL, ""); + if (r < 0) + return r; + } + + r = bus_verify_manage_units_async_full( + u, + is_image ? "mount-image" : "bind-mount", + CAP_SYS_ADMIN, + N_("Authentication is required to mount on '$(unit)'."), + true, + message, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + + if (u->type != UNIT_SERVICE) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not of type .service"); + + /* If it would be dropped at startup time, return an error. The context should always be available, but + * there's an assert in exec_needs_mount_namespace, so double-check just in case. */ + c = unit_get_exec_context(u); + if (!c) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot access unit execution context"); + if (path_startswith_strv(dest, c->inaccessible_paths)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s is not accessible to this unit", dest); + + /* Ensure that the unit was started in a private mount namespace */ + if (!exec_needs_mount_namespace(c, NULL, unit_get_exec_runtime(u))) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit not running in private mount namespace, cannot activate bind mount"); + + unit_pid = unit_main_pid(u); + if (unit_pid == 0 || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit is not running"); + + propagate_directory = strjoina("/run/systemd/propagate/", u->id); + if (is_image) + r = mount_image_in_namespace(unit_pid, + propagate_directory, + "/run/systemd/incoming/", + src, dest, read_only, make_file_or_directory, options); + else + r = bind_mount_in_namespace(unit_pid, + propagate_directory, + "/run/systemd/incoming/", + src, dest, read_only, make_file_or_directory); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in unit's namespace: %m", src, dest); + + return sd_bus_reply_method_return(message, NULL); +} + +int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_service_method_mount(message, userdata, error, false); +} + +int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_service_method_mount(message, userdata, error, true); +} + const sd_bus_vtable bus_service_vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST), @@ -146,6 +244,27 @@ const sd_bus_vtable bus_service_vtable[] = { BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), BUS_EXEC_EX_COMMAND_LIST_VTABLE("ExecStopPostEx", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION), + SD_BUS_METHOD_WITH_NAMES("BindMount", + "ssbb", + SD_BUS_PARAM(source) + SD_BUS_PARAM(destination) + SD_BUS_PARAM(read_only) + SD_BUS_PARAM(mkdir), + NULL,, + bus_service_method_bind_mount, + SD_BUS_VTABLE_UNPRIVILEGED), + + SD_BUS_METHOD_WITH_NAMES("MountImage", + "ssbba(ss)", + SD_BUS_PARAM(source) + SD_BUS_PARAM(destination) + SD_BUS_PARAM(read_only) + SD_BUS_PARAM(mkdir) + SD_BUS_PARAM(options), + NULL,, + bus_service_method_mount_image, + SD_BUS_VTABLE_UNPRIVILEGED), + /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */ SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_ratelimit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_ratelimit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h index 69311675c..9a0546580 100644 --- a/src/core/dbus-service.h +++ b/src/core/dbus-service.h @@ -9,4 +9,6 @@ extern const sd_bus_vtable bus_service_vtable[]; int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitWriteFlags flags, sd_bus_error *error); +int bus_service_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error); +int bus_service_method_mount_image(sd_bus_message *message, void *userdata, sd_bus_error *error); int bus_service_commit_properties(Unit *u); diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c index 8e69c1732..88b2f2cac 100644 --- a/src/core/dbus-timer.c +++ b/src/core/dbus-timer.c @@ -338,7 +338,7 @@ static int bus_timer_set_transient_property( b = timer_base_from_string(name); if (b < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown timer base"); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown timer base %s", name); r = sd_bus_message_read(message, "t", &usec); if (r < 0) diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 427152a75..39d6799b5 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -323,36 +323,37 @@ static int property_get_load_error( return sd_bus_message_append(reply, "(ss)", NULL, NULL); } -static int bus_verify_manage_units_async_full( - Unit *u, - const char *verb, - int capability, - const char *polkit_message, - bool interactive, - sd_bus_message *call, +static int property_get_markers( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, sd_bus_error *error) { - const char *details[9] = { - "unit", u->id, - "verb", verb, - }; + unsigned *markers = userdata; + int r; - if (polkit_message) { - details[4] = "polkit.message"; - details[5] = polkit_message; - details[6] = "polkit.gettext_domain"; - details[7] = GETTEXT_PACKAGE; - } + assert(bus); + assert(reply); + assert(markers); - return bus_verify_polkit_async( - call, - capability, - "org.freedesktop.systemd1.manage-units", - details, - interactive, - UID_INVALID, - &u->manager->polkit_registry, - error); + r = sd_bus_message_open_container(reply, 'a', "s"); + if (r < 0) + return r; + + /* Make sure out values fit in the bitfield. */ + assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8); + + for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++) + if (FLAGS_SET(*markers, 1u << m)) { + r = sd_bus_message_append(reply, "s", unit_marker_to_string(m)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); } static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = { @@ -810,7 +811,6 @@ static int property_get_refs( sd_bus_error *error) { Unit *u = userdata; - const char *i; int r; assert(bus); @@ -820,15 +820,15 @@ static int property_get_refs( if (r < 0) return r; - for (i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) { - int c, k; + for (const char *i = sd_bus_track_first(u->bus_track); i; i = sd_bus_track_next(u->bus_track)) { + int c; c = sd_bus_track_count_name(u->bus_track, i); if (c < 0) return c; /* Add the item multiple times if the ref count for each is above 1 */ - for (k = 0; k < c; k++) { + for (int k = 0; k < c; k++) { r = sd_bus_message_append(reply, "s", i); if (r < 0) return r; @@ -896,6 +896,7 @@ const sd_bus_vtable bus_unit_vtable[] = { SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("Markers", "as", property_get_markers, offsetof(Unit, markers), 0), SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), @@ -1068,7 +1069,7 @@ static int property_get_current_memory( void *userdata, sd_bus_error *error) { - uint64_t sz = (uint64_t) -1; + uint64_t sz = UINT64_MAX; Unit *u = userdata; int r; @@ -1092,7 +1093,7 @@ static int property_get_current_tasks( void *userdata, sd_bus_error *error) { - uint64_t cn = (uint64_t) -1; + uint64_t cn = UINT64_MAX; Unit *u = userdata; int r; @@ -1116,7 +1117,7 @@ static int property_get_cpu_usage( void *userdata, sd_bus_error *error) { - nsec_t ns = (nsec_t) -1; + nsec_t ns = NSEC_INFINITY; Unit *u = userdata; int r; @@ -1715,6 +1716,89 @@ void bus_unit_send_removed_signal(Unit *u) { log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id); } +int bus_unit_queue_job_one( + sd_bus_message *message, + Unit *u, + JobType type, + JobMode mode, + BusUnitQueueFlags flags, + sd_bus_message *reply, + sd_bus_error *error) { + + _cleanup_set_free_ Set *affected = NULL; + _cleanup_free_ char *job_path = NULL, *unit_path = NULL; + Job *j, *a; + int r; + + if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) { + affected = set_new(NULL); + if (!affected) + return -ENOMEM; + } + + r = manager_add_job(u->manager, type, u, mode, affected, error, &j); + if (r < 0) + return r; + + r = bus_job_track_sender(j, message); + if (r < 0) + return r; + + /* Before we send the method reply, force out the announcement JobNew for this job */ + bus_job_send_pending_change_signal(j, true); + + job_path = job_dbus_path(j); + if (!job_path) + return -ENOMEM; + + /* The classic response is just a job object path */ + if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) + return sd_bus_message_append(reply, "o", job_path); + + /* In verbose mode respond with the anchor job plus everything that has been affected */ + + unit_path = unit_dbus_path(j->unit); + if (!unit_path) + return -ENOMEM; + + r = sd_bus_message_append(reply, "uosos", + j->id, job_path, + j->unit->id, unit_path, + job_type_to_string(j->type)); + if (r < 0) + return r; + + r = sd_bus_message_open_container(reply, 'a', "(uosos)"); + if (r < 0) + return r; + + SET_FOREACH(a, affected) { + if (a->id == j->id) + continue; + + /* Free paths from previous iteration */ + job_path = mfree(job_path); + unit_path = mfree(unit_path); + + job_path = job_dbus_path(a); + if (!job_path) + return -ENOMEM; + + unit_path = unit_dbus_path(a->unit); + if (!unit_path) + return -ENOMEM; + + r = sd_bus_message_append(reply, "(uosos)", + a->id, job_path, + a->unit->id, unit_path, + job_type_to_string(a->type)); + if (r < 0) + return r; + } + + return sd_bus_message_close_container(reply); +} + int bus_unit_queue_job( sd_bus_message *message, Unit *u, @@ -1724,9 +1808,6 @@ int bus_unit_queue_job( sd_bus_error *error) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; - _cleanup_free_ char *job_path = NULL, *unit_path = NULL; - _cleanup_set_free_ Set *affected = NULL; - Job *j, *a; int r; assert(message); @@ -1759,77 +1840,11 @@ int bus_unit_queue_job( (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id); - if (FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) { - affected = set_new(NULL); - if (!affected) - return -ENOMEM; - } - - r = manager_add_job(u->manager, type, u, mode, affected, error, &j); - if (r < 0) - return r; - - r = bus_job_track_sender(j, message); - if (r < 0) - return r; - - /* Before we send the method reply, force out the announcement JobNew for this job */ - bus_job_send_pending_change_signal(j, true); - - job_path = job_dbus_path(j); - if (!job_path) - return -ENOMEM; - - /* The classic response is just a job object path */ - if (!FLAGS_SET(flags, BUS_UNIT_QUEUE_VERBOSE_REPLY)) - return sd_bus_reply_method_return(message, "o", job_path); - - /* In verbose mode respond with the anchor job plus everything that has been affected */ r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; - unit_path = unit_dbus_path(j->unit); - if (!unit_path) - return -ENOMEM; - - r = sd_bus_message_append(reply, "uosos", - j->id, job_path, - j->unit->id, unit_path, - job_type_to_string(j->type)); - if (r < 0) - return r; - - r = sd_bus_message_open_container(reply, 'a', "(uosos)"); - if (r < 0) - return r; - - SET_FOREACH(a, affected) { - - if (a->id == j->id) - continue; - - /* Free paths from previous iteration */ - job_path = mfree(job_path); - unit_path = mfree(unit_path); - - job_path = job_dbus_path(a); - if (!job_path) - return -ENOMEM; - - unit_path = unit_dbus_path(a->unit); - if (!unit_path) - return -ENOMEM; - - r = sd_bus_message_append(reply, "(uosos)", - a->id, job_path, - a->unit->id, unit_path, - job_type_to_string(a->type)); - if (r < 0) - return r; - } - - r = sd_bus_message_close_container(reply); + r = bus_unit_queue_job_one(message, u, type, mode, flags, reply, error); if (r < 0) return r; @@ -1849,8 +1864,8 @@ static int bus_unit_set_live_property( assert(name); assert(message); - /* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for transient - * units that are being created). */ + /* Handles setting properties both "live" (i.e. at any time during runtime), and during creation (for + * transient units that are being created). */ if (streq(name, "Description")) { const char *d; @@ -1870,6 +1885,63 @@ static int bus_unit_set_live_property( return 1; } + /* A setting that only applies to active units. We don't actually write this to /run, this state is + * managed internally. "+foo" sets flag foo, "-foo" unsets flag foo, just "foo" resets flags to + * foo. The last type cannot be mixed with "+" or "-". */ + + if (streq(name, "Markers")) { + unsigned settings = 0, mask = 0; + bool some_plus_minus = false, some_absolute = false; + + r = sd_bus_message_enter_container(message, 'a', "s"); + if (r < 0) + return r; + + for (;;) { + const char *word; + bool b; + + r = sd_bus_message_read(message, "s", &word); + if (r < 0) + return r; + if (r == 0) + break; + + if (IN_SET(word[0], '+', '-')) { + b = word[0] == '+'; + word++; + some_plus_minus = true; + } else { + b = true; + some_absolute = true; + } + + UnitMarker m = unit_marker_from_string(word); + if (m < 0) + return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, + "Unknown marker \"%s\".", word); + + SET_FLAG(settings, 1u << m, b); + SET_FLAG(mask, 1u << m, true); + } + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (some_plus_minus && some_absolute) + return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Bad marker syntax."); + + if (!UNIT_WRITE_FLAGS_NOOP(flags)) { + if (some_absolute) + u->markers = settings; + else + u->markers = settings | (u->markers & ~mask); + } + + return 1; + } + return 0; } @@ -2014,15 +2086,15 @@ static int bus_unit_set_transient_property( UnitWriteFlags flags, sd_bus_error *error) { - UnitDependency d = _UNIT_DEPENDENCY_INVALID; + UnitDependency d; int r; assert(u); assert(name); assert(message); - /* Handles settings when transient units are created. This settings cannot be altered anymore after the unit - * has been created. */ + /* Handles settings when transient units are created. This settings cannot be altered anymore after + * the unit has been created. */ if (streq(name, "SourcePath")) return bus_set_transient_path(u, name, &u->source_path, message, flags, error); @@ -2330,7 +2402,8 @@ int bus_unit_set_properties( return r; if (!UNIT_VTABLE(u)->bus_set_property) - return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); + return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, + "Objects of this type do not support setting properties."); r = sd_bus_message_enter_container(message, 'v', NULL); if (r < 0) @@ -2348,7 +2421,8 @@ int bus_unit_set_properties( return r; if (r == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); + return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, + "Cannot set property %s, or unknown property.", name); r = sd_bus_message_exit_container(message); if (r < 0) @@ -2388,7 +2462,8 @@ int bus_unit_validate_load_state(Unit *u, sd_bus_error *error) { return sd_bus_error_setf(error, BUS_ERROR_BAD_UNIT_SETTING, "Unit %s has a bad unit file setting.", u->id); case UNIT_ERROR: /* Only show .load_error in UNIT_ERROR state */ - return sd_bus_error_set_errnof(error, u->load_error, "Unit %s failed to load properly: %m.", u->id); + return sd_bus_error_set_errnof(error, u->load_error, + "Unit %s failed to load properly, please adjust/correct and reload service manager: %m", u->id); case UNIT_MASKED: return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id); @@ -2466,8 +2541,8 @@ int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) { int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) { assert(u); - /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an - * error */ + /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, + * return an error */ if (!u->bus_track) return -EUNATCH; diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 1da3cfeb9..a3ac32049 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -33,7 +33,21 @@ typedef enum BusUnitQueueFlags { BUS_UNIT_QUEUE_VERBOSE_REPLY = 1 << 1, } BusUnitQueueFlags; -int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, BusUnitQueueFlags flags, sd_bus_error *error); +int bus_unit_queue_job_one( + sd_bus_message *message, + Unit *u, + JobType type, + JobMode mode, + BusUnitQueueFlags flags, + sd_bus_message *reply, + sd_bus_error *error); +int bus_unit_queue_job( + sd_bus_message *message, + Unit *u, + JobType type, + JobMode mode, + BusUnitQueueFlags flags, + sd_bus_error *error); int bus_unit_validate_load_state(Unit *u, sd_bus_error *error); int bus_unit_track_add_name(Unit *u, const char *name); diff --git a/src/core/dbus-util.c b/src/core/dbus-util.c index d6223db30..44a2ccfca 100644 --- a/src/core/dbus-util.c +++ b/src/core/dbus-util.c @@ -1,7 +1,9 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "bus-polkit.h" #include "bus-util.h" #include "dbus-util.h" +#include "escape.h" #include "parse-util.h" #include "path-util.h" #include "unit-printf.h" @@ -91,35 +93,6 @@ int bus_set_transient_bool( return 1; } -int bus_set_transient_percent( - Unit *u, - const char *name, - int *p, - sd_bus_message *message, - UnitWriteFlags flags, - sd_bus_error *error) { - - const char *v; - int r; - - assert(p); - - r = sd_bus_message_read(message, "s", &v); - if (r < 0) - return r; - - r = parse_percent(v); - if (r < 0) - return r; - - if (!UNIT_WRITE_FLAGS_NOOP(flags)) { - *p = r; - unit_write_settingf(u, flags, name, "%s=%d%%", name, r); - } - - return 1; -} - int bus_set_transient_usec_internal( Unit *u, const char *name, @@ -153,3 +126,110 @@ int bus_set_transient_usec_internal( return 1; } + +int bus_verify_manage_units_async_full( + Unit *u, + const char *verb, + int capability, + const char *polkit_message, + bool interactive, + sd_bus_message *call, + sd_bus_error *error) { + + const char *details[9] = { + "unit", u->id, + "verb", verb, + }; + + if (polkit_message) { + details[4] = "polkit.message"; + details[5] = polkit_message; + details[6] = "polkit.gettext_domain"; + details[7] = GETTEXT_PACKAGE; + } + + return bus_verify_polkit_async( + call, + capability, + "org.freedesktop.systemd1.manage-units", + details, + interactive, + UID_INVALID, + &u->manager->polkit_registry, + error); +} + +/* ret_format_str is an accumulator, so if it has any pre-existing content, new options will be appended to it */ +int bus_read_mount_options( + sd_bus_message *message, + sd_bus_error *error, + MountOptions **ret_options, + char **ret_format_str, + const char *separator) { + + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + _cleanup_free_ char *format_str = NULL; + const char *mount_options, *partition; + int r; + + assert(message); + assert(ret_options); + assert(separator); + + r = sd_bus_message_enter_container(message, 'a', "(ss)"); + if (r < 0) + return r; + + while ((r = sd_bus_message_read(message, "(ss)", &partition, &mount_options)) > 0) { + _cleanup_free_ char *previous = NULL, *escaped = NULL; + _cleanup_free_ MountOptions *o = NULL; + PartitionDesignator partition_designator; + + if (chars_intersect(mount_options, WHITESPACE)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, + "Invalid mount options string, contains whitespace character(s): %s", mount_options); + + partition_designator = partition_designator_from_string(partition); + if (partition_designator < 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid partition name %s", partition); + + /* Need to store the options with the escapes, so that they can be parsed again */ + escaped = shell_escape(mount_options, ":"); + if (!escaped) + return -ENOMEM; + + previous = TAKE_PTR(format_str); + format_str = strjoin(previous, previous ? separator : "", partition, ":", escaped); + if (!format_str) + return -ENOMEM; + + o = new(MountOptions, 1); + if (!o) + return -ENOMEM; + *o = (MountOptions) { + .partition_designator = partition_designator, + .options = strdup(mount_options), + }; + if (!o->options) + return -ENOMEM; + LIST_APPEND(mount_options, options, TAKE_PTR(o)); + } + if (r < 0) + return r; + + r = sd_bus_message_exit_container(message); + if (r < 0) + return r; + + if (!LIST_IS_EMPTY(options)) { + if (ret_format_str) { + char *final = strjoin(*ret_format_str, !isempty(*ret_format_str) ? separator : "", format_str); + if (!final) + return -ENOMEM; + free_and_replace(*ret_format_str, final); + } + LIST_JOIN(mount_options, *ret_options, options); + } + + return 0; +} diff --git a/src/core/dbus-util.h b/src/core/dbus-util.h index 4e7c68e84..799136737 100644 --- a/src/core/dbus-util.h +++ b/src/core/dbus-util.h @@ -3,6 +3,7 @@ #include "sd-bus.h" +#include "dissect-image.h" #include "unit.h" int bus_property_get_triggered_unit(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); @@ -240,7 +241,6 @@ int bus_set_transient_user_relaxed(Unit *u, const char *name, char **p, sd_bus_m int bus_set_transient_path(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_string(Unit *u, const char *name, char **p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_bool(Unit *u, const char *name, bool *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); -int bus_set_transient_percent(Unit *u, const char *name, int *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); int bus_set_transient_usec_internal(Unit *u, const char *name, usec_t *p, bool fix_0, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error); static inline int bus_set_transient_usec(Unit *u, const char *name, usec_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error) { return bus_set_transient_usec_internal(u, name, p, false, message, flags, error); @@ -248,3 +248,6 @@ static inline int bus_set_transient_usec(Unit *u, const char *name, usec_t *p, s static inline int bus_set_transient_usec_fix_0(Unit *u, const char *name, usec_t *p, sd_bus_message *message, UnitWriteFlags flags, sd_bus_error *error) { return bus_set_transient_usec_internal(u, name, p, true, message, flags, error); } +int bus_verify_manage_units_async_full(Unit *u, const char *verb, int capability, const char *polkit_message, bool interactive, sd_bus_message *call, sd_bus_error *error); + +int bus_read_mount_options(sd_bus_message *message, sd_bus_error *error, MountOptions **ret_options, char **ret_format_str, const char *separator); diff --git a/src/core/dbus.c b/src/core/dbus.c index 3e435c98c..5db484b8d 100644 --- a/src/core/dbus.c +++ b/src/core/dbus.c @@ -679,12 +679,6 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } - r = set_ensure_allocated(&m->private_buses, NULL); - if (r < 0) { - log_oom(); - return 0; - } - r = sd_bus_new(&bus); if (r < 0) { log_warning_errno(r, "Failed to allocate new private connection bus: %m"); @@ -752,13 +746,17 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void return 0; } - r = set_put(m->private_buses, bus); + r = set_ensure_put(&m->private_buses, NULL, bus); + if (r == -ENOMEM) { + log_oom(); + return 0; + } if (r < 0) { log_warning_errno(r, "Failed to add new connection bus to set: %m"); return 0; } - bus = NULL; + TAKE_PTR(bus); log_debug("Accepted new private connection."); diff --git a/src/core/device.c b/src/core/device.c index 9a1d88270..356c389c5 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -7,7 +7,6 @@ #include "bus-error.h" #include "dbus-device.h" #include "dbus-unit.h" -#include "device-private.h" #include "device-util.h" #include "device.h" #include "log.h" @@ -193,15 +192,14 @@ static const struct { static int device_found_to_string_many(DeviceFound flags, char **ret) { _cleanup_free_ char *s = NULL; - unsigned i; assert(ret); - for (i = 0; i < ELEMENTSOF(device_found_map); i++) { + for (size_t i = 0; i < ELEMENTSOF(device_found_map); i++) { if (!FLAGS_SET(flags, device_found_map[i].flag)) continue; - if (!strextend_with_separator(&s, ",", device_found_map[i].name, NULL)) + if (!strextend_with_separator(&s, ",", device_found_map[i].name)) return -ENOMEM; } @@ -515,11 +513,10 @@ static int device_setup_unit(Manager *m, sd_device *dev, const char *path, bool if (DEVICE(u)->state == DEVICE_PLUGGED && DEVICE(u)->sysfs && sysfs && - !path_equal(DEVICE(u)->sysfs, sysfs)) { - log_unit_debug(u, "Device %s appeared twice with different sysfs paths %s and %s, ignoring the latter.", - e, DEVICE(u)->sysfs, sysfs); - return -EEXIST; - } + !path_equal(DEVICE(u)->sysfs, sysfs)) + return log_unit_debug_errno(u, SYNTHETIC_ERRNO(EEXIST), + "Device %s appeared twice with different sysfs paths %s and %s, ignoring the latter.", + e, DEVICE(u)->sysfs, sysfs); delete = false; @@ -918,8 +915,8 @@ static int device_remove_old(Manager *m, sd_device *dev) { } static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void *userdata) { + sd_device_action_t action; Manager *m = userdata; - DeviceAction action; const char *sysfs; int r; @@ -932,22 +929,22 @@ static int device_dispatch_io(sd_device_monitor *monitor, sd_device *dev, void * return 0; } - r = device_get_action(dev, &action); + r = sd_device_get_action(dev, &action); if (r < 0) { log_device_error_errno(dev, r, "Failed to get udev action: %m"); return 0; } - if (!IN_SET(action, DEVICE_ACTION_ADD, DEVICE_ACTION_REMOVE, DEVICE_ACTION_MOVE)) + if (!IN_SET(action, SD_DEVICE_ADD, SD_DEVICE_REMOVE, SD_DEVICE_MOVE)) device_propagate_reload_by_sysfs(m, sysfs); - if (action == DEVICE_ACTION_MOVE) + if (action == SD_DEVICE_MOVE) (void) device_remove_old(m, dev); /* A change event can signal that a device is becoming ready, in particular if the device is using * the SYSTEMD_READY logic in udev so we need to reach the else block of the following if, even for * change events */ - if (action == DEVICE_ACTION_REMOVE) { + if (action == SD_DEVICE_REMOVE) { r = swap_process_device_remove(m, dev); if (r < 0) log_device_warning_errno(dev, r, "Failed to process swap device remove event, ignoring: %m"); @@ -1015,7 +1012,7 @@ static int validate_node(Manager *m, const char *node, sd_device **ret) { } else { _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - r = device_new_from_stat_rdev(&dev, &st); + r = sd_device_new_from_stat_rdev(&dev, &st); if (r == -ENOENT) { *ret = NULL; return 1; /* good! (though missing) */ diff --git a/src/core/efi-random.c b/src/core/efi-random.c index 2bc74fab9..94e138b35 100644 --- a/src/core/efi-random.c +++ b/src/core/efi-random.c @@ -43,7 +43,6 @@ static void lock_down_efi_variables(void) { int efi_take_random_seed(void) { _cleanup_free_ void *value = NULL; - _cleanup_close_ int random_fd = -1; size_t size; int r; @@ -77,17 +76,13 @@ int efi_take_random_seed(void) { if (size == 0) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Random seed passed from boot loader has zero size? Ignoring."); - random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (random_fd < 0) - return log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m"); - /* Before we use the seed, let's mark it as used, so that we never credit it twice. Also, it's a nice * way to let users known that we successfully acquired entropy from the boot laoder. */ r = touch("/run/systemd/efi-random-seed-taken"); if (r < 0) return log_warning_errno(r, "Unable to mark EFI random seed as used, not using it: %m"); - r = random_write_entropy(random_fd, value, size, true); + r = random_write_entropy(-1, value, size, true); if (r < 0) return log_warning_errno(errno, "Failed to credit entropy, ignoring: %m"); diff --git a/src/core/emergency-action.h b/src/core/emergency-action.h index 95d49a816..4d7e755ae 100644 --- a/src/core/emergency-action.h +++ b/src/core/emergency-action.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + typedef enum EmergencyAction { EMERGENCY_ACTION_NONE, EMERGENCY_ACTION_REBOOT, @@ -13,7 +15,7 @@ typedef enum EmergencyAction { _EMERGENCY_ACTION_FIRST_USER_ACTION = EMERGENCY_ACTION_EXIT, EMERGENCY_ACTION_EXIT_FORCE, _EMERGENCY_ACTION_MAX, - _EMERGENCY_ACTION_INVALID = -1 + _EMERGENCY_ACTION_INVALID = -EINVAL, } EmergencyAction; typedef enum EmergencyActionFlags { diff --git a/src/core/execute.c b/src/core/execute.c index c992b8d5d..35aea2f83 100644 --- a/src/core/execute.c +++ b/src/core/execute.c @@ -93,7 +93,7 @@ #include "terminal-util.h" #include "tmpfile-util.h" #include "umask-util.h" -#include "unit.h" +#include "unit-serialize.h" #include "user-util.h" #include "utmp-wtmp.h" @@ -446,12 +446,12 @@ static int fixup_input( return std_input; } -static int fixup_output(ExecOutput std_output, int socket_fd) { +static int fixup_output(ExecOutput output, int socket_fd) { - if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0) + if (output == EXEC_OUTPUT_SOCKET && socket_fd < 0) return EXEC_OUTPUT_INHERIT; - return std_output; + return output; } static int setup_input( @@ -562,7 +562,7 @@ static bool can_inherit_stderr_from_stdout( if (e == EXEC_OUTPUT_NAMED_FD) return streq_ptr(context->stdio_fdname[STDOUT_FILENO], context->stdio_fdname[STDERR_FILENO]); - if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) + if (IN_SET(e, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE)) return streq_ptr(context->stdio_file[STDOUT_FILENO], context->stdio_file[STDERR_FILENO]); return true; @@ -622,7 +622,7 @@ static int setup_output( o == EXEC_OUTPUT_INHERIT && i == EXEC_INPUT_NULL && !is_terminal_input(context->std_input) && - getppid () != 1) + getppid() != 1) return fileno; /* Duplicate from stdout if possible */ @@ -666,7 +666,8 @@ static int setup_output( case EXEC_OUTPUT_JOURNAL_AND_CONSOLE: r = connect_logger_as(unit, context, params, o, ident, fileno, uid, gid); if (r < 0) { - log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr"); + log_unit_warning_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", + fileno == STDOUT_FILENO ? "stdout" : "stderr"); r = open_null_as(O_WRONLY, fileno); } else { struct stat st; @@ -698,7 +699,8 @@ static int setup_output( return dup2(named_iofds[fileno], fileno) < 0 ? -errno : fileno; case EXEC_OUTPUT_FILE: - case EXEC_OUTPUT_FILE_APPEND: { + case EXEC_OUTPUT_FILE_APPEND: + case EXEC_OUTPUT_FILE_TRUNCATE: { bool rw; int fd, flags; @@ -713,6 +715,8 @@ static int setup_output( flags = O_WRONLY; if (o == EXEC_OUTPUT_FILE_APPEND) flags |= O_APPEND; + else if (o == EXEC_OUTPUT_FILE_TRUNCATE) + flags |= O_TRUNC; fd = acquire_path(context->stdio_file[fileno], flags, 0666 & ~context->umask); if (fd < 0) @@ -1248,8 +1252,8 @@ static int setup_pam( * termination */ barrier_set_role(&barrier, BARRIER_CHILD); - /* Make sure we don't keep open the passed fds in this child. We assume that otherwise only those fds - * are open here that have been opened by PAM. */ + /* Make sure we don't keep open the passed fds in this child. We assume that otherwise only + * those fds are open here that have been opened by PAM. */ (void) close_many(fds, n_fds); /* Drop privileges - we don't need any to pam_close_session @@ -1265,7 +1269,7 @@ static int setup_pam( if (setresuid(uid, uid, uid) < 0) log_warning_errno(errno, "Failed to setresuid() in sd-pam: %m"); - (void) ignore_signals(SIGPIPE, -1); + (void) ignore_signals(SIGPIPE); /* Wait until our parent died. This will only work if * the above setresuid() succeeds, otherwise the kernel @@ -1426,21 +1430,21 @@ static bool context_has_no_new_privileges(const ExecContext *c) { return false; /* We need NNP if we have any form of seccomp and are unprivileged */ - return context_has_address_families(c) || + return c->lock_personality || c->memory_deny_write_execute || - c->restrict_realtime || - c->restrict_suid_sgid || - exec_context_restrict_namespaces_set(c) || + c->private_devices || c->protect_clock || + c->protect_hostname || c->protect_kernel_tunables || c->protect_kernel_modules || c->protect_kernel_logs || - c->private_devices || - context_has_syscall_filters(c) || - context_has_syscall_logs(c) || + context_has_address_families(c) || + exec_context_restrict_namespaces_set(c) || + c->restrict_realtime || + c->restrict_suid_sgid || !set_isempty(c->syscall_archs) || - c->lock_personality || - c->protect_hostname; + context_has_syscall_filters(c) || + context_has_syscall_logs(c); } static bool exec_context_has_credentials(const ExecContext *context) { @@ -1791,7 +1795,7 @@ static int build_environment( assert(p); assert(ret); -#define N_ENV_VARS 16 +#define N_ENV_VARS 17 our_env = new0(char*, N_ENV_VARS + _EXEC_DIRECTORY_TYPE_MAX); if (!our_env) return -ENOMEM; @@ -1947,6 +1951,11 @@ static int build_environment( our_env[n_env++] = x; } + if (asprintf(&x, "SYSTEMD_EXEC_PID=" PID_FMT, getpid_cached()) < 0) + return -ENOMEM; + + our_env[n_env++] = x; + our_env[n_env++] = NULL; assert(n_env <= N_ENV_VARS + _EXEC_DIRECTORY_TYPE_MAX); #undef N_ENV_VARS @@ -1984,20 +1993,21 @@ static int build_pass_environment(const ExecContext *c, char ***ret) { return 0; } -static bool exec_needs_mount_namespace( +bool exec_needs_mount_namespace( const ExecContext *context, const ExecParameters *params, const ExecRuntime *runtime) { assert(context); - assert(params); if (context->root_image) return true; if (!strv_isempty(context->read_write_paths) || !strv_isempty(context->read_only_paths) || - !strv_isempty(context->inaccessible_paths)) + !strv_isempty(context->inaccessible_paths) || + !strv_isempty(context->exec_paths) || + !strv_isempty(context->no_exec_paths)) return true; if (context->n_bind_mounts > 0) @@ -2009,6 +2019,9 @@ static bool exec_needs_mount_namespace( if (context->n_mount_images > 0) return true; + if (context->n_extension_images > 0) + return true; + if (!IN_SET(context->mount_flags, 0, MS_SHARED)) return true; @@ -2024,7 +2037,9 @@ static bool exec_needs_mount_namespace( context->protect_kernel_logs || context->protect_control_groups || context->protect_proc != PROTECT_PROC_DEFAULT || - context->proc_subset != PROC_SUBSET_ALL) + context->proc_subset != PROC_SUBSET_ALL || + context->private_ipc || + context->ipc_namespace_path) return true; if (context->root_directory) { @@ -2032,7 +2047,7 @@ static bool exec_needs_mount_namespace( return true; for (ExecDirectoryType t = 0; t < _EXEC_DIRECTORY_TYPE_MAX; t++) { - if (!params->prefix[t]) + if (params && !params->prefix[t]) continue; if (!strv_isempty(context->directories[t].paths)) @@ -2493,7 +2508,7 @@ static int write_credential( * user can no longer chmod() the file to gain write access. */ return r; - if (fchown(fd, uid, (gid_t) -1) < 0) + if (fchown(fd, uid, GID_INVALID) < 0) return -errno; } } @@ -2576,7 +2591,7 @@ static int acquire_credentials( if (source) - r = read_full_file_full(AT_FDCWD, source, flags, bindname, &data, &size); + r = read_full_file_full(AT_FDCWD, source, UINT64_MAX, SIZE_MAX, flags, bindname, &data, &size); else r = -ENOENT; if (r == -ENOENT && @@ -2611,7 +2626,7 @@ static int acquire_credentials( if (!ownership_ok) return r; - if (fchown(dfd, uid, (gid_t) -1) < 0) + if (fchown(dfd, uid, GID_INVALID) < 0) return -errno; } } @@ -2893,11 +2908,11 @@ static int setup_credentials( #if ENABLE_SMACK static int setup_smack( const ExecContext *context, - const char *executable) { + int executable_fd) { int r; assert(context); - assert(executable); + assert(executable_fd >= 0); if (context->smack_process_label) { r = mac_smack_apply_pid(0, context->smack_process_label); @@ -2908,7 +2923,7 @@ static int setup_smack( else { _cleanup_free_ char *exec_label = NULL; - r = mac_smack_read(executable, SMACK_ATTR_EXEC, &exec_label); + r = mac_smack_read_fd(executable_fd, SMACK_ATTR_EXEC, &exec_label); if (r < 0 && !IN_SET(r, -ENODATA, -EOPNOTSUPP)) return r; @@ -3112,7 +3127,7 @@ static int apply_mount_namespace( _cleanup_strv_free_ char **empty_directories = NULL; const char *tmp_dir = NULL, *var_tmp_dir = NULL; const char *root_dir = NULL, *root_image = NULL; - _cleanup_free_ char *creds_path = NULL; + _cleanup_free_ char *creds_path = NULL, *incoming_dir = NULL, *propagate_dir = NULL; NamespaceInfo ns_info; bool needs_sandboxing; BindMount *bind_mounts = NULL; @@ -3165,6 +3180,7 @@ static int apply_mount_namespace( .protect_system = context->protect_system, .protect_proc = context->protect_proc, .proc_subset = context->proc_subset, + .private_ipc = context->private_ipc || context->ipc_namespace_path, }; } else if (!context->dynamic_user && root_dir) /* @@ -3181,7 +3197,9 @@ static int apply_mount_namespace( if (context->mount_flags == MS_SHARED) log_unit_debug(u, "shared mount propagation hidden by other fs namespacing unit settings: ignoring"); - if (exec_context_has_credentials(context) && params->prefix[EXEC_DIRECTORY_RUNTIME]) { + if (exec_context_has_credentials(context) && + params->prefix[EXEC_DIRECTORY_RUNTIME] && + FLAGS_SET(params->flags, EXEC_WRITE_CREDENTIALS)) { creds_path = path_join(params->prefix[EXEC_DIRECTORY_RUNTIME], "credentials", u->id); if (!creds_path) { r = -ENOMEM; @@ -3189,10 +3207,26 @@ static int apply_mount_namespace( } } + if (MANAGER_IS_SYSTEM(u->manager)) { + propagate_dir = path_join("/run/systemd/propagate/", u->id); + if (!propagate_dir) { + r = -ENOMEM; + goto finalize; + } + + incoming_dir = strdup("/run/systemd/incoming"); + if (!incoming_dir) { + r = -ENOMEM; + goto finalize; + } + } + r = setup_namespace(root_dir, root_image, context->root_image_options, &ns_info, context->read_write_paths, needs_sandboxing ? context->read_only_paths : NULL, needs_sandboxing ? context->inaccessible_paths : NULL, + needs_sandboxing ? context->exec_paths : NULL, + needs_sandboxing ? context->no_exec_paths : NULL, empty_directories, bind_mounts, n_bind_mounts, @@ -3208,6 +3242,11 @@ static int apply_mount_namespace( context->root_hash, context->root_hash_size, context->root_hash_path, context->root_hash_sig, context->root_hash_sig_size, context->root_hash_sig_path, context->root_verity, + context->extension_images, + context->n_extension_images, + propagate_dir, + incoming_dir, + root_dir || root_image ? params->notify_socket : NULL, DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK, error_path); @@ -3419,7 +3458,6 @@ static int close_remaining_fds( const DynamicCreds *dcreds, int user_lookup_fd, int socket_fd, - int exec_fd, const int *fds, size_t n_fds) { size_t n_dont_close = 0; @@ -3436,15 +3474,15 @@ static int close_remaining_fds( if (socket_fd >= 0) dont_close[n_dont_close++] = socket_fd; - if (exec_fd >= 0) - dont_close[n_dont_close++] = exec_fd; if (n_fds > 0) { memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds); n_dont_close += n_fds; } - if (runtime) + if (runtime) { append_socket_pair(dont_close, &n_dont_close, runtime->netns_storage_socket); + append_socket_pair(dont_close, &n_dont_close, runtime->ipcns_storage_socket); + } if (dcreds) { if (dcreds->user) @@ -3614,6 +3652,35 @@ bool exec_context_get_cpu_affinity_from_numa(const ExecContext *c) { return c->cpu_affinity_from_numa; } +static int add_shifted_fd(int *fds, size_t fds_size, size_t *n_fds, int fd, int *ret_fd) { + int r; + + assert(fds); + assert(n_fds); + assert(*n_fds < fds_size); + assert(ret_fd); + + if (fd < 0) { + *ret_fd = -1; + return 0; + } + + if (fd < 3 + (int) *n_fds) { + /* Let's move the fd up, so that it's outside of the fd range we will use to store + * the fds we pass to the process (or which are closed only during execve). */ + + r = fcntl(fd, F_DUPFD_CLOEXEC, 3 + (int) *n_fds); + if (r < 0) + return -errno; + + CLOSE_AND_REPLACE(fd, r); + } + + *ret_fd = fds[*n_fds] = fd; + (*n_fds) ++; + return 1; +} + static int exec_child( Unit *unit, const ExecCommand *command, @@ -3631,7 +3698,7 @@ static int exec_child( int *exit_status) { _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **replaced_argv = NULL; - int *fds_with_exec_fd, n_fds_with_exec_fd, r, ngids = 0, exec_fd = -1; + int r, ngids = 0, exec_fd; _cleanup_free_ gid_t *supplementary_gids = NULL; const char *username = NULL, *groupname = NULL; _cleanup_free_ char *home_buffer = NULL; @@ -3658,7 +3725,8 @@ static int exec_child( gid_t saved_gid = getgid(); uid_t uid = UID_INVALID; gid_t gid = GID_INVALID; - size_t n_fds; + size_t n_fds = n_socket_fds + n_storage_fds, /* fds to pass to the child */ + n_keep_fds; /* total number of fds not to close */ int secure_bits; _cleanup_free_ gid_t *gids_after_pam = NULL; int ngids_after_pam = 0; @@ -3671,16 +3739,14 @@ static int exec_child( rename_process_from_path(command->path); - /* We reset exactly these signals, since they are the - * only ones we set to SIG_IGN in the main daemon. All - * others we leave untouched because we set them to - * SIG_DFL or a valid handler initially, both of which - * will be demoted to SIG_DFL. */ + /* We reset exactly these signals, since they are the only ones we set to SIG_IGN in the main + * daemon. All others we leave untouched because we set them to SIG_DFL or a valid handler initially, + * both of which will be demoted to SIG_DFL. */ (void) default_signals(SIGNALS_CRASH_HANDLER, - SIGNALS_IGNORE, -1); + SIGNALS_IGNORE); if (context->ignore_sigpipe) - (void) ignore_signals(SIGPIPE, -1); + (void) ignore_signals(SIGPIPE); r = reset_signal_mask(); if (r < 0) { @@ -3702,8 +3768,17 @@ static int exec_child( /* In case anything used libc syslog(), close this here, too */ closelog(); - n_fds = n_socket_fds + n_storage_fds; - r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, params->exec_fd, fds, n_fds); + int keep_fds[n_fds + 2]; + memcpy_safe(keep_fds, fds, n_fds * sizeof(int)); + n_keep_fds = n_fds; + + r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, params->exec_fd, &exec_fd); + if (r < 0) { + *exit_status = EXIT_FDS; + return log_unit_error_errno(unit, r, "Failed to shift fd and set FD_CLOEXEC: %m"); + } + + r = close_remaining_fds(params, runtime, dcreds, user_lookup_fd, socket_fd, keep_fds, n_keep_fds); if (r < 0) { *exit_status = EXIT_FDS; return log_unit_error_errno(unit, r, "Failed to close unwanted file descriptors: %m"); @@ -3769,23 +3844,20 @@ static int exec_child( r = dynamic_creds_realize(dcreds, suggested_paths, &uid, &gid); if (r < 0) { *exit_status = EXIT_USER; - if (r == -EILSEQ) { - log_unit_error(unit, "Failed to update dynamic user credentials: User or group with specified name already exists."); - return -EOPNOTSUPP; - } + if (r == -EILSEQ) + return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP), + "Failed to update dynamic user credentials: User or group with specified name already exists."); return log_unit_error_errno(unit, r, "Failed to update dynamic user credentials: %m"); } if (!uid_is_valid(uid)) { *exit_status = EXIT_USER; - log_unit_error(unit, "UID validation failed for \""UID_FMT"\"", uid); - return -ESRCH; + return log_unit_error_errno(unit, SYNTHETIC_ERRNO(ESRCH), "UID validation failed for \""UID_FMT"\"", uid); } if (!gid_is_valid(gid)) { *exit_status = EXIT_USER; - log_unit_error(unit, "GID validation failed for \""GID_FMT"\"", gid); - return -ESRCH; + return log_unit_error_errno(unit, SYNTHETIC_ERRNO(ESRCH), "GID validation failed for \""GID_FMT"\"", gid); } if (dcreds->user) @@ -3851,13 +3923,21 @@ static int exec_child( } if (context->network_namespace_path && runtime && runtime->netns_storage_socket[0] >= 0) { - r = open_netns_path(runtime->netns_storage_socket, context->network_namespace_path); + r = open_shareable_ns_path(runtime->netns_storage_socket, context->network_namespace_path, CLONE_NEWNET); if (r < 0) { *exit_status = EXIT_NETWORK; return log_unit_error_errno(unit, r, "Failed to open network namespace path %s: %m", context->network_namespace_path); } } + if (context->ipc_namespace_path && runtime && runtime->ipcns_storage_socket[0] >= 0) { + r = open_shareable_ns_path(runtime->ipcns_storage_socket, context->ipc_namespace_path, CLONE_NEWIPC); + if (r < 0) { + *exit_status = EXIT_NAMESPACE; + return log_unit_error_errno(unit, r, "Failed to open IPC namespace path %s: %m", context->ipc_namespace_path); + } + } + r = setup_input(context, params, socket_fd, named_iofds); if (r < 0) { *exit_status = EXIT_STDIN; @@ -4098,6 +4178,7 @@ static int exec_child( /* Let's call into PAM after we set up our own idea of resource limits to that pam_limits * wins here. (See above.) */ + /* All fds passed in the fds array will be closed in the pam child process. */ r = setup_pam(context->pam_name, username, uid, gid, context->tty_path, &accum_env, fds, n_fds); if (r < 0) { *exit_status = EXIT_PAM; @@ -4127,7 +4208,7 @@ static int exec_child( if ((context->private_network || context->network_namespace_path) && runtime && runtime->netns_storage_socket[0] >= 0) { if (ns_type_supported(NAMESPACE_NET)) { - r = setup_netns(runtime->netns_storage_socket); + r = setup_shareable_ns(runtime->netns_storage_socket, CLONE_NEWNET); if (r == -EPERM) log_unit_warning_errno(unit, r, "PrivateNetwork=yes is configured, but network namespace setup failed, ignoring: %m"); @@ -4143,6 +4224,25 @@ static int exec_child( log_unit_warning(unit, "PrivateNetwork=yes is configured, but the kernel does not support network namespaces, ignoring."); } + if ((context->private_ipc || context->ipc_namespace_path) && runtime && runtime->ipcns_storage_socket[0] >= 0) { + + if (ns_type_supported(NAMESPACE_IPC)) { + r = setup_shareable_ns(runtime->ipcns_storage_socket, CLONE_NEWIPC); + if (r == -EPERM) + log_unit_warning_errno(unit, r, + "PrivateIPC=yes is configured, but IPC namespace setup failed, ignoring: %m"); + else if (r < 0) { + *exit_status = EXIT_NAMESPACE; + return log_unit_error_errno(unit, r, "Failed to set up IPC namespacing: %m"); + } + } else if (context->ipc_namespace_path) { + *exit_status = EXIT_NAMESPACE; + return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EOPNOTSUPP), + "IPCNamespacePath= is not supported, refusing."); + } else + log_unit_warning(unit, "PrivateIPC=yes is configured, but the kernel does not support IPC namespaces, ignoring."); + } + needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime); if (needs_mount_namespace) { _cleanup_free_ char *error_path = NULL; @@ -4205,7 +4305,8 @@ static int exec_child( * shall execute. */ _cleanup_free_ char *executable = NULL; - r = find_executable_full(command->path, false, &executable); + _cleanup_close_ int executable_fd = -1; + r = find_executable_full(command->path, false, &executable, &executable_fd); if (r < 0) { if (r != -ENOMEM && (command->flags & EXEC_COMMAND_IGNORE_FAILURE)) { log_struct_errno(LOG_INFO, r, @@ -4228,6 +4329,12 @@ static int exec_child( "EXECUTABLE=%s", command->path); } + r = add_shifted_fd(keep_fds, ELEMENTSOF(keep_fds), &n_keep_fds, executable_fd, &executable_fd); + if (r < 0) { + *exit_status = EXIT_FDS; + return log_unit_error_errno(unit, r, "Failed to shift fd and set FD_CLOEXEC: %m"); + } + #if HAVE_SELINUX if (needs_sandboxing && use_selinux && params->selinux_context_net && socket_fd >= 0) { r = mac_selinux_get_child_mls_label(socket_fd, executable, context->selinux_context, &mac_selinux_context_net); @@ -4239,44 +4346,10 @@ static int exec_child( #endif /* We repeat the fd closing here, to make sure that nothing is leaked from the PAM modules. Note that we are - * more aggressive this time since socket_fd and the netns fds we don't need anymore. We do keep the exec_fd + * more aggressive this time since socket_fd and the netns and ipcns fds we don't need anymore. We do keep the exec_fd * however if we have it as we want to keep it open until the final execve(). */ - if (params->exec_fd >= 0) { - exec_fd = params->exec_fd; - - if (exec_fd < 3 + (int) n_fds) { - int moved_fd; - - /* Let's move the exec fd far up, so that it's outside of the fd range we want to pass to the - * process we are about to execute. */ - - moved_fd = fcntl(exec_fd, F_DUPFD_CLOEXEC, 3 + (int) n_fds); - if (moved_fd < 0) { - *exit_status = EXIT_FDS; - return log_unit_error_errno(unit, errno, "Couldn't move exec fd up: %m"); - } - - CLOSE_AND_REPLACE(exec_fd, moved_fd); - } else { - /* This fd should be FD_CLOEXEC already, but let's make sure. */ - r = fd_cloexec(exec_fd, true); - if (r < 0) { - *exit_status = EXIT_FDS; - return log_unit_error_errno(unit, r, "Failed to make exec fd FD_CLOEXEC: %m"); - } - } - - fds_with_exec_fd = newa(int, n_fds + 1); - memcpy_safe(fds_with_exec_fd, fds, n_fds * sizeof(int)); - fds_with_exec_fd[n_fds] = exec_fd; - n_fds_with_exec_fd = n_fds + 1; - } else { - fds_with_exec_fd = fds; - n_fds_with_exec_fd = n_fds; - } - - r = close_all_fds(fds_with_exec_fd, n_fds_with_exec_fd); + r = close_all_fds(keep_fds, n_keep_fds); if (r >= 0) r = shift_fds(fds, n_fds); if (r >= 0) @@ -4310,7 +4383,7 @@ static int exec_child( /* LSM Smack needs the capability CAP_MAC_ADMIN to change the current execution security context of the * process. This is the latest place before dropping capabilities. Other MAC context are set later. */ if (use_smack) { - r = setup_smack(context, executable); + r = setup_smack(context, executable_fd); if (r < 0) { *exit_status = EXIT_SMACK_PROCESS_LABEL; return log_unit_error_errno(unit, r, "Failed to set SMACK process label: %m"); @@ -4580,8 +4653,7 @@ static int exec_child( } } - execve(executable, final_argv, accum_env); - r = -errno; + r = fexecve_or_execve(executable_fd, executable, final_argv, accum_env); if (exec_fd >= 0) { uint8_t hot = 0; @@ -4628,15 +4700,11 @@ int exec_spawn(Unit *unit, context->std_output == EXEC_OUTPUT_SOCKET || context->std_error == EXEC_OUTPUT_SOCKET) { - if (params->n_socket_fds > 1) { - log_unit_error(unit, "Got more than one socket."); - return -EINVAL; - } + if (params->n_socket_fds > 1) + return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got more than one socket."); - if (params->n_socket_fds == 0) { - log_unit_error(unit, "Got no socket."); - return -EINVAL; - } + if (params->n_socket_fds == 0) + return log_unit_error_errno(unit, SYNTHETIC_ERRNO(EINVAL), "Got no socket."); socket_fd = params->fds[0]; } else { @@ -4679,6 +4747,10 @@ int exec_spawn(Unit *unit, r = cg_create(SYSTEMD_CGROUP_CONTROLLER, subcgroup_path); if (r < 0) return log_unit_error_errno(unit, r, "Failed to create control group '%s': %m", subcgroup_path); + + /* Normally we would not propagate the oomd xattrs to children but since we created this + * sub-cgroup internally we should do it. */ + cgroup_oomd_xattr_apply(unit, subcgroup_path); } } @@ -4785,6 +4857,7 @@ void exec_context_done(ExecContext *c) { c->root_hash_sig_size = 0; c->root_hash_sig_path = mfree(c->root_hash_sig_path); c->root_verity = mfree(c->root_verity); + c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images); c->tty_path = mfree(c->tty_path); c->syslog_identifier = mfree(c->syslog_identifier); c->user = mfree(c->user); @@ -4797,6 +4870,8 @@ void exec_context_done(ExecContext *c) { c->read_only_paths = strv_free(c->read_only_paths); c->read_write_paths = strv_free(c->read_write_paths); c->inaccessible_paths = strv_free(c->inaccessible_paths); + c->exec_paths = strv_free(c->exec_paths); + c->no_exec_paths = strv_free(c->no_exec_paths); bind_mount_free_many(c->bind_mounts, c->n_bind_mounts); c->bind_mounts = NULL; @@ -4893,9 +4968,7 @@ static void exec_command_done(ExecCommand *c) { } void exec_command_done_array(ExecCommand *c, size_t n) { - size_t i; - - for (i = 0; i < n; i++) + for (size_t i = 0; i < n; i++) exec_command_done(c+i); } @@ -5146,6 +5219,18 @@ static void strv_fprintf(FILE *f, char **l) { fprintf(f, " %s", *g); } +static void strv_dump(FILE* f, const char *prefix, const char *name, char **strv) { + assert(f); + assert(prefix); + assert(name); + + if (!strv_isempty(strv)) { + fprintf(f, "%s%s:", name, prefix); + strv_fprintf(f, strv); + fputs("\n", f); + } +} + void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { char **e, **d, buf_clean[FORMAT_TIMESPAN_MAX]; int r; @@ -5355,10 +5440,14 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sStandardOutputFile: %s\n", prefix, c->stdio_file[STDOUT_FILENO]); if (c->std_output == EXEC_OUTPUT_FILE_APPEND) fprintf(f, "%sStandardOutputFileToAppend: %s\n", prefix, c->stdio_file[STDOUT_FILENO]); + if (c->std_output == EXEC_OUTPUT_FILE_TRUNCATE) + fprintf(f, "%sStandardOutputFileToTruncate: %s\n", prefix, c->stdio_file[STDOUT_FILENO]); if (c->std_error == EXEC_OUTPUT_FILE) fprintf(f, "%sStandardErrorFile: %s\n", prefix, c->stdio_file[STDERR_FILENO]); if (c->std_error == EXEC_OUTPUT_FILE_APPEND) fprintf(f, "%sStandardErrorFileToAppend: %s\n", prefix, c->stdio_file[STDERR_FILENO]); + if (c->std_error == EXEC_OUTPUT_FILE_TRUNCATE) + fprintf(f, "%sStandardErrorFileToTruncate: %s\n", prefix, c->stdio_file[STDERR_FILENO]); if (c->tty_path) fprintf(f, @@ -5454,32 +5543,16 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { fprintf(f, "%sDynamicUser: %s\n", prefix, yes_no(c->dynamic_user)); - if (!strv_isempty(c->supplementary_groups)) { - fprintf(f, "%sSupplementaryGroups:", prefix); - strv_fprintf(f, c->supplementary_groups); - fputs("\n", f); - } + strv_dump(f, prefix, "SupplementaryGroups", c->supplementary_groups); if (c->pam_name) fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name); - if (!strv_isempty(c->read_write_paths)) { - fprintf(f, "%sReadWritePaths:", prefix); - strv_fprintf(f, c->read_write_paths); - fputs("\n", f); - } - - if (!strv_isempty(c->read_only_paths)) { - fprintf(f, "%sReadOnlyPaths:", prefix); - strv_fprintf(f, c->read_only_paths); - fputs("\n", f); - } - - if (!strv_isempty(c->inaccessible_paths)) { - fprintf(f, "%sInaccessiblePaths:", prefix); - strv_fprintf(f, c->inaccessible_paths); - fputs("\n", f); - } + strv_dump(f, prefix, "ReadWritePaths", c->read_write_paths); + strv_dump(f, prefix, "ReadOnlyPaths", c->read_only_paths); + strv_dump(f, prefix, "InaccessiblePaths", c->inaccessible_paths); + strv_dump(f, prefix, "ExecPaths", c->exec_paths); + strv_dump(f, prefix, "NoExecPaths", c->no_exec_paths); for (size_t i = 0; i < c->n_bind_mounts; i++) fprintf(f, "%s%s: %s%s:%s:%s\n", prefix, @@ -5617,15 +5690,27 @@ void exec_context_dump(const ExecContext *c, FILE* f, const char *prefix) { for (size_t i = 0; i < c->n_mount_images; i++) { MountOptions *o; - fprintf(f, "%sMountImages: %s%s:%s%s", prefix, + fprintf(f, "%sMountImages: %s%s:%s", prefix, c->mount_images[i].ignore_enoent ? "-": "", c->mount_images[i].source, - c->mount_images[i].destination, - LIST_IS_EMPTY(c->mount_images[i].mount_options) ? "": ":"); + c->mount_images[i].destination); LIST_FOREACH(mount_options, o, c->mount_images[i].mount_options) - fprintf(f, "%s:%s", + fprintf(f, ":%s:%s", partition_designator_to_string(o->partition_designator), - o->options); + strempty(o->options)); + fprintf(f, "\n"); + } + + for (size_t i = 0; i < c->n_extension_images; i++) { + MountOptions *o; + + fprintf(f, "%sExtensionImages: %s%s", prefix, + c->extension_images[i].ignore_enoent ? "-": "", + c->extension_images[i].source); + LIST_FOREACH(mount_options, o, c->extension_images[i].mount_options) + fprintf(f, ":%s:%s", + partition_designator_to_string(o->partition_designator), + strempty(o->options)); fprintf(f, "\n"); } } @@ -6004,6 +6089,7 @@ static ExecRuntime* exec_runtime_free(ExecRuntime *rt, bool destroy) { rt->tmp_dir = mfree(rt->tmp_dir); rt->var_tmp_dir = mfree(rt->var_tmp_dir); safe_close_pair(rt->netns_storage_socket); + safe_close_pair(rt->ipcns_storage_socket); return mfree(rt); } @@ -6028,6 +6114,7 @@ static int exec_runtime_allocate(ExecRuntime **ret, const char *id) { *n = (ExecRuntime) { .id = TAKE_PTR(id_copy), .netns_storage_socket = { -1, -1 }, + .ipcns_storage_socket = { -1, -1 }, }; *ret = n; @@ -6040,6 +6127,7 @@ static int exec_runtime_add( char **tmp_dir, char **var_tmp_dir, int netns_storage_socket[2], + int ipcns_storage_socket[2], ExecRuntime **ret) { _cleanup_(exec_runtime_freep) ExecRuntime *rt = NULL; @@ -6048,17 +6136,13 @@ static int exec_runtime_add( assert(m); assert(id); - /* tmp_dir, var_tmp_dir, netns_storage_socket fds are donated on success */ - - r = hashmap_ensure_allocated(&m->exec_runtime_by_id, &string_hash_ops); - if (r < 0) - return r; + /* tmp_dir, var_tmp_dir, {net,ipc}ns_storage_socket fds are donated on success */ r = exec_runtime_allocate(&rt, id); if (r < 0) return r; - r = hashmap_put(m->exec_runtime_by_id, rt->id, rt); + r = hashmap_ensure_put(&m->exec_runtime_by_id, &string_hash_ops, rt->id, rt); if (r < 0) return r; @@ -6071,6 +6155,11 @@ static int exec_runtime_add( rt->netns_storage_socket[1] = TAKE_FD(netns_storage_socket[1]); } + if (ipcns_storage_socket) { + rt->ipcns_storage_socket[0] = TAKE_FD(ipcns_storage_socket[0]); + rt->ipcns_storage_socket[1] = TAKE_FD(ipcns_storage_socket[1]); + } + rt->manager = m; if (ret) @@ -6087,7 +6176,7 @@ static int exec_runtime_make( ExecRuntime **ret) { _cleanup_(namespace_cleanup_tmpdirp) char *tmp_dir = NULL, *var_tmp_dir = NULL; - _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 }; + _cleanup_close_pair_ int netns_storage_socket[2] = { -1, -1 }, ipcns_storage_socket[2] = { -1, -1 }; int r; assert(m); @@ -6095,7 +6184,7 @@ static int exec_runtime_make( assert(id); /* It is not necessary to create ExecRuntime object. */ - if (!c->private_network && !c->private_tmp && !c->network_namespace_path) { + if (!c->private_network && !c->private_ipc && !c->private_tmp && !c->network_namespace_path) { *ret = NULL; return 0; } @@ -6114,7 +6203,12 @@ static int exec_runtime_make( return -errno; } - r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ret); + if (c->private_ipc || c->ipc_namespace_path) { + if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, ipcns_storage_socket) < 0) + return -errno; + } + + r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_storage_socket, ipcns_storage_socket, ret); if (r < 0) return r; @@ -6205,6 +6299,26 @@ int exec_runtime_serialize(const Manager *m, FILE *f, FDSet *fds) { fprintf(f, " netns-socket-1=%i", copy); } + if (rt->ipcns_storage_socket[0] >= 0) { + int copy; + + copy = fdset_put_dup(fds, rt->ipcns_storage_socket[0]); + if (copy < 0) + return copy; + + fprintf(f, " ipcns-socket-0=%i", copy); + } + + if (rt->ipcns_storage_socket[1] >= 0) { + int copy; + + copy = fdset_put_dup(fds, rt->ipcns_storage_socket[1]); + if (copy < 0) + return copy; + + fprintf(f, " ipcns-socket-1=%i", copy); + } + fputc('\n', f); } @@ -6286,6 +6400,28 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, safe_close(rt->netns_storage_socket[1]); rt->netns_storage_socket[1] = fdset_remove(fds, fd); + + } else if (streq(key, "ipcns-socket-0")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) { + log_unit_debug(u, "Failed to parse ipcns socket value: %s", value); + return 0; + } + + safe_close(rt->ipcns_storage_socket[0]); + rt->ipcns_storage_socket[0] = fdset_remove(fds, fd); + + } else if (streq(key, "ipcns-socket-1")) { + int fd; + + if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd)) { + log_unit_debug(u, "Failed to parse ipcns socket value: %s", value); + return 0; + } + + safe_close(rt->ipcns_storage_socket[1]); + rt->ipcns_storage_socket[1] = fdset_remove(fds, fd); } else return 0; @@ -6309,7 +6445,7 @@ int exec_runtime_deserialize_compat(Unit *u, const char *key, const char *value, int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) { _cleanup_free_ char *tmp_dir = NULL, *var_tmp_dir = NULL; char *id = NULL; - int r, fdpair[] = {-1, -1}; + int r, netns_fdpair[] = {-1, -1}, ipcns_fdpair[] = {-1, -1}; const char *p, *v = value; size_t n; @@ -6352,13 +6488,13 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) { n = strcspn(v, " "); buf = strndupa(v, n); - r = safe_atoi(buf, &fdpair[0]); + r = safe_atoi(buf, &netns_fdpair[0]); if (r < 0) return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-0=%s: %m", buf); - if (!fdset_contains(fds, fdpair[0])) + if (!fdset_contains(fds, netns_fdpair[0])) return log_debug_errno(SYNTHETIC_ERRNO(EBADF), - "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", fdpair[0]); - fdpair[0] = fdset_remove(fds, fdpair[0]); + "exec-runtime specification netns-socket-0= refers to unknown fd %d: %m", netns_fdpair[0]); + netns_fdpair[0] = fdset_remove(fds, netns_fdpair[0]); if (v[n] != ' ') goto finalize; p = v + n + 1; @@ -6370,17 +6506,56 @@ int exec_runtime_deserialize_one(Manager *m, const char *value, FDSet *fds) { n = strcspn(v, " "); buf = strndupa(v, n); - r = safe_atoi(buf, &fdpair[1]); + + r = safe_atoi(buf, &netns_fdpair[1]); if (r < 0) return log_debug_errno(r, "Unable to parse exec-runtime specification netns-socket-1=%s: %m", buf); - if (!fdset_contains(fds, fdpair[1])) + if (!fdset_contains(fds, netns_fdpair[1])) return log_debug_errno(SYNTHETIC_ERRNO(EBADF), - "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", fdpair[1]); - fdpair[1] = fdset_remove(fds, fdpair[1]); + "exec-runtime specification netns-socket-1= refers to unknown fd %d: %m", netns_fdpair[1]); + netns_fdpair[1] = fdset_remove(fds, netns_fdpair[1]); + if (v[n] != ' ') + goto finalize; + p = v + n + 1; + } + + v = startswith(p, "ipcns-socket-0="); + if (v) { + char *buf; + + n = strcspn(v, " "); + buf = strndupa(v, n); + + r = safe_atoi(buf, &ipcns_fdpair[0]); + if (r < 0) + return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-0=%s: %m", buf); + if (!fdset_contains(fds, ipcns_fdpair[0])) + return log_debug_errno(SYNTHETIC_ERRNO(EBADF), + "exec-runtime specification ipcns-socket-0= refers to unknown fd %d: %m", ipcns_fdpair[0]); + ipcns_fdpair[0] = fdset_remove(fds, ipcns_fdpair[0]); + if (v[n] != ' ') + goto finalize; + p = v + n + 1; + } + + v = startswith(p, "ipcns-socket-1="); + if (v) { + char *buf; + + n = strcspn(v, " "); + buf = strndupa(v, n); + + r = safe_atoi(buf, &ipcns_fdpair[1]); + if (r < 0) + return log_debug_errno(r, "Unable to parse exec-runtime specification ipcns-socket-1=%s: %m", buf); + if (!fdset_contains(fds, ipcns_fdpair[1])) + return log_debug_errno(SYNTHETIC_ERRNO(EBADF), + "exec-runtime specification ipcns-socket-1= refers to unknown fd %d: %m", ipcns_fdpair[1]); + ipcns_fdpair[1] = fdset_remove(fds, ipcns_fdpair[1]); } finalize: - r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, fdpair, NULL); + r = exec_runtime_add(m, id, &tmp_dir, &var_tmp_dir, netns_fdpair, ipcns_fdpair, NULL); if (r < 0) return log_debug_errno(r, "Failed to add exec-runtime: %m"); return 0; @@ -6447,6 +6622,7 @@ static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = { [EXEC_OUTPUT_NAMED_FD] = "fd", [EXEC_OUTPUT_FILE] = "file", [EXEC_OUTPUT_FILE_APPEND] = "append", + [EXEC_OUTPUT_FILE_TRUNCATE] = "truncate", }; DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput); diff --git a/src/core/execute.h b/src/core/execute.h index 33d7e1693..4c7a5b874 100644 --- a/src/core/execute.h +++ b/src/core/execute.h @@ -33,7 +33,7 @@ typedef enum ExecUtmpMode { EXEC_UTMP_LOGIN, EXEC_UTMP_USER, _EXEC_UTMP_MODE_MAX, - _EXEC_UTMP_MODE_INVALID = -1 + _EXEC_UTMP_MODE_INVALID = -EINVAL, } ExecUtmpMode; typedef enum ExecInput { @@ -46,7 +46,7 @@ typedef enum ExecInput { EXEC_INPUT_DATA, EXEC_INPUT_FILE, _EXEC_INPUT_MAX, - _EXEC_INPUT_INVALID = -1 + _EXEC_INPUT_INVALID = -EINVAL, } ExecInput; typedef enum ExecOutput { @@ -61,8 +61,9 @@ typedef enum ExecOutput { EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, + EXEC_OUTPUT_FILE_TRUNCATE, _EXEC_OUTPUT_MAX, - _EXEC_OUTPUT_INVALID = -1 + _EXEC_OUTPUT_INVALID = -EINVAL, } ExecOutput; typedef enum ExecPreserveMode { @@ -70,7 +71,7 @@ typedef enum ExecPreserveMode { EXEC_PRESERVE_YES, EXEC_PRESERVE_RESTART, _EXEC_PRESERVE_MODE_MAX, - _EXEC_PRESERVE_MODE_INVALID = -1 + _EXEC_PRESERVE_MODE_INVALID = -EINVAL, } ExecPreserveMode; typedef enum ExecKeyringMode { @@ -78,7 +79,7 @@ typedef enum ExecKeyringMode { EXEC_KEYRING_PRIVATE, EXEC_KEYRING_SHARED, _EXEC_KEYRING_MODE_MAX, - _EXEC_KEYRING_MODE_INVALID = -1, + _EXEC_KEYRING_MODE_INVALID = -EINVAL, } ExecKeyringMode; /* Contains start and exit information about an executed command. */ @@ -116,6 +117,9 @@ struct ExecRuntime { /* An AF_UNIX socket pair, that contains a datagram containing a file descriptor referring to the network * namespace. */ int netns_storage_socket[2]; + + /* Like netns_storage_socket, but the file descriptor is referring to the IPC namespace. */ + int ipcns_storage_socket[2]; }; typedef enum ExecDirectoryType { @@ -125,7 +129,7 @@ typedef enum ExecDirectoryType { EXEC_DIRECTORY_LOGS, EXEC_DIRECTORY_CONFIGURATION, _EXEC_DIRECTORY_TYPE_MAX, - _EXEC_DIRECTORY_TYPE_INVALID = -1, + _EXEC_DIRECTORY_TYPE_INVALID = -EINVAL, } ExecDirectoryType; typedef struct ExecDirectory { @@ -143,7 +147,7 @@ typedef enum ExecCleanMask { EXEC_CLEAN_CONFIGURATION = 1U << EXEC_DIRECTORY_CONFIGURATION, EXEC_CLEAN_NONE = 0, EXEC_CLEAN_ALL = (1U << _EXEC_DIRECTORY_TYPE_MAX) - 1, - _EXEC_CLEAN_MASK_INVALID = -1, + _EXEC_CLEAN_MASK_INVALID = -EINVAL, } ExecCleanMask; /* A credential configured with SetCredential= */ @@ -242,7 +246,7 @@ struct ExecContext { char *apparmor_profile; char *smack_process_label; - char **read_write_paths, **read_only_paths, **inaccessible_paths; + char **read_write_paths, **read_only_paths, **inaccessible_paths, **exec_paths, **no_exec_paths; unsigned long mount_flags; BindMount *bind_mounts; size_t n_bind_mounts; @@ -250,6 +254,8 @@ struct ExecContext { size_t n_temporary_filesystems; MountImage *mount_images; size_t n_mount_images; + MountImage *extension_images; + size_t n_extension_images; uint64_t capability_bounding_set; uint64_t capability_ambient_set; @@ -277,6 +283,7 @@ struct ExecContext { bool private_devices; bool private_users; bool private_mounts; + bool private_ipc; bool protect_kernel_tunables; bool protect_kernel_modules; bool protect_kernel_logs; @@ -311,6 +318,7 @@ struct ExecContext { Set *address_families; char *network_namespace_path; + char *ipc_namespace_path; ExecDirectory directories[_EXEC_DIRECTORY_TYPE_MAX]; ExecPreserveMode runtime_directory_preserve_mode; @@ -383,6 +391,8 @@ struct ExecParameters { /* An fd that is closed by the execve(), and thus will result in EOF when the execve() is done */ int exec_fd; + + const char *notify_socket; }; #include "unit.h" @@ -470,3 +480,5 @@ ExecDirectoryType exec_directory_type_from_string(const char *s) _pure_; const char* exec_resource_type_to_string(ExecDirectoryType i) _const_; ExecDirectoryType exec_resource_type_from_string(const char *s) _pure_; + +bool exec_needs_mount_namespace(const ExecContext *context, const ExecParameters *params, const ExecRuntime *runtime); diff --git a/src/fuzz/fuzz-unit-file.c b/src/core/fuzz-unit-file.c similarity index 98% rename from src/fuzz/fuzz-unit-file.c rename to src/core/fuzz-unit-file.c index e67f6e919..311ffcecc 100644 --- a/src/fuzz/fuzz-unit-file.c +++ b/src/core/fuzz-unit-file.c @@ -7,7 +7,7 @@ #include "install.h" #include "load-fragment.h" #include "string-util.h" -#include "unit.h" +#include "unit-serialize.h" #include "utf8.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { diff --git a/src/fuzz/fuzz-unit-file.options b/src/core/fuzz-unit-file.options similarity index 100% rename from src/fuzz/fuzz-unit-file.options rename to src/core/fuzz-unit-file.options diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c deleted file mode 100644 index 867ea1990..000000000 --- a/src/core/hostname-setup.c +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include -#include -#include - -#include "alloc-util.h" -#include "fileio.h" -#include "hostname-setup.h" -#include "hostname-util.h" -#include "log.h" -#include "macro.h" -#include "proc-cmdline.h" -#include "string-util.h" -#include "util.h" - -int hostname_setup(void) { - _cleanup_free_ char *b = NULL; - const char *hn = NULL; - bool enoent = false; - int r; - - r = proc_cmdline_get_key("systemd.hostname", 0, &b); - if (r < 0) - log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m"); - else if (r > 0) { - if (hostname_is_valid(b, true)) - hn = b; - else { - log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b); - b = mfree(b); - } - } - - if (!hn) { - r = read_etc_hostname(NULL, &b); - if (r < 0) { - if (r == -ENOENT) - enoent = true; - else - log_warning_errno(r, "Failed to read configured hostname: %m"); - } else - hn = b; - } - - if (isempty(hn)) { - /* Don't override the hostname if it is already set and not explicitly configured */ - if (hostname_is_set()) - return 0; - - if (enoent) - log_info("No hostname configured."); - - hn = FALLBACK_HOSTNAME; - } - - r = sethostname_idempotent(hn); - if (r < 0) - return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn); - - log_info("Set hostname to <%s>.", hn); - return 0; -} diff --git a/src/core/job.c b/src/core/job.c index f3c1a0283..56c99f93e 100644 --- a/src/core/job.c +++ b/src/core/job.c @@ -263,11 +263,7 @@ int job_install_deserialized(Job *j) { return log_unit_debug_errno(j->unit, SYNTHETIC_ERRNO(EEXIST), "Unit already has a job installed. Not installing deserialized job."); - r = hashmap_ensure_allocated(&j->manager->jobs, NULL); - if (r < 0) - return r; - - r = hashmap_put(j->manager->jobs, UINT32_TO_PTR(j->id), j); + r = hashmap_ensure_put(&j->manager->jobs, NULL, UINT32_TO_PTR(j->id), j); if (r == -EEXIST) return log_unit_debug_errno(j->unit, r, "Job ID %" PRIu32 " already used, cannot deserialize job.", j->id); if (r < 0) @@ -882,8 +878,7 @@ static void job_log_done_status_message(Unit *u, uint32_t job_id, JobType t, Job return; /* Show condition check message if the job did not actually do anything due to failed condition. */ - if ((t == JOB_START && result == JOB_DONE && !u->condition_result) || - (t == JOB_START && result == JOB_SKIPPED)) { + if (t == JOB_START && result == JOB_DONE && !u->condition_result) { log_struct(LOG_INFO, "MESSAGE=Condition check resulted in %s being skipped.", unit_status_string(u), "JOB_ID=%" PRIu32, job_id, diff --git a/src/core/job.h b/src/core/job.h index 1b3ddc7b4..64ea847ff 100644 --- a/src/core/job.h +++ b/src/core/job.h @@ -57,14 +57,14 @@ enum JobType { JOB_RELOAD_OR_START, /* if running, reload, otherwise start */ _JOB_TYPE_MAX, - _JOB_TYPE_INVALID = -1 + _JOB_TYPE_INVALID = -EINVAL, }; enum JobState { JOB_WAITING, JOB_RUNNING, _JOB_STATE_MAX, - _JOB_STATE_INVALID = -1 + _JOB_STATE_INVALID = -EINVAL, }; enum JobMode { @@ -77,7 +77,7 @@ enum JobMode { JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */ JOB_TRIGGERING, /* Adds TRIGGERED_BY dependencies to the same transaction */ _JOB_MODE_MAX, - _JOB_MODE_INVALID = -1 + _JOB_MODE_INVALID = -EINVAL, }; enum JobResult { @@ -93,7 +93,7 @@ enum JobResult { JOB_COLLECTED, /* Job was garbage collected, since nothing needed it anymore */ JOB_ONCE, /* Unit was started before, and hence can't be started again */ _JOB_RESULT_MAX, - _JOB_RESULT_INVALID = -1 + _JOB_RESULT_INVALID = -EINVAL, }; #include "unit.h" diff --git a/src/core/kill.h b/src/core/kill.h index 012e433b6..dbf884d15 100644 --- a/src/core/kill.h +++ b/src/core/kill.h @@ -15,7 +15,7 @@ typedef enum KillMode { KILL_MIXED, KILL_NONE, _KILL_MODE_MAX, - _KILL_MODE_INVALID = -1 + _KILL_MODE_INVALID = -EINVAL, } KillMode; struct KillContext { @@ -37,7 +37,7 @@ typedef enum KillWho { KILL_CONTROL_FAIL, KILL_ALL_FAIL, _KILL_WHO_MAX, - _KILL_WHO_INVALID = -1 + _KILL_WHO_INVALID = -EINVAL, } KillWho; void kill_context_init(KillContext *c); diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c index d1c85e23b..3bb48564c 100644 --- a/src/core/load-dropin.c +++ b/src/core/load-dropin.c @@ -112,6 +112,7 @@ int unit_load_dropin(Unit *u) { return log_oom(); } + u->dropin_mtime = 0; STRV_FOREACH(f, u->dropin_paths) (void) config_parse( u->id, *f, NULL, diff --git a/src/core/load-fragment-gperf-nulstr.awk b/src/core/load-fragment-gperf-nulstr.awk index 44bc1fb69..a1b7d1c6c 100644 --- a/src/core/load-fragment-gperf-nulstr.awk +++ b/src/core/load-fragment-gperf-nulstr.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ keywords=0 ; FS="," ; print "extern const char load_fragment_gperf_nulstr[];" ; diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4 index 946862c39..21bbcffe4 100644 --- a/src/core/load-fragment-gperf.gperf.m4 +++ b/src/core/load-fragment-gperf.gperf.m4 @@ -1,3 +1,4 @@ +m4_dnl SPDX-License-Identifier: LGPL-2.1-or-later %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -27,6 +28,7 @@ $1.RootImageOptions, config_parse_root_image_options, $1.RootHash, config_parse_exec_root_hash, 0, offsetof($1, exec_context) $1.RootHashSignature, config_parse_exec_root_hash_sig, 0, offsetof($1, exec_context) $1.RootVerity, config_parse_unit_path_printf, true, offsetof($1, exec_context.root_verity) +$1.ExtensionImages, config_parse_extension_images, 0, offsetof($1, exec_context) $1.MountImages, config_parse_mount_images, 0, offsetof($1, exec_context) $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) @@ -118,6 +120,8 @@ $1.InaccessibleDirectories, config_parse_namespace_path_strv, $1.ReadWritePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths) $1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths) $1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths) +$1.ExecPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.exec_paths) +$1.NoExecPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.no_exec_paths) $1.BindPaths, config_parse_bind_paths, 0, offsetof($1, exec_context) $1.BindReadOnlyPaths, config_parse_bind_paths, 0, offsetof($1, exec_context) $1.TemporaryFileSystem, config_parse_temporary_filesystems, 0, offsetof($1, exec_context) @@ -129,14 +133,16 @@ $1.ProtectKernelLogs, config_parse_bool, $1.ProtectClock, config_parse_bool, 0, offsetof($1, exec_context.protect_clock) $1.ProtectControlGroups, config_parse_bool, 0, offsetof($1, exec_context.protect_control_groups) $1.NetworkNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.network_namespace_path) +$1.IPCNamespacePath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.ipc_namespace_path) $1.LogNamespace, config_parse_log_namespace, 0, offsetof($1, exec_context) $1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network) $1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users) $1.PrivateMounts, config_parse_bool, 0, offsetof($1, exec_context.private_mounts) +$1.PrivateIPC, config_parse_bool, 0, offsetof($1, exec_context.private_ipc) $1.ProtectSystem, config_parse_protect_system, 0, offsetof($1, exec_context.protect_system) $1.ProtectHome, config_parse_protect_home, 0, offsetof($1, exec_context.protect_home) $1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context.mount_flags) -$1.MountAPIVFS, config_parse_bool, 0, offsetof($1, exec_context.mount_apivfs) +$1.MountAPIVFS, config_parse_exec_mount_apivfs, 0, offsetof($1, exec_context) $1.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality) $1.RuntimeDirectoryPreserve, config_parse_runtime_preserve_mode, 0, offsetof($1, exec_context.runtime_directory_preserve_mode) $1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.directories[EXEC_DIRECTORY_RUNTIME].mode) @@ -226,7 +232,8 @@ $1.IPIngressFilterPath, config_parse_ip_filter_bpf_progs, $1.IPEgressFilterPath, config_parse_ip_filter_bpf_progs, 0, offsetof($1, cgroup_context.ip_filters_egress) $1.ManagedOOMSwap, config_parse_managed_oom_mode, 0, offsetof($1, cgroup_context.moom_swap) $1.ManagedOOMMemoryPressure, config_parse_managed_oom_mode, 0, offsetof($1, cgroup_context.moom_mem_pressure) -$1.ManagedOOMMemoryPressureLimitPercent, config_parse_managed_oom_mem_pressure_limit, 0, offsetof($1, cgroup_context.moom_mem_pressure_limit) +$1.ManagedOOMMemoryPressureLimit, config_parse_managed_oom_mem_pressure_limit, 0, offsetof($1, cgroup_context.moom_mem_pressure_limit) +$1.ManagedOOMPreference, config_parse_managed_oom_preference, 0, offsetof($1, cgroup_context.moom_preference) $1.NetClass, config_parse_warn_compat, DISABLED_LEGACY, 0' )m4_dnl Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description) diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c index 4964249bf..c6fc4fe08 100644 --- a/src/core/load-fragment.c +++ b/src/core/load-fragment.c @@ -46,6 +46,7 @@ #include "nulstr-util.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "process-util.h" #if HAVE_SECCOMP #include "seccomp-util.h" @@ -133,6 +134,7 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceR DEFINE_CONFIG_PARSE_ENUM(config_parse_service_timeout_failure_mode, service_timeout_failure_mode, ServiceTimeoutFailureMode, "Failed to parse timeout failure mode"); DEFINE_CONFIG_PARSE_ENUM(config_parse_socket_bind, socket_address_bind_ipv6_only_or_bool, SocketAddressBindIPv6Only, "Failed to parse bind IPv6 only value"); DEFINE_CONFIG_PARSE_ENUM(config_parse_oom_policy, oom_policy, OOMPolicy, "Failed to parse OOM policy"); +DEFINE_CONFIG_PARSE_ENUM(config_parse_managed_oom_preference, managed_oom_preference, ManagedOOMPreference, "Failed to parse ManagedOOMPreference="); DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_ip_tos, ip_tos, int, -1, "Failed to parse IP TOS value"); DEFINE_CONFIG_PARSE_PTR(config_parse_blockio_weight, cg_blkio_weight_parse, uint64_t, "Invalid block IO weight"); DEFINE_CONFIG_PARSE_PTR(config_parse_cg_weight, cg_weight_parse, uint64_t, "Invalid weight"); @@ -660,7 +662,7 @@ int config_parse_kill_mode( m = kill_mode_from_string(rvalue); if (m < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, m, "Failed to parse kill mode specification, ignoring: %s", rvalue); return 0; } @@ -920,10 +922,7 @@ int config_parse_socket_bindtodevice( return 0; } - if (free_and_strdup(&s->bind_to_device, rvalue) < 0) - return log_oom(); - - return 0; + return free_and_strdup_warn(&s->bind_to_device, rvalue); } int config_parse_exec_input( @@ -990,7 +989,7 @@ int config_parse_exec_input( } else { ei = exec_input_from_string(rvalue); if (ei < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse input specifier, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, ei, "Failed to parse input specifier, ignoring: %s", rvalue); return 0; } } @@ -1095,7 +1094,7 @@ int config_parse_exec_input_data( return 0; } - r = unbase64mem(rvalue, (size_t) -1, &p, &sz); + r = unbase64mem(rvalue, SIZE_MAX, &p, &sz); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to decode base64 data, ignoring: %s", rvalue); @@ -1202,10 +1201,24 @@ int config_parse_exec_output( return 0; eo = EXEC_OUTPUT_FILE_APPEND; + + } else if ((n = startswith(rvalue, "truncate:"))) { + + r = unit_full_printf(u, n, &resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", n); + return 0; + } + + r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE | PATH_CHECK_FATAL, unit, filename, line, lvalue); + if (r < 0) + return 0; + + eo = EXEC_OUTPUT_FILE_TRUNCATE; } else { eo = exec_output_from_string(rvalue); if (eo < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse output specifier, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, eo, "Failed to parse output specifier, ignoring: %s", rvalue); return 0; } } @@ -1264,7 +1277,7 @@ int config_parse_exec_io_class(const char *unit, x = ioprio_class_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse IO scheduling class, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse IO scheduling class, ignoring: %s", rvalue); return 0; } @@ -1339,7 +1352,7 @@ int config_parse_exec_cpu_sched_policy(const char *unit, x = sched_policy_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse CPU scheduling policy, ignoring: %s", rvalue); return 0; } @@ -1513,7 +1526,8 @@ int config_parse_root_image_options( partition_designator = partition_designator_from_string(partition); if (partition_designator < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid partition name %s, ignoring", partition); + log_syntax(unit, LOG_WARNING, filename, line, partition_designator, + "Invalid partition name %s, ignoring", partition); continue; } r = unit_full_printf(u, mount_options, &mount_options_resolved); @@ -1668,16 +1682,17 @@ int config_parse_exec_root_hash_sig( return 0; } -int config_parse_exec_cpu_affinity(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_exec_cpu_affinity( + 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) { ExecContext *c = data; int r; @@ -1698,7 +1713,7 @@ int config_parse_exec_cpu_affinity(const char *unit, if (r >= 0) c->cpu_affinity_from_numa = false; - return r; + return 0; } int config_parse_capability_set( @@ -2000,7 +2015,7 @@ int config_parse_trigger_unit( type = unit_name_to_type(p); if (type < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, type, "Unit type not valid, ignoring: %s", rvalue); return 0; } if (unit_has_name(u, p)) { @@ -2047,7 +2062,7 @@ int config_parse_path_spec(const char *unit, b = path_type_from_string(lvalue); if (b < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse path type, ignoring: %s", lvalue); + log_syntax(unit, LOG_WARNING, filename, line, b, "Failed to parse path type, ignoring: %s", lvalue); return 0; } @@ -2622,7 +2637,7 @@ int config_parse_environ( } for (const char *p = rvalue;; ) { - _cleanup_free_ char *word = NULL, *k = NULL; + _cleanup_free_ char *word = NULL, *resolved = NULL; r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); if (r == 0) @@ -2636,26 +2651,24 @@ int config_parse_environ( } if (u) { - r = unit_full_printf(u, word, &k); + r = unit_full_printf(u, word, &resolved); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", word); continue; } } else - k = TAKE_PTR(word); + resolved = TAKE_PTR(word); - if (!env_assignment_is_valid(k)) { + if (!env_assignment_is_valid(resolved)) { log_syntax(unit, LOG_WARNING, filename, line, 0, - "Invalid environment assignment, ignoring: %s", k); + "Invalid environment assignment, ignoring: %s", resolved); continue; } - r = strv_env_replace(env, k); + r = strv_env_replace_consume(env, TAKE_PTR(resolved)); if (r < 0) - return log_oom(); - - k = NULL; + return log_error_errno(r, "Failed to update environment: %m"); } } @@ -2728,7 +2741,7 @@ int config_parse_pass_environ( if (n) { r = strv_extend_strv(passenv, n, true); if (r < 0) - return r; + return log_oom(); } return 0; @@ -2803,7 +2816,7 @@ int config_parse_unset_environ( if (n) { r = strv_extend_strv(unsetenv, n, true); if (r < 0) - return r; + return log_oom(); } return 0; @@ -3081,16 +3094,17 @@ int config_parse_unit_requires_mounts_for( } } -int config_parse_documentation(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_documentation( + 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) { Unit *u = userdata; int r; @@ -3124,7 +3138,7 @@ int config_parse_documentation(const char *unit, if (b) *b = NULL; - return r; + return 0; } #if HAVE_SECCOMP @@ -3195,13 +3209,20 @@ int config_parse_syscall_filter( if (r == -ENOMEM) return log_oom(); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); return 0; } r = parse_syscall_and_errno(word, &name, &num); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall:errno, ignoring: %s", word); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse syscall:errno, ignoring: %s", word); + continue; + } + if (!invert && num >= 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Allow-listed system calls cannot take error number, ignoring: %s", word); continue; } @@ -3266,8 +3287,7 @@ int config_parse_syscall_log( p = rvalue; for (;;) { - _cleanup_free_ char *word = NULL, *name = NULL; - int num; + _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, NULL, 0); if (r == 0) @@ -3279,14 +3299,8 @@ int config_parse_syscall_log( return 0; } - r = parse_syscall_and_errno(word, &name, &num); - if (r < 0 || num >= 0) { /* errno code not allowed */ - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse syscall, ignoring: %s", word); - continue; - } - r = seccomp_parse_syscall_filter( - name, 0, c->syscall_log, + word, -1, c->syscall_log, SECCOMP_PARSE_LOG|SECCOMP_PARSE_PERMISSIVE| (invert ? SECCOMP_PARSE_INVERT : 0)| (c->syscall_log_allow_list ? SECCOMP_PARSE_ALLOW_LIST : 0), @@ -3370,8 +3384,12 @@ int config_parse_syscall_errno( } e = parse_errno(rvalue); - if (e <= 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse error number, ignoring: %s", rvalue); + if (e < 0) { + log_syntax(unit, LOG_WARNING, filename, line, e, "Failed to parse error number, ignoring: %s", rvalue); + return 0; + } + if (e == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid error number, ignoring: %s", rvalue); return 0; } @@ -3576,13 +3594,13 @@ int config_parse_cpu_quota( return 0; } - r = parse_permille_unbounded(rvalue); + r = parse_permyriad_unbounded(rvalue); if (r <= 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid CPU quota '%s', ignoring.", rvalue); return 0; } - c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 1000U; + c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 10000U; return 0; } @@ -3647,7 +3665,7 @@ int config_parse_memory_limit( bytes = CGROUP_LIMIT_MIN; else if (!isempty(rvalue) && !streq(rvalue, "infinity")) { - r = parse_permille(rvalue); + r = parse_permyriad(rvalue); if (r < 0) { r = parse_size(rvalue, 1024, &bytes); if (r < 0) { @@ -3655,7 +3673,7 @@ int config_parse_memory_limit( return 0; } } else - bytes = physical_memory_scale(r, 1000U); + bytes = physical_memory_scale(r, 10000U); if (bytes >= UINT64_MAX || (bytes <= 0 && !STR_IN_SET(lvalue, "MemorySwapMax", "MemoryLow", "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin"))) { @@ -3717,9 +3735,9 @@ int config_parse_tasks_max( return 0; } - r = parse_permille(rvalue); + r = parse_permyriad(rvalue); if (r >= 0) - *tasks_max = (TasksMax) { r, 1000U }; /* r‰ */ + *tasks_max = (TasksMax) { r, 10000U }; /* r‱ */ else { r = safe_atou64(rvalue, &v); if (r < 0) { @@ -3825,6 +3843,7 @@ int config_parse_managed_oom_mode( const char *rvalue, void *data, void *userdata) { + ManagedOOMMode *mode = data, m; UnitType t; @@ -3841,9 +3860,10 @@ int config_parse_managed_oom_mode( m = managed_oom_mode_from_string(rvalue); if (m < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid syntax, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, m, "Invalid syntax, ignoring: %s", rvalue); return 0; } + *mode = m; return 0; } @@ -3859,7 +3879,8 @@ int config_parse_managed_oom_mem_pressure_limit( const char *rvalue, void *data, void *userdata) { - int *limit = data; + + uint32_t *limit = data; UnitType t; int r; @@ -3874,13 +3895,14 @@ int config_parse_managed_oom_mem_pressure_limit( return 0; } - r = parse_percent(rvalue); + r = parse_permyriad(rvalue); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse limit percent value, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse memory pressure limit value, ignoring: %s", rvalue); return 0; } - *limit = r; + /* Normalize to 2^32-1 == 100% */ + *limit = UINT32_SCALE_FROM_PERMYRIAD(r); return 0; } @@ -4522,13 +4544,14 @@ int config_parse_set_credential( sc->data = TAKE_PTR(unescaped); sc->size = l; - r = hashmap_ensure_allocated(&context->set_credentials, &exec_set_credential_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(context->set_credentials, sc->id, sc); - if (r < 0) + r = hashmap_ensure_put(&context->set_credentials, &exec_set_credential_hash_ops, sc->id, sc); + if (r == -ENOMEM) return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, l, + "Duplicated credential value '%s', ignoring assignment: %s", sc->id, rvalue); + return 0; + } TAKE_PTR(sc); } @@ -4651,7 +4674,7 @@ int config_parse_set_status( } else { r = signal_from_string(word); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse value, ignoring: %s", word); continue; } @@ -4999,20 +5022,20 @@ int config_parse_mount_images( if (r == 0) continue; - r = unit_full_printf(u, first, &sresolved); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to resolve unit specifiers in \"%s\", ignoring: %m", first); - continue; - } - - s = sresolved; + s = first; if (s[0] == '-') { permissive = true; s++; } - r = path_simplify_and_warn(s, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue); + r = unit_full_printf(u, s, &sresolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s); + continue; + } + + r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue); if (r < 0) continue; @@ -5068,7 +5091,8 @@ int config_parse_mount_images( partition_designator = partition_designator_from_string(partition); if (partition_designator < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid partition name %s, ignoring", partition); + log_syntax(unit, LOG_WARNING, filename, line, partition_designator, + "Invalid partition name %s, ignoring", partition); continue; } r = unit_full_printf(u, mount_options, &mount_options_resolved); @@ -5089,10 +5113,152 @@ int config_parse_mount_images( r = mount_image_add(&c->mount_images, &c->n_mount_images, &(MountImage) { - .source = s, + .source = sresolved, .destination = dresolved, .mount_options = options, .ignore_enoent = permissive, + .type = MOUNT_IMAGE_DISCRETE, + }); + if (r < 0) + return log_oom(); + } +} + +int config_parse_extension_images( + 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) { + + ExecContext *c = data; + const Unit *u = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + c->extension_images = mount_image_free_many(c->extension_images, &c->n_extension_images); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *source = NULL, *tuple = NULL, *sresolved = NULL; + _cleanup_(mount_options_free_allp) MountOptions *options = NULL; + bool permissive = false; + const char *q = NULL; + char *s = NULL; + + r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax %s=%s, ignoring: %m", lvalue, rvalue); + return 0; + } + if (r == 0) + return 0; + + q = tuple; + r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax in %s=, ignoring: %s", lvalue, tuple); + return 0; + } + if (r == 0) + continue; + + s = source; + if (s[0] == '-') { + permissive = true; + s++; + } + + r = unit_full_printf(u, s, &sresolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to resolve unit specifiers in \"%s\", ignoring: %m", s); + continue; + } + + r = path_simplify_and_warn(sresolved, PATH_CHECK_ABSOLUTE, unit, filename, line, lvalue); + if (r < 0) + continue; + + for (;;) { + _cleanup_free_ char *partition = NULL, *mount_options = NULL, *mount_options_resolved = NULL; + MountOptions *o = NULL; + PartitionDesignator partition_designator; + + r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", q); + return 0; + } + if (r == 0) + break; + /* Single set of options, applying to the root partition/single filesystem */ + if (r == 1) { + r = unit_full_printf(u, partition, &mount_options_resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", partition); + continue; + } + + o = new(MountOptions, 1); + if (!o) + return log_oom(); + *o = (MountOptions) { + .partition_designator = PARTITION_ROOT, + .options = TAKE_PTR(mount_options_resolved), + }; + LIST_APPEND(mount_options, options, o); + + break; + } + + partition_designator = partition_designator_from_string(partition); + if (partition_designator < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid partition name %s, ignoring", partition); + continue; + } + r = unit_full_printf(u, mount_options, &mount_options_resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to resolve unit specifiers in %s, ignoring: %m", mount_options); + continue; + } + + o = new(MountOptions, 1); + if (!o) + return log_oom(); + *o = (MountOptions) { + .partition_designator = partition_designator, + .options = TAKE_PTR(mount_options_resolved), + }; + LIST_APPEND(mount_options, options, o); + } + + r = mount_image_add(&c->extension_images, &c->n_extension_images, + &(MountImage) { + .source = sresolved, + .mount_options = options, + .ignore_enoent = permissive, + .type = MOUNT_IMAGE_EXTENSION, }); if (r < 0) return log_oom(); @@ -5515,10 +5681,11 @@ int unit_load_fragment(Unit *u) { } } - /* We do the merge dance here because for some unit types, the unit might have aliases which are not + /* Call merge_by_names with the name derived from the fragment path as the preferred name. + * + * We do the merge dance here because for some unit types, the unit might have aliases which are not * declared in the file system. In particular, this is true (and frequent) for device and swap units. */ - Unit *merged; const char *id = u->id; _cleanup_free_ char *free_id = NULL; @@ -5535,7 +5702,7 @@ int unit_load_fragment(Unit *u) { } } - merged = u; + Unit *merged = u; r = merge_by_names(&merged, names, id); if (r < 0) return r; @@ -5757,12 +5924,12 @@ int config_parse_output_restricted( } else { t = exec_output_from_string(rvalue); if (t < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse output type, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, t, "Failed to parse output type, ignoring: %s", rvalue); return 0; } - if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Standard output types socket, fd:, file:, append: are not supported as defaults, ignoring: %s", rvalue); + if (IN_SET(t, EXEC_OUTPUT_SOCKET, EXEC_OUTPUT_NAMED_FD, EXEC_OUTPUT_FILE, EXEC_OUTPUT_FILE_APPEND, EXEC_OUTPUT_FILE_TRUNCATE)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Standard output types socket, fd:, file:, append:, truncate: are not supported as defaults, ignoring: %s", rvalue); return 0; } } diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h index 6b2175cd2..b8a6d5fea 100644 --- a/src/core/load-fragment.h +++ b/src/core/load-fragment.h @@ -78,6 +78,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tasks_max); CONFIG_PARSER_PROTOTYPE(config_parse_delegate); CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mode); CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_mem_pressure_limit); +CONFIG_PARSER_PROTOTYPE(config_parse_managed_oom_preference); CONFIG_PARSER_PROTOTYPE(config_parse_device_policy); CONFIG_PARSER_PROTOTYPE(config_parse_device_allow); CONFIG_PARSER_PROTOTYPE(config_parse_io_device_latency); @@ -137,6 +138,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_timeout_abort); CONFIG_PARSER_PROTOTYPE(config_parse_swap_priority); CONFIG_PARSER_PROTOTYPE(config_parse_mount_images); CONFIG_PARSER_PROTOTYPE(config_parse_socket_timestamping); +CONFIG_PARSER_PROTOTYPE(config_parse_extension_images); /* gperf prototypes */ const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, GPERF_LEN_TYPE length); diff --git a/src/core/main.c b/src/core/main.c index a280b756f..0ddd62985 100644 --- a/src/core/main.c +++ b/src/core/main.c @@ -58,6 +58,7 @@ #include "mount-setup.h" #include "os-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -133,6 +134,7 @@ static usec_t arg_kexec_watchdog; static char *arg_early_core_pattern; static char *arg_watchdog_device; static char **arg_default_environment; +static char **arg_manager_environment; static struct rlimit *arg_default_rlimit[_RLIMIT_MAX]; static uint64_t arg_capability_bounding_set; static bool arg_no_new_privs; @@ -162,6 +164,36 @@ static char **saved_env = NULL; static int parse_configuration(const struct rlimit *saved_rlimit_nofile, const struct rlimit *saved_rlimit_memlock); +static int manager_find_user_config_paths(char ***ret_files, char ***ret_dirs) { + _cleanup_free_ char *base = NULL; + _cleanup_strv_free_ char **files = NULL, **dirs = NULL; + int r; + + r = xdg_user_config_dir(&base, "/systemd"); + if (r < 0) + return r; + + r = strv_extendf(&files, "%s/user.conf", base); + if (r < 0) + return r; + + r = strv_extend(&files, PKGSYSCONFDIR "/user.conf"); + if (r < 0) + return r; + + r = strv_consume(&dirs, TAKE_PTR(base)); + if (r < 0) + return r; + + r = strv_extend_strv(&dirs, CONF_PATHS_STRV("systemd"), false); + if (r < 0) + return r; + + *ret_files = TAKE_PTR(files); + *ret_dirs = TAKE_PTR(dirs); + return 0; +} + _noreturn_ static void freeze_or_exit_or_reboot(void) { /* If we are running in a container, let's prefer exiting, after all we can propagate an exit code to @@ -291,9 +323,8 @@ static void install_crash_handler(void) { }; int r; - /* We ignore the return value here, since, we don't mind if we - * cannot set up a crash handler */ - r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1); + /* We ignore the return value here, since, we don't mind if we cannot set up a crash handler */ + r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER); if (r < 0) log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m"); } @@ -358,7 +389,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return 0; if (path_is_absolute(value)) - (void) parse_path_argument_and_warn(value, false, &arg_early_core_pattern); + (void) parse_path_argument(value, false, &arg_early_core_pattern); else log_warning("Specified core pattern '%s' is not an absolute path, ignoring.", value); @@ -452,16 +483,13 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - if (env_assignment_is_valid(value)) { - char **env; - - env = strv_env_set(arg_default_environment, value); - if (!env) + if (!env_assignment_is_valid(value)) + log_warning("Environment variable assignment '%s' is not valid. Ignoring.", value); + else { + r = strv_env_replace_strdup(&arg_default_environment, value); + if (r < 0) return log_oom(); - - arg_default_environment = env; - } else - log_warning("Environment variable name '%s' is not valid. Ignoring.", value); + } } else if (proc_cmdline_key_streq(key, "systemd.machine_id")) { @@ -498,7 +526,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - (void) parse_path_argument_and_warn(value, false, &arg_watchdog_device); + (void) parse_path_argument(value, false, &arg_watchdog_device); } else if (proc_cmdline_key_streq(key, "systemd.clock_usec")) { @@ -516,7 +544,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - r = unbase64mem(value, (size_t) -1, &p, &sz); + r = unbase64mem(value, SIZE_MAX, &p, &sz); if (r < 0) log_warning_errno(r, "Failed to parse systemd.random_seed= argument, ignoring: %s", value); @@ -642,6 +670,7 @@ static int parse_config_file(void) { { "Manager", "DefaultStartLimitIntervalSec", config_parse_sec, 0, &arg_default_start_limit_interval }, { "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst }, { "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment }, + { "Manager", "ManagerEnvironment", config_parse_environ, 0, &arg_manager_environment }, { "Manager", "DefaultLimitCPU", config_parse_rlimit, RLIMIT_CPU, arg_default_rlimit }, { "Manager", "DefaultLimitFSIZE", config_parse_rlimit, RLIMIT_FSIZE, arg_default_rlimit }, { "Manager", "DefaultLimitDATA", config_parse_rlimit, RLIMIT_DATA, arg_default_rlimit }, @@ -670,26 +699,32 @@ static int parse_config_file(void) { {} }; - const char *fn, *conf_dirs_nulstr; + _cleanup_strv_free_ char **files = NULL, **dirs = NULL; + const char *suffix; + int r; - fn = arg_system ? - PKGSYSCONFDIR "/system.conf" : - PKGSYSCONFDIR "/user.conf"; + if (arg_system) + suffix = "system.conf.d"; + else { + r = manager_find_user_config_paths(&files, &dirs); + if (r < 0) + return log_error_errno(r, "Failed to determine config file paths: %m"); - conf_dirs_nulstr = arg_system ? - CONF_PATHS_NULSTR("systemd/system.conf.d") : - CONF_PATHS_NULSTR("systemd/user.conf.d"); + suffix = "user.conf.d"; + } - (void) config_parse_many_nulstr( - fn, conf_dirs_nulstr, + (void) config_parse_many( + (const char* const*) (files ?: STRV_MAKE(PKGSYSCONFDIR "/system.conf")), + (const char* const*) (dirs ?: CONF_PATHS_STRV("systemd")), + suffix, "Manager\0", config_item_table_lookup, items, CONFIG_PARSE_WARN, NULL, NULL); - /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY - * like everywhere else. */ + /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we use + * USEC_INFINITY like everywhere else. */ if (arg_default_timeout_start_usec <= 0) arg_default_timeout_start_usec = USEC_INFINITY; if (arg_default_timeout_stop_usec <= 0) @@ -820,6 +855,7 @@ static int parse_argv(int argc, char *argv[]) { }; int c, r; + bool user_arg_seen = false; assert(argc >= 1); assert(argv); @@ -909,6 +945,7 @@ static int parse_argv(int argc, char *argv[]) { case ARG_USER: arg_system = false; + user_arg_seen = true; break; case ARG_TEST: @@ -937,15 +974,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DUMP_CORE: - if (!optarg) - arg_dump_core = true; - else { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(r, "Failed to parse dump core boolean: \"%s\": %m", - optarg); - arg_dump_core = r; - } + r = parse_boolean_argument("--dump-core", optarg, &arg_dump_core); + if (r < 0) + return r; break; case ARG_CRASH_CHVT: @@ -956,27 +987,15 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_CRASH_SHELL: - if (!optarg) - arg_crash_shell = true; - else { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(r, "Failed to parse crash shell boolean: \"%s\": %m", - optarg); - arg_crash_shell = r; - } + r = parse_boolean_argument("--crash-shell", optarg, &arg_crash_shell); + if (r < 0) + return r; break; case ARG_CRASH_REBOOT: - if (!optarg) - arg_crash_reboot = true; - else { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(r, "Failed to parse crash shell boolean: \"%s\": %m", - optarg); - arg_crash_reboot = r; - } + r = parse_boolean_argument("--crash-reboot", optarg, &arg_crash_reboot); + if (r < 0) + return r; break; case ARG_CONFIRM_SPAWN: @@ -989,11 +1008,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SERVICE_WATCHDOGS: - r = parse_boolean(optarg); + r = parse_boolean_argument("--service-watchdogs=", optarg, &arg_service_watchdogs); if (r < 0) - return log_error_errno(r, "Failed to parse service watchdogs boolean: \"%s\": %m", - optarg); - arg_service_watchdogs = r; + return r; break; case ARG_SHOW_STATUS: @@ -1065,10 +1082,12 @@ static int parse_argv(int argc, char *argv[]) { } if (optind < argc && getpid_cached() != 1) - /* Hmm, when we aren't run as init system - * let's complain about excess arguments */ + /* Hmm, when we aren't run as init system let's complain about excess arguments */ + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Excess arguments."); + + if (arg_action == ACTION_RUN && !arg_system && !user_arg_seen) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Excess arguments."); + "Explicit --user argument required to run as user manager."); return 0; } @@ -1108,12 +1127,13 @@ static int help(void) { " --log-time[=BOOL] Prefix log messages with current time\n" " --default-standard-output= Set default standard output for services\n" " --default-standard-error= Set default standard error output for services\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , ansi_underline(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + ansi_underline(), + ansi_normal(), + link); return 0; } @@ -1273,8 +1293,8 @@ static int bump_rlimit_memlock(struct rlimit *saved_rlimit) { * must be unsigned, hence this is a given, but let's make this clear here. */ assert_cc(RLIM_INFINITY > 0); - mm = physical_memory() / 8; /* Let's scale how much we allow to be locked by the amount of physical - * RAM. We allow an eighth to be locked by us, just to pick a value. */ + mm = physical_memory_scale(1, 8); /* Let's scale how much we allow to be locked by the amount of physical + * RAM. We allow an eighth to be locked by us, just to pick a value. */ new_rlimit = (struct rlimit) { .rlim_cur = MAX3(HIGH_RLIMIT_MEMLOCK, saved_rlimit->rlim_cur, mm), @@ -1329,8 +1349,7 @@ static int status_welcome(void) { r = parse_os_release(NULL, "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color, - NULL); + "ANSI_COLOR", &ansi_color); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read os-release file, ignoring: %m"); @@ -1432,7 +1451,7 @@ static void redirect_telinit(int argc, char *argv[]) { if (getpid_cached() == 1) return; - if (!strstr(program_invocation_short_name, "init")) + if (!invoked_as(argv, "init")) return; execv(SYSTEMCTL_BINARY_PATH, argv); @@ -1605,7 +1624,6 @@ static void apply_clock_update(void) { } static void cmdline_take_random_seed(void) { - _cleanup_close_ int random_fd = -1; size_t suggested; int r; @@ -1622,13 +1640,7 @@ static void cmdline_take_random_seed(void) { log_warning("Random seed specified on kernel command line has size %zu, but %zu bytes required to fill entropy pool.", arg_random_seed_size, suggested); - random_fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (random_fd < 0) { - log_warning_errno(errno, "Failed to open /dev/urandom for writing, ignoring: %m"); - return; - } - - r = random_write_entropy(random_fd, arg_random_seed, arg_random_seed_size, true); + r = random_write_entropy(-1, arg_random_seed, arg_random_seed_size, true); if (r < 0) { log_warning_errno(r, "Failed to credit entropy specified on kernel command line, ignoring: %m"); return; @@ -1987,8 +1999,9 @@ static void log_execution_mode(bool *ret_first_boot) { if (arg_system) { int v; - log_info("systemd " GIT_VERSION " running in %ssystem mode. (" SYSTEMD_FEATURES ")", - arg_action == ACTION_TEST ? "test " : "" ); + log_info("systemd " GIT_VERSION " running in %ssystem mode. (%s)", + arg_action == ACTION_TEST ? "test " : "", + systemd_features); v = detect_virtualization(); if (v > 0) @@ -2026,8 +2039,9 @@ static void log_execution_mode(bool *ret_first_boot) { _cleanup_free_ char *t; t = uid_to_name(getuid()); - log_debug("systemd " GIT_VERSION " running in %suser mode for user " UID_FMT "/%s. (" SYSTEMD_FEATURES ")", - arg_action == ACTION_TEST ? " test" : "", getuid(), strna(t)); + log_debug("systemd " GIT_VERSION " running in %suser mode for user " UID_FMT "/%s. (%s)", + arg_action == ACTION_TEST ? " test" : "", + getuid(), strna(t), systemd_features); } *ret_first_boot = false; @@ -2069,7 +2083,7 @@ static int initialize_runtime( } status_welcome(); - hostname_setup(); + (void) hostname_setup(true); /* Force transient machine-id on first boot. */ machine_id_setup(NULL, first_boot, arg_machine_id, NULL); (void) loopback_setup(); @@ -2285,6 +2299,19 @@ static void fallback_rlimit_memlock(const struct rlimit *saved_rlimit_memlock) { arg_default_rlimit[RLIMIT_MEMLOCK] = rl; } +static void setenv_manager_environment(void) { + char **p; + int r; + + STRV_FOREACH(p, arg_manager_environment) { + log_debug("Setting '%s' in our own environment.", *p); + + r = putenv_dup(*p, true); + if (r < 0) + log_warning_errno(errno, "Failed to setenv \"%s\", ignoring: %m", *p); + } +} + static void reset_arguments(void) { /* Frees/resets arg_* variables, with a few exceptions commented below. */ @@ -2318,6 +2345,7 @@ static void reset_arguments(void) { arg_watchdog_device = NULL; arg_default_environment = strv_free(arg_default_environment); + arg_manager_environment = strv_free(arg_manager_environment); rlimit_free_all(arg_default_rlimit); arg_capability_bounding_set = CAP_ALL; @@ -2379,6 +2407,9 @@ static int parse_configuration(const struct rlimit *saved_rlimit_nofile, if (arg_show_status == _SHOW_STATUS_INVALID) arg_show_status = SHOW_STATUS_YES; + /* Push variables into the manager environment block */ + setenv_manager_environment(); + return 0; } @@ -2724,7 +2755,7 @@ int main(int argc, char *argv[]) { /* Reset all signal handlers. */ (void) reset_all_signal_handlers(); - (void) ignore_signals(SIGNALS_IGNORE, -1); + (void) ignore_signals(SIGNALS_IGNORE); (void) parse_configuration(&saved_rlimit_nofile, &saved_rlimit_memlock); diff --git a/src/core/manager.c b/src/core/manager.c index a1d6f7cc1..629966ea6 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -80,6 +80,7 @@ #include "transaction.h" #include "umask-util.h" #include "unit-name.h" +#include "unit-serialize.h" #include "user-util.h" #include "virt.h" #include "watchdog.h" @@ -510,7 +511,7 @@ static int manager_setup_signals(Manager *m) { SIGCHLD, /* Child died */ SIGTERM, /* Reexecute daemon */ SIGHUP, /* Reload configuration */ - SIGUSR1, /* systemd/upstart: reconnect to D-Bus */ + SIGUSR1, /* systemd: reconnect to D-Bus */ SIGUSR2, /* systemd: dump status */ SIGINT, /* Kernel sends us this on control-alt-del */ SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */ @@ -641,22 +642,14 @@ int manager_default_environment(Manager *m) { /* Import locale variables LC_*= from configuration */ (void) locale_setup(&m->transient_environment); } else { - _cleanup_free_ char *k = NULL; - - /* The user manager passes its own environment - * along to its children, except for $PATH. */ + /* The user manager passes its own environment along to its children, except for $PATH. */ m->transient_environment = strv_copy(environ); if (!m->transient_environment) return log_oom(); - k = strdup("PATH=" DEFAULT_USER_PATH); - if (!k) - return log_oom(); - - r = strv_env_replace(&m->transient_environment, k); + r = strv_env_replace_strdup(&m->transient_environment, "PATH=" DEFAULT_USER_PATH); if (r < 0) return log_oom(); - TAKE_PTR(k); } sanitize_environment(m->transient_environment); @@ -1187,18 +1180,15 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) { is_bad = false; } - if (u->refs_by_target) { - const UnitRef *ref; + const UnitRef *ref; + LIST_FOREACH(refs_by_target, ref, u->refs_by_target) { + unit_gc_sweep(ref->source, gc_marker); - LIST_FOREACH(refs_by_target, ref, u->refs_by_target) { - unit_gc_sweep(ref->source, gc_marker); + if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD) + goto good; - if (ref->source->gc_marker == gc_marker + GC_OFFSET_GOOD) - goto good; - - if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD) - is_bad = false; - } + if (ref->source->gc_marker != gc_marker + GC_OFFSET_BAD) + is_bad = false; } if (is_bad) @@ -2210,7 +2200,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { /* When we are reloading, let's not wait with generating signals, since we need to exit the manager as quickly * as we can. There's no point in throttling generation of signals in that case. */ if (MANAGER_IS_RELOADING(m) || m->send_reloading_done || m->pending_reload_message) - budget = (unsigned) -1; /* infinite budget in this case */ + budget = UINT_MAX; /* infinite budget in this case */ else { /* Anything to do at all? */ if (!m->dbus_unit_queue && !m->dbus_job_queue) @@ -2242,7 +2232,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { bus_unit_send_change_signal(u); n++; - if (budget != (unsigned) -1) + if (budget != UINT_MAX) budget--; } @@ -2252,7 +2242,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) { bus_job_send_change_signal(j); n++; - if (budget != (unsigned) -1) + if (budget != UINT_MAX) budget--; } @@ -3180,22 +3170,19 @@ static bool manager_timestamp_shall_serialize(ManagerTimestamp t) { #define DESTROY_IPC_FLAG (UINT32_C(1) << 31) static void manager_serialize_uid_refs_internal( - Manager *m, FILE *f, - Hashmap **uid_refs, + Hashmap *uid_refs, const char *field_name) { void *p, *k; - assert(m); assert(f); - assert(uid_refs); assert(field_name); /* Serialize the UID reference table. Or actually, just the IPC destruction flag of it, as * the actual counter of it is better rebuild after a reload/reexec. */ - HASHMAP_FOREACH_KEY(p, k, *uid_refs) { + HASHMAP_FOREACH_KEY(p, k, uid_refs) { uint32_t c; uid_t uid; @@ -3210,11 +3197,11 @@ static void manager_serialize_uid_refs_internal( } static void manager_serialize_uid_refs(Manager *m, FILE *f) { - manager_serialize_uid_refs_internal(m, f, &m->uid_refs, "destroy-ipc-uid"); + manager_serialize_uid_refs_internal(f, m->uid_refs, "destroy-ipc-uid"); } static void manager_serialize_gid_refs(Manager *m, FILE *f) { - manager_serialize_uid_refs_internal(m, f, &m->gid_refs, "destroy-ipc-gid"); + manager_serialize_uid_refs_internal(f, m->gid_refs, "destroy-ipc-gid"); } int manager_serialize( @@ -3474,7 +3461,6 @@ void manager_retry_runtime_watchdog(Manager *m) { } static void manager_deserialize_uid_refs_one_internal( - Manager *m, Hashmap** uid_refs, const char *value) { @@ -3482,18 +3468,16 @@ static void manager_deserialize_uid_refs_one_internal( uint32_t c; int r; - assert(m); assert(uid_refs); assert(value); r = parse_uid(value, &uid); if (r < 0 || uid == 0) { - log_debug("Unable to parse UID reference serialization: " UID_FMT, uid); + log_debug("Unable to parse UID/GID reference serialization: " UID_FMT, uid); return; } - r = hashmap_ensure_allocated(uid_refs, &trivial_hash_ops); - if (r < 0) { + if (hashmap_ensure_allocated(uid_refs, &trivial_hash_ops) < 0) { log_oom(); return; } @@ -3506,17 +3490,17 @@ static void manager_deserialize_uid_refs_one_internal( r = hashmap_replace(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)); if (r < 0) { - log_debug_errno(r, "Failed to add UID reference entry: %m"); + log_debug_errno(r, "Failed to add UID/GID reference entry: %m"); return; } } static void manager_deserialize_uid_refs_one(Manager *m, const char *value) { - manager_deserialize_uid_refs_one_internal(m, &m->uid_refs, value); + manager_deserialize_uid_refs_one_internal(&m->uid_refs, value); } static void manager_deserialize_gid_refs_one(Manager *m, const char *value) { - manager_deserialize_uid_refs_one_internal(m, &m->gid_refs, value); + manager_deserialize_uid_refs_one_internal(&m->gid_refs, value); } int manager_deserialize(Manager *m, FILE *f, FDSet *fds) { @@ -3842,6 +3826,9 @@ int manager_reload(Manager *m) { /* Clean up runtime objects no longer referenced */ manager_vacuum(m); + /* Clean up deserialized tracked clients */ + m->deserialized_subscribed = strv_free(m->deserialized_subscribed); + /* Consider the reload process complete now. */ assert(m->n_reloading > 0); m->n_reloading--; @@ -4105,7 +4092,8 @@ static int manager_run_environment_generators(Manager *m) { RUN_WITH_UMASK(0022) r = execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, gather_environment, - args, NULL, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS); + args, NULL, m->transient_environment, + EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS | EXEC_DIR_SET_SYSTEMD_EXEC_PID); return r; } @@ -4140,7 +4128,8 @@ static int manager_run_generators(Manager *m) { RUN_WITH_UMASK(0022) (void) execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, NULL, NULL, - (char**) argv, m->transient_environment, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS); + (char**) argv, m->transient_environment, + EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS | EXEC_DIR_SET_SYSTEMD_EXEC_PID); r = 0; @@ -4585,16 +4574,13 @@ ManagerState manager_state(Manager *m) { } static void manager_unref_uid_internal( - Manager *m, - Hashmap **uid_refs, + Hashmap *uid_refs, uid_t uid, bool destroy_now, int (*_clean_ipc)(uid_t uid)) { uint32_t c, n; - assert(m); - assert(uid_refs); assert(uid_is_valid(uid)); assert(_clean_ipc); @@ -4612,14 +4598,14 @@ static void manager_unref_uid_internal( if (uid == 0) /* We don't keep track of root, and will never destroy it */ return; - c = PTR_TO_UINT32(hashmap_get(*uid_refs, UID_TO_PTR(uid))); + c = PTR_TO_UINT32(hashmap_get(uid_refs, UID_TO_PTR(uid))); n = c & ~DESTROY_IPC_FLAG; assert(n > 0); n--; if (destroy_now && n == 0) { - hashmap_remove(*uid_refs, UID_TO_PTR(uid)); + hashmap_remove(uid_refs, UID_TO_PTR(uid)); if (c & DESTROY_IPC_FLAG) { log_debug("%s " UID_FMT " is no longer referenced, cleaning up its IPC.", @@ -4629,20 +4615,19 @@ static void manager_unref_uid_internal( } } else { c = n | (c & DESTROY_IPC_FLAG); - assert_se(hashmap_update(*uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)) >= 0); + assert_se(hashmap_update(uid_refs, UID_TO_PTR(uid), UINT32_TO_PTR(c)) >= 0); } } void manager_unref_uid(Manager *m, uid_t uid, bool destroy_now) { - manager_unref_uid_internal(m, &m->uid_refs, uid, destroy_now, clean_ipc_by_uid); + manager_unref_uid_internal(m->uid_refs, uid, destroy_now, clean_ipc_by_uid); } void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now) { - manager_unref_uid_internal(m, &m->gid_refs, (uid_t) gid, destroy_now, clean_ipc_by_gid); + manager_unref_uid_internal(m->gid_refs, (uid_t) gid, destroy_now, clean_ipc_by_gid); } static int manager_ref_uid_internal( - Manager *m, Hashmap **uid_refs, uid_t uid, bool clean_ipc) { @@ -4650,7 +4635,6 @@ static int manager_ref_uid_internal( uint32_t c, n; int r; - assert(m); assert(uid_refs); assert(uid_is_valid(uid)); @@ -4681,25 +4665,22 @@ static int manager_ref_uid_internal( } int manager_ref_uid(Manager *m, uid_t uid, bool clean_ipc) { - return manager_ref_uid_internal(m, &m->uid_refs, uid, clean_ipc); + return manager_ref_uid_internal(&m->uid_refs, uid, clean_ipc); } int manager_ref_gid(Manager *m, gid_t gid, bool clean_ipc) { - return manager_ref_uid_internal(m, &m->gid_refs, (uid_t) gid, clean_ipc); + return manager_ref_uid_internal(&m->gid_refs, (uid_t) gid, clean_ipc); } static void manager_vacuum_uid_refs_internal( - Manager *m, - Hashmap **uid_refs, + Hashmap *uid_refs, int (*_clean_ipc)(uid_t uid)) { void *p, *k; - assert(m); - assert(uid_refs); assert(_clean_ipc); - HASHMAP_FOREACH_KEY(p, k, *uid_refs) { + HASHMAP_FOREACH_KEY(p, k, uid_refs) { uint32_t c, n; uid_t uid; @@ -4717,16 +4698,16 @@ static void manager_vacuum_uid_refs_internal( (void) _clean_ipc(uid); } - assert_se(hashmap_remove(*uid_refs, k) == p); + assert_se(hashmap_remove(uid_refs, k) == p); } } static void manager_vacuum_uid_refs(Manager *m) { - manager_vacuum_uid_refs_internal(m, &m->uid_refs, clean_ipc_by_uid); + manager_vacuum_uid_refs_internal(m->uid_refs, clean_ipc_by_uid); } static void manager_vacuum_gid_refs(Manager *m) { - manager_vacuum_uid_refs_internal(m, &m->gid_refs, clean_ipc_by_gid); + manager_vacuum_uid_refs_internal(m->gid_refs, clean_ipc_by_gid); } static void manager_vacuum(Manager *m) { @@ -4818,6 +4799,7 @@ char *manager_taint_string(Manager *m) { buf = new(char, sizeof("split-usr:" "cgroups-missing:" + "cgrousv1:" "local-hwclock:" "var-run-bad:" "overflowuid-not-65534:" @@ -4834,6 +4816,9 @@ char *manager_taint_string(Manager *m) { if (access("/proc/cgroups", F_OK) < 0) e = stpcpy(e, "cgroups-missing:"); + if (cg_all_unified() == 0) + e = stpcpy(e, "cgroupsv1:"); + if (clock_is_localtime(NULL) > 0) e = stpcpy(e, "local-hwclock:"); diff --git a/src/core/manager.h b/src/core/manager.h index 19df889dd..f58982a36 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -36,7 +36,7 @@ typedef enum ManagerState { MANAGER_MAINTENANCE, MANAGER_STOPPING, _MANAGER_STATE_MAX, - _MANAGER_STATE_INVALID = -1 + _MANAGER_STATE_INVALID = -EINVAL, } ManagerState; typedef enum ManagerObjective { @@ -50,7 +50,7 @@ typedef enum ManagerObjective { MANAGER_KEXEC, MANAGER_SWITCH_ROOT, _MANAGER_OBJECTIVE_MAX, - _MANAGER_OBJECTIVE_INVALID = -1 + _MANAGER_OBJECTIVE_INVALID = -EINVAL, } ManagerObjective; typedef enum StatusType { @@ -65,7 +65,7 @@ typedef enum OOMPolicy { OOM_STOP, /* The kernel kills the process it wants to kill, and we stop the unit */ OOM_KILL, /* The kernel kills the process it wants to kill, and all others in the unit, and we stop the unit */ _OOM_POLICY_MAX, - _OOM_POLICY_INVALID = -1 + _OOM_POLICY_INVALID = -EINVAL, } OOMPolicy; /* Notes: @@ -111,7 +111,7 @@ typedef enum ManagerTimestamp { MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START, MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH, _MANAGER_TIMESTAMP_MAX, - _MANAGER_TIMESTAMP_INVALID = -1, + _MANAGER_TIMESTAMP_INVALID = -EINVAL, } ManagerTimestamp; typedef enum WatchdogType { @@ -311,25 +311,25 @@ struct Manager { /* The stat() data the last time we saw /etc/localtime */ usec_t etc_localtime_mtime; - bool etc_localtime_accessible:1; + bool etc_localtime_accessible; - ManagerObjective objective:5; + ManagerObjective objective; /* Flags */ - bool dispatching_load_queue:1; + bool dispatching_load_queue; - bool taint_usr:1; + bool taint_usr; /* Have we already sent out the READY=1 notification? */ - bool ready_sent:1; + bool ready_sent; /* Have we already printed the taint line if necessary? */ - bool taint_logged:1; + bool taint_logged; /* Have we ever changed the "kernel.pid_max" sysctl? */ - bool sysctl_pid_max_changed:1; + bool sysctl_pid_max_changed; - ManagerTestRunFlags test_run_flags:8; + ManagerTestRunFlags test_run_flags; /* If non-zero, exit with the following value when the systemd * process terminate. Useful for containers: systemd-nspawn could get @@ -366,8 +366,8 @@ struct Manager { int original_log_level; LogTarget original_log_target; - bool log_level_overridden:1; - bool log_target_overridden:1; + bool log_level_overridden; + bool log_target_overridden; struct rlimit *rlimit[_RLIMIT_MAX]; @@ -537,7 +537,7 @@ void manager_unref_uid(Manager *m, uid_t uid, bool destroy_now); int manager_ref_uid(Manager *m, uid_t uid, bool clean_ipc); void manager_unref_gid(Manager *m, gid_t gid, bool destroy_now); -int manager_ref_gid(Manager *m, gid_t gid, bool destroy_now); +int manager_ref_gid(Manager *m, gid_t gid, bool clean_ipc); char *manager_taint_string(Manager *m); diff --git a/src/core/meson.build b/src/core/meson.build index 77767eb60..a389c906b 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -1,16 +1,5 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -libcore_shared_sources = ''' - killall.c - killall.h - loopback-setup.c - loopback-setup.h - machine-id-setup.c - machine-id-setup.h - mount-setup.c - mount-setup.h -'''.split() - libcore_sources = ''' apparmor-setup.c apparmor-setup.h @@ -76,8 +65,6 @@ libcore_sources = ''' execute.h generator-setup.c generator-setup.h - hostname-setup.c - hostname-setup.h ima-setup.c ima-setup.h ip-address-access.c @@ -128,6 +115,8 @@ libcore_sources = ''' transaction.h unit-printf.c unit-printf.h + unit-serialize.c + unit-serialize.h unit.c unit.h '''.split() @@ -153,22 +142,12 @@ load_fragment_gperf_nulstr_c = custom_target( command : [awk, '-f', '@INPUT0@', '@INPUT1@'], capture : true) -# A convenience library to share code with other binaries: -# systemd-shutdown, systemd-remount-fs, systemd-machine-id-setup, … -libcore_shared = static_library( - 'core-shared', - libcore_shared_sources, - include_directories : includes, - dependencies : [versiondep, - libmount]) - libcore = static_library( 'core', libcore_sources, load_fragment_gperf_c, load_fragment_gperf_nulstr_c, include_directories : includes, - link_whole : libcore_shared, dependencies : [versiondep, threads, librt, @@ -181,18 +160,18 @@ libcore = static_library( libmount, libacl]) +core_includes = [includes, include_directories('.')] + systemd_sources = files('main.c') -in_files = [['macros.systemd', rpmmacrosdir], - ['system.conf', pkgsysconfdir], +in_files = [['system.conf', pkgsysconfdir], ['user.conf', pkgsysconfdir], - ['systemd.pc', pkgconfigdatadir], - ['triggers.systemd', '']] + ['systemd.pc', pkgconfigdatadir]] foreach item : in_files file = item[0] dir = item[1] - if install_sysconfdir or dir != pkgsysconfdir + if install_sysconfdir_samples or dir != pkgsysconfdir configure_file( input : file + '.in', output : file, @@ -224,3 +203,12 @@ if install_sysconfdir meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(pkgsysconfdir, 'user'))) meson.add_install_script('sh', '-c', mkdir_p.format(join_paths(sysconfdir, 'xdg/systemd'))) endif + +############################################################ + +fuzzers += [ + [['src/core/fuzz-unit-file.c'], + [libcore, + libshared], + [libmount]], +] diff --git a/src/core/mount.c b/src/core/mount.c index 8e83de0ba..ca5d0939a 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -549,25 +549,19 @@ static int mount_verify(Mount *m) { if (r < 0) return log_unit_error_errno(UNIT(m), r, "Failed to generate unit name from mount path: %m"); - if (!unit_has_name(UNIT(m), e)) { - log_unit_error(UNIT(m), "Where= setting doesn't match unit name. Refusing."); - return -ENOEXEC; - } + if (!unit_has_name(UNIT(m), e)) + return log_unit_error_errno(UNIT(m), SYNTHETIC_ERRNO(ENOEXEC), "Where= setting doesn't match unit name. Refusing."); - if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) { - log_unit_error(UNIT(m), "Cannot create mount unit for API file system %s. Refusing.", m->where); - return -ENOEXEC; - } + if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) + return log_unit_error_errno(UNIT(m), SYNTHETIC_ERRNO(ENOEXEC), "Cannot create mount unit for API file system %s. Refusing.", m->where); p = get_mount_parameters_fragment(m); if (p && !p->what && !UNIT(m)->perpetual) return log_unit_error_errno(UNIT(m), SYNTHETIC_ERRNO(ENOEXEC), "What= setting is missing. Refusing."); - if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) { - log_unit_error(UNIT(m), "Unit has PAM enabled. Kill mode must be set to control-group'. Refusing."); - return -ENOEXEC; - } + if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) + return log_unit_error_errno(UNIT(m), SYNTHETIC_ERRNO(ENOEXEC), "Unit has PAM enabled. Kill mode must be set to control-group'. Refusing."); return 0; } @@ -1016,14 +1010,16 @@ static void mount_enter_mounting(Mount *m) { p = get_mount_parameters_fragment(m); if (p && mount_is_bind(p)) { r = mkdir_p_label(p->what, m->directory_mode); - if (r < 0) + /* mkdir_p_label() can return -EEXIST if the target path exists and is not a directory - which is + * totally OK, in case the user wants us to overmount a non-directory inode. */ + if (r < 0 && r != -EEXIST) log_unit_error_errno(UNIT(m), r, "Failed to make bind mount source '%s': %m", p->what); } if (p) { _cleanup_free_ char *opts = NULL; - r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts); + r = fstab_filter_options(p->options, "nofail\0" "noauto\0" "auto\0", NULL, NULL, NULL, &opts); if (r < 0) goto fail; @@ -1253,8 +1249,9 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F if (streq(key, "state")) { MountState state; - if ((state = mount_state_from_string(value)) < 0) - log_unit_debug(u, "Failed to parse state value: %s", value); + state = mount_state_from_string(value); + if (state < 0) + log_unit_debug_errno(u, state, "Failed to parse state value: %s", value); else m->deserialized_state = state; @@ -1263,7 +1260,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F f = mount_result_from_string(value); if (f < 0) - log_unit_debug(u, "Failed to parse result value: %s", value); + log_unit_debug_errno(u, f, "Failed to parse result value: %s", value); else if (f != MOUNT_SUCCESS) m->result = f; @@ -1272,7 +1269,7 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F f = mount_result_from_string(value); if (f < 0) - log_unit_debug(u, "Failed to parse reload result value: %s", value); + log_unit_debug_errno(u, f, "Failed to parse reload result value: %s", value); else if (f != MOUNT_SUCCESS) m->reload_result = f; @@ -1280,19 +1277,20 @@ static int mount_deserialize_item(Unit *u, const char *key, const char *value, F r = safe_atou(value, &m->n_retry_umount); if (r < 0) - log_unit_debug(u, "Failed to parse n-retry-umount value: %s", value); + log_unit_debug_errno(u, r, "Failed to parse n-retry-umount value: %s", value); } else if (streq(key, "control-pid")) { - if (parse_pid(value, &m->control_pid) < 0) - log_unit_debug(u, "Failed to parse control-pid value: %s", value); + r = parse_pid(value, &m->control_pid); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to parse control-pid value: %s", value); } else if (streq(key, "control-command")) { MountExecCommand id; id = mount_exec_command_from_string(value); if (id < 0) - log_unit_debug(u, "Failed to parse exec-command value: %s", value); + log_unit_debug_errno(u, id, "Failed to parse exec-command value: %s", value); else { m->control_command_id = id; m->control_command = m->exec_command + id; @@ -1861,6 +1859,12 @@ static void mount_enumerate(Manager *m) { goto fail; } + r = sd_event_source_set_ratelimit(m->mount_event_source, 1 * USEC_PER_SEC, 5); + if (r < 0) { + log_error_errno(r, "Failed to enable rate limit for mount events: %m"); + goto fail; + } + (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch"); } diff --git a/src/core/mount.h b/src/core/mount.h index ad0e01608..1a0d9fc5e 100644 --- a/src/core/mount.h +++ b/src/core/mount.h @@ -12,7 +12,7 @@ typedef enum MountExecCommand { MOUNT_EXEC_UNMOUNT, MOUNT_EXEC_REMOUNT, _MOUNT_EXEC_COMMAND_MAX, - _MOUNT_EXEC_COMMAND_INVALID = -1 + _MOUNT_EXEC_COMMAND_INVALID = -EINVAL, } MountExecCommand; typedef enum MountResult { @@ -25,7 +25,7 @@ typedef enum MountResult { MOUNT_FAILURE_START_LIMIT_HIT, MOUNT_FAILURE_PROTOCOL, _MOUNT_RESULT_MAX, - _MOUNT_RESULT_INVALID = -1 + _MOUNT_RESULT_INVALID = -EINVAL, } MountResult; typedef struct MountParameters { diff --git a/src/core/namespace.c b/src/core/namespace.c index cdf427a6e..d47531408 100644 --- a/src/core/namespace.c +++ b/src/core/namespace.c @@ -11,6 +11,9 @@ #include "alloc-util.h" #include "base-filesystem.h" #include "dev-setup.h" +#include "env-util.h" +#include "escape.h" +#include "extension-release.h" #include "fd-util.h" #include "format-util.h" #include "fs-util.h" @@ -23,7 +26,9 @@ #include "mountpoint-util.h" #include "namespace-util.h" #include "namespace.h" +#include "nsflags.h" #include "nulstr-util.h" +#include "os-util.h" #include "path-util.h" #include "selinux-util.h" #include "socket-util.h" @@ -41,6 +46,7 @@ typedef enum MountMode { /* This is ordered by priority! */ INACCESSIBLE, + OVERLAY_MOUNT, MOUNT_IMAGES, BIND_MOUNT, BIND_MOUNT_RECURSIVE, @@ -51,9 +57,14 @@ typedef enum MountMode { EMPTY_DIR, SYSFS, PROCFS, + RUN, READONLY, READWRITE, + NOEXEC, + EXEC, TMPFS, + EXTENSION_IMAGES, /* Mounted outside the root directory, and used by subsequent mounts */ + MQUEUEFS, READWRITE_IMPLICIT, /* Should have the lowest priority. */ _MOUNT_MODE_MAX, } MountMode; @@ -65,8 +76,12 @@ typedef struct MountEntry { bool has_prefix:1; /* Already is prefixed by the root dir? */ bool read_only:1; /* Shall this mount point be read-only? */ bool nosuid:1; /* Shall set MS_NOSUID on the mount itself */ + bool noexec:1; /* Shall set MS_NOEXEC on the mount itself */ + bool exec:1; /* Shall clear MS_NOEXEC on the mount itself */ bool applied:1; /* Already applied */ char *path_malloc; /* Use this instead of 'path_const' if we had to allocate memory */ + const char *unprefixed_path_const; /* If the path was amended with a prefix, these will save the original */ + char *unprefixed_path_malloc; const char *source_const; /* The source path, for bind mounts or images */ char *source_malloc; const char *options_const;/* Mount options for tmpfs */ @@ -76,12 +91,13 @@ typedef struct MountEntry { LIST_HEAD(MountOptions, image_options); } MountEntry; -/* If MountAPIVFS= is used, let's mount /sys and /proc into the it, but only as a fallback if the user hasn't mounted +/* If MountAPIVFS= is used, let's mount /sys, /proc, /dev and /run into the it, but only as a fallback if the user hasn't mounted * something there already. These mounts are hence overridden by any other explicitly configured mounts. */ static const MountEntry apivfs_table[] = { { "/proc", PROCFS, false }, { "/dev", BIND_DEV, false }, { "/sys", SYSFS, false }, + { "/run", RUN, false, .options_const = "mode=755" TMPFS_LIMITS_RUN, .flags = MS_NOSUID|MS_NODEV|MS_STRICTATIME }, }; /* ProtectKernelTunables= option and the related filesystem APIs */ @@ -197,6 +213,7 @@ static const MountEntry protect_system_strict_table[] = { static const char * const mount_mode_table[_MOUNT_MODE_MAX] = { [INACCESSIBLE] = "inaccessible", + [OVERLAY_MOUNT] = "overlay", [BIND_MOUNT] = "bind", [BIND_MOUNT_RECURSIVE] = "rbind", [PRIVATE_TMP] = "private-tmp", @@ -210,6 +227,9 @@ static const char * const mount_mode_table[_MOUNT_MODE_MAX] = { [TMPFS] = "tmpfs", [MOUNT_IMAGES] = "mount-images", [READWRITE_IMPLICIT] = "rw-implicit", + [EXEC] = "exec", + [NOEXEC] = "noexec", + [MQUEUEFS] = "mqueuefs", }; DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(mount_mode, MountMode); @@ -223,12 +243,47 @@ static const char *mount_entry_path(const MountEntry *p) { return p->path_malloc ?: p->path_const; } +static const char *mount_entry_unprefixed_path(const MountEntry *p) { + assert(p); + + /* Returns the unprefixed path (ie: before prefix_where_needed() ran), if any */ + + return p->unprefixed_path_malloc ?: p->unprefixed_path_const ?: mount_entry_path(p); +} + +static void mount_entry_consume_prefix(MountEntry *p, char *new_path) { + assert(p); + assert(p->path_malloc || p->path_const); + assert(new_path); + + /* Saves current path in unprefixed_ variable, and takes over new_path */ + + free_and_replace(p->unprefixed_path_malloc, p->path_malloc); + /* If we didn't have a path on the heap, then it's a static one */ + if (!p->unprefixed_path_malloc) + p->unprefixed_path_const = p->path_const; + p->path_malloc = new_path; + p->has_prefix = true; +} + static bool mount_entry_read_only(const MountEntry *p) { assert(p); return p->read_only || IN_SET(p->mode, READONLY, INACCESSIBLE, PRIVATE_TMP_READONLY); } +static bool mount_entry_noexec(const MountEntry *p) { + assert(p); + + return p->noexec || IN_SET(p->mode, NOEXEC, INACCESSIBLE); +} + +static bool mount_entry_exec(const MountEntry *p) { + assert(p); + + return p->exec || p->mode == EXEC; +} + static const char *mount_entry_source(const MountEntry *p) { assert(p); @@ -245,6 +300,7 @@ static void mount_entry_done(MountEntry *p) { assert(p); p->path_malloc = mfree(p->path_malloc); + p->unprefixed_path_malloc = mfree(p->unprefixed_path_malloc); p->source_malloc = mfree(p->source_malloc); p->options_malloc = mfree(p->options_malloc); p->image_options = mount_options_free_all(p->image_options); @@ -310,11 +366,9 @@ static int append_empty_dir_mounts(MountEntry **p, char **strv) { } static int append_bind_mounts(MountEntry **p, const BindMount *binds, size_t n) { - size_t i; - assert(p); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { const BindMount *b = binds + i; *((*p)++) = (MountEntry) { @@ -348,6 +402,101 @@ static int append_mount_images(MountEntry **p, const MountImage *mount_images, s return 0; } +static int append_extension_images( + MountEntry **p, + const char *root, + const char *extension_dir, + char **hierarchies, + const MountImage *mount_images, + size_t n) { + + _cleanup_strv_free_ char **overlays = NULL; + char **hierarchy; + int r; + + assert(p); + assert(extension_dir); + + if (n == 0) + return 0; + + /* Prepare a list of overlays, that will have as each element a string suitable for being + * passed as a lowerdir= parameter, so start with the hierarchy on the root. + * The overlays vector will have the same number of elements and will correspond to the + * hierarchies vector, so they can be iterated upon together. */ + STRV_FOREACH(hierarchy, hierarchies) { + _cleanup_free_ char *prefixed_hierarchy = NULL; + + prefixed_hierarchy = path_join(root, *hierarchy); + if (!prefixed_hierarchy) + return -ENOMEM; + + r = strv_consume(&overlays, TAKE_PTR(prefixed_hierarchy)); + if (r < 0) + return r; + } + + /* First, prepare a mount for each image, but these won't be visible to the unit, instead + * they will be mounted in our propagate directory, and used as a source for the overlay. */ + for (size_t i = 0; i < n; i++) { + _cleanup_free_ char *mount_point = NULL; + const MountImage *m = mount_images + i; + + r = asprintf(&mount_point, "%s/%zu", extension_dir, i); + if (r < 0) + return -ENOMEM; + + for (size_t j = 0; hierarchies && hierarchies[j]; ++j) { + _cleanup_free_ char *prefixed_hierarchy = NULL, *escaped = NULL, *lowerdir = NULL; + + prefixed_hierarchy = path_join(mount_point, hierarchies[j]); + if (!prefixed_hierarchy) + return -ENOMEM; + + escaped = shell_escape(prefixed_hierarchy, ",:"); + if (!escaped) + return -ENOMEM; + + /* Note that lowerdir= parameters are in 'reverse' order, so the + * top-most directory in the overlay comes first in the list. */ + lowerdir = strjoin(escaped, ":", overlays[j]); + if (!lowerdir) + return -ENOMEM; + + free_and_replace(overlays[j], lowerdir); + } + + *((*p)++) = (MountEntry) { + .path_malloc = TAKE_PTR(mount_point), + .image_options = m->mount_options, + .ignore = m->ignore_enoent, + .source_const = m->source, + .mode = EXTENSION_IMAGES, + .has_prefix = true, + }; + } + + /* Then, for each hierarchy, prepare an overlay with the list of lowerdir= strings + * set up earlier. */ + for (size_t i = 0; hierarchies && hierarchies[i]; ++i) { + _cleanup_free_ char *prefixed_hierarchy = NULL; + + prefixed_hierarchy = path_join(root, hierarchies[i]); + if (!prefixed_hierarchy) + return -ENOMEM; + + *((*p)++) = (MountEntry) { + .path_malloc = TAKE_PTR(prefixed_hierarchy), + .options_malloc = TAKE_PTR(overlays[i]), + .mode = OVERLAY_MOUNT, + .has_prefix = true, + .ignore = true, /* If the source image doesn't set the ignore bit it will fail earlier. */ + }; + } + + return 0; +} + static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, size_t n) { assert(p); @@ -388,14 +537,12 @@ static int append_tmpfs_mounts(MountEntry **p, const TemporaryFileSystem *tmpfs, } static int append_static_mounts(MountEntry **p, const MountEntry *mounts, size_t n, bool ignore_protect) { - size_t i; - assert(p); assert(mounts); /* Adds a list of static pre-defined entries */ - for (i = 0; i < n; i++) + for (size_t i = 0; i < n; i++) *((*p)++) = (MountEntry) { .path_const = mount_entry_path(mounts+i), .mode = mounts[i].mode, @@ -452,6 +599,12 @@ static int append_protect_system(MountEntry **p, ProtectSystem protect_system, b static int mount_path_compare(const MountEntry *a, const MountEntry *b) { int d; + /* EXTENSION_IMAGES will be used by other mounts as a base, so sort them first + * regardless of the prefix - they are set up in the propagate directory anyway */ + d = -CMP(a->mode == EXTENSION_IMAGES, b->mode == EXTENSION_IMAGES); + if (d != 0) + return d; + /* If the paths are not equal, then order prefixes first */ d = path_compare(mount_entry_path(a), mount_entry_path(b)); if (d != 0) @@ -462,11 +615,11 @@ static int mount_path_compare(const MountEntry *a, const MountEntry *b) { } static int prefix_where_needed(MountEntry *m, size_t n, const char *root_directory) { - size_t i; - /* Prefixes all paths in the bind mount table with the root directory if the entry needs that. */ - for (i = 0; i < n; i++) { + assert(m || n == 0); + + for (size_t i = 0; i < n; i++) { char *s; if (m[i].has_prefix) @@ -476,8 +629,7 @@ static int prefix_where_needed(MountEntry *m, size_t n, const char *root_directo if (!s) return -ENOMEM; - free_and_replace(m[i].path_malloc, s); - m[i].has_prefix = true; + mount_entry_consume_prefix(&m[i], s); } return 0; @@ -499,7 +651,10 @@ static void drop_duplicates(MountEntry *m, size_t *n) { path_equal(mount_entry_path(f), mount_entry_path(previous)) && !f->applied && !previous->applied) { log_debug("%s (%s) is duplicate.", mount_entry_path(f), mount_mode_to_string(f->mode)); - previous->read_only = previous->read_only || mount_entry_read_only(f); /* Propagate the read-only flag to the remaining entry */ + /* Propagate the flags to the remaining entry */ + previous->read_only = previous->read_only || mount_entry_read_only(f); + previous->noexec = previous->noexec || mount_entry_noexec(f); + previous->exec = previous->exec || mount_entry_exec(f); mount_entry_done(f); continue; } @@ -596,7 +751,8 @@ static void drop_outside_root(const char *root_directory, MountEntry *m, size_t for (f = m, t = m; f < m + *n; f++) { - if (!path_startswith(mount_entry_path(f), root_directory)) { + /* ExtensionImages bases are opened in /run/systemd/unit-extensions on the host */ + if (f->mode != EXTENSION_IMAGES && !path_startswith(mount_entry_path(f), root_directory)) { log_debug("%s is outside of root directory.", mount_entry_path(f)); mount_entry_done(f); continue; @@ -859,25 +1015,15 @@ static int mount_sysfs(const MountEntry *m) { } static int mount_procfs(const MountEntry *m, const NamespaceInfo *ns_info) { + _cleanup_free_ char *opts = NULL; const char *entry_path; - int r; + int r, n; assert(m); assert(ns_info); - entry_path = mount_entry_path(m); - - /* Mount a new instance, so that we get the one that matches our user namespace, if we are running in - * one. i.e we don't reuse existing mounts here under any condition, we want a new instance owned by - * our user namespace and with our hidepid= settings applied. Hence, let's get rid of everything - * mounted on /proc/ first. */ - - (void) mkdir_p_label(entry_path, 0755); - (void) umount_recursive(entry_path, 0); - if (ns_info->protect_proc != PROTECT_PROC_DEFAULT || ns_info->proc_subset != PROC_SUBSET_ALL) { - _cleanup_free_ char *opts = NULL; /* Starting with kernel 5.8 procfs' hidepid= logic is truly per-instance (previously it * pretended to be per-instance but actually was per-namespace), hence let's make use of it @@ -891,22 +1037,40 @@ static int mount_procfs(const MountEntry *m, const NamespaceInfo *ns_info) { ns_info->proc_subset == PROC_SUBSET_PID ? ",subset=pid" : ""); if (!opts) return -ENOMEM; - - r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, opts); - if (r < 0) { - if (r != -EINVAL) - return r; - - /* If this failed with EINVAL then this likely means the textual hidepid= stuff is - * not supported by the kernel, and thus the per-instance hidepid= neither, which - * means we really don't want to use it, since it would affect our host's /proc - * mount. Hence let's gracefully fallback to a classic, unrestricted version. */ - } else - return 1; } - r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); - if (r < 0) + entry_path = mount_entry_path(m); + (void) mkdir_p_label(entry_path, 0755); + + /* Mount a new instance, so that we get the one that matches our user namespace, if we are running in + * one. i.e we don't reuse existing mounts here under any condition, we want a new instance owned by + * our user namespace and with our hidepid= settings applied. Hence, let's get rid of everything + * mounted on /proc/ first. */ + + n = umount_recursive(entry_path, 0); + + r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, opts); + if (r == -EINVAL && opts) + /* If this failed with EINVAL then this likely means the textual hidepid= stuff is + * not supported by the kernel, and thus the per-instance hidepid= neither, which + * means we really don't want to use it, since it would affect our host's /proc + * mount. Hence let's gracefully fallback to a classic, unrestricted version. */ + r = mount_nofollow_verbose(LOG_DEBUG, "proc", entry_path, "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL); + if (r == -EPERM) { + /* When we do not have enough privileges to mount /proc, fallback to use existing /proc. */ + + if (n > 0) + /* /proc or some of sub-mounts are umounted in the above. Refuse incomplete tree. + * Propagate the original error code returned by mount() in the above. */ + return -EPERM; + + r = path_is_mount_point(entry_path, NULL, 0); + if (r < 0) + return log_debug_errno(r, "Unable to determine whether /proc is already mounted: %m"); + if (r == 0) + /* /proc is not mounted. Propagate the original error code. */ + return -EPERM; + } else if (r < 0) return r; return 1; @@ -919,7 +1083,7 @@ static int mount_tmpfs(const MountEntry *m) { assert(m); entry_path = mount_entry_path(m); - inner_path = m->path_const; + inner_path = mount_entry_unprefixed_path(m); /* First, get rid of everything that is below if there is anything. Then, overmount with our new tmpfs */ @@ -937,76 +1101,83 @@ static int mount_tmpfs(const MountEntry *m) { return 1; } -static int mount_images(const MountEntry *m) { - _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_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT; - DissectImageFlags dissect_image_flags; +static int mount_run(const MountEntry *m) { int r; assert(m); - r = verity_settings_load(&verity, mount_entry_source(m), NULL, NULL); - if (r < 0) - return log_debug_errno(r, "Failed to load root hash: %m"); + r = path_is_mount_point(mount_entry_path(m), NULL, 0); + if (r < 0 && r != -ENOENT) + return log_debug_errno(r, "Unable to determine whether /run is already mounted: %m"); + if (r > 0) /* make this a NOP if /run is already a mount point */ + return 0; - dissect_image_flags = - (m->read_only ? DISSECT_IMAGE_READ_ONLY : 0) | - (verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0); + return mount_tmpfs(m); +} - r = loop_device_make_by_path( - mount_entry_source(m), - m->read_only ? O_RDONLY : -1 /* < 0 means writable if possible, read-only as fallback */, - verity.data_path ? 0 : LO_FLAGS_PARTSCAN, - &loop_device); - if (r < 0) - return log_debug_errno(r, "Failed to create loop device for image: %m"); +static int mount_mqueuefs(const MountEntry *m) { + int r; + const char *entry_path; - r = dissect_image( - loop_device->fd, - &verity, - m->image_options, - dissect_image_flags, - &dissected_image); - /* No partition table? Might be a single-filesystem image, try again */ - if (!verity.data_path && r == -ENOPKG) - r = dissect_image( - loop_device->fd, - &verity, - m->image_options, - dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE, - &dissected_image); - if (r < 0) - return log_debug_errno(r, "Failed to dissect image: %m"); + assert(m); - r = dissected_image_decrypt( - dissected_image, - NULL, - &verity, - dissect_image_flags, - &decrypted_image); - if (r < 0) - return log_debug_errno(r, "Failed to decrypt dissected image: %m"); + entry_path = mount_entry_path(m); - r = mkdir_p_label(mount_entry_path(m), 0755); - if (r < 0) - return log_debug_errno(r, "Failed to create destination directory %s: %m", mount_entry_path(m)); - r = umount_recursive(mount_entry_path(m), 0); - if (r < 0) - return log_debug_errno(r, "Failed to umount under destination directory %s: %m", mount_entry_path(m)); + (void) mkdir_p_label(entry_path, 0755); + (void) umount_recursive(entry_path, 0); - r = dissected_image_mount(dissected_image, mount_entry_path(m), UID_INVALID, dissect_image_flags); + r = mount_nofollow_verbose(LOG_DEBUG, "mqueue", entry_path, "mqueue", m->flags, mount_entry_options(m)); if (r < 0) - return log_debug_errno(r, "Failed to mount image: %m"); + return r; - if (decrypted_image) { - r = decrypted_image_relinquish(decrypted_image); + return 0; +} + +static int mount_image(const MountEntry *m, const char *root_directory) { + + _cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL, + *host_os_release_sysext_level = NULL; + int r; + + assert(m); + + if (m->mode == EXTENSION_IMAGES) { + r = parse_os_release( + empty_to_root(root_directory), + "ID", &host_os_release_id, + "VERSION_ID", &host_os_release_version_id, + "SYSEXT_LEVEL", &host_os_release_sysext_level, + NULL); if (r < 0) - return log_debug_errno(r, "Failed to relinquish decrypted image: %m"); + return log_debug_errno(r, "Failed to acquire 'os-release' data of OS tree '%s': %m", empty_to_root(root_directory)); } - loop_device_relinquish(loop_device); + r = verity_dissect_and_mount( + mount_entry_source(m), mount_entry_path(m), m->image_options, + host_os_release_id, host_os_release_version_id, host_os_release_sysext_level); + if (r == -ENOENT && m->ignore) + return 0; + if (r < 0) + return log_debug_errno(r, "Failed to mount image %s on %s: %m", mount_entry_source(m), mount_entry_path(m)); + + return 1; +} + +static int mount_overlay(const MountEntry *m) { + const char *options; + int r; + + assert(m); + + options = strjoina("lowerdir=", mount_entry_options(m)); + + (void) mkdir_p_label(mount_entry_path(m), 0755); + + r = mount_nofollow_verbose(LOG_DEBUG, "overlay", mount_entry_path(m), "overlay", MS_RDONLY, options); + if (r == -ENOENT && m->ignore) + return 0; + if (r < 0) + return r; return 1; } @@ -1036,15 +1207,14 @@ static int follow_symlink( log_debug("Followed mount entry path symlink %s → %s.", mount_entry_path(m), target); - free_and_replace(m->path_malloc, target); - m->has_prefix = true; + mount_entry_consume_prefix(m, TAKE_PTR(target)); m->n_followed ++; return 0; } -static int apply_mount( +static int apply_one_mount( const char *root_directory, MountEntry *m, const NamespaceInfo *ns_info) { @@ -1099,6 +1269,8 @@ static int apply_mount( case READONLY: case READWRITE: case READWRITE_IMPLICIT: + case EXEC: + case NOEXEC: r = path_is_mount_point(mount_entry_path(m), root_directory, 0); if (r == -ENOENT && m->ignore) return 0; @@ -1106,7 +1278,7 @@ static int apply_mount( return log_debug_errno(r, "Failed to determine whether %s is already a mount point: %m", mount_entry_path(m)); if (r > 0) /* Nothing to do here, it is already a mount. We just later toggle the MS_RDONLY - * bit for the mount point if needed. */ + * and MS_NOEXEC bits for the mount point if needed. */ return 0; /* This isn't a mount point yet, let's make it one. */ what = mount_entry_path(m); @@ -1162,8 +1334,20 @@ static int apply_mount( case PROCFS: return mount_procfs(m, ns_info); + case RUN: + return mount_run(m); + + case MQUEUEFS: + return mount_mqueuefs(m); + case MOUNT_IMAGES: - return mount_images(m); + return mount_image(m, NULL); + + case EXTENSION_IMAGES: + return mount_image(m, root_directory); + + case OVERLAY_MOUNT: + return mount_overlay(m); default: assert_not_reached("Unknown mode"); @@ -1176,29 +1360,19 @@ static int apply_mount( bool try_again = false; if (r == -ENOENT && make) { - struct stat st; + int q; /* Hmm, either the source or the destination are missing. Let's see if we can create the destination, then try again. */ - if (stat(what, &st) < 0) - log_error_errno(errno, "Mount point source '%s' is not accessible: %m", what); - else { - int q; + (void) mkdir_parents(mount_entry_path(m), 0755); - (void) mkdir_parents(mount_entry_path(m), 0755); - - if (S_ISDIR(st.st_mode)) - q = mkdir(mount_entry_path(m), 0755) < 0 ? -errno : 0; - else - q = touch(mount_entry_path(m)); - - if (q < 0) - log_error_errno(q, "Failed to create destination mount point node '%s': %m", - mount_entry_path(m)); - else - try_again = true; - } + q = make_mount_point_inode_from_path(what, mount_entry_path(m), 0755); + if (q < 0) + log_error_errno(q, "Failed to create destination mount point node '%s': %m", + mount_entry_path(m)); + else + try_again = true; } if (try_again) @@ -1244,7 +1418,7 @@ static int make_read_only(const MountEntry *m, char **deny_list, FILE *proc_self else r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo); - /* Not that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked + /* Note that we only turn on the MS_RDONLY flag here, we never turn it off. Something that was marked * read-only already stays this way. This improves compatibility with container managers, where we * won't attempt to undo read-only mounts already applied. */ @@ -1256,6 +1430,40 @@ static int make_read_only(const MountEntry *m, char **deny_list, FILE *proc_self return 0; } +static int make_noexec(const MountEntry *m, char **deny_list, FILE *proc_self_mountinfo) { + unsigned long new_flags = 0, flags_mask = 0; + bool submounts = false; + int r = 0; + + assert(m); + assert(proc_self_mountinfo); + + if (mount_entry_noexec(m)) { + new_flags |= MS_NOEXEC; + flags_mask |= MS_NOEXEC; + } else if (mount_entry_exec(m)) { + new_flags &= ~MS_NOEXEC; + flags_mask |= MS_NOEXEC; + } + + if (flags_mask == 0) /* No Change? */ + return 0; + + submounts = !IN_SET(m->mode, EMPTY_DIR, TMPFS); + + if (submounts) + r = bind_remount_recursive_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, deny_list, proc_self_mountinfo); + else + r = bind_remount_one_with_mountinfo(mount_entry_path(m), new_flags, flags_mask, proc_self_mountinfo); + + if (r == -ENOENT && m->ignore) + return 0; + if (r < 0) + return log_debug_errno(r, "Failed to re-mount '%s'%s: %m", mount_entry_path(m), + submounts ? " and its submounts" : ""); + return 0; +} + static bool namespace_info_mount_apivfs(const NamespaceInfo *ns_info) { assert(ns_info); @@ -1277,14 +1485,20 @@ static size_t namespace_calculate_mounts( char** read_write_paths, char** read_only_paths, char** inaccessible_paths, + char** exec_paths, + char** no_exec_paths, char** empty_directories, size_t n_bind_mounts, size_t n_temporary_filesystems, size_t n_mount_images, + size_t n_extension_images, + size_t n_hierarchies, const char* tmp_dir, const char* var_tmp_dir, const char *creds_path, - const char* log_namespace) { + const char* log_namespace, + bool setup_propagate, + const char* notify_socket) { size_t protect_home_cnt; size_t protect_system_cnt = @@ -1307,9 +1521,12 @@ static size_t namespace_calculate_mounts( strv_length(read_write_paths) + strv_length(read_only_paths) + strv_length(inaccessible_paths) + + strv_length(exec_paths) + + strv_length(no_exec_paths) + strv_length(empty_directories) + n_bind_mounts + n_mount_images + + (n_extension_images > 0 ? n_hierarchies + n_extension_images : 0) + /* Mount each image plus an overlay per hierarchy */ n_temporary_filesystems + ns_info->private_dev + (ns_info->protect_kernel_tunables ? ELEMENTSOF(protect_kernel_tunables_table) : 0) + @@ -1320,7 +1537,10 @@ static size_t namespace_calculate_mounts( (ns_info->protect_hostname ? 2 : 0) + (namespace_info_mount_apivfs(ns_info) ? ELEMENTSOF(apivfs_table) : 0) + (creds_path ? 2 : 1) + - !!log_namespace; + !!log_namespace + + setup_propagate + /* /run/systemd/incoming */ + !!notify_socket + + ns_info->private_ipc; /* /dev/mqueue */ } static void normalize_mounts(const char *root_directory, MountEntry *mounts, size_t *n_mounts) { @@ -1336,6 +1556,113 @@ static void normalize_mounts(const char *root_directory, MountEntry *mounts, siz drop_nop(mounts, n_mounts); } +static int apply_mounts( + const char *root, + const NamespaceInfo *ns_info, + MountEntry *mounts, + size_t *n_mounts, + char **error_path) { + + _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; + _cleanup_free_ char **deny_list = NULL; + int r; + + if (n_mounts == 0) /* Shortcut: nothing to do */ + return 0; + + assert(root); + assert(mounts); + assert(n_mounts); + + /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of + * /proc. For example, this is the case with the option: 'InaccessiblePaths=/proc'. */ + proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); + if (!proc_self_mountinfo) { + r = -errno; + + if (error_path) + *error_path = strdup("/proc/self/mountinfo"); + + return log_debug_errno(r, "Failed to open /proc/self/mountinfo: %m"); + } + + /* First round, establish all mounts we need */ + for (;;) { + bool again = false; + + for (MountEntry *m = mounts; m < mounts + *n_mounts; ++m) { + + if (m->applied) + continue; + + /* ExtensionImages are first opened in the propagate directory, not in the root_directory */ + r = follow_symlink(m->mode != EXTENSION_IMAGES ? root : NULL, m); + if (r < 0) { + if (error_path && mount_entry_path(m)) + *error_path = strdup(mount_entry_path(m)); + return r; + } + if (r == 0) { + /* We hit a symlinked mount point. The entry got rewritten and might + * point to a very different place now. Let's normalize the changed + * list, and start from the beginning. After all to mount the entry + * at the new location we might need some other mounts first */ + again = true; + break; + } + + r = apply_one_mount(root, m, ns_info); + if (r < 0) { + if (error_path && mount_entry_path(m)) + *error_path = strdup(mount_entry_path(m)); + return r; + } + + m->applied = true; + } + + if (!again) + break; + + normalize_mounts(root, mounts, n_mounts); + } + + /* Create a deny list we can pass to bind_mount_recursive() */ + deny_list = new(char*, (*n_mounts)+1); + if (!deny_list) + return -ENOMEM; + for (size_t j = 0; j < *n_mounts; j++) + deny_list[j] = (char*) mount_entry_path(mounts+j); + deny_list[*n_mounts] = NULL; + + /* Second round, flip the ro bits if necessary. */ + for (MountEntry *m = mounts; m < mounts + *n_mounts; ++m) { + r = make_read_only(m, deny_list, proc_self_mountinfo); + if (r < 0) { + if (error_path && mount_entry_path(m)) + *error_path = strdup(mount_entry_path(m)); + return r; + } + } + + /* Third round, flip the noexec bits with a simplified deny list. */ + for (size_t j = 0; j < *n_mounts; j++) + if (IN_SET((mounts+j)->mode, EXEC, NOEXEC)) + deny_list[j] = (char*) mount_entry_path(mounts+j); + deny_list[*n_mounts] = NULL; + + for (MountEntry *m = mounts; m < mounts + *n_mounts; ++m) { + r = make_noexec(m, deny_list, proc_self_mountinfo); + if (r < 0) { + if (error_path && mount_entry_path(m)) + *error_path = strdup(mount_entry_path(m)); + return r; + } + } + + return 1; +} + static bool root_read_only( char **read_only_paths, ProtectSystem protect_system) { @@ -1361,8 +1688,6 @@ static bool home_read_only( size_t n_temporary_filesystems, ProtectHome protect_home) { - size_t i; - /* Determine whether the /home directory is going to be read-only given the configured settings. Yes, * this is a bit sloppy, since we don't bother checking for cases where / is affected by multiple * settings. */ @@ -1375,12 +1700,12 @@ static bool home_read_only( prefixed_path_strv_contains(empty_directories, "/home")) return true; - for (i = 0; i < n_temporary_filesystems; i++) + for (size_t i = 0; i < n_temporary_filesystems; i++) if (path_equal(temporary_filesystems[i].path, "/home")) return true; /* If /home is overmounted with some dir from the host it's not writable. */ - for (i = 0; i < n_bind_mounts; i++) + for (size_t i = 0; i < n_bind_mounts; i++) if (path_equal(bind_mounts[i].destination, "/home")) return true; @@ -1451,6 +1776,8 @@ int setup_namespace( char** read_write_paths, char** read_only_paths, char** inaccessible_paths, + char** exec_paths, + char** no_exec_paths, char** empty_directories, const BindMount *bind_mounts, size_t n_bind_mounts, @@ -1470,6 +1797,11 @@ int setup_namespace( size_t root_hash_sig_size, const char *root_hash_sig_path, const char *verity_data_path, + const MountImage *extension_images, + size_t n_extension_images, + const char *propagate_dir, + const char *incoming_dir, + const char *notify_socket, DissectImageFlags dissect_image_flags, char **error_path) { @@ -1477,14 +1809,18 @@ int setup_namespace( _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; _cleanup_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT; + _cleanup_strv_free_ char **hierarchies = NULL; MountEntry *m = NULL, *mounts = NULL; - bool require_prefix = false; - const char *root; + bool require_prefix = false, setup_propagate = false; + const char *root, *extension_dir = "/run/systemd/unit-extensions"; size_t n_mounts; int r; assert(ns_info); + if (!isempty(propagate_dir) && !isempty(incoming_dir)) + setup_propagate = true; + if (mount_flags == 0) mount_flags = MS_SHARED; @@ -1557,18 +1893,30 @@ int setup_namespace( require_prefix = true; } + if (n_extension_images > 0) { + r = parse_env_extension_hierarchies(&hierarchies); + if (r < 0) + return r; + } + n_mounts = namespace_calculate_mounts( ns_info, read_write_paths, read_only_paths, inaccessible_paths, + exec_paths, + no_exec_paths, empty_directories, n_bind_mounts, n_temporary_filesystems, n_mount_images, + n_extension_images, + strv_length(hierarchies), tmp_dir, var_tmp_dir, creds_path, - log_namespace); + log_namespace, + setup_propagate, + notify_socket); if (n_mounts > 0) { m = mounts = new0(MountEntry, n_mounts); @@ -1587,6 +1935,14 @@ int setup_namespace( if (r < 0) goto finish; + r = append_access_mounts(&m, exec_paths, EXEC, require_prefix); + if (r < 0) + goto finish; + + r = append_access_mounts(&m, no_exec_paths, NOEXEC, require_prefix); + if (r < 0) + goto finish; + r = append_empty_dir_mounts(&m, empty_directories); if (r < 0) goto finish; @@ -1623,6 +1979,10 @@ int setup_namespace( if (r < 0) goto finish; + r = append_extension_images(&m, root, extension_dir, hierarchies, extension_images, n_extension_images); + if (r < 0) + goto finish; + if (ns_info->private_dev) *(m++) = (MountEntry) { .path_const = "/dev", @@ -1691,6 +2051,13 @@ int setup_namespace( }; } + if (ns_info->private_ipc) + *(m++) = (MountEntry) { + .path_const = "/dev/mqueue", + .mode = MQUEUEFS, + .flags = MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_RELATIME, + }; + if (creds_path) { /* If our service has a credentials store configured, then bind that one in, but hide * everything else. */ @@ -1737,6 +2104,23 @@ int setup_namespace( }; } + /* Will be used to add bind mounts at runtime */ + if (setup_propagate) + *(m++) = (MountEntry) { + .source_const = propagate_dir, + .path_const = incoming_dir, + .mode = BIND_MOUNT, + .read_only = true, + }; + + if (notify_socket) + *(m++) = (MountEntry) { + .path_const = notify_socket, + .source_const = notify_socket, + .mode = BIND_MOUNT, + .read_only = true, + }; + assert(mounts + n_mounts == m); /* Prepend the root directory where that's necessary */ @@ -1761,6 +2145,15 @@ int setup_namespace( goto finish; } + /* Create the source directory to allow runtime propagation of mounts */ + if (setup_propagate) + (void) mkdir_p(propagate_dir, 0600); + + if (n_extension_images > 0) + /* ExtensionImages mountpoint directories will be created + * while parsing the mounts to create, so have the parent ready */ + (void) mkdir_p(extension_dir, 0600); + /* Remount / as SLAVE so that nothing now mounted in the namespace * shows up in the parent */ if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0) { @@ -1811,81 +2204,10 @@ int setup_namespace( if (root_image || root_directory) (void) base_filesystem_create(root, UID_INVALID, GID_INVALID); - if (n_mounts > 0) { - _cleanup_fclose_ FILE *proc_self_mountinfo = NULL; - _cleanup_free_ char **deny_list = NULL; - size_t j; - - /* Open /proc/self/mountinfo now as it may become unavailable if we mount anything on top of - * /proc. For example, this is the case with the option: 'InaccessiblePaths=/proc'. */ - proc_self_mountinfo = fopen("/proc/self/mountinfo", "re"); - if (!proc_self_mountinfo) { - r = log_debug_errno(errno, "Failed to open /proc/self/mountinfo: %m"); - if (error_path) - *error_path = strdup("/proc/self/mountinfo"); - goto finish; - } - - /* First round, establish all mounts we need */ - for (;;) { - bool again = false; - - for (m = mounts; m < mounts + n_mounts; ++m) { - - if (m->applied) - continue; - - r = follow_symlink(root, m); - if (r < 0) { - if (error_path && mount_entry_path(m)) - *error_path = strdup(mount_entry_path(m)); - goto finish; - } - if (r == 0) { - /* We hit a symlinked mount point. The entry got rewritten and might - * point to a very different place now. Let's normalize the changed - * list, and start from the beginning. After all to mount the entry - * at the new location we might need some other mounts first */ - again = true; - break; - } - - r = apply_mount(root, m, ns_info); - if (r < 0) { - if (error_path && mount_entry_path(m)) - *error_path = strdup(mount_entry_path(m)); - goto finish; - } - - m->applied = true; - } - - if (!again) - break; - - normalize_mounts(root, mounts, &n_mounts); - } - - /* Create a deny list we can pass to bind_mount_recursive() */ - deny_list = new(char*, n_mounts+1); - if (!deny_list) { - r = -ENOMEM; - goto finish; - } - for (j = 0; j < n_mounts; j++) - deny_list[j] = (char*) mount_entry_path(mounts+j); - deny_list[j] = NULL; - - /* Second round, flip the ro bits if necessary. */ - for (m = mounts; m < mounts + n_mounts; ++m) { - r = make_read_only(m, deny_list, proc_self_mountinfo); - if (r < 0) { - if (error_path && mount_entry_path(m)) - *error_path = strdup(mount_entry_path(m)); - goto finish; - } - } - } + /* Now make the magic happen */ + r = apply_mounts(root, ns_info, mounts, &n_mounts, error_path); + if (r < 0) + goto finish; /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */ r = mount_move_root(root); @@ -1902,6 +2224,16 @@ int setup_namespace( goto finish; } + /* bind_mount_in_namespace() will MS_MOVE into that directory, and that's only + * supported for non-shared mounts. This needs to happen after remounting / or it will fail. */ + if (setup_propagate) { + r = mount(NULL, incoming_dir, NULL, MS_SLAVE, NULL); + if (r < 0) { + log_error_errno(r, "Failed to remount %s with MS_SLAVE: %m", incoming_dir); + goto finish; + } + } + r = 0; finish: @@ -1915,11 +2247,9 @@ finish: } void bind_mount_free_many(BindMount *b, size_t n) { - size_t i; - assert(b || n == 0); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { free(b[i].source); free(b[i].destination); } @@ -1962,12 +2292,10 @@ int bind_mount_add(BindMount **b, size_t *n, const BindMount *item) { } MountImage* mount_image_free_many(MountImage *m, size_t *n) { - size_t i; - assert(n); assert(m || *n == 0); - for (i = 0; i < *n; i++) { + for (size_t i = 0; i < *n; i++) { free(m[i].source); free(m[i].destination); mount_options_free_all(m[i].mount_options); @@ -1992,9 +2320,11 @@ int mount_image_add(MountImage **m, size_t *n, const MountImage *item) { if (!s) return -ENOMEM; - d = strdup(item->destination); - if (!d) - return -ENOMEM; + if (item->destination) { + d = strdup(item->destination); + if (!d) + return -ENOMEM; + } LIST_FOREACH(mount_options, i, item->mount_options) { _cleanup_(mount_options_free_allp) MountOptions *o; @@ -2024,17 +2354,16 @@ int mount_image_add(MountImage **m, size_t *n, const MountImage *item) { .destination = TAKE_PTR(d), .mount_options = TAKE_PTR(options), .ignore_enoent = item->ignore_enoent, + .type = item->type, }; return 0; } void temporary_filesystem_free_many(TemporaryFileSystem *t, size_t n) { - size_t i; - assert(t || n == 0); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { free(t[i].path); free(t[i].options); } @@ -2210,13 +2539,17 @@ int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) { return 0; } -int setup_netns(const int netns_storage_socket[static 2]) { - _cleanup_close_ int netns = -1; +int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag) { + _cleanup_close_ int ns = -1; int r, q; + const char *ns_name, *ns_path; - assert(netns_storage_socket); - assert(netns_storage_socket[0] >= 0); - assert(netns_storage_socket[1] >= 0); + assert(ns_storage_socket); + assert(ns_storage_socket[0] >= 0); + assert(ns_storage_socket[1] >= 0); + + ns_name = namespace_single_flag_to_string(nsflag); + assert(ns_name); /* We use the passed socketpair as a storage buffer for our * namespace reference fd. Whatever process runs this first @@ -2226,35 +2559,36 @@ int setup_netns(const int netns_storage_socket[static 2]) { * * It's a bit crazy, but hey, works great! */ - if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0) + if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0) return -errno; - netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT); - if (netns == -EAGAIN) { + ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT); + if (ns == -EAGAIN) { /* Nothing stored yet, so let's create a new namespace. */ - if (unshare(CLONE_NEWNET) < 0) { + if (unshare(nsflag) < 0) { r = -errno; goto fail; } (void) loopback_setup(); - netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (netns < 0) { + ns_path = strjoina("/proc/self/ns/", ns_name); + ns = open(ns_path, O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (ns < 0) { r = -errno; goto fail; } r = 1; - } else if (netns < 0) { - r = netns; + } else if (ns < 0) { + r = ns; goto fail; } else { /* Yay, found something, so let's join the namespace */ - if (setns(netns, CLONE_NEWNET) < 0) { + if (setns(ns, nsflag) < 0) { r = -errno; goto fail; } @@ -2262,45 +2596,45 @@ int setup_netns(const int netns_storage_socket[static 2]) { r = 0; } - q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT); + q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT); if (q < 0) { r = q; goto fail; } fail: - (void) lockf(netns_storage_socket[0], F_ULOCK, 0); + (void) lockf(ns_storage_socket[0], F_ULOCK, 0); return r; } -int open_netns_path(const int netns_storage_socket[static 2], const char *path) { - _cleanup_close_ int netns = -1; +int open_shareable_ns_path(const int ns_storage_socket[static 2], const char *path, unsigned long nsflag) { + _cleanup_close_ int ns = -1; int q, r; - assert(netns_storage_socket); - assert(netns_storage_socket[0] >= 0); - assert(netns_storage_socket[1] >= 0); + assert(ns_storage_socket); + assert(ns_storage_socket[0] >= 0); + assert(ns_storage_socket[1] >= 0); assert(path); - /* If the storage socket doesn't contain a netns fd yet, open one via the file system and store it in - * it. This is supposed to be called ahead of time, i.e. before setup_netns() which will allocate a - * new anonymous netns if needed. */ + /* If the storage socket doesn't contain a ns fd yet, open one via the file system and store it in + * it. This is supposed to be called ahead of time, i.e. before setup_shareable_ns() which will + * allocate a new anonymous ns if needed. */ - if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0) + if (lockf(ns_storage_socket[0], F_LOCK, 0) < 0) return -errno; - netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT); - if (netns == -EAGAIN) { + ns = receive_one_fd(ns_storage_socket[0], MSG_DONTWAIT); + if (ns == -EAGAIN) { /* Nothing stored yet. Open the file from the file system. */ - netns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (netns < 0) { + ns = open(path, O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (ns < 0) { r = -errno; goto fail; } - r = fd_is_network_ns(netns); - if (r == 0) { /* Not a netns? Refuse early. */ + r = fd_is_ns(ns, nsflag); + if (r == 0) { /* Not a ns of our type? Refuse early. */ r = -EINVAL; goto fail; } @@ -2309,20 +2643,20 @@ int open_netns_path(const int netns_storage_socket[static 2], const char *path) r = 1; - } else if (netns < 0) { - r = netns; + } else if (ns < 0) { + r = ns; goto fail; } else r = 0; /* Already allocated */ - q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT); + q = send_one_fd(ns_storage_socket[1], ns, MSG_DONTWAIT); if (q < 0) { r = q; goto fail; } fail: - (void) lockf(netns_storage_socket[0], F_ULOCK, 0); + (void) lockf(ns_storage_socket[0], F_ULOCK, 0); return r; } diff --git a/src/core/namespace.h b/src/core/namespace.h index da0861c40..2806db8fd 100644 --- a/src/core/namespace.h +++ b/src/core/namespace.h @@ -23,7 +23,7 @@ typedef enum ProtectHome { PROTECT_HOME_READ_ONLY, PROTECT_HOME_TMPFS, _PROTECT_HOME_MAX, - _PROTECT_HOME_INVALID = -1 + _PROTECT_HOME_INVALID = -EINVAL, } ProtectHome; typedef enum NamespaceType { @@ -35,7 +35,7 @@ typedef enum NamespaceType { NAMESPACE_PID, NAMESPACE_NET, _NAMESPACE_TYPE_MAX, - _NAMESPACE_TYPE_INVALID = -1, + _NAMESPACE_TYPE_INVALID = -EINVAL, } NamespaceType; typedef enum ProtectSystem { @@ -44,7 +44,7 @@ typedef enum ProtectSystem { PROTECT_SYSTEM_FULL, PROTECT_SYSTEM_STRICT, _PROTECT_SYSTEM_MAX, - _PROTECT_SYSTEM_INVALID = -1 + _PROTECT_SYSTEM_INVALID = -EINVAL, } ProtectSystem; typedef enum ProtectProc { @@ -53,14 +53,14 @@ typedef enum ProtectProc { PROTECT_PROC_INVISIBLE, /* hidepid=invisible */ PROTECT_PROC_PTRACEABLE, /* hidepid=ptraceable */ _PROTECT_PROC_MAX, - _PROTECT_PROC_INVALID = -1, + _PROTECT_PROC_INVALID = -EINVAL, } ProtectProc; typedef enum ProcSubset { PROC_SUBSET_ALL, PROC_SUBSET_PID, /* subset=pid */ _PROC_SUBSET_MAX, - _PROC_SUBSET_INVALID = -1, + _PROC_SUBSET_INVALID = -EINVAL, } ProcSubset; struct NamespaceInfo { @@ -73,6 +73,7 @@ struct NamespaceInfo { bool protect_kernel_logs; bool mount_apivfs; bool protect_hostname; + bool private_ipc; ProtectHome protect_home; ProtectSystem protect_system; ProtectProc protect_proc; @@ -93,11 +94,19 @@ struct TemporaryFileSystem { char *options; }; +typedef enum MountImageType { + MOUNT_IMAGE_DISCRETE, + MOUNT_IMAGE_EXTENSION, + _MOUNT_IMAGE_TYPE_MAX, + _MOUNT_IMAGE_TYPE_INVALID = -EINVAL, +} MountImageType; + struct MountImage { char *source; - char *destination; + char *destination; /* Unused if MountImageType == MOUNT_IMAGE_EXTENSION */ LIST_HEAD(MountOptions, mount_options); bool ignore_enoent; + MountImageType type; }; int setup_namespace( @@ -108,6 +117,8 @@ int setup_namespace( char **read_write_paths, char **read_only_paths, char **inaccessible_paths, + char **exec_paths, + char **no_exec_paths, char **empty_directories, const BindMount *bind_mounts, size_t n_bind_mounts, @@ -127,16 +138,21 @@ int setup_namespace( size_t root_hash_sig_size, const char *root_hash_sig_path, const char *root_verity, + const MountImage *extension_images, + size_t n_extension_images, + const char *propagate_dir, + const char *incoming_dir, + const char *notify_socket, DissectImageFlags dissected_image_flags, char **error_path); #define RUN_SYSTEMD_EMPTY "/run/systemd/empty" -static inline void namespace_cleanup_tmpdir(char *p) { +static inline char* namespace_cleanup_tmpdir(char *p) { PROTECT_ERRNO; if (!streq_ptr(p, RUN_SYSTEMD_EMPTY)) (void) rmdir(p); - free(p); + return mfree(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, namespace_cleanup_tmpdir); @@ -145,8 +161,8 @@ int setup_tmp_dirs( char **tmp_dir, char **var_tmp_dir); -int setup_netns(const int netns_storage_socket[static 2]); -int open_netns_path(const int netns_storage_socket[static 2], const char *path); +int setup_shareable_ns(const int ns_storage_socket[static 2], unsigned long nsflag); +int open_shareable_ns_path(const int netns_storage_socket[static 2], const char *path, unsigned long nsflag); const char* protect_home_to_string(ProtectHome p) _const_; ProtectHome protect_home_from_string(const char *s) _pure_; diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf index 8b3237983..f405b2765 100644 --- a/src/core/org.freedesktop.systemd1.conf +++ b/src/core/org.freedesktop.systemd1.conf @@ -222,6 +222,14 @@ send_interface="org.freedesktop.systemd1.Manager" send_member="ReloadOrTryRestartUnit"/> + + + + @@ -392,6 +400,14 @@ send_interface="org.freedesktop.systemd1.Service" send_member="AttachProcesses"/> + + + + load_state == UNIT_LOADED); - if (!p->specs) { - log_unit_error(UNIT(p), "Path unit lacks path setting. Refusing."); - return -ENOEXEC; - } + if (!p->specs) + return log_unit_error_errno(UNIT(p), SYNTHETIC_ERRNO(ENOEXEC), "Path unit lacks path setting. Refusing."); return 0; } diff --git a/src/core/path.h b/src/core/path.h index fb33b12ab..66ae857dc 100644 --- a/src/core/path.h +++ b/src/core/path.h @@ -13,7 +13,7 @@ typedef enum PathType { PATH_CHANGED, PATH_MODIFIED, _PATH_TYPE_MAX, - _PATH_TYPE_INVALID = -1 + _PATH_TYPE_INVALID = -EINVAL, } PathType; typedef struct PathSpec { @@ -47,7 +47,7 @@ typedef enum PathResult { PATH_FAILURE_START_LIMIT_HIT, PATH_FAILURE_UNIT_START_LIMIT_HIT, _PATH_RESULT_MAX, - _PATH_RESULT_INVALID = -1 + _PATH_RESULT_INVALID = -EINVAL, } PathResult; struct Path { diff --git a/src/core/scope.c b/src/core/scope.c index 5448d44bd..a247da206 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -131,10 +131,8 @@ static int scope_verify(Scope *s) { if (set_isempty(UNIT(s)->pids) && !MANAGER_IS_RELOADING(UNIT(s)->manager) && - !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) { - log_unit_error(UNIT(s), "Scope has no PIDs. Refusing."); - return -ENOENT; - } + !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOENT), "Scope has no PIDs. Refusing."); return 0; } @@ -500,11 +498,7 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F if (parse_pid(value, &pid) < 0) log_unit_debug(u, "Failed to parse pids value: %s", value); else { - r = set_ensure_allocated(&u->pids, NULL); - if (r < 0) - return r; - - r = set_put(u->pids, PID_TO_PTR(pid)); + r = set_ensure_put(&u->pids, NULL, PID_TO_PTR(pid)); if (r < 0) return r; } diff --git a/src/core/scope.h b/src/core/scope.h index 5f791b7d1..0b0e1f873 100644 --- a/src/core/scope.h +++ b/src/core/scope.h @@ -12,7 +12,7 @@ typedef enum ScopeResult { SCOPE_FAILURE_RESOURCES, SCOPE_FAILURE_TIMEOUT, _SCOPE_RESULT_MAX, - _SCOPE_RESULT_INVALID = -1 + _SCOPE_RESULT_INVALID = -EINVAL, } ScopeResult; struct Scope { diff --git a/src/core/service.c b/src/core/service.c index d7bdeb7cc..df3ed05cf 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -548,51 +548,35 @@ static int service_verify(Service *s) { assert(s); assert(UNIT(s)->load_state == UNIT_LOADED); - if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP] - && UNIT(s)->success_action == EMERGENCY_ACTION_NONE) { + if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP] && + UNIT(s)->success_action == EMERGENCY_ACTION_NONE) /* FailureAction= only makes sense if one of the start or stop commands is specified. * SuccessAction= will be executed unconditionally if no commands are specified. Hence, * either a command or SuccessAction= are required. */ - log_unit_error(UNIT(s), "Service has no ExecStart=, ExecStop=, or SuccessAction=. Refusing."); - return -ENOEXEC; - } + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has no ExecStart=, ExecStop=, or SuccessAction=. Refusing."); - if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) { - log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing."); - return -ENOEXEC; - } + if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing."); - if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START] && UNIT(s)->success_action == EMERGENCY_ACTION_NONE) { - log_unit_error(UNIT(s), "Service has no ExecStart= and no SuccessAction= settings and does not have RemainAfterExit=yes set. Refusing."); - return -ENOEXEC; - } + if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START] && UNIT(s)->success_action == EMERGENCY_ACTION_NONE) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has no ExecStart= and no SuccessAction= settings and does not have RemainAfterExit=yes set. Refusing."); - if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) { - log_unit_error(UNIT(s), "Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing."); - return -ENOEXEC; - } + if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing."); - if (s->type == SERVICE_ONESHOT - && !IN_SET(s->restart, SERVICE_RESTART_NO, SERVICE_RESTART_ON_FAILURE, SERVICE_RESTART_ON_ABNORMAL, SERVICE_RESTART_ON_WATCHDOG, SERVICE_RESTART_ON_ABORT)) { - log_unit_error(UNIT(s), "Service has Restart= set to either always or on-success, which isn't allowed for Type=oneshot services. Refusing."); - return -ENOEXEC; - } + if (s->type == SERVICE_ONESHOT && + !IN_SET(s->restart, SERVICE_RESTART_NO, SERVICE_RESTART_ON_FAILURE, SERVICE_RESTART_ON_ABNORMAL, SERVICE_RESTART_ON_WATCHDOG, SERVICE_RESTART_ON_ABORT)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has Restart= set to either always or on-success, which isn't allowed for Type=oneshot services. Refusing."); - if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) { - log_unit_error(UNIT(s), "Service has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing."); - return -ENOEXEC; - } + if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing."); - if (s->type == SERVICE_DBUS && !s->bus_name) { - log_unit_error(UNIT(s), "Service is of type D-Bus but no D-Bus service name has been specified. Refusing."); - return -ENOEXEC; - } + if (s->type == SERVICE_DBUS && !s->bus_name) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service is of type D-Bus but no D-Bus service name has been specified. Refusing."); - if (s->exec_context.pam_name && !IN_SET(s->kill_context.kill_mode, KILL_CONTROL_GROUP, KILL_MIXED)) { - log_unit_error(UNIT(s), "Service has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing."); - return -ENOEXEC; - } + if (s->exec_context.pam_name && !IN_SET(s->kill_context.kill_mode, KILL_CONTROL_GROUP, KILL_MIXED)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Service has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing."); if (s->usb_function_descriptors && !s->usb_function_strings) log_unit_warning(UNIT(s), "Service has USBFunctionDescriptors= setting, but no USBFunctionStrings=. Ignoring."); @@ -914,20 +898,14 @@ static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) { * PID is questionnable but should be accepted if the source of configuration is trusted. > 0 if the PID is * good */ - if (pid == getpid_cached() || pid == 1) { - log_unit_full(UNIT(s), prio, "New main PID "PID_FMT" is the manager, refusing.", pid); - return -EPERM; - } + if (pid == getpid_cached() || pid == 1) + return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the manager, refusing.", pid); - if (pid == s->control_pid) { - log_unit_full(UNIT(s), prio, "New main PID "PID_FMT" is the control process, refusing.", pid); - return -EPERM; - } + if (pid == s->control_pid) + return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the control process, refusing.", pid); - if (!pid_is_alive(pid)) { - log_unit_full(UNIT(s), prio, "New main PID "PID_FMT" does not exist or is a zombie.", pid); - return -ESRCH; - } + if (!pid_is_alive(pid)) + return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(ESRCH), "New main PID "PID_FMT" does not exist or is a zombie.", pid); owner = manager_get_unit_by_pid(UNIT(s)->manager, pid); if (owner == UNIT(s)) { @@ -988,20 +966,18 @@ static int service_load_pid_file(Service *s, bool may_warn) { if (r == 0) { struct stat st; - if (questionable_pid_file) { - log_unit_error(UNIT(s), "Refusing to accept PID outside of service control group, acquired through unsafe symlink chain: %s", s->pid_file); - return -EPERM; - } + if (questionable_pid_file) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(EPERM), + "Refusing to accept PID outside of service control group, acquired through unsafe symlink chain: %s", s->pid_file); /* Hmm, it's not clear if the new main PID is safe. Let's allow this if the PID file is owned by root */ if (fstat(fd, &st) < 0) return log_unit_error_errno(UNIT(s), errno, "Failed to fstat() PID file O_PATH fd: %m"); - if (st.st_uid != 0) { - log_unit_error(UNIT(s), "New main PID "PID_FMT" does not belong to service, and PID file is not owned by root. Refusing.", pid); - return -EPERM; - } + if (st.st_uid != 0) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(EPERM), + "New main PID "PID_FMT" does not belong to service, and PID file is not owned by root. Refusing.", pid); log_unit_debug(UNIT(s), "New main PID "PID_FMT" does not belong to service, but we'll accept it since PID file is owned by root.", pid); } @@ -1129,8 +1105,7 @@ static void service_set_state(Service *s, ServiceState state) { unit_notify(UNIT(s), table[old_state], table[state], (s->reload_result == SERVICE_SUCCESS ? 0 : UNIT_NOTIFY_RELOAD_FAILURE) | - (s->will_auto_restart ? UNIT_NOTIFY_WILL_AUTO_RESTART : 0) | - (s->result == SERVICE_SKIP_CONDITION ? UNIT_NOTIFY_SKIP_CONDITION : 0)); + (s->will_auto_restart ? UNIT_NOTIFY_WILL_AUTO_RESTART : 0)); } static usec_t service_coldplug_timeout(Service *s) { @@ -1498,10 +1473,13 @@ static int service_spawn( if (!our_env) return -ENOMEM; - if (service_exec_needs_notify_socket(s, flags)) + if (service_exec_needs_notify_socket(s, flags)) { if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) return -ENOMEM; + exec_params.notify_socket = UNIT(s)->manager->notify_socket; + } + if (s->main_pid > 0) if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) return -ENOMEM; @@ -2127,8 +2105,7 @@ static void service_enter_start(Service *s) { /* There's no command line configured for the main command? Hmm, that is strange. * This can only happen if the configuration changes at runtime. In this case, * let's enter a failure state. */ - log_unit_error(UNIT(s), "There's no 'start' task anymore we could start."); - r = -ENXIO; + r = log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENXIO), "There's no 'start' task anymore we could start."); goto fail; } @@ -2761,7 +2738,7 @@ static int service_deserialize_exec_command( STATE_EXEC_COMMAND_PATH, STATE_EXEC_COMMAND_ARGS, _STATE_EXEC_COMMAND_MAX, - _STATE_EXEC_COMMAND_INVALID = -1, + _STATE_EXEC_COMMAND_INVALID = -EINVAL, } state; assert(s); @@ -2785,14 +2762,14 @@ static int service_deserialize_exec_command( case STATE_EXEC_COMMAND_TYPE: id = service_exec_command_from_string(arg); if (id < 0) - return -EINVAL; + return id; state = STATE_EXEC_COMMAND_INDEX; break; case STATE_EXEC_COMMAND_INDEX: r = safe_atou(arg, &idx); if (r < 0) - return -EINVAL; + return r; state = STATE_EXEC_COMMAND_PATH; break; @@ -3546,10 +3523,6 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { } else if (s->control_pid == pid) { s->control_pid = 0; - /* ExecCondition= calls that exit with (0, 254] should invoke skip-like behavior instead of failing */ - if (f == SERVICE_FAILURE_EXIT_CODE && s->state == SERVICE_CONDITION && status < 255) - f = SERVICE_SKIP_CONDITION; - if (s->control_command) { exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status); @@ -3557,6 +3530,15 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { f = SERVICE_SUCCESS; } + /* ExecCondition= calls that exit with (0, 254] should invoke skip-like behavior instead of failing */ + if (s->state == SERVICE_CONDITION) { + if (f == SERVICE_FAILURE_EXIT_CODE && status < 255) { + UNIT(s)->condition_result = false; + f = SERVICE_SKIP_CONDITION; + } else if (f == SERVICE_SUCCESS) + UNIT(s)->condition_result = true; + } + unit_log_process_exit( u, "Control process", @@ -4601,7 +4583,6 @@ const UnitVTable service_vtable = { }, .finished_start_job = { [JOB_FAILED] = "Failed to start %s.", - [JOB_SKIPPED] = "Skipped %s.", }, .finished_stop_job = { [JOB_DONE] = "Stopped %s.", diff --git a/src/core/service.h b/src/core/service.h index 11c3d3f37..af474aa40 100644 --- a/src/core/service.h +++ b/src/core/service.h @@ -20,7 +20,7 @@ typedef enum ServiceRestart { SERVICE_RESTART_ON_ABORT, SERVICE_RESTART_ALWAYS, _SERVICE_RESTART_MAX, - _SERVICE_RESTART_INVALID = -1 + _SERVICE_RESTART_INVALID = -EINVAL, } ServiceRestart; typedef enum ServiceType { @@ -32,7 +32,7 @@ typedef enum ServiceType { SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */ SERVICE_EXEC, /* we fork and wait until we execute exec() (this means our own setup is waited for) */ _SERVICE_TYPE_MAX, - _SERVICE_TYPE_INVALID = -1 + _SERVICE_TYPE_INVALID = -EINVAL, } ServiceType; typedef enum ServiceExecCommand { @@ -44,7 +44,7 @@ typedef enum ServiceExecCommand { SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST, _SERVICE_EXEC_COMMAND_MAX, - _SERVICE_EXEC_COMMAND_INVALID = -1 + _SERVICE_EXEC_COMMAND_INVALID = -EINVAL, } ServiceExecCommand; typedef enum NotifyState { @@ -53,7 +53,7 @@ typedef enum NotifyState { NOTIFY_RELOADING, NOTIFY_STOPPING, _NOTIFY_STATE_MAX, - _NOTIFY_STATE_INVALID = -1 + _NOTIFY_STATE_INVALID = -EINVAL, } NotifyState; /* The values of this enum are referenced in man/systemd.exec.xml and src/shared/bus-unit-util.c. @@ -71,7 +71,7 @@ typedef enum ServiceResult { SERVICE_FAILURE_OOM_KILL, SERVICE_SKIP_CONDITION, _SERVICE_RESULT_MAX, - _SERVICE_RESULT_INVALID = -1 + _SERVICE_RESULT_INVALID = -EINVAL, } ServiceResult; typedef enum ServiceTimeoutFailureMode { @@ -79,7 +79,7 @@ typedef enum ServiceTimeoutFailureMode { SERVICE_TIMEOUT_ABORT, SERVICE_TIMEOUT_KILL, _SERVICE_TIMEOUT_FAILURE_MODE_MAX, - _SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -1 + _SERVICE_TIMEOUT_FAILURE_MODE_INVALID = -EINVAL, } ServiceTimeoutFailureMode; struct ServiceFDStore { diff --git a/src/core/show-status.h b/src/core/show-status.h index c37ccd908..dfcf5f410 100644 --- a/src/core/show-status.h +++ b/src/core/show-status.h @@ -14,7 +14,7 @@ typedef enum ShowStatus { SHOW_STATUS_TEMPORARY, /* enabled temporarily, may flip back to _AUTO */ SHOW_STATUS_YES, /* printing of status is enabled */ _SHOW_STATUS_MAX, - _SHOW_STATUS_INVALID = -1, + _SHOW_STATUS_INVALID = -EINVAL, } ShowStatus; typedef enum ShowStatusFlags { @@ -26,7 +26,7 @@ typedef enum StatusUnitFormat { STATUS_UNIT_FORMAT_NAME, STATUS_UNIT_FORMAT_DESCRIPTION, _STATUS_UNIT_FORMAT_MAX, - _STATUS_UNIT_FORMAT_INVALID = -1, + _STATUS_UNIT_FORMAT_INVALID = -EINVAL, } StatusUnitFormat; static inline bool show_status_on(ShowStatus s) { diff --git a/src/core/slice.c b/src/core/slice.c index ee5c25932..94eb56e1c 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -94,19 +94,15 @@ static int slice_verify(Slice *s) { assert(s); assert(UNIT(s)->load_state == UNIT_LOADED); - if (!slice_name_is_valid(UNIT(s)->id)) { - log_unit_error(UNIT(s), "Slice name %s is not valid. Refusing.", UNIT(s)->id); - return -ENOEXEC; - } + if (!slice_name_is_valid(UNIT(s)->id)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Slice name %s is not valid. Refusing.", UNIT(s)->id); r = slice_build_parent_slice(UNIT(s)->id, &parent); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m"); - if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) { - log_unit_error(UNIT(s), "Located outside of parent slice. Refusing."); - return -ENOEXEC; - } + if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Located outside of parent slice. Refusing."); return 0; } diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c index 1fe592af7..8cc1696a4 100644 --- a/src/core/smack-setup.c +++ b/src/core/smack-setup.c @@ -384,8 +384,7 @@ int mac_smack_setup(bool *loaded_policy) { log_info("Successfully wrote Smack onlycap list."); break; default: - log_emergency_errno(r, "Failed to write Smack onlycap list: %m"); - return r; + return log_emergency_errno(r, "Failed to write Smack onlycap list: %m"); } *loaded_policy = true; diff --git a/src/core/socket.c b/src/core/socket.c index 7f8ac4eae..016986401 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -99,7 +99,7 @@ static void socket_init(Unit *u) { s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID; s->trigger_limit.interval = USEC_INFINITY; - s->trigger_limit.burst = (unsigned) -1; + s->trigger_limit.burst = UINT_MAX; } static void socket_unwatch_control_pid(Socket *s) { @@ -313,7 +313,7 @@ static int socket_add_extras(Socket *s) { if (s->trigger_limit.interval == USEC_INFINITY) s->trigger_limit.interval = 2 * USEC_PER_SEC; - if (s->trigger_limit.burst == (unsigned) -1) { + if (s->trigger_limit.burst == UINT_MAX) { if (s->accept) s->trigger_limit.burst = 200; else @@ -402,35 +402,23 @@ static int socket_verify(Socket *s) { assert(s); assert(UNIT(s)->load_state == UNIT_LOADED); - if (!s->ports) { - log_unit_error(UNIT(s), "Unit has no Listen setting (ListenStream=, ListenDatagram=, ListenFIFO=, ...). Refusing."); - return -ENOEXEC; - } + if (!s->ports) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Unit has no Listen setting (ListenStream=, ListenDatagram=, ListenFIFO=, ...). Refusing."); - if (s->accept && have_non_accept_socket(s)) { - log_unit_error(UNIT(s), "Unit configured for accepting sockets, but sockets are non-accepting. Refusing."); - return -ENOEXEC; - } + if (s->accept && have_non_accept_socket(s)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Unit configured for accepting sockets, but sockets are non-accepting. Refusing."); - if (s->accept && s->max_connections <= 0) { - log_unit_error(UNIT(s), "MaxConnection= setting too small. Refusing."); - return -ENOEXEC; - } + if (s->accept && s->max_connections <= 0) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "MaxConnection= setting too small. Refusing."); - if (s->accept && UNIT_DEREF(s->service)) { - log_unit_error(UNIT(s), "Explicit service configuration for accepting socket units not supported. Refusing."); - return -ENOEXEC; - } + if (s->accept && UNIT_DEREF(s->service)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Explicit service configuration for accepting socket units not supported. Refusing."); - if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { - log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing."); - return -ENOEXEC; - } + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing."); - if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) { - log_unit_error(UNIT(s), "Unit has symlinks set but none or more than one node in the file system. Refusing."); - return -ENOEXEC; - } + if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Unit has symlinks set but none or more than one node in the file system. Refusing."); return 0; } @@ -981,6 +969,8 @@ static void socket_close_fds(Socket *s) { if (s->remove_on_stop) STRV_FOREACH(i, s->symlinks) (void) unlink(*i); + + /* Note that we don't return NULL here, since s has not been freed. */ } static void socket_apply_socket_options(Socket *s, SocketPort *p, int fd) { @@ -1331,7 +1321,7 @@ static int usbffs_select_ep(const struct dirent *d) { static int usbffs_dispatch_eps(SocketPort *p) { _cleanup_free_ struct dirent **ent = NULL; - size_t n, k, i; + size_t n, k; int r; r = scandir(p->path, &ent, usbffs_select_ep, alphasort); @@ -1348,7 +1338,7 @@ static int usbffs_dispatch_eps(SocketPort *p) { p->n_auxiliary_fds = n; k = 0; - for (i = 0; i < n; ++i) { + for (size_t i = 0; i < n; ++i) { _cleanup_free_ char *ep = NULL; ep = path_make_absolute(ent[i]->d_name, p->path); @@ -1375,7 +1365,7 @@ fail: p->n_auxiliary_fds = 0; clear: - for (i = 0; i < n; ++i) + for (size_t i = 0; i < n; ++i) free(ent[i]); return r; @@ -1557,11 +1547,19 @@ static int socket_address_listen_in_cgroup( if (s->exec_context.network_namespace_path && s->exec_runtime && s->exec_runtime->netns_storage_socket[0] >= 0) { - r = open_netns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path); + r = open_shareable_ns_path(s->exec_runtime->netns_storage_socket, s->exec_context.network_namespace_path, CLONE_NEWNET); if (r < 0) return log_unit_error_errno(UNIT(s), r, "Failed to open network namespace path %s: %m", s->exec_context.network_namespace_path); } + if (s->exec_context.ipc_namespace_path && + s->exec_runtime && + s->exec_runtime->ipcns_storage_socket[0] >= 0) { + r = open_shareable_ns_path(s->exec_runtime->ipcns_storage_socket, s->exec_context.ipc_namespace_path, CLONE_NEWIPC); + if (r < 0) + return log_unit_error_errno(UNIT(s), r, "Failed to open IPC namespace path %s: %m", s->exec_context.ipc_namespace_path); + } + if (socketpair(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC, 0, pair) < 0) return log_unit_error_errno(UNIT(s), errno, "Failed to create communication channel: %m"); @@ -1578,7 +1576,7 @@ static int socket_address_listen_in_cgroup( s->exec_runtime->netns_storage_socket[0] >= 0) { if (ns_type_supported(NAMESPACE_NET)) { - r = setup_netns(s->exec_runtime->netns_storage_socket); + r = setup_shareable_ns(s->exec_runtime->netns_storage_socket, CLONE_NEWNET); if (r < 0) { log_unit_error_errno(UNIT(s), r, "Failed to join network namespace: %m"); _exit(EXIT_NETWORK); @@ -1621,10 +1619,10 @@ static int socket_address_listen_in_cgroup( return fd; } -DEFINE_TRIVIAL_CLEANUP_FUNC(Socket *, socket_close_fds); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(Socket *, socket_close_fds, NULL); -static int socket_open_fds(Socket *_s) { - _cleanup_(socket_close_fdsp) Socket *s = _s; +static int socket_open_fds(Socket *orig_s) { + _cleanup_(socket_close_fdsp) Socket *s = orig_s; _cleanup_(mac_selinux_freep) char *label = NULL; bool know_label = false; SocketPort *p; @@ -2507,17 +2505,13 @@ static int socket_start(Unit *u) { service = SERVICE(UNIT_DEREF(s->service)); - if (UNIT(service)->load_state != UNIT_LOADED) { - log_unit_error(u, "Socket service %s not loaded, refusing.", UNIT(service)->id); - return -ENOENT; - } + if (UNIT(service)->load_state != UNIT_LOADED) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT), "Socket service %s not loaded, refusing.", UNIT(service)->id); /* If the service is already active we cannot start the * socket */ - if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) { - log_unit_error(u, "Socket service %s already active, refusing.", UNIT(service)->id); - return -EBUSY; - } + if (!IN_SET(service->state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART)) + return log_unit_error_errno(u, SYNTHETIC_ERRNO(EBUSY), "Socket service %s already active, refusing.", UNIT(service)->id); } assert(IN_SET(s->state, SOCKET_DEAD, SOCKET_FAILED)); diff --git a/src/core/socket.h b/src/core/socket.h index ebe85c2aa..a65195f2a 100644 --- a/src/core/socket.h +++ b/src/core/socket.h @@ -16,7 +16,7 @@ typedef enum SocketExecCommand { SOCKET_EXEC_STOP_PRE, SOCKET_EXEC_STOP_POST, _SOCKET_EXEC_COMMAND_MAX, - _SOCKET_EXEC_COMMAND_INVALID = -1 + _SOCKET_EXEC_COMMAND_INVALID = -EINVAL, } SocketExecCommand; typedef enum SocketType { @@ -26,7 +26,7 @@ typedef enum SocketType { SOCKET_MQUEUE, SOCKET_USB_FUNCTION, _SOCKET_TYPE_MAX, - _SOCKET_TYPE_INVALID = -1 + _SOCKET_TYPE_INVALID = -EINVAL, } SocketType; typedef enum SocketResult { @@ -40,7 +40,7 @@ typedef enum SocketResult { SOCKET_FAILURE_TRIGGER_LIMIT_HIT, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT, _SOCKET_RESULT_MAX, - _SOCKET_RESULT_INVALID = -1 + _SOCKET_RESULT_INVALID = -EINVAL, } SocketResult; typedef struct SocketPort { @@ -63,7 +63,7 @@ typedef enum SocketTimestamping { SOCKET_TIMESTAMPING_US, /* SO_TIMESTAMP */ SOCKET_TIMESTAMPING_NS, /* SO_TIMESTAMPNS */ _SOCKET_TIMESTAMPING_MAX, - _SOCKET_TIMESTAMPING_INVALID = -1, + _SOCKET_TIMESTAMPING_INVALID = -EINVAL, } SocketTimestamping; struct Socket { diff --git a/src/core/swap.c b/src/core/swap.c index 76e491ad9..a81b1928b 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -10,7 +10,6 @@ #include "alloc-util.h" #include "dbus-swap.h" #include "dbus-unit.h" -#include "device-private.h" #include "device-util.h" #include "device.h" #include "escape.h" @@ -287,15 +286,11 @@ static int swap_verify(Swap *s) { if (r < 0) return log_unit_error_errno(UNIT(s), r, "Failed to generate unit name from path: %m"); - if (!unit_has_name(UNIT(s), e)) { - log_unit_error(UNIT(s), "Value of What= and unit name do not match, not loading."); - return -ENOEXEC; - } + if (!unit_has_name(UNIT(s), e)) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Value of What= and unit name do not match, not loading."); - if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) { - log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load."); - return -ENOEXEC; - } + if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) + return log_unit_error_errno(UNIT(s), SYNTHETIC_ERRNO(ENOEXEC), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load."); return 0; } @@ -311,7 +306,7 @@ static int swap_load_devnode(Swap *s) { if (stat(s->what, &st) < 0 || !S_ISBLK(st.st_mode)) return 0; - r = device_new_from_stat_rdev(&d, &st); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) { log_unit_full_errno(UNIT(s), r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to allocate device for swap %s: %m", s->what); @@ -514,7 +509,7 @@ static int swap_process_new(Manager *m, const char *device, int prio, bool set_f if (stat(device, &st) < 0 || !S_ISBLK(st.st_mode)) return 0; - r = device_new_from_stat_rdev(&d, &st); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) { log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to allocate device for swap %s: %m", device); @@ -1187,15 +1182,13 @@ static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userd } static int swap_load_proc_swaps(Manager *m, bool set_flags) { - unsigned i; - assert(m); rewind(m->proc_swaps); (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n"); - for (i = 1;; i++) { + for (unsigned i = 1;; i++) { _cleanup_free_ char *dev = NULL, *d = NULL; int prio = 0, k; diff --git a/src/core/swap.h b/src/core/swap.h index 6ce9bfd9b..c0e3f118e 100644 --- a/src/core/swap.h +++ b/src/core/swap.h @@ -14,7 +14,7 @@ typedef enum SwapExecCommand { SWAP_EXEC_ACTIVATE, SWAP_EXEC_DEACTIVATE, _SWAP_EXEC_COMMAND_MAX, - _SWAP_EXEC_COMMAND_INVALID = -1 + _SWAP_EXEC_COMMAND_INVALID = -EINVAL, } SwapExecCommand; typedef enum SwapResult { @@ -26,7 +26,7 @@ typedef enum SwapResult { SWAP_FAILURE_CORE_DUMP, SWAP_FAILURE_START_LIMIT_HIT, _SWAP_RESULT_MAX, - _SWAP_RESULT_INVALID = -1 + _SWAP_RESULT_INVALID = -EINVAL, } SwapResult; typedef struct SwapParameters { diff --git a/src/core/system.conf.in b/src/core/system.conf.in index 40bb54888..fa6fb690c 100644 --- a/src/core/system.conf.in +++ b/src/core/system.conf.in @@ -1,13 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. +# +# Use 'systemd-analyze cat-config systemd/system.conf' to display the full config. # # See systemd-system.conf(5) for details. @@ -23,7 +26,7 @@ #CrashShell=no #CrashReboot=no #CtrlAltDelBurstAction=reboot-force -#CPUAffinity=1 2 +#CPUAffinity= #NUMAPolicy=default #NUMAMask= #RuntimeWatchdogSec=0 diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in index f2c045511..b5cc8f94a 100644 --- a/src/core/systemd.pc.in +++ b/src/core/systemd.pc.in @@ -26,10 +26,10 @@ systemdsystemunitdir=${systemd_system_unit_dir} systemd_system_preset_dir=${rootprefix}/lib/systemd/system-preset systemdsystempresetdir=${systemd_system_preset_dir} -systemd_user_unit_dir=/usr/lib/systemd/user +systemd_user_unit_dir=${prefix}/lib/systemd/user systemduserunitdir=${systemd_user_unit_dir} -systemd_user_preset_dir=/usr/lib/systemd/user-preset +systemd_user_preset_dir=${prefix}/lib/systemd/user-preset systemduserpresetdir=${systemd_user_preset_dir} systemd_system_conf_dir=${sysconfdir}/systemd/system @@ -47,7 +47,7 @@ systemduserunitpath=${systemd_user_unit_path} systemd_system_generator_dir=${root_prefix}/lib/systemd/system-generators systemdsystemgeneratordir=${systemd_system_generator_dir} -systemd_user_generator_dir=/usr/lib/systemd/user-generators +systemd_user_generator_dir=${prefix}/lib/systemd/user-generators systemdusergeneratordir=${systemd_user_generator_dir} systemd_system_generator_path=/run/systemd/system-generators:/etc/systemd/system-generators:/usr/local/lib/systemd/system-generators:${systemd_system_generator_dir} @@ -62,7 +62,7 @@ systemdsleepdir=${systemd_sleep_dir} systemd_shutdown_dir=${root_prefix}/lib/systemd/system-shutdown systemdshutdowndir=${systemd_shutdown_dir} -tmpfiles_dir=/usr/lib/tmpfiles.d +tmpfiles_dir=${prefix}/lib/tmpfiles.d tmpfilesdir=${tmpfiles_dir} sysusers_dir=${rootprefix}/lib/sysusers.d @@ -77,7 +77,7 @@ binfmtdir=${binfmt_dir} modules_load_dir=${rootprefix}/lib/modules-load.d modulesloaddir=${modules_load_dir} -catalog_dir=/usr/lib/systemd/catalog +catalog_dir=${prefix}/lib/systemd/catalog catalogdir=${catalog_dir} system_uid_max=@SYSTEM_UID_MAX@ diff --git a/src/core/target.c b/src/core/target.c index a42205680..5755f2661 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -45,7 +45,6 @@ static int target_add_default_dependencies(Target *t) { }; int r; - unsigned k; assert(t); @@ -55,7 +54,7 @@ static int target_add_default_dependencies(Target *t) { /* Imply ordering for requirement dependencies on target units. Note that when the user created a contradicting * ordering manually we won't add anything in here to make sure we don't create a loop. */ - for (k = 0; k < ELEMENTSOF(deps); k++) { + for (size_t k = 0; k < ELEMENTSOF(deps); k++) { Unit *other; void *v; diff --git a/src/core/timer.c b/src/core/timer.c index 651f18b5a..32abdb74d 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -75,10 +75,8 @@ static int timer_verify(Timer *t) { assert(t); assert(UNIT(t)->load_state == UNIT_LOADED); - if (!t->values && !t->on_clock_change && !t->on_timezone_change) { - log_unit_error(UNIT(t), "Timer unit lacks value setting. Refusing."); - return -ENOEXEC; - } + if (!t->values && !t->on_clock_change && !t->on_timezone_change) + return log_unit_error_errno(UNIT(t), SYNTHETIC_ERRNO(ENOEXEC), "Timer unit lacks value setting. Refusing."); return 0; } @@ -102,12 +100,18 @@ static int timer_add_default_dependencies(Timer *t) { return r; LIST_FOREACH(value, v, t->values) { - if (v->base == TIMER_CALENDAR) { - r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, true, UNIT_DEPENDENCY_DEFAULT); + const char *target; + + if (v->base != TIMER_CALENDAR) + continue; + + FOREACH_STRING(target, SPECIAL_TIME_SYNC_TARGET, SPECIAL_TIME_SET_TARGET) { + r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, target, true, UNIT_DEPENDENCY_DEFAULT); if (r < 0) return r; - break; } + + break; } } @@ -259,8 +263,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) { prefix, yes_no(t->on_clock_change), prefix, yes_no(t->on_timezone_change)); - LIST_FOREACH(value, v, t->values) { - + LIST_FOREACH(value, v, t->values) if (v->base == TIMER_CALENDAR) { _cleanup_free_ char *p = NULL; @@ -280,7 +283,6 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) { timer_base_to_string(v->base), format_timespan(timespan1, sizeof(timespan1), v->value, 0)); } - } } static void timer_set_state(Timer *t, TimerState state) { @@ -670,9 +672,7 @@ static int timer_start(Unit *u) { } } else if (errno == ENOENT) - /* The timer has never run before, - * make sure a stamp file exists. - */ + /* The timer has never run before, make sure a stamp file exists. */ (void) touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID); } diff --git a/src/core/timer.h b/src/core/timer.h index 14fa31706..a51fbf56f 100644 --- a/src/core/timer.h +++ b/src/core/timer.h @@ -14,7 +14,7 @@ typedef enum TimerBase { TIMER_UNIT_INACTIVE, TIMER_CALENDAR, _TIMER_BASE_MAX, - _TIMER_BASE_INVALID = -1 + _TIMER_BASE_INVALID = -EINVAL, } TimerBase; typedef struct TimerValue { @@ -33,7 +33,7 @@ typedef enum TimerResult { TIMER_FAILURE_RESOURCES, TIMER_FAILURE_START_LIMIT_HIT, _TIMER_RESULT_MAX, - _TIMER_RESULT_INVALID = -1 + _TIMER_RESULT_INVALID = -EINVAL, } TimerResult; struct Timer { diff --git a/src/core/transaction.c b/src/core/transaction.c index ae77bae65..1d3cf8f1f 100644 --- a/src/core/transaction.c +++ b/src/core/transaction.c @@ -405,7 +405,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi j->unit->id, unit_id == array ? "ordering cycle" : "dependency", *unit_id, *job_type, - unit_ids); + "%s", unit_ids); if (delete) { const char *status; @@ -414,7 +414,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi "MESSAGE=%s: Job %s/%s deleted to break ordering cycle starting with %s/%s", j->unit->id, delete->unit->id, job_type_to_string(delete->type), j->unit->id, job_type_to_string(j->type), - unit_ids); + "%s", unit_ids); if (log_get_show_color()) status = ANSI_HIGHLIGHT_RED " SKIP " ANSI_NORMAL; @@ -432,7 +432,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi log_struct(LOG_ERR, "MESSAGE=%s: Unable to break cycle starting with %s/%s", j->unit->id, j->unit->id, job_type_to_string(j->type), - unit_ids); + "%s", unit_ids); return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details."); @@ -648,11 +648,7 @@ static int transaction_apply( assert(!j->transaction_prev); assert(!j->transaction_next); - r = hashmap_ensure_allocated(&m->jobs, NULL); - if (r < 0) - return r; - - r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j); + r = hashmap_ensure_put(&m->jobs, NULL, UINT32_TO_PTR(j->id), j); if (r < 0) goto rollback; } diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c index 0c1e20d9c..8e50a81b9 100644 --- a/src/core/unit-printf.c +++ b/src/core/unit-printf.c @@ -181,7 +181,7 @@ int unit_name_printf(const Unit *u, const char* format, char **ret) { * %N: the id of the unit without the suffix (foo-aaa@bar) * %p: the prefix (foo-aaa) * %i: the instance (bar) - * %j: the last componet of the prefix (aaa) + * %j: the last component of the prefix (aaa) */ const Specifier table[] = { diff --git a/src/core/unit-serialize.c b/src/core/unit-serialize.c new file mode 100644 index 000000000..3f099248c --- /dev/null +++ b/src/core/unit-serialize.c @@ -0,0 +1,780 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "bus-util.h" +#include "dbus.h" +#include "fileio-label.h" +#include "fileio.h" +#include "format-util.h" +#include "parse-util.h" +#include "serialize.h" +#include "string-table.h" +#include "unit-serialize.h" +#include "user-util.h" + +static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) { + _cleanup_free_ char *s = NULL; + int r; + + assert(f); + assert(key); + + if (mask == 0) + return 0; + + r = cg_mask_to_string(mask, &s); + if (r < 0) + return log_error_errno(r, "Failed to format cgroup mask: %m"); + + return serialize_item(f, key, s); +} + +/* Make sure out values fit in the bitfield. */ +assert_cc(_UNIT_MARKER_MAX <= sizeof(((Unit){}).markers) * 8); + +static int serialize_markers(FILE *f, unsigned markers) { + assert(f); + + if (markers == 0) + return 0; + + fputs("markers=", f); + for (UnitMarker m = 0; m < _UNIT_MARKER_MAX; m++) + if (FLAGS_SET(markers, 1u << m)) + fputs(unit_marker_to_string(m), f); + fputc('\n', f); + return 0; +} + +static int deserialize_markers(Unit *u, const char *value) { + assert(u); + assert(value); + int r; + + for (const char *p = value;;) { + _cleanup_free_ char *word = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r <= 0) + return r; + + UnitMarker m = unit_marker_from_string(word); + if (m < 0) { + log_unit_debug_errno(u, m, "Unknown unit marker \"%s\", ignoring.", word); + continue; + } + + u->markers |= 1u << m; + } +} + +static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes", + [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets", + [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes", + [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets", +}; + +static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base", + [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base", + [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base", + [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base", +}; + +static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { + [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last", + [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last", + [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last", + [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last", +}; + +int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { + int r; + + assert(u); + assert(f); + assert(fds); + + if (unit_can_serialize(u)) { + r = UNIT_VTABLE(u)->serialize(u, f, fds); + if (r < 0) + return r; + } + + (void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp); + + (void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); + (void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp); + (void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp); + (void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); + + (void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp); + (void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp); + + if (dual_timestamp_is_set(&u->condition_timestamp)) + (void) serialize_bool(f, "condition-result", u->condition_result); + + if (dual_timestamp_is_set(&u->assert_timestamp)) + (void) serialize_bool(f, "assert-result", u->assert_result); + + (void) serialize_bool(f, "transient", u->transient); + (void) serialize_bool(f, "in-audit", u->in_audit); + + (void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id); + (void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max); + (void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields); + (void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval); + (void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst); + + (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base); + if (u->cpu_usage_last != NSEC_INFINITY) + (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last); + + if (u->managed_oom_kill_last > 0) + (void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last); + + if (u->oom_kill_last > 0) + (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last); + + for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) { + (void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]); + + if (u->io_accounting_last[im] != UINT64_MAX) + (void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]); + } + + if (u->cgroup_path) + (void) serialize_item(f, "cgroup", u->cgroup_path); + + (void) serialize_bool(f, "cgroup-realized", u->cgroup_realized); + (void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask); + (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask); + (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask); + + if (uid_is_valid(u->ref_uid)) + (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid); + if (gid_is_valid(u->ref_gid)) + (void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid); + + if (!sd_id128_is_null(u->invocation_id)) + (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)); + + (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u))); + (void) serialize_markers(f, u->markers); + + bus_track_serialize(u->bus_track, f, "ref"); + + for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) { + uint64_t v; + + r = unit_get_ip_accounting(u, m, &v); + if (r >= 0) + (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v); + } + + if (serialize_jobs) { + if (u->job) { + fputs("job\n", f); + job_serialize(u->job, f); + } + + if (u->nop_job) { + fputs("job\n", f); + job_serialize(u->nop_job, f); + } + } + + /* End marker */ + fputc('\n', f); + return 0; +} + +static int unit_deserialize_job(Unit *u, FILE *f) { + _cleanup_(job_freep) Job *j = NULL; + int r; + + assert(u); + assert(f); + + j = job_new_raw(u); + if (!j) + return log_oom(); + + r = job_deserialize(j, f); + if (r < 0) + return r; + + r = job_install_deserialized(j); + if (r < 0) + return r; + + TAKE_PTR(j); + return 0; +} + +#define MATCH_DESERIALIZE(key, l, v, parse_func, target) \ + ({ \ + bool _deserialize_matched = streq(l, key); \ + if (_deserialize_matched) { \ + int _deserialize_r = parse_func(v); \ + if (_deserialize_r < 0) \ + log_unit_debug_errno(u, _deserialize_r, \ + "Failed to parse \"%s=%s\", ignoring.", l, v); \ + else \ + target = _deserialize_r; \ + }; \ + _deserialize_matched; \ + }) + +#define MATCH_DESERIALIZE_IMMEDIATE(key, l, v, parse_func, target) \ + ({ \ + bool _deserialize_matched = streq(l, key); \ + if (_deserialize_matched) { \ + int _deserialize_r = parse_func(v, &target); \ + if (_deserialize_r < 0) \ + log_unit_debug_errno(u, _deserialize_r, \ + "Failed to parse \"%s=%s\", ignoring", l, v); \ + }; \ + _deserialize_matched; \ + }) + +int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { + int r; + + assert(u); + assert(f); + assert(fds); + + for (;;) { + _cleanup_free_ char *line = NULL; + char *l, *v; + ssize_t m; + size_t k; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) /* eof */ + break; + + l = strstrip(line); + if (isempty(l)) /* End marker */ + break; + + k = strcspn(l, "="); + + if (l[k] == '=') { + l[k] = 0; + v = l+k+1; + } else + v = l+k; + + if (streq(l, "job")) { + if (v[0] == '\0') { + /* New-style serialized job */ + r = unit_deserialize_job(u, f); + if (r < 0) + return r; + } else /* Legacy for pre-44 */ + log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v); + continue; + } else if (streq(l, "state-change-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->state_change_timestamp); + continue; + } else if (streq(l, "inactive-exit-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp); + continue; + } else if (streq(l, "active-enter-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->active_enter_timestamp); + continue; + } else if (streq(l, "active-exit-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->active_exit_timestamp); + continue; + } else if (streq(l, "inactive-enter-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp); + continue; + } else if (streq(l, "condition-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->condition_timestamp); + continue; + } else if (streq(l, "assert-timestamp")) { + (void) deserialize_dual_timestamp(v, &u->assert_timestamp); + continue; + + } else if (MATCH_DESERIALIZE("condition-result", l, v, parse_boolean, u->condition_result)) + continue; + + else if (MATCH_DESERIALIZE("assert-result", l, v, parse_boolean, u->assert_result)) + continue; + + else if (MATCH_DESERIALIZE("transient", l, v, parse_boolean, u->transient)) + continue; + + else if (MATCH_DESERIALIZE("in-audit", l, v, parse_boolean, u->in_audit)) + continue; + + else if (MATCH_DESERIALIZE("exported-invocation-id", l, v, parse_boolean, u->exported_invocation_id)) + continue; + + else if (MATCH_DESERIALIZE("exported-log-level-max", l, v, parse_boolean, u->exported_log_level_max)) + continue; + + else if (MATCH_DESERIALIZE("exported-log-extra-fields", l, v, parse_boolean, u->exported_log_extra_fields)) + continue; + + else if (MATCH_DESERIALIZE("exported-log-rate-limit-interval", l, v, parse_boolean, u->exported_log_ratelimit_interval)) + continue; + + else if (MATCH_DESERIALIZE("exported-log-rate-limit-burst", l, v, parse_boolean, u->exported_log_ratelimit_burst)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-base", l, v, safe_atou64, u->cpu_usage_base) || + MATCH_DESERIALIZE_IMMEDIATE("cpuacct-usage-base", l, v, safe_atou64, u->cpu_usage_base)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("cpu-usage-last", l, v, safe_atou64, u->cpu_usage_last)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("managed-oom-kill-last", l, v, safe_atou64, u->managed_oom_kill_last)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("oom-kill-last", l, v, safe_atou64, u->oom_kill_last)) + continue; + + else if (streq(l, "cgroup")) { + r = unit_set_cgroup_path(u, v); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v); + + (void) unit_watch_cgroup(u); + (void) unit_watch_cgroup_memory(u); + + continue; + + } else if (MATCH_DESERIALIZE("cgroup-realized", l, v, parse_boolean, u->cgroup_realized)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-realized-mask", l, v, cg_mask_from_string, u->cgroup_realized_mask)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-enabled-mask", l, v, cg_mask_from_string, u->cgroup_enabled_mask)) + continue; + + else if (MATCH_DESERIALIZE_IMMEDIATE("cgroup-invalidated-mask", l, v, cg_mask_from_string, u->cgroup_invalidated_mask)) + continue; + + else if (streq(l, "ref-uid")) { + uid_t uid; + + r = parse_uid(v, &uid); + if (r < 0) + log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v); + else + unit_ref_uid_gid(u, uid, GID_INVALID); + continue; + + } else if (streq(l, "ref-gid")) { + gid_t gid; + + r = parse_gid(v, &gid); + if (r < 0) + log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v); + else + unit_ref_uid_gid(u, UID_INVALID, gid); + continue; + + } else if (streq(l, "ref")) { + r = strv_extend(&u->deserialized_refs, v); + if (r < 0) + return log_oom(); + continue; + + } else if (streq(l, "invocation-id")) { + sd_id128_t id; + + r = sd_id128_from_string(v, &id); + if (r < 0) + log_unit_debug(u, "Failed to parse \"%s=%s\", ignoring.", l, v); + else { + r = unit_set_invocation_id(u, id); + if (r < 0) + log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m"); + } + + continue; + + } else if (MATCH_DESERIALIZE("freezer-state", l, v, freezer_state_from_string, u->freezer_state)) + continue; + + else if (streq(l, "markers")) { + r = deserialize_markers(u, v); + if (r < 0) + log_unit_debug_errno(u, r, "Failed to deserialize \"%s=%s\", ignoring: %m", l, v); + continue; + } + + /* Check if this is an IP accounting metric serialization field */ + m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l); + if (m >= 0) { + uint64_t c; + + r = safe_atou64(v, &c); + if (r < 0) + log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v); + else + u->ip_accounting_extra[m] = c; + continue; + } + + m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l); + if (m >= 0) { + uint64_t c; + + r = safe_atou64(v, &c); + if (r < 0) + log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v); + else + u->io_accounting_base[m] = c; + continue; + } + + m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l); + if (m >= 0) { + uint64_t c; + + r = safe_atou64(v, &c); + if (r < 0) + log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v); + else + u->io_accounting_last[m] = c; + continue; + } + + if (unit_can_serialize(u)) { + r = exec_runtime_deserialize_compat(u, l, v, fds); + if (r < 0) { + log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l); + continue; + } + + /* Returns positive if key was handled by the call */ + if (r > 0) + continue; + + r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds); + if (r < 0) + log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l); + } + } + + /* Versions before 228 did not carry a state change timestamp. In this case, take the current + * time. This is useful, so that timeouts based on this timestamp don't trigger too early, and is + * in-line with the logic from before 228 where the base for timeouts was not persistent across + * reboots. */ + + if (!dual_timestamp_is_set(&u->state_change_timestamp)) + dual_timestamp_get(&u->state_change_timestamp); + + /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings + * applied after we are done. For that we invalidate anything already realized, so that we can + * realize it again. */ + unit_invalidate_cgroup(u, _CGROUP_MASK_ALL); + unit_invalidate_cgroup_bpf(u); + + return 0; +} + +int unit_deserialize_skip(FILE *f) { + int r; + assert(f); + + /* Skip serialized data for this unit. We don't know what it is. */ + + for (;;) { + _cleanup_free_ char *line = NULL; + char *l; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read serialization line: %m"); + if (r == 0) + return 0; + + l = strstrip(line); + + /* End marker */ + if (isempty(l)) + return 1; + } +} + +static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) { + const struct { + UnitDependencyMask mask; + const char *name; + } table[] = { + { UNIT_DEPENDENCY_FILE, "file" }, + { UNIT_DEPENDENCY_IMPLICIT, "implicit" }, + { UNIT_DEPENDENCY_DEFAULT, "default" }, + { UNIT_DEPENDENCY_UDEV, "udev" }, + { UNIT_DEPENDENCY_PATH, "path" }, + { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" }, + { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" }, + { UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" }, + }; + + assert(f); + assert(kind); + assert(space); + + for (size_t i = 0; i < ELEMENTSOF(table); i++) { + + if (mask == 0) + break; + + if (FLAGS_SET(mask, table[i].mask)) { + if (*space) + fputc(' ', f); + else + *space = true; + + fputs(kind, f); + fputs("-", f); + fputs(table[i].name, f); + + mask &= ~table[i].mask; + } + } + + assert(mask == 0); +} + +void unit_dump(Unit *u, FILE *f, const char *prefix) { + char *t, **j; + const char *prefix2; + char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX]; + Unit *following; + _cleanup_set_free_ Set *following_set = NULL; + CGroupMask m; + int r; + + assert(u); + assert(u->type >= 0); + + prefix = strempty(prefix); + prefix2 = strjoina(prefix, "\t"); + + fprintf(f, + "%s-> Unit %s:\n", + prefix, u->id); + + SET_FOREACH(t, u->aliases) + fprintf(f, "%s\tAlias: %s\n", prefix, t); + + fprintf(f, + "%s\tDescription: %s\n" + "%s\tInstance: %s\n" + "%s\tUnit Load State: %s\n" + "%s\tUnit Active State: %s\n" + "%s\tState Change Timestamp: %s\n" + "%s\tInactive Exit Timestamp: %s\n" + "%s\tActive Enter Timestamp: %s\n" + "%s\tActive Exit Timestamp: %s\n" + "%s\tInactive Enter Timestamp: %s\n" + "%s\tMay GC: %s\n" + "%s\tNeed Daemon Reload: %s\n" + "%s\tTransient: %s\n" + "%s\tPerpetual: %s\n" + "%s\tGarbage Collection Mode: %s\n" + "%s\tSlice: %s\n" + "%s\tCGroup: %s\n" + "%s\tCGroup realized: %s\n", + prefix, unit_description(u), + prefix, strna(u->instance), + prefix, unit_load_state_to_string(u->load_state), + prefix, unit_active_state_to_string(unit_active_state(u)), + prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)), + prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)), + prefix, yes_no(unit_may_gc(u)), + prefix, yes_no(unit_need_daemon_reload(u)), + prefix, yes_no(u->transient), + prefix, yes_no(u->perpetual), + prefix, collect_mode_to_string(u->collect_mode), + prefix, strna(unit_slice_name(u)), + prefix, strna(u->cgroup_path), + prefix, yes_no(u->cgroup_realized)); + + if (u->markers != 0) { + fprintf(f, "%s\tMarkers:", prefix); + + for (UnitMarker marker = 0; marker < _UNIT_MARKER_MAX; marker++) + if (FLAGS_SET(u->markers, 1u << marker)) + fprintf(f, " %s", unit_marker_to_string(marker)); + fputs("\n", f); + } + + if (u->cgroup_realized_mask != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(u->cgroup_realized_mask, &s); + fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s)); + } + + if (u->cgroup_enabled_mask != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(u->cgroup_enabled_mask, &s); + fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s)); + } + + m = unit_get_own_mask(u); + if (m != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(m, &s); + fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s)); + } + + m = unit_get_members_mask(u); + if (m != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(m, &s); + fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s)); + } + + m = unit_get_delegate_mask(u); + if (m != 0) { + _cleanup_free_ char *s = NULL; + (void) cg_mask_to_string(m, &s); + fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s)); + } + + if (!sd_id128_is_null(u->invocation_id)) + fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n", + prefix, SD_ID128_FORMAT_VAL(u->invocation_id)); + + STRV_FOREACH(j, u->documentation) + fprintf(f, "%s\tDocumentation: %s\n", prefix, *j); + + following = unit_following(u); + if (following) + fprintf(f, "%s\tFollowing: %s\n", prefix, following->id); + + r = unit_following_set(u, &following_set); + if (r >= 0) { + Unit *other; + + SET_FOREACH(other, following_set) + fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id); + } + + if (u->fragment_path) + fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path); + + if (u->source_path) + fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path); + + STRV_FOREACH(j, u->dropin_paths) + fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j); + + if (u->failure_action != EMERGENCY_ACTION_NONE) + fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action)); + if (u->failure_action_exit_status >= 0) + fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status); + if (u->success_action != EMERGENCY_ACTION_NONE) + fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action)); + if (u->success_action_exit_status >= 0) + fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status); + + if (u->job_timeout != USEC_INFINITY) + fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0)); + + if (u->job_timeout_action != EMERGENCY_ACTION_NONE) + fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action)); + + if (u->job_timeout_reboot_arg) + fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg); + + condition_dump_list(u->conditions, f, prefix, condition_type_to_string); + condition_dump_list(u->asserts, f, prefix, assert_type_to_string); + + if (dual_timestamp_is_set(&u->condition_timestamp)) + fprintf(f, + "%s\tCondition Timestamp: %s\n" + "%s\tCondition Result: %s\n", + prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)), + prefix, yes_no(u->condition_result)); + + if (dual_timestamp_is_set(&u->assert_timestamp)) + fprintf(f, + "%s\tAssert Timestamp: %s\n" + "%s\tAssert Result: %s\n", + prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)), + prefix, yes_no(u->assert_result)); + + for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { + UnitDependencyInfo di; + Unit *other; + + HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) { + bool space = false; + + fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id); + + print_unit_dependency_mask(f, "origin", di.origin_mask, &space); + print_unit_dependency_mask(f, "destination", di.destination_mask, &space); + + fputs(")\n", f); + } + } + + if (!hashmap_isempty(u->requires_mounts_for)) { + UnitDependencyInfo di; + const char *path; + + HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) { + bool space = false; + + fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path); + + print_unit_dependency_mask(f, "origin", di.origin_mask, &space); + print_unit_dependency_mask(f, "destination", di.destination_mask, &space); + + fputs(")\n", f); + } + } + + if (u->load_state == UNIT_LOADED) { + + fprintf(f, + "%s\tStopWhenUnneeded: %s\n" + "%s\tRefuseManualStart: %s\n" + "%s\tRefuseManualStop: %s\n" + "%s\tDefaultDependencies: %s\n" + "%s\tOnFailureJobMode: %s\n" + "%s\tIgnoreOnIsolate: %s\n", + prefix, yes_no(u->stop_when_unneeded), + prefix, yes_no(u->refuse_manual_start), + prefix, yes_no(u->refuse_manual_stop), + prefix, yes_no(u->default_dependencies), + prefix, job_mode_to_string(u->on_failure_job_mode), + prefix, yes_no(u->ignore_on_isolate)); + + if (UNIT_VTABLE(u)->dump) + UNIT_VTABLE(u)->dump(u, f, prefix2); + + } else if (u->load_state == UNIT_MERGED) + fprintf(f, + "%s\tMerged into: %s\n", + prefix, u->merged_into->id); + else if (u->load_state == UNIT_ERROR) + fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error)); + + for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track)) + fprintf(f, "%s\tBus Ref: %s\n", prefix, n); + + if (u->job) + job_dump(u->job, f, prefix2); + + if (u->nop_job) + job_dump(u->nop_job, f, prefix2); +} diff --git a/src/core/unit-serialize.h b/src/core/unit-serialize.h new file mode 100644 index 000000000..599d883de --- /dev/null +++ b/src/core/unit-serialize.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "unit.h" +#include "fdset.h" + +int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); +int unit_deserialize(Unit *u, FILE *f, FDSet *fds); +int unit_deserialize_skip(FILE *f); + +void unit_dump(Unit *u, FILE *f, const char *prefix); diff --git a/src/core/unit.c b/src/core/unit.c index 45a417a09..2c5dc5437 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -26,8 +26,8 @@ #include "fileio.h" #include "format-util.h" #include "id128-util.h" -#include "io-util.h" #include "install.h" +#include "io-util.h" #include "label.h" #include "load-dropin.h" #include "load-fragment.h" @@ -35,11 +35,9 @@ #include "macro.h" #include "missing_audit.h" #include "mkdir.h" -#include "parse-util.h" #include "path-util.h" #include "process-util.h" #include "rm-rf.h" -#include "serialize.h" #include "set.h" #include "signal-util.h" #include "sparse-endian.h" @@ -84,7 +82,7 @@ const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = { static void maybe_warn_about_dependency(Unit *u, const char *other, UnitDependency dependency); -Unit *unit_new(Manager *m, size_t size) { +Unit* unit_new(Manager *m, size_t size) { Unit *u; assert(m); @@ -609,11 +607,11 @@ static void unit_done(Unit *u) { cgroup_context_done(cc); } -void unit_free(Unit *u) { +Unit* unit_free(Unit *u) { char *t; if (!u) - return; + return NULL; u->transient_file = safe_fclose(u->transient_file); @@ -743,7 +741,7 @@ void unit_free(Unit *u) { set_free_free(u->aliases); free(u->id); - free(u); + return mfree(u); } FreezerState unit_freezer_state(Unit *u) { @@ -1166,269 +1164,6 @@ const char *unit_status_string(Unit *u) { return unit_description(u); } -static void print_unit_dependency_mask(FILE *f, const char *kind, UnitDependencyMask mask, bool *space) { - const struct { - UnitDependencyMask mask; - const char *name; - } table[] = { - { UNIT_DEPENDENCY_FILE, "file" }, - { UNIT_DEPENDENCY_IMPLICIT, "implicit" }, - { UNIT_DEPENDENCY_DEFAULT, "default" }, - { UNIT_DEPENDENCY_UDEV, "udev" }, - { UNIT_DEPENDENCY_PATH, "path" }, - { UNIT_DEPENDENCY_MOUNTINFO_IMPLICIT, "mountinfo-implicit" }, - { UNIT_DEPENDENCY_MOUNTINFO_DEFAULT, "mountinfo-default" }, - { UNIT_DEPENDENCY_PROC_SWAP, "proc-swap" }, - }; - - assert(f); - assert(kind); - assert(space); - - for (size_t i = 0; i < ELEMENTSOF(table); i++) { - - if (mask == 0) - break; - - if (FLAGS_SET(mask, table[i].mask)) { - if (*space) - fputc(' ', f); - else - *space = true; - - fputs(kind, f); - fputs("-", f); - fputs(table[i].name, f); - - mask &= ~table[i].mask; - } - } - - assert(mask == 0); -} - -void unit_dump(Unit *u, FILE *f, const char *prefix) { - char *t, **j; - const char *prefix2; - char timestamp[5][FORMAT_TIMESTAMP_MAX], timespan[FORMAT_TIMESPAN_MAX]; - Unit *following; - _cleanup_set_free_ Set *following_set = NULL; - CGroupMask m; - int r; - - assert(u); - assert(u->type >= 0); - - prefix = strempty(prefix); - prefix2 = strjoina(prefix, "\t"); - - fprintf(f, - "%s-> Unit %s:\n", - prefix, u->id); - - SET_FOREACH(t, u->aliases) - fprintf(f, "%s\tAlias: %s\n", prefix, t); - - fprintf(f, - "%s\tDescription: %s\n" - "%s\tInstance: %s\n" - "%s\tUnit Load State: %s\n" - "%s\tUnit Active State: %s\n" - "%s\tState Change Timestamp: %s\n" - "%s\tInactive Exit Timestamp: %s\n" - "%s\tActive Enter Timestamp: %s\n" - "%s\tActive Exit Timestamp: %s\n" - "%s\tInactive Enter Timestamp: %s\n" - "%s\tMay GC: %s\n" - "%s\tNeed Daemon Reload: %s\n" - "%s\tTransient: %s\n" - "%s\tPerpetual: %s\n" - "%s\tGarbage Collection Mode: %s\n" - "%s\tSlice: %s\n" - "%s\tCGroup: %s\n" - "%s\tCGroup realized: %s\n", - prefix, unit_description(u), - prefix, strna(u->instance), - prefix, unit_load_state_to_string(u->load_state), - prefix, unit_active_state_to_string(unit_active_state(u)), - prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->state_change_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp[1], sizeof(timestamp[1]), u->inactive_exit_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp[2], sizeof(timestamp[2]), u->active_enter_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp[3], sizeof(timestamp[3]), u->active_exit_timestamp.realtime)), - prefix, strna(format_timestamp(timestamp[4], sizeof(timestamp[4]), u->inactive_enter_timestamp.realtime)), - prefix, yes_no(unit_may_gc(u)), - prefix, yes_no(unit_need_daemon_reload(u)), - prefix, yes_no(u->transient), - prefix, yes_no(u->perpetual), - prefix, collect_mode_to_string(u->collect_mode), - prefix, strna(unit_slice_name(u)), - prefix, strna(u->cgroup_path), - prefix, yes_no(u->cgroup_realized)); - - if (u->cgroup_realized_mask != 0) { - _cleanup_free_ char *s = NULL; - (void) cg_mask_to_string(u->cgroup_realized_mask, &s); - fprintf(f, "%s\tCGroup realized mask: %s\n", prefix, strnull(s)); - } - - if (u->cgroup_enabled_mask != 0) { - _cleanup_free_ char *s = NULL; - (void) cg_mask_to_string(u->cgroup_enabled_mask, &s); - fprintf(f, "%s\tCGroup enabled mask: %s\n", prefix, strnull(s)); - } - - m = unit_get_own_mask(u); - if (m != 0) { - _cleanup_free_ char *s = NULL; - (void) cg_mask_to_string(m, &s); - fprintf(f, "%s\tCGroup own mask: %s\n", prefix, strnull(s)); - } - - m = unit_get_members_mask(u); - if (m != 0) { - _cleanup_free_ char *s = NULL; - (void) cg_mask_to_string(m, &s); - fprintf(f, "%s\tCGroup members mask: %s\n", prefix, strnull(s)); - } - - m = unit_get_delegate_mask(u); - if (m != 0) { - _cleanup_free_ char *s = NULL; - (void) cg_mask_to_string(m, &s); - fprintf(f, "%s\tCGroup delegate mask: %s\n", prefix, strnull(s)); - } - - if (!sd_id128_is_null(u->invocation_id)) - fprintf(f, "%s\tInvocation ID: " SD_ID128_FORMAT_STR "\n", - prefix, SD_ID128_FORMAT_VAL(u->invocation_id)); - - STRV_FOREACH(j, u->documentation) - fprintf(f, "%s\tDocumentation: %s\n", prefix, *j); - - following = unit_following(u); - if (following) - fprintf(f, "%s\tFollowing: %s\n", prefix, following->id); - - r = unit_following_set(u, &following_set); - if (r >= 0) { - Unit *other; - - SET_FOREACH(other, following_set) - fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id); - } - - if (u->fragment_path) - fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path); - - if (u->source_path) - fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path); - - STRV_FOREACH(j, u->dropin_paths) - fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j); - - if (u->failure_action != EMERGENCY_ACTION_NONE) - fprintf(f, "%s\tFailure Action: %s\n", prefix, emergency_action_to_string(u->failure_action)); - if (u->failure_action_exit_status >= 0) - fprintf(f, "%s\tFailure Action Exit Status: %i\n", prefix, u->failure_action_exit_status); - if (u->success_action != EMERGENCY_ACTION_NONE) - fprintf(f, "%s\tSuccess Action: %s\n", prefix, emergency_action_to_string(u->success_action)); - if (u->success_action_exit_status >= 0) - fprintf(f, "%s\tSuccess Action Exit Status: %i\n", prefix, u->success_action_exit_status); - - if (u->job_timeout != USEC_INFINITY) - fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0)); - - if (u->job_timeout_action != EMERGENCY_ACTION_NONE) - fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, emergency_action_to_string(u->job_timeout_action)); - - if (u->job_timeout_reboot_arg) - fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg); - - condition_dump_list(u->conditions, f, prefix, condition_type_to_string); - condition_dump_list(u->asserts, f, prefix, assert_type_to_string); - - if (dual_timestamp_is_set(&u->condition_timestamp)) - fprintf(f, - "%s\tCondition Timestamp: %s\n" - "%s\tCondition Result: %s\n", - prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->condition_timestamp.realtime)), - prefix, yes_no(u->condition_result)); - - if (dual_timestamp_is_set(&u->assert_timestamp)) - fprintf(f, - "%s\tAssert Timestamp: %s\n" - "%s\tAssert Result: %s\n", - prefix, strna(format_timestamp(timestamp[0], sizeof(timestamp[0]), u->assert_timestamp.realtime)), - prefix, yes_no(u->assert_result)); - - for (UnitDependency d = 0; d < _UNIT_DEPENDENCY_MAX; d++) { - UnitDependencyInfo di; - Unit *other; - - HASHMAP_FOREACH_KEY(di.data, other, u->dependencies[d]) { - bool space = false; - - fprintf(f, "%s\t%s: %s (", prefix, unit_dependency_to_string(d), other->id); - - print_unit_dependency_mask(f, "origin", di.origin_mask, &space); - print_unit_dependency_mask(f, "destination", di.destination_mask, &space); - - fputs(")\n", f); - } - } - - if (!hashmap_isempty(u->requires_mounts_for)) { - UnitDependencyInfo di; - const char *path; - - HASHMAP_FOREACH_KEY(di.data, path, u->requires_mounts_for) { - bool space = false; - - fprintf(f, "%s\tRequiresMountsFor: %s (", prefix, path); - - print_unit_dependency_mask(f, "origin", di.origin_mask, &space); - print_unit_dependency_mask(f, "destination", di.destination_mask, &space); - - fputs(")\n", f); - } - } - - if (u->load_state == UNIT_LOADED) { - - fprintf(f, - "%s\tStopWhenUnneeded: %s\n" - "%s\tRefuseManualStart: %s\n" - "%s\tRefuseManualStop: %s\n" - "%s\tDefaultDependencies: %s\n" - "%s\tOnFailureJobMode: %s\n" - "%s\tIgnoreOnIsolate: %s\n", - prefix, yes_no(u->stop_when_unneeded), - prefix, yes_no(u->refuse_manual_start), - prefix, yes_no(u->refuse_manual_stop), - prefix, yes_no(u->default_dependencies), - prefix, job_mode_to_string(u->on_failure_job_mode), - prefix, yes_no(u->ignore_on_isolate)); - - if (UNIT_VTABLE(u)->dump) - UNIT_VTABLE(u)->dump(u, f, prefix2); - - } else if (u->load_state == UNIT_MERGED) - fprintf(f, - "%s\tMerged into: %s\n", - prefix, u->merged_into->id); - else if (u->load_state == UNIT_ERROR) - fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror_safe(u->load_error)); - - for (const char *n = sd_bus_track_first(u->bus_track); n; n = sd_bus_track_next(u->bus_track)) - fprintf(f, "%s\tBus Ref: %s\n", prefix, n); - - if (u->job) - job_dump(u->job, f, prefix2); - - if (u->nop_job) - job_dump(u->nop_job, f, prefix2); -} - /* Common implementation for multiple backends */ int unit_load_fragment_and_dropin(Unit *u, bool fragment_required) { int r; @@ -1668,8 +1403,8 @@ int unit_load(Unit *u) { goto fail; if (u->on_failure_job_mode == JOB_ISOLATE && hashmap_size(u->dependencies[UNIT_ON_FAILURE]) > 1) { - log_unit_error(u, "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing."); - r = -ENOEXEC; + r = log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOEXEC), + "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing."); goto fail; } @@ -2022,10 +1757,8 @@ int unit_reload(Unit *u) { if (state == UNIT_RELOADING) return -EAGAIN; - if (state != UNIT_ACTIVE) { - log_unit_warning(u, "Unit cannot be reloaded because it is inactive."); - return -ENOEXEC; - } + if (state != UNIT_ACTIVE) + return log_unit_warning_errno(u, SYNTHETIC_ERRNO(ENOEXEC), "Unit cannot be reloaded because it is inactive."); following = unit_following(u); if (following) { @@ -2561,8 +2294,6 @@ static bool unit_process_job(Job *j, UnitActiveState ns, UnitNotifyFlags flags) if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { if (ns == UNIT_FAILED) result = JOB_FAILED; - else if (FLAGS_SET(flags, UNIT_NOTIFY_SKIP_CONDITION)) - result = JOB_SKIPPED; else result = JOB_DONE; @@ -2659,9 +2390,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag /* Make sure the cgroup and state files are always removed when we become inactive */ if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { + SET_FLAG(u->markers, + (1u << UNIT_MARKER_NEEDS_RELOAD)|(1u << UNIT_MARKER_NEEDS_RESTART), + false); unit_prune_cgroup(u); unit_unlink_state_files(u); - } + } else if (ns != os && ns == UNIT_RELOADING) + SET_FLAG(u->markers, 1u << UNIT_MARKER_NEEDS_RELOAD, false); unit_update_on_console(u); @@ -3245,7 +2980,7 @@ char *unit_dbus_path_invocation_id(Unit *u) { return unit_dbus_path_from_name(u->invocation_id_string); } -static int unit_set_invocation_id(Unit *u, sd_id128_t id) { +int unit_set_invocation_id(Unit *u, sd_id128_t id) { int r; assert(u); @@ -3530,539 +3265,6 @@ bool unit_can_serialize(Unit *u) { return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item; } -static int serialize_cgroup_mask(FILE *f, const char *key, CGroupMask mask) { - _cleanup_free_ char *s = NULL; - int r; - - assert(f); - assert(key); - - if (mask == 0) - return 0; - - r = cg_mask_to_string(mask, &s); - if (r < 0) - return log_error_errno(r, "Failed to format cgroup mask: %m"); - - return serialize_item(f, key, s); -} - -static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IP_INGRESS_BYTES] = "ip-accounting-ingress-bytes", - [CGROUP_IP_INGRESS_PACKETS] = "ip-accounting-ingress-packets", - [CGROUP_IP_EGRESS_BYTES] = "ip-accounting-egress-bytes", - [CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets", -}; - -static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base", - [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base", - [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base", - [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base", -}; - -static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = { - [CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last", - [CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last", - [CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last", - [CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last", -}; - -int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) { - int r; - - assert(u); - assert(f); - assert(fds); - - if (unit_can_serialize(u)) { - r = UNIT_VTABLE(u)->serialize(u, f, fds); - if (r < 0) - return r; - } - - (void) serialize_dual_timestamp(f, "state-change-timestamp", &u->state_change_timestamp); - - (void) serialize_dual_timestamp(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp); - (void) serialize_dual_timestamp(f, "active-enter-timestamp", &u->active_enter_timestamp); - (void) serialize_dual_timestamp(f, "active-exit-timestamp", &u->active_exit_timestamp); - (void) serialize_dual_timestamp(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp); - - (void) serialize_dual_timestamp(f, "condition-timestamp", &u->condition_timestamp); - (void) serialize_dual_timestamp(f, "assert-timestamp", &u->assert_timestamp); - - if (dual_timestamp_is_set(&u->condition_timestamp)) - (void) serialize_bool(f, "condition-result", u->condition_result); - - if (dual_timestamp_is_set(&u->assert_timestamp)) - (void) serialize_bool(f, "assert-result", u->assert_result); - - (void) serialize_bool(f, "transient", u->transient); - (void) serialize_bool(f, "in-audit", u->in_audit); - - (void) serialize_bool(f, "exported-invocation-id", u->exported_invocation_id); - (void) serialize_bool(f, "exported-log-level-max", u->exported_log_level_max); - (void) serialize_bool(f, "exported-log-extra-fields", u->exported_log_extra_fields); - (void) serialize_bool(f, "exported-log-rate-limit-interval", u->exported_log_ratelimit_interval); - (void) serialize_bool(f, "exported-log-rate-limit-burst", u->exported_log_ratelimit_burst); - - (void) serialize_item_format(f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base); - if (u->cpu_usage_last != NSEC_INFINITY) - (void) serialize_item_format(f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last); - - if (u->managed_oom_kill_last > 0) - (void) serialize_item_format(f, "managed-oom-kill-last", "%" PRIu64, u->managed_oom_kill_last); - - if (u->oom_kill_last > 0) - (void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last); - - for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) { - (void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]); - - if (u->io_accounting_last[im] != UINT64_MAX) - (void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]); - } - - if (u->cgroup_path) - (void) serialize_item(f, "cgroup", u->cgroup_path); - - (void) serialize_bool(f, "cgroup-realized", u->cgroup_realized); - (void) serialize_cgroup_mask(f, "cgroup-realized-mask", u->cgroup_realized_mask); - (void) serialize_cgroup_mask(f, "cgroup-enabled-mask", u->cgroup_enabled_mask); - (void) serialize_cgroup_mask(f, "cgroup-invalidated-mask", u->cgroup_invalidated_mask); - - if (uid_is_valid(u->ref_uid)) - (void) serialize_item_format(f, "ref-uid", UID_FMT, u->ref_uid); - if (gid_is_valid(u->ref_gid)) - (void) serialize_item_format(f, "ref-gid", GID_FMT, u->ref_gid); - - if (!sd_id128_is_null(u->invocation_id)) - (void) serialize_item_format(f, "invocation-id", SD_ID128_FORMAT_STR, SD_ID128_FORMAT_VAL(u->invocation_id)); - - (void) serialize_item_format(f, "freezer-state", "%s", freezer_state_to_string(unit_freezer_state(u))); - - bus_track_serialize(u->bus_track, f, "ref"); - - for (CGroupIPAccountingMetric m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) { - uint64_t v; - - r = unit_get_ip_accounting(u, m, &v); - if (r >= 0) - (void) serialize_item_format(f, ip_accounting_metric_field[m], "%" PRIu64, v); - } - - if (serialize_jobs) { - if (u->job) { - fputs("job\n", f); - job_serialize(u->job, f); - } - - if (u->nop_job) { - fputs("job\n", f); - job_serialize(u->nop_job, f); - } - } - - /* End marker */ - fputc('\n', f); - return 0; -} - -static int unit_deserialize_job(Unit *u, FILE *f) { - _cleanup_(job_freep) Job *j = NULL; - int r; - - assert(u); - assert(f); - - j = job_new_raw(u); - if (!j) - return log_oom(); - - r = job_deserialize(j, f); - if (r < 0) - return r; - - r = job_install_deserialized(j); - if (r < 0) - return r; - - TAKE_PTR(j); - return 0; -} - -int unit_deserialize(Unit *u, FILE *f, FDSet *fds) { - int r; - - assert(u); - assert(f); - assert(fds); - - for (;;) { - _cleanup_free_ char *line = NULL; - char *l, *v; - ssize_t m; - size_t k; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return log_error_errno(r, "Failed to read serialization line: %m"); - if (r == 0) /* eof */ - break; - - l = strstrip(line); - if (isempty(l)) /* End marker */ - break; - - k = strcspn(l, "="); - - if (l[k] == '=') { - l[k] = 0; - v = l+k+1; - } else - v = l+k; - - if (streq(l, "job")) { - if (v[0] == '\0') { - /* New-style serialized job */ - r = unit_deserialize_job(u, f); - if (r < 0) - return r; - } else /* Legacy for pre-44 */ - log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v); - continue; - } else if (streq(l, "state-change-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->state_change_timestamp); - continue; - } else if (streq(l, "inactive-exit-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->inactive_exit_timestamp); - continue; - } else if (streq(l, "active-enter-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->active_enter_timestamp); - continue; - } else if (streq(l, "active-exit-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->active_exit_timestamp); - continue; - } else if (streq(l, "inactive-enter-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->inactive_enter_timestamp); - continue; - } else if (streq(l, "condition-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->condition_timestamp); - continue; - } else if (streq(l, "assert-timestamp")) { - (void) deserialize_dual_timestamp(v, &u->assert_timestamp); - continue; - } else if (streq(l, "condition-result")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v); - else - u->condition_result = r; - - continue; - - } else if (streq(l, "assert-result")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v); - else - u->assert_result = r; - - continue; - - } else if (streq(l, "transient")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v); - else - u->transient = r; - - continue; - - } else if (streq(l, "in-audit")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse in-audit bool %s, ignoring.", v); - else - u->in_audit = r; - - continue; - - } else if (streq(l, "exported-invocation-id")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse exported invocation ID bool %s, ignoring.", v); - else - u->exported_invocation_id = r; - - continue; - - } else if (streq(l, "exported-log-level-max")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse exported log level max bool %s, ignoring.", v); - else - u->exported_log_level_max = r; - - continue; - - } else if (streq(l, "exported-log-extra-fields")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse exported log extra fields bool %s, ignoring.", v); - else - u->exported_log_extra_fields = r; - - continue; - - } else if (streq(l, "exported-log-rate-limit-interval")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse exported log rate limit interval %s, ignoring.", v); - else - u->exported_log_ratelimit_interval = r; - - continue; - - } else if (streq(l, "exported-log-rate-limit-burst")) { - - r = parse_boolean(v); - if (r < 0) - log_unit_debug(u, "Failed to parse exported log rate limit burst %s, ignoring.", v); - else - u->exported_log_ratelimit_burst = r; - - continue; - - } else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) { - - r = safe_atou64(v, &u->cpu_usage_base); - if (r < 0) - log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v); - - continue; - - } else if (streq(l, "cpu-usage-last")) { - - r = safe_atou64(v, &u->cpu_usage_last); - if (r < 0) - log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v); - - continue; - - } else if (streq(l, "managed-oom-kill-last")) { - - r = safe_atou64(v, &u->managed_oom_kill_last); - if (r < 0) - log_unit_debug(u, "Failed to read managed OOM kill last %s, ignoring.", v); - - continue; - - } else if (streq(l, "oom-kill-last")) { - - r = safe_atou64(v, &u->oom_kill_last); - if (r < 0) - log_unit_debug(u, "Failed to read OOM kill last %s, ignoring.", v); - - continue; - - } else if (streq(l, "cgroup")) { - - r = unit_set_cgroup_path(u, v); - if (r < 0) - log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v); - - (void) unit_watch_cgroup(u); - (void) unit_watch_cgroup_memory(u); - - continue; - } else if (streq(l, "cgroup-realized")) { - int b; - - b = parse_boolean(v); - if (b < 0) - log_unit_debug(u, "Failed to parse cgroup-realized bool %s, ignoring.", v); - else - u->cgroup_realized = b; - - continue; - - } else if (streq(l, "cgroup-realized-mask")) { - - r = cg_mask_from_string(v, &u->cgroup_realized_mask); - if (r < 0) - log_unit_debug(u, "Failed to parse cgroup-realized-mask %s, ignoring.", v); - continue; - - } else if (streq(l, "cgroup-enabled-mask")) { - - r = cg_mask_from_string(v, &u->cgroup_enabled_mask); - if (r < 0) - log_unit_debug(u, "Failed to parse cgroup-enabled-mask %s, ignoring.", v); - continue; - - } else if (streq(l, "cgroup-invalidated-mask")) { - - r = cg_mask_from_string(v, &u->cgroup_invalidated_mask); - if (r < 0) - log_unit_debug(u, "Failed to parse cgroup-invalidated-mask %s, ignoring.", v); - continue; - - } else if (streq(l, "ref-uid")) { - uid_t uid; - - r = parse_uid(v, &uid); - if (r < 0) - log_unit_debug(u, "Failed to parse referenced UID %s, ignoring.", v); - else - unit_ref_uid_gid(u, uid, GID_INVALID); - - continue; - - } else if (streq(l, "ref-gid")) { - gid_t gid; - - r = parse_gid(v, &gid); - if (r < 0) - log_unit_debug(u, "Failed to parse referenced GID %s, ignoring.", v); - else - unit_ref_uid_gid(u, UID_INVALID, gid); - - continue; - - } else if (streq(l, "ref")) { - - r = strv_extend(&u->deserialized_refs, v); - if (r < 0) - return log_oom(); - - continue; - } else if (streq(l, "invocation-id")) { - sd_id128_t id; - - r = sd_id128_from_string(v, &id); - if (r < 0) - log_unit_debug(u, "Failed to parse invocation id %s, ignoring.", v); - else { - r = unit_set_invocation_id(u, id); - if (r < 0) - log_unit_warning_errno(u, r, "Failed to set invocation ID for unit: %m"); - } - - continue; - } else if (streq(l, "freezer-state")) { - FreezerState s; - - s = freezer_state_from_string(v); - if (s < 0) - log_unit_debug(u, "Failed to deserialize freezer-state '%s', ignoring.", v); - else - u->freezer_state = s; - - continue; - } - - /* Check if this is an IP accounting metric serialization field */ - m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l); - if (m >= 0) { - uint64_t c; - - r = safe_atou64(v, &c); - if (r < 0) - log_unit_debug(u, "Failed to parse IP accounting value %s, ignoring.", v); - else - u->ip_accounting_extra[m] = c; - continue; - } - - m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l); - if (m >= 0) { - uint64_t c; - - r = safe_atou64(v, &c); - if (r < 0) - log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v); - else - u->io_accounting_base[m] = c; - continue; - } - - m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l); - if (m >= 0) { - uint64_t c; - - r = safe_atou64(v, &c); - if (r < 0) - log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v); - else - u->io_accounting_last[m] = c; - continue; - } - - if (unit_can_serialize(u)) { - r = exec_runtime_deserialize_compat(u, l, v, fds); - if (r < 0) { - log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l); - continue; - } - - /* Returns positive if key was handled by the call */ - if (r > 0) - continue; - - r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds); - if (r < 0) - log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l); - } - } - - /* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is - * useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from - * before 228 where the base for timeouts was not persistent across reboots. */ - - if (!dual_timestamp_is_set(&u->state_change_timestamp)) - dual_timestamp_get(&u->state_change_timestamp); - - /* Let's make sure that everything that is deserialized also gets any potential new cgroup settings applied - * after we are done. For that we invalidate anything already realized, so that we can realize it again. */ - unit_invalidate_cgroup(u, _CGROUP_MASK_ALL); - unit_invalidate_cgroup_bpf(u); - - return 0; -} - -int unit_deserialize_skip(FILE *f) { - int r; - assert(f); - - /* Skip serialized data for this unit. We don't know what it is. */ - - for (;;) { - _cleanup_free_ char *line = NULL; - char *l; - - r = read_line(f, LONG_LINE_MAX, &line); - if (r < 0) - return log_error_errno(r, "Failed to read serialization line: %m"); - if (r == 0) - return 0; - - l = strstrip(line); - - /* End marker */ - if (isempty(l)) - return 1; - } -} - int unit_add_node_dependency(Unit *u, const char *what, UnitDependency dep, UnitDependencyMask mask) { _cleanup_free_ char *e = NULL; Unit *device; @@ -5554,8 +4756,8 @@ int unit_fork_helper_process(Unit *u, const char *name, pid_t *ret) { if (r != 0) return r; - (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1); - (void) ignore_signals(SIGPIPE, -1); + (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE); + (void) ignore_signals(SIGPIPE); (void) prctl(PR_SET_PDEATHSIG, SIGTERM); @@ -6098,7 +5300,7 @@ void unit_log_success(Unit *u) { "MESSAGE_ID=" SD_MESSAGE_UNIT_SUCCESS_STR, LOG_UNIT_ID(u), LOG_UNIT_INVOCATION_ID(u), - LOG_UNIT_MESSAGE(u, "Succeeded.")); + LOG_UNIT_MESSAGE(u, "Deactivated successfully.")); } void unit_log_failure(Unit *u, const char *result) { diff --git a/src/core/unit.h b/src/core/unit.h index 02b2b2420..6d38e6668 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -5,6 +5,8 @@ #include #include +#include "sd-id128.h" + #include "bpf-program.h" #include "condition.h" #include "emergency-action.h" @@ -23,14 +25,14 @@ typedef enum KillOperation { KILL_KILL, KILL_WATCHDOG, _KILL_OPERATION_MAX, - _KILL_OPERATION_INVALID = -1 + _KILL_OPERATION_INVALID = -EINVAL, } KillOperation; typedef enum CollectMode { COLLECT_INACTIVE, COLLECT_INACTIVE_OR_FAILED, _COLLECT_MODE_MAX, - _COLLECT_MODE_INVALID = -1, + _COLLECT_MODE_INVALID = -EINVAL, } CollectMode; static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) { @@ -118,9 +120,6 @@ typedef struct Unit { UnitLoadState load_state; Unit *merged_into; - FreezerState freezer_state; - sd_bus_message *pending_freezer_message; - char *id; /* The one special name that we use for identification */ char *instance; @@ -148,6 +147,16 @@ typedef struct Unit { /* If this is a transient unit we are currently writing, this is where we are writing it to */ FILE *transient_file; + /* Freezer state */ + sd_bus_message *pending_freezer_message; + FreezerState freezer_state; + + /* Job timeout and action to take */ + EmergencyAction job_timeout_action; + usec_t job_timeout; + usec_t job_running_timeout; + char *job_timeout_reboot_arg; + /* If there is something to do with this unit, then this is the installed job for it */ Job *job; @@ -162,13 +171,6 @@ typedef struct Unit { sd_bus_track *bus_track; char **deserialized_refs; - /* Job timeout and action to take */ - usec_t job_timeout; - usec_t job_running_timeout; - bool job_running_timeout_set:1; - EmergencyAction job_timeout_action; - char *job_timeout_reboot_arg; - /* References to this */ LIST_HEAD(UnitRef, refs_by_target); @@ -240,6 +242,9 @@ typedef struct Unit { RateLimit start_ratelimit; EmergencyAction start_limit_action; + /* The unit has been marked for reload, restart, etc. Stored as 1u << marker1 | 1u << marker2. */ + unsigned markers; + /* What to do on failure or success */ EmergencyAction success_action, failure_action; int success_action_exit_status, failure_action_exit_status; @@ -357,6 +362,8 @@ typedef struct Unit { bool sent_dbus_new_signal:1; + bool job_running_timeout_set:1; + bool in_audit:1; bool on_console:1; @@ -667,8 +674,8 @@ static inline Unit* UNIT_TRIGGER(Unit *u) { return hashmap_first_key(u->dependencies[UNIT_TRIGGERS]); } -Unit *unit_new(Manager *m, size_t size); -void unit_free(Unit *u); +Unit* unit_new(Manager *m, size_t size); +Unit* unit_free(Unit *u); DEFINE_TRIVIAL_CLEANUP_FUNC(Unit *, unit_free); int unit_new_for_name(Manager *m, size_t size, const char *name, Unit **ret); @@ -721,8 +728,6 @@ int unit_freezer_state_kernel(Unit *u, FreezerState *ret); const char* unit_sub_state_to_string(Unit *u); -void unit_dump(Unit *u, FILE *f, const char *prefix); - bool unit_can_reload(Unit *u) _pure_; bool unit_can_start(Unit *u) _pure_; bool unit_can_stop(Unit *u) _pure_; @@ -738,7 +743,6 @@ int unit_kill_common(Unit *u, KillWho who, int signo, pid_t main_pid, pid_t cont typedef enum UnitNotifyFlags { UNIT_NOTIFY_RELOAD_FAILURE = 1 << 0, UNIT_NOTIFY_WILL_AUTO_RESTART = 1 << 1, - UNIT_NOTIFY_SKIP_CONDITION = 1 << 2, } UnitNotifyFlags; void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags); @@ -765,10 +769,6 @@ int unit_load_related_unit(Unit *u, const char *type, Unit **_found); bool unit_can_serialize(Unit *u) _pure_; -int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs); -int unit_deserialize(Unit *u, FILE *f, FDSet *fds); -int unit_deserialize_skip(FILE *f); - int unit_add_node_dependency(Unit *u, const char *what, UnitDependency d, UnitDependencyMask mask); int unit_add_blockdev_dependency(Unit *u, const char *what, UnitDependencyMask mask); @@ -848,6 +848,7 @@ void unit_unref_uid_gid(Unit *u, bool destroy_now); void unit_notify_user_lookup(Unit *u, uid_t uid, gid_t gid); +int unit_set_invocation_id(Unit *u, sd_id128_t id); int unit_acquire_invocation_id(Unit *u); bool unit_shall_confirm_spawn(Unit *u); diff --git a/src/core/user.conf.in b/src/core/user.conf.in index bbe06319c..d3887e1c8 100644 --- a/src/core/user.conf.in +++ b/src/core/user.conf.in @@ -1,14 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# You can override the directives in this file by creating files in -# /etc/systemd/user.conf.d/*.conf. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See systemd-user.conf(5) for details +# See systemd-user.conf(5) for details. [Manager] #LogLevel=info diff --git a/src/coredump/coredump-vacuum.c b/src/coredump/coredump-vacuum.c index 30c67ffe7..95c3fca66 100644 --- a/src/coredump/coredump-vacuum.c +++ b/src/coredump/coredump-vacuum.c @@ -22,24 +22,23 @@ #define DEFAULT_KEEP_FREE_UPPER (uint64_t) (4ULL*1024ULL*1024ULL*1024ULL) /* 4 GiB */ #define DEFAULT_KEEP_FREE (uint64_t) (1024ULL*1024ULL) /* 1 MB */ -struct vacuum_candidate { +typedef struct VacuumCandidate { unsigned n_files; char *oldest_file; usec_t oldest_mtime; -}; +} VacuumCandidate; -static void vacuum_candidate_free(struct vacuum_candidate *c) { +static VacuumCandidate* vacuum_candidate_free(VacuumCandidate *c) { if (!c) - return; + return NULL; free(c->oldest_file); - free(c); + return mfree(c); } +DEFINE_TRIVIAL_CLEANUP_FUNC(VacuumCandidate*, vacuum_candidate_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct vacuum_candidate*, vacuum_candidate_free); - -static void vacuum_candidate_hashmap_free(Hashmap *h) { - hashmap_free_with_destructor(h, vacuum_candidate_free); +static Hashmap* vacuum_candidate_hashmap_free(Hashmap *h) { + return hashmap_free_with_destructor(h, vacuum_candidate_free); } DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, vacuum_candidate_hashmap_free); @@ -67,7 +66,7 @@ static int uid_from_file_name(const char *filename, uid_t *uid) { } static bool vacuum_necessary(int fd, uint64_t sum, uint64_t keep_free, uint64_t max_use) { - uint64_t fs_size = 0, fs_free = (uint64_t) -1; + uint64_t fs_size = 0, fs_free = UINT64_MAX; struct statvfs sv; assert(fd >= 0); @@ -77,7 +76,7 @@ static bool vacuum_necessary(int fd, uint64_t sum, uint64_t keep_free, uint64_t fs_free = sv.f_frsize * sv.f_bfree; } - if (max_use == (uint64_t) -1) { + if (max_use == UINT64_MAX) { if (fs_size > 0) { max_use = PAGE_ALIGN(fs_size / 10); /* 10% */ @@ -95,7 +94,7 @@ static bool vacuum_necessary(int fd, uint64_t sum, uint64_t keep_free, uint64_t if (max_use > 0 && sum > max_use) return true; - if (keep_free == (uint64_t) -1) { + if (keep_free == UINT64_MAX) { if (fs_size > 0) { keep_free = PAGE_ALIGN((fs_size * 3) / 20); /* 15% */ @@ -142,14 +141,14 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { for (;;) { _cleanup_(vacuum_candidate_hashmap_freep) Hashmap *h = NULL; - struct vacuum_candidate *worst = NULL; + VacuumCandidate *worst = NULL; struct dirent *de; uint64_t sum = 0; rewinddir(d); FOREACH_DIRENT(de, d, goto fail) { - struct vacuum_candidate *c; + VacuumCandidate *c; struct stat st; uid_t uid; usec_t t; @@ -196,9 +195,9 @@ int coredump_vacuum(int exclude_fd, uint64_t keep_free, uint64_t max_use) { } } else { - _cleanup_(vacuum_candidate_freep) struct vacuum_candidate *n = NULL; + _cleanup_(vacuum_candidate_freep) VacuumCandidate *n = NULL; - n = new0(struct vacuum_candidate, 1); + n = new0(VacuumCandidate, 1); if (!n) return log_oom(); diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c index 0a1cb9103..2fb240450 100644 --- a/src/coredump/coredump.c +++ b/src/coredump/coredump.c @@ -124,7 +124,7 @@ typedef enum CoredumpStorage { COREDUMP_STORAGE_EXTERNAL, COREDUMP_STORAGE_JOURNAL, _COREDUMP_STORAGE_MAX, - _COREDUMP_STORAGE_INVALID = -1 + _COREDUMP_STORAGE_INVALID = -EINVAL, } CoredumpStorage; static const char* const coredump_storage_table[_COREDUMP_STORAGE_MAX] = { @@ -141,8 +141,8 @@ static bool arg_compress = true; static uint64_t arg_process_size_max = PROCESS_SIZE_MAX; static uint64_t arg_external_size_max = EXTERNAL_SIZE_MAX; static uint64_t arg_journal_size_max = JOURNAL_SIZE_MAX; -static uint64_t arg_keep_free = (uint64_t) -1; -static uint64_t arg_max_use = (uint64_t) -1; +static uint64_t arg_keep_free = UINT64_MAX; +static uint64_t arg_max_use = UINT64_MAX; static int parse_config(void) { static const ConfigTableItem items[] = { @@ -210,14 +210,13 @@ static int fix_xattr(int fd, const Context *context) { }; int r = 0; - unsigned i; assert(fd >= 0); /* Attach some metadata to coredumps via extended * attributes. Just because we can. */ - for (i = 0; i < _META_MAX; i++) { + for (unsigned i = 0; i < _META_MAX; i++) { int k; if (isempty(context->meta[i]) || !xattrs[i]) @@ -355,7 +354,7 @@ static int save_external_coredump( context->meta[META_ARGV_RLIMIT]); if (rlimit < page_size()) /* Is coredumping disabled? Then don't bother saving/processing the - * coredump. Anything below PAGE_SIZE cannot give a readable coredump + * coredump. Anything below PAGE_SIZE cannot give a readable coredump * (the kernel uses ELF_EXEC_PAGESIZE which is not easily accessible, but * is usually the same as PAGE_SIZE. */ return log_info_errno(SYNTHETIC_ERRNO(EBADSLT), @@ -436,10 +435,10 @@ static int save_external_coredump( if (tmp) unlink_noerrno(tmp); - *ret_filename = TAKE_PTR(fn_compressed); /* compressed */ - *ret_node_fd = TAKE_FD(fd_compressed); /* compressed */ - *ret_data_fd = TAKE_FD(fd); /* uncompressed */ - *ret_size = (uint64_t) st.st_size; /* uncompressed */ + *ret_filename = TAKE_PTR(fn_compressed); /* compressed */ + *ret_node_fd = TAKE_FD(fd_compressed); /* compressed */ + *ret_data_fd = TAKE_FD(fd); /* uncompressed */ + *ret_size = (uint64_t) st.st_size; /* uncompressed */ return 0; @@ -808,7 +807,7 @@ log: } static int save_context(Context *context, const struct iovec_wrapper *iovw) { - unsigned n, i, count = 0; + unsigned count = 0; const char *unit; int r; @@ -818,10 +817,10 @@ static int save_context(Context *context, const struct iovec_wrapper *iovw) { /* The context does not allocate any memory on its own */ - for (n = 0; n < iovw->count; n++) { + for (size_t n = 0; n < iovw->count; n++) { struct iovec *iovec = iovw->iovec + n; - for (i = 0; i < ELEMENTSOF(meta_field_names); i++) { + for (size_t i = 0; i < ELEMENTSOF(meta_field_names); i++) { char *p; /* Note that these strings are NUL terminated, because we made sure that a @@ -858,11 +857,11 @@ static int process_socket(int fd) { Context context = {}; struct iovec_wrapper iovw = {}; struct iovec iovec; - int i, r; + int r; assert(fd >= 0); - log_setup_service(); + log_setup(); log_debug("Processing coredump received on stdin..."); @@ -936,7 +935,7 @@ static int process_socket(int fd) { goto finish; /* Make sure we received at least all fields we need. */ - for (i = 0; i < _META_MANDATORY_MAX; i++) + for (int i = 0; i < _META_MANDATORY_MAX; i++) if (!context.meta[i]) { r = log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A mandatory argument (%i) has not been sent, aborting.", @@ -958,7 +957,6 @@ static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) { .un.sun_path = "/run/systemd/coredump", }; _cleanup_close_ int fd = -1; - size_t i; int r; assert(iovw); @@ -971,7 +969,7 @@ static int send_iovec(const struct iovec_wrapper *iovw, int input_fd) { if (connect(fd, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) return log_error_errno(errno, "Failed to connect to coredump service: %m"); - for (i = 0; i < iovw->count; i++) { + for (size_t i = 0; i < iovw->count; i++) { struct msghdr mh = { .msg_iov = iovw->iovec + i, .msg_iovlen = 1, @@ -1022,7 +1020,7 @@ static int gather_pid_metadata_from_argv( int argc, char **argv) { _cleanup_free_ char *free_timestamp = NULL; - int i, r, signo; + int r, signo; char *t; /* We gather all metadata that were passed via argv[] into an array of iovecs that @@ -1033,7 +1031,7 @@ static int gather_pid_metadata_from_argv( "Not enough arguments passed by the kernel (%i, expected %i).", argc, _META_ARGV_MAX); - for (i = 0; i < _META_ARGV_MAX; i++) { + for (int i = 0; i < _META_ARGV_MAX; i++) { t = argv[i]; @@ -1127,23 +1125,23 @@ static int gather_pid_metadata(struct iovec_wrapper *iovw, Context *context) { (void) iovw_put_string_field_free(iovw, "COREDUMP_OPEN_FDS=", t); p = procfs_file_alloca(pid, "status"); - if (read_full_file(p, &t, NULL) >= 0) + if (read_full_virtual_file(p, &t, NULL) >= 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_STATUS=", t); p = procfs_file_alloca(pid, "maps"); - if (read_full_file(p, &t, NULL) >= 0) + if (read_full_virtual_file(p, &t, NULL) >= 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MAPS=", t); p = procfs_file_alloca(pid, "limits"); - if (read_full_file(p, &t, NULL) >= 0) + if (read_full_virtual_file(p, &t, NULL) >= 0) (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_LIMITS=", t); p = procfs_file_alloca(pid, "cgroup"); - if (read_full_file(p, &t, NULL) >=0) + if (read_full_virtual_file(p, &t, NULL) >=0) (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_CGROUP=", t); p = procfs_file_alloca(pid, "mountinfo"); - if (read_full_file(p, &t, NULL) >=0) + if (read_full_virtual_file(p, &t, NULL) >=0) (void) iovw_put_string_field_free(iovw, "COREDUMP_PROC_MOUNTINFO=", t); if (get_process_cwd(pid, &t) >= 0) @@ -1224,7 +1222,6 @@ static int process_backtrace(int argc, char *argv[]) { Context context = {}; struct iovec_wrapper *iovw; char *message; - size_t i; int r; _cleanup_(journal_importer_cleanup) JournalImporter importer = JOURNAL_IMPORTER_INIT(STDIN_FILENO); @@ -1274,7 +1271,7 @@ static int process_backtrace(int argc, char *argv[]) { /* The imported iovecs are not supposed to be freed by us so let's store * them at the end of the array so we can skip them while freeing the * rest. */ - for (i = 0; i < importer.iovw.count; i++) { + for (size_t i = 0; i < importer.iovw.count; i++) { struct iovec *iovec = importer.iovw.iovec + i; iovw_put(iovw, iovec->iov_base, iovec->iov_len); diff --git a/src/coredump/coredump.conf b/src/coredump/coredump.conf index c2f0643e0..56c100824 100644 --- a/src/coredump/coredump.conf +++ b/src/coredump/coredump.conf @@ -1,13 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. +# +# Use 'systemd-analyze cat-config systemd/coredump.conf' to display the full config. # # See coredump.conf(5) for details. diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c index 91356ad3c..0c4ef2e12 100644 --- a/src/coredump/coredumpctl.c +++ b/src/coredump/coredumpctl.c @@ -16,6 +16,7 @@ #include "compress.h" #include "def.h" #include "fd-util.h" +#include "format-table.h" #include "fs-util.h" #include "glob-util.h" #include "journal-internal.h" @@ -24,6 +25,7 @@ #include "macro.h" #include "main-func.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -44,15 +46,18 @@ static usec_t arg_since = USEC_INFINITY, arg_until = USEC_INFINITY; static const char* arg_field = NULL; static const char *arg_debugger = NULL; +static char **arg_debugger_args = NULL; static const char *arg_directory = NULL; static char **arg_file = NULL; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static PagerFlags arg_pager_flags = 0; -static int arg_no_legend = false; -static int arg_one = false; +static int arg_legend = true; +static size_t arg_rows_max = SIZE_MAX; static const char* arg_output = NULL; static bool arg_reverse = false; static bool arg_quiet = false; +STATIC_DESTRUCTOR_REGISTER(arg_debugger_args, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_file, strv_freep); static int add_match(sd_journal *j, const char *match) { @@ -153,34 +158,39 @@ static int help(void) { if (r < 0) return log_oom(); - printf("%s [OPTIONS...] COMMAND ...\n\n" - "%sList or retrieve coredumps from the journal.%s\n" - "\nCommands:\n" + printf("%1$s [OPTIONS...] COMMAND ...\n\n" + "%5$sList or retrieve coredumps from the journal.%6$s\n" + "\n%3$sCommands:%4$s\n" " list [MATCHES...] List available coredumps (default)\n" " info [MATCHES...] Show detailed information about one or more coredumps\n" " dump [MATCHES...] Print first matching coredump to stdout\n" " debug [MATCHES...] Start a debugger for the first matching coredump\n" - "\nOptions:\n" - " -h --help Show this help\n" - " --version Print version string\n" - " --no-pager Do not pipe output into a pager\n" - " --no-legend Do not print the column headers\n" - " --debugger=DEBUGGER Use the given debugger\n" - " -1 Show information about most recent entry only\n" - " -S --since=DATE Only print coredumps since the date\n" - " -U --until=DATE Only print coredumps until the date\n" - " -r --reverse Show the newest entries first\n" - " -F --field=FIELD List all values a certain field takes\n" - " -o --output=FILE Write output to FILE\n" - " --file=PATH Use journal file\n" - " -D --directory=DIR Use journal files from directory\n\n" - " -q --quiet Do not show info messages and privilege warning\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\n%3$sOptions:%4$s\n" + " -h --help Show this help\n" + " --version Print version string\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not print the column headers\n" + " --json=pretty|short|off\n" + " Generate JSON output\n" + " --debugger=DEBUGGER Use the given debugger\n" + " -A --debugger-arguments=ARGS Pass the given arguments to the debugger\n" + " -n INT Show maximum number of rows\n" + " -1 Show information about most recent entry only\n" + " -S --since=DATE Only print coredumps since the date\n" + " -U --until=DATE Only print coredumps until the date\n" + " -r --reverse Show the newest entries first\n" + " -F --field=FIELD List all values a certain field takes\n" + " -o --output=FILE Write output to FILE\n" + " --file=PATH Use journal file\n" + " -D --directory=DIR Use journal files from directory\n\n" + " -q --quiet Do not show info messages and privilege warning\n" + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); return 0; } @@ -190,6 +200,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_NO_PAGER, ARG_NO_LEGEND, + ARG_JSON, ARG_DEBUGGER, ARG_FILE, }; @@ -197,26 +208,28 @@ static int parse_argv(int argc, char *argv[]) { int c, r; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version" , no_argument, NULL, ARG_VERSION }, - { "no-pager", no_argument, NULL, ARG_NO_PAGER }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, - { "debugger", required_argument, NULL, ARG_DEBUGGER }, - { "output", required_argument, NULL, 'o' }, - { "field", required_argument, NULL, 'F' }, - { "file", required_argument, NULL, ARG_FILE }, - { "directory", required_argument, NULL, 'D' }, - { "reverse", no_argument, NULL, 'r' }, - { "since", required_argument, NULL, 'S' }, - { "until", required_argument, NULL, 'U' }, - { "quiet", no_argument, NULL, 'q' }, + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "debugger", required_argument, NULL, ARG_DEBUGGER }, + { "debugger-arguments", required_argument, NULL, 'A' }, + { "output", required_argument, NULL, 'o' }, + { "field", required_argument, NULL, 'F' }, + { "file", required_argument, NULL, ARG_FILE }, + { "directory", required_argument, NULL, 'D' }, + { "reverse", no_argument, NULL, 'r' }, + { "since", required_argument, NULL, 'S' }, + { "until", required_argument, NULL, 'U' }, + { "quiet", no_argument, NULL, 'q' }, + { "json", required_argument, NULL, ARG_JSON }, {} }; assert(argc >= 0); assert(argv); - while ((c = getopt_long(argc, argv, "ho:F:1D:rS:U:q", options, NULL)) >= 0) + while ((c = getopt_long(argc, argv, "hA:o:F:1D:rS:U:qn:", options, NULL)) >= 0) switch(c) { case 'h': return help(); @@ -229,13 +242,22 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NO_LEGEND: - arg_no_legend = true; + arg_legend = false; break; case ARG_DEBUGGER: arg_debugger = optarg; break; + case 'A': { + _cleanup_strv_free_ char **l = NULL; + r = strv_split_full(&l, optarg, WHITESPACE, EXTRACT_UNQUOTE); + if (r < 0) + return log_error_errno(r, "Failed to parse debugger arguments '%s': %m", optarg); + strv_free_and_replace(arg_debugger_args, l); + break; + } + case ARG_FILE: r = glob_extend(&arg_file, optarg, GLOB_NOCHECK); if (r < 0) @@ -270,9 +292,22 @@ static int parse_argv(int argc, char *argv[]) { break; case '1': - arg_one = true; + arg_rows_max = 1; + arg_reverse = true; break; + case 'n': { + unsigned n; + + r = safe_atou(optarg, &n); + if (r < 0 || n < 1) + return log_error_errno(r < 0 ? r : SYNTHETIC_ERRNO(EINVAL), + "Invalid numeric parameter to -n: %s", optarg); + + arg_rows_max = n; + break; + } + case 'D': arg_directory = optarg; break; @@ -285,6 +320,13 @@ static int parse_argv(int argc, char *argv[]) { arg_quiet = true; break; + case ARG_JSON: + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; + + break; + case '?': return -EINVAL; @@ -364,21 +406,78 @@ static int print_field(FILE* file, sd_journal *j) { continue; \ } -static int print_list(FILE* file, sd_journal *j, int had_legend) { +static void analyze_coredump_file( + const char *path, + const char **ret_state, + const char **ret_color, + uint64_t *ret_size) { + + _cleanup_close_ int fd = -1; + struct stat st; + int r; + + assert(path); + assert(ret_state); + assert(ret_color); + assert(ret_size); + + fd = open(path, O_PATH|O_CLOEXEC); + if (fd < 0) { + if (errno == ENOENT) { + *ret_state = "missing"; + *ret_color = ansi_grey(); + *ret_size = UINT64_MAX; + return; + } + + r = -errno; + } else + r = access_fd(fd, R_OK); + if (ERRNO_IS_PRIVILEGE(r)) { + *ret_state = "inaccessible"; + *ret_color = ansi_highlight_yellow(); + *ret_size = UINT64_MAX; + return; + } + if (r < 0) + goto error; + + if (fstat(fd, &st) < 0) + goto error; + + if (!S_ISREG(st.st_mode)) + goto error; + + *ret_state = "present"; + *ret_color = NULL; + *ret_size = st.st_size; + return; + +error: + *ret_state = "error"; + *ret_color = ansi_highlight_red(); + *ret_size = UINT64_MAX; +} + +static int print_list(FILE* file, sd_journal *j, Table *t) { _cleanup_free_ char *mid = NULL, *pid = NULL, *uid = NULL, *gid = NULL, *sgnl = NULL, *exe = NULL, *comm = NULL, *cmdline = NULL, *filename = NULL, *truncated = NULL, *coredump = NULL; const void *d; size_t l; - usec_t t; - char buf[FORMAT_TIMESTAMP_MAX]; - int r; - const char *present; + usec_t ts; + int r, signal_as_int = 0; + const char *present = NULL, *color = NULL; + uint64_t size = UINT64_MAX; bool normal_coredump; + uid_t uid_as_int = UID_INVALID; + gid_t gid_as_int = GID_INVALID; + pid_t pid_as_int = 0; assert(file); assert(j); + assert(t); SD_JOURNAL_FOREACH_DATA(j, d, l) { RETRIEVE(d, l, "MESSAGE_ID", mid); @@ -394,54 +493,46 @@ static int print_list(FILE* file, sd_journal *j, int had_legend) { RETRIEVE(d, l, "COREDUMP", coredump); } - if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) { - log_warning("Empty coredump log entry"); - return -EINVAL; - } + if (!pid && !uid && !gid && !sgnl && !exe && !comm && !cmdline && !filename) + return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "Empty coredump log entry"); - r = sd_journal_get_realtime_usec(j, &t); + (void) parse_uid(uid, &uid_as_int); + (void) parse_gid(gid, &gid_as_int); + (void) parse_pid(pid, &pid_as_int); + signal_as_int = signal_from_string(sgnl); + + r = sd_journal_get_realtime_usec(j, &ts); if (r < 0) return log_error_errno(r, "Failed to get realtime timestamp: %m"); - format_timestamp(buf, sizeof(buf), t); - - if (!had_legend && !arg_no_legend) - fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n", - FORMAT_TIMESTAMP_WIDTH, "TIME", - 6, "PID", - 5, "UID", - 5, "GID", - 3, "SIG", - 9, "COREFILE", - "EXE"); - normal_coredump = streq_ptr(mid, SD_MESSAGE_COREDUMP_STR); if (filename) - if (access(filename, R_OK) == 0) - present = "present"; - else if (errno == ENOENT) - present = "missing"; - else - present = "error"; + analyze_coredump_file(filename, &present, &color, &size); else if (coredump) present = "journal"; - else if (normal_coredump) + else if (normal_coredump) { present = "none"; - else - present = "-"; + color = ansi_grey(); + } else + present = NULL; - if (STR_IN_SET(present, "present", "journal") && truncated && parse_boolean(truncated) > 0) + if (STRPTR_IN_SET(present, "present", "journal") && truncated && parse_boolean(truncated) > 0) present = "truncated"; - fprintf(file, "%-*s %*s %*s %*s %*s %-*s %s\n", - FORMAT_TIMESTAMP_WIDTH, buf, - 6, strna(pid), - 5, strna(uid), - 5, strna(gid), - 3, normal_coredump ? strna(sgnl) : "-", - 9, present, - strna(exe ?: (comm ?: cmdline))); + r = table_add_many( + t, + TABLE_TIMESTAMP, ts, + TABLE_PID, pid_as_int, + TABLE_UID, uid_as_int, + TABLE_GID, gid_as_int, + TABLE_SIGNAL, normal_coredump ? signal_as_int : 0, + TABLE_STRING, present, + TABLE_SET_COLOR, color, + TABLE_STRING, exe ?: comm ?: cmdline, + TABLE_SIZE, size); + if (r < 0) + return table_log_add_error(r); return 0; } @@ -472,6 +563,7 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { RETRIEVE(d, l, "COREDUMP_EXE", exe); RETRIEVE(d, l, "COREDUMP_COMM", comm); RETRIEVE(d, l, "COREDUMP_CMDLINE", cmdline); + RETRIEVE(d, l, "COREDUMP_HOSTNAME", hostname); RETRIEVE(d, l, "COREDUMP_UNIT", unit); RETRIEVE(d, l, "COREDUMP_USER_UNIT", user_unit); RETRIEVE(d, l, "COREDUMP_SESSION", session); @@ -484,7 +576,6 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { RETRIEVE(d, l, "COREDUMP", coredump); RETRIEVE(d, l, "_BOOT_ID", boot_id); RETRIEVE(d, l, "_MACHINE_ID", machine_id); - RETRIEVE(d, l, "_HOSTNAME", hostname); RETRIEVE(d, l, "MESSAGE", message); } @@ -600,24 +691,27 @@ static int print_info(FILE *file, sd_journal *j, bool need_space) { fprintf(file, " Hostname: %s\n", hostname); if (filename) { - bool inacc, trunc; + const char *state = NULL, *color = NULL; + uint64_t size = UINT64_MAX; + char buf[FORMAT_BYTES_MAX]; - inacc = access(filename, R_OK) < 0; - trunc = truncated && parse_boolean(truncated) > 0; + analyze_coredump_file(filename, &state, &color, &size); - if (inacc || trunc) - fprintf(file, " Storage: %s%s (%s%s%s)%s\n", - ansi_highlight_red(), - filename, - inacc ? "inaccessible" : "", - inacc && trunc ? ", " : "", - trunc ? "truncated" : "", - ansi_normal()); - else - fprintf(file, " Storage: %s\n", filename); - } + if (STRPTR_IN_SET(state, "present", "journal") && truncated && parse_boolean(truncated) > 0) + state = "truncated"; - else if (coredump) + fprintf(file, + " Storage: %s%s (%s)%s\n", + strempty(color), + filename, + state, + ansi_normal()); + + if (size != UINT64_MAX) + fprintf(file, + " Disk Size: %s\n", + format_bytes(buf, sizeof(buf), size)); + } else if (coredump) fprintf(file, " Storage: journal\n"); else fprintf(file, " Storage: none\n"); @@ -647,43 +741,61 @@ static int focus(sd_journal *j) { return r; } -static int print_entry(sd_journal *j, unsigned n_found, bool verb_is_info) { +static int print_entry( + sd_journal *j, + size_t n_found, + Table *t) { + assert(j); - if (verb_is_info) - return print_info(stdout, j, n_found); + if (t) + return print_list(stdout, j, t); else if (arg_field) return print_field(stdout, j); else - return print_list(stdout, j, n_found); + return print_info(stdout, j, n_found > 0); } static int dump_list(int argc, char **argv, void *userdata) { _cleanup_(sd_journal_closep) sd_journal *j = NULL; - unsigned n_found = 0; + _cleanup_(table_unrefp) Table *t = NULL; + size_t n_found = 0; bool verb_is_info; int r; - verb_is_info = (argc >= 1 && streq(argv[0], "info")); + verb_is_info = argc >= 1 && streq(argv[0], "info"); r = acquire_journal(&j, argv + 1); if (r < 0) return r; - (void) pager_open(arg_pager_flags); + /* The coredumps are likely compressed, and for just listing them we don't need to decompress them, + * so let's pick a fairly low data threshold here */ + (void) sd_journal_set_data_threshold(j, 4096); - /* The coredumps are likely to compressed, and for just - * listing them we don't need to decompress them, so let's - * pick a fairly low data threshold here */ - sd_journal_set_data_threshold(j, 4096); + if (!verb_is_info && !arg_field) { + t = table_new("time", "pid", "uid", "gid", "sig", "corefile", "exe", "size"); + if (!t) + return log_oom(); + + (void) table_set_align_percent(t, TABLE_HEADER_CELL(1), 100); + (void) table_set_align_percent(t, TABLE_HEADER_CELL(2), 100); + (void) table_set_align_percent(t, TABLE_HEADER_CELL(3), 100); + (void) table_set_align_percent(t, TABLE_HEADER_CELL(7), 100); + + (void) table_set_empty_string(t, "-"); + } else + (void) pager_open(arg_pager_flags); /* "info" without pattern implies "-1" */ - if (arg_one || (verb_is_info && argc == 1)) { + if ((arg_rows_max == 1 && arg_reverse) || (verb_is_info && argc == 1)) { r = focus(j); if (r < 0) return r; - return print_entry(j, 0, verb_is_info); + r = print_entry(j, 0, t); + if (r < 0) + return r; } else { if (arg_since != USEC_INFINITY && !arg_reverse) r = sd_journal_seek_realtime_usec(j, arg_since); @@ -701,10 +813,8 @@ static int dump_list(int argc, char **argv, void *userdata) { r = sd_journal_next(j); else r = sd_journal_previous(j); - if (r < 0) return log_error_errno(r, "Failed to iterate through journal: %m"); - if (r == 0) break; @@ -728,9 +838,12 @@ static int dump_list(int argc, char **argv, void *userdata) { continue; } - r = print_entry(j, n_found++, verb_is_info); + r = print_entry(j, n_found++, t); if (r < 0) return r; + + if (arg_rows_max != SIZE_MAX && n_found >= arg_rows_max) + break; } if (!arg_field && n_found <= 0) { @@ -740,6 +853,12 @@ static int dump_list(int argc, char **argv, void *userdata) { } } + if (t) { + r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); + if (r < 0) + return r; + } + return 0; } @@ -921,7 +1040,8 @@ static int dump_core(int argc, char **argv, void *userdata) { static int run_debug(int argc, char **argv, void *userdata) { _cleanup_(sd_journal_closep) sd_journal *j = NULL; - _cleanup_free_ char *exe = NULL, *path = NULL, *debugger = NULL; + _cleanup_free_ char *exe = NULL, *path = NULL; + _cleanup_strv_free_ char **debugger_call = NULL; bool unlink_path = false; const char *data, *fork_name; size_t len; @@ -938,9 +1058,13 @@ static int run_debug(int argc, char **argv, void *userdata) { arg_debugger = "gdb"; } - debugger = strdup(arg_debugger); - if (!debugger) - return -ENOMEM; + r = strv_extend(&debugger_call, arg_debugger); + if (r < 0) + return log_oom(); + + r = strv_extend_strv(&debugger_call, arg_debugger_args, false); + if (r < 0) + return log_oom(); if (arg_field) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -954,8 +1078,10 @@ static int run_debug(int argc, char **argv, void *userdata) { if (r < 0) return r; - print_info(stdout, j, false); - fputs("\n", stdout); + if (!arg_quiet) { + print_info(stdout, j, false); + fputs("\n", stdout); + } r = sd_journal_get_data(j, "COREDUMP_EXE", (const void**) &data, &len); if (r < 0) @@ -981,25 +1107,29 @@ static int run_debug(int argc, char **argv, void *userdata) { if (r < 0) return r; + r = strv_extend_strv(&debugger_call, STRV_MAKE(exe, "-c", path), false); + if (r < 0) + return log_oom(); + /* Don't interfere with gdb and its handling of SIGINT. */ - (void) ignore_signals(SIGINT, -1); + (void) ignore_signals(SIGINT); - fork_name = strjoina("(", debugger, ")"); + fork_name = strjoina("(", debugger_call[0], ")"); - r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &pid); + r = safe_fork(fork_name, FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_CLOSE_ALL_FDS|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG|FORK_FLUSH_STDIO, &pid); if (r < 0) goto finish; if (r == 0) { - execlp(debugger, debugger, exe, "-c", path, NULL); + execvp(debugger_call[0], debugger_call); log_open(); - log_error_errno(errno, "Failed to invoke %s: %m", debugger); + log_error_errno(errno, "Failed to invoke %s: %m", debugger_call[0]); _exit(EXIT_FAILURE); } - r = wait_for_terminate_and_check(debugger, pid, WAIT_LOG_ABNORMAL); + r = wait_for_terminate_and_check(debugger_call[0], pid, WAIT_LOG_ABNORMAL); finish: - (void) default_signals(SIGINT, -1); + (void) default_signals(SIGINT); if (unlink_path) { log_debug("Removed temporary file %s", path); @@ -1087,7 +1217,7 @@ static int run(int argc, char *argv[]) { int r, units_active; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/coredump/meson.build b/src/coredump/meson.build index ebd99bd37..5607a78cf 100644 --- a/src/coredump/meson.build +++ b/src/coredump/meson.build @@ -7,13 +7,14 @@ systemd_coredump_sources = files(''' '''.split()) if conf.get('HAVE_ELFUTILS') == 1 - systemd_coredump_sources += files(['stacktrace.c', - 'stacktrace.h']) + systemd_coredump_sources += files( + 'stacktrace.c', + 'stacktrace.h') endif coredumpctl_sources = files('coredumpctl.c') -if conf.get('ENABLE_COREDUMP') == 1 and install_sysconfdir +if conf.get('ENABLE_COREDUMP') == 1 and install_sysconfdir_samples install_data('coredump.conf', install_dir : pkgsysconfdir) endif @@ -22,7 +23,5 @@ tests += [ [['src/coredump/test-coredump-vacuum.c', 'src/coredump/coredump-vacuum.c', 'src/coredump/coredump-vacuum.h'], - [], - [], - 'ENABLE_COREDUMP', 'manual'], + [], [], [], '', 'manual'], ] diff --git a/src/coredump/test-coredump-vacuum.c b/src/coredump/test-coredump-vacuum.c index ac212ea23..840884d96 100644 --- a/src/coredump/test-coredump-vacuum.c +++ b/src/coredump/test-coredump-vacuum.c @@ -6,7 +6,7 @@ int main(int argc, char *argv[]) { - if (coredump_vacuum(-1, (uint64_t) -1, 70 * 1024) < 0) + if (coredump_vacuum(-1, UINT64_MAX, 70 * 1024) < 0) return EXIT_FAILURE; return EXIT_SUCCESS; diff --git a/src/cryptenroll/cryptenroll-fido2.c b/src/cryptenroll/cryptenroll-fido2.c new file mode 100644 index 000000000..1b3ae8d67 --- /dev/null +++ b/src/cryptenroll/cryptenroll-fido2.c @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "cryptenroll-fido2.h" +#include "hexdecoct.h" +#include "json.h" +#include "libfido2-util.h" +#include "memory-util.h" +#include "random-util.h" + +int enroll_fido2( + struct crypt_device *cd, + const void *volume_key, + size_t volume_key_size, + const char *device) { + + _cleanup_(erase_and_freep) void *salt = NULL, *secret = NULL; + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *keyslot_as_string = NULL; + size_t cid_size, salt_size, secret_size; + _cleanup_free_ void *cid = NULL; + const char *node, *un; + int r, keyslot; + + assert_se(cd); + assert_se(volume_key); + assert_se(volume_key_size > 0); + assert_se(device); + + assert_se(node = crypt_get_device_name(cd)); + + un = strempty(crypt_get_uuid(cd)); + + r = fido2_generate_hmac_hash( + device, + /* rp_id= */ "io.systemd.cryptsetup", + /* rp_name= */ "Encrypted Volume", + /* user_id= */ un, strlen(un), /* We pass the user ID and name as the same: the disk's UUID if we have it */ + /* user_name= */ un, + /* user_display_name= */ node, + /* user_icon_name= */ NULL, + /* askpw_icon_name= */ "drive-harddisk", + &cid, &cid_size, + &salt, &salt_size, + &secret, &secret_size, + NULL); + if (r < 0) + return r; + + /* Before we use the secret, we base64 encode it, for compat with homed, and to make it easier to type in manually */ + r = base64mem(secret, secret_size, &base64_encoded); + if (r < 0) + return log_error_errno(r, "Failed to base64 encode secret key: %m"); + + r = cryptsetup_set_minimal_pbkdf(cd); + if (r < 0) + return log_error_errno(r, "Failed to set minimal PBKDF: %m"); + + keyslot = crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + base64_encoded, + strlen(base64_encoded)); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new PKCS#11 key to %s: %m", node); + + if (asprintf(&keyslot_as_string, "%i", keyslot) < 0) + return log_oom(); + + r = json_build(&v, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-fido2")), + JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))), + JSON_BUILD_PAIR("fido2-credential", JSON_BUILD_BASE64(cid, cid_size)), + JSON_BUILD_PAIR("fido2-salt", JSON_BUILD_BASE64(salt, salt_size)), + JSON_BUILD_PAIR("fido2-rp", JSON_BUILD_STRING("io.systemd.cryptsetup")))); + if (r < 0) + return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m"); + + r = cryptsetup_add_token_json(cd, v); + if (r < 0) + return log_error_errno(r, "Failed to add FIDO2 JSON token to LUKS2 header: %m"); + + log_info("New FIDO2 token enrolled as key slot %i.", keyslot); + return keyslot; +} diff --git a/src/cryptenroll/cryptenroll-fido2.h b/src/cryptenroll/cryptenroll-fido2.h new file mode 100644 index 000000000..936792071 --- /dev/null +++ b/src/cryptenroll/cryptenroll-fido2.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" +#include "log.h" + +#if HAVE_LIBFIDO2 +int enroll_fido2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device); +#else +static inline int enroll_fido2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device) { + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 key enrollment not supported."); +} +#endif diff --git a/src/cryptenroll/cryptenroll-list.c b/src/cryptenroll/cryptenroll-list.c new file mode 100644 index 000000000..d56deaa6b --- /dev/null +++ b/src/cryptenroll/cryptenroll-list.c @@ -0,0 +1,126 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "cryptenroll-list.h" +#include "cryptenroll.h" +#include "format-table.h" +#include "parse-util.h" + +int list_enrolled(struct crypt_device *cd) { + + struct keyslot_metadata { + int slot; + const char *type; + } *keyslot_metadata = NULL; + size_t n_keyslot_metadata = 0, n_keyslot_metadata_allocated = 0; + _cleanup_(table_unrefp) Table *t = NULL; + int slot_max, r; + TableCell *cell; + + assert(cd); + + /* First step, find out all currently used slots */ + assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0); + for (int slot = 0; slot < slot_max; slot++) { + crypt_keyslot_info status; + + status = crypt_keyslot_status(cd, slot); + if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST)) + continue; + + if (!GREEDY_REALLOC(keyslot_metadata, n_keyslot_metadata_allocated, n_keyslot_metadata+1)) + return log_oom(); + + keyslot_metadata[n_keyslot_metadata++] = (struct keyslot_metadata) { + .slot = slot, + }; + } + + /* Second step, enumerate through all tokens, and update the slot table, indicating what kind of + * token they are assigned to */ + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + const char *type; + JsonVariant *w, *z; + EnrollType et; + + r = cryptsetup_get_token_as_json(cd, token, NULL, &v); + if (IN_SET(r, -ENOENT, -EINVAL)) + continue; + if (r < 0) { + log_warning_errno(r, "Failed to read JSON token data off disk, ignoring: %m"); + continue; + } + + w = json_variant_by_key(v, "type"); + if (!w || !json_variant_is_string(w)) { + log_warning("Token JSON data lacks type field, ignoring."); + continue; + } + + et = luks2_token_type_from_string(json_variant_string(w)); + if (et < 0) + type = "other"; + else + type = enroll_type_to_string(et); + + w = json_variant_by_key(v, "keyslots"); + if (!w || !json_variant_is_array(w)) { + log_warning("Token JSON data lacks keyslots field, ignoring."); + continue; + } + + JSON_VARIANT_ARRAY_FOREACH(z, w) { + unsigned u; + + if (!json_variant_is_string(z)) { + log_warning("Token JSON data's keyslot field is not an array of strings, ignoring."); + continue; + } + + r = safe_atou(json_variant_string(z), &u); + if (r < 0) { + log_warning_errno(r, "Token JSON data's keyslot filed is not an integer formatted as string, ignoring."); + continue; + } + + for (size_t i = 0; i < n_keyslot_metadata; i++) { + if ((unsigned) keyslot_metadata[i].slot != u) + continue; + + if (keyslot_metadata[i].type) /* Slot claimed multiple times? */ + keyslot_metadata[i].type = POINTER_MAX; + else + keyslot_metadata[i].type = type; + } + } + } + + /* Finally, create a table out of it all */ + t = table_new("slot", "type"); + if (!t) + return log_oom(); + + assert_se(cell = table_get_cell(t, 0, 0)); + (void) table_set_align_percent(t, cell, 100); + + for (size_t i = 0; i < n_keyslot_metadata; i++) { + r = table_add_many( + t, + TABLE_INT, keyslot_metadata[i].slot, + TABLE_STRING, keyslot_metadata[i].type == POINTER_MAX ? "conflict" : + keyslot_metadata[i].type ?: "password"); + if (r < 0) + return table_log_add_error(r); + } + + if (table_get_rows(t) <= 1) { + log_info("No slots found."); + return 0; + } + + r = table_print(t, stdout); + if (r < 0) + return log_error_errno(r, "Failed to show slot table: %m"); + + return 0; +} diff --git a/src/cryptenroll/cryptenroll-list.h b/src/cryptenroll/cryptenroll-list.h new file mode 100644 index 000000000..d322988f7 --- /dev/null +++ b/src/cryptenroll/cryptenroll-list.h @@ -0,0 +1,6 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "cryptsetup-util.h" + +int list_enrolled(struct crypt_device *cd); diff --git a/src/cryptenroll/cryptenroll-password.c b/src/cryptenroll/cryptenroll-password.c new file mode 100644 index 000000000..e08f564d3 --- /dev/null +++ b/src/cryptenroll/cryptenroll-password.c @@ -0,0 +1,105 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "ask-password-api.h" +#include "cryptenroll-password.h" +#include "escape.h" +#include "memory-util.h" +#include "pwquality-util.h" +#include "strv.h" + +int enroll_password( + struct crypt_device *cd, + const void *volume_key, + size_t volume_key_size) { + + _cleanup_(erase_and_freep) char *new_password = NULL; + _cleanup_free_ char *error = NULL; + const char *node; + int r, keyslot; + char *e; + + assert_se(node = crypt_get_device_name(cd)); + + e = getenv("NEWPASSWORD"); + if (e) { + + new_password = strdup(e); + if (!new_password) + return log_oom(); + + string_erase(e); + assert_se(unsetenv("NEWPASSWORD") == 0); + + } else { + _cleanup_free_ char *disk_path = NULL; + unsigned i = 5; + const char *id; + + assert_se(node = crypt_get_device_name(cd)); + + (void) suggest_passwords(); + + disk_path = cescape(node); + if (!disk_path) + return log_oom(); + + id = strjoina("cryptsetup:", disk_path); + + for (;;) { + _cleanup_strv_free_erase_ char **passwords = NULL, **passwords2 = NULL; + _cleanup_free_ char *question = NULL; + + if (--i == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), + "Too many attempts, giving up:"); + + question = strjoin("Please enter new passphrase for disk ", node, ":"); + if (!question) + return log_oom(); + + r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords); + if (r < 0) + return log_error_errno(r, "Failed to query password: %m"); + + assert(strv_length(passwords) == 1); + + free(question); + question = strjoin("Please enter new passphrase for disk ", node, " (repeat):"); + if (!question) + return log_oom(); + + r = ask_password_auto(question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, 0, &passwords2); + if (r < 0) + return log_error_errno(r, "Failed to query password: %m"); + + assert(strv_length(passwords2) == 1); + + if (strv_equal(passwords, passwords2)) { + new_password = passwords2[0]; + passwords2 = mfree(passwords2); + break; + } + + log_error("Password didn't match, try again."); + } + } + + r = quality_check_password(new_password, NULL, &error); + if (r < 0) + return log_error_errno(r, "Failed to check password for quality: %m"); + if (r == 0) + log_warning_errno(r, "Specified password does not pass quality checks (%s), proceeding anyway.", error); + + keyslot = crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + new_password, + strlen(new_password)); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new password to %s: %m", node); + + log_info("New password enrolled as key slot %i.", keyslot); + return keyslot; +} diff --git a/src/cryptenroll/cryptenroll-password.h b/src/cryptenroll/cryptenroll-password.h new file mode 100644 index 000000000..ddeee1318 --- /dev/null +++ b/src/cryptenroll/cryptenroll-password.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" + +int enroll_password(struct crypt_device *cd, const void *volume_key, size_t volume_key_size); diff --git a/src/cryptenroll/cryptenroll-pkcs11.c b/src/cryptenroll/cryptenroll-pkcs11.c new file mode 100644 index 000000000..15ae6c942 --- /dev/null +++ b/src/cryptenroll/cryptenroll-pkcs11.c @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "cryptenroll-pkcs11.h" +#include "hexdecoct.h" +#include "json.h" +#include "memory-util.h" +#include "openssl-util.h" +#include "pkcs11-util.h" +#include "random-util.h" + +int enroll_pkcs11( + struct crypt_device *cd, + const void *volume_key, + size_t volume_key_size, + const char *uri) { + + _cleanup_(erase_and_freep) void *decrypted_key = NULL; + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ char *keyslot_as_string = NULL; + size_t decrypted_key_size, encrypted_key_size; + _cleanup_free_ void *encrypted_key = NULL; + _cleanup_(X509_freep) X509 *cert = NULL; + const char *node; + EVP_PKEY *pkey; + int keyslot, r; + + assert_se(cd); + assert_se(volume_key); + assert_se(volume_key_size > 0); + assert_se(uri); + + assert_se(node = crypt_get_device_name(cd)); + + r = pkcs11_acquire_certificate(uri, "volume enrollment operation", "drive-harddisk", &cert, NULL); + if (r < 0) + return r; + + pkey = X509_get0_pubkey(cert); + if (!pkey) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to extract public key from X.509 certificate."); + + r = rsa_pkey_to_suitable_key_size(pkey, &decrypted_key_size); + if (r < 0) + return log_error_errno(r, "Failed to determine RSA public key size."); + + log_debug("Generating %zu bytes random key.", decrypted_key_size); + + decrypted_key = malloc(decrypted_key_size); + if (!decrypted_key) + return log_oom(); + + r = genuine_random_bytes(decrypted_key, decrypted_key_size, RANDOM_BLOCK); + if (r < 0) + return log_error_errno(r, "Failed to generate random key: %m"); + + r = rsa_encrypt_bytes(pkey, decrypted_key, decrypted_key_size, &encrypted_key, &encrypted_key_size); + if (r < 0) + return log_error_errno(r, "Failed to encrypt key: %m"); + + /* Let's base64 encode the key to use, for compat with homed (and it's easier to type it in by + * keyboard, if that might ever end up being necessary.) */ + r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); + if (r < 0) + return log_error_errno(r, "Failed to base64 encode secret key: %m"); + + r = cryptsetup_set_minimal_pbkdf(cd); + if (r < 0) + return log_error_errno(r, "Failed to set minimal PBKDF: %m"); + + keyslot = crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + base64_encoded, + strlen(base64_encoded)); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new PKCS#11 key to %s: %m", node); + + if (asprintf(&keyslot_as_string, "%i", keyslot) < 0) + return log_oom(); + + r = json_build(&v, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-pkcs11")), + JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))), + JSON_BUILD_PAIR("pkcs11-uri", JSON_BUILD_STRING(uri)), + JSON_BUILD_PAIR("pkcs11-key", JSON_BUILD_BASE64(encrypted_key, encrypted_key_size)))); + if (r < 0) + return log_error_errno(r, "Failed to prepare PKCS#11 JSON token object: %m"); + + r = cryptsetup_add_token_json(cd, v); + if (r < 0) + return log_error_errno(r, "Failed to add PKCS#11 JSON token to LUKS2 header: %m"); + + log_info("New PKCS#11 token enrolled as key slot %i.", keyslot); + return keyslot; +} diff --git a/src/cryptenroll/cryptenroll-pkcs11.h b/src/cryptenroll/cryptenroll-pkcs11.h new file mode 100644 index 000000000..b6d28bd92 --- /dev/null +++ b/src/cryptenroll/cryptenroll-pkcs11.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" +#include "log.h" + +#if HAVE_P11KIT && HAVE_OPENSSL +int enroll_pkcs11(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *uri); +#else +static inline int enroll_pkcs11(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *uri) { + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PKCS#11 key enrollment not supported."); +} +#endif diff --git a/src/cryptenroll/cryptenroll-recovery.c b/src/cryptenroll/cryptenroll-recovery.c new file mode 100644 index 000000000..3204c463a --- /dev/null +++ b/src/cryptenroll/cryptenroll-recovery.c @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "cryptenroll-recovery.h" +#include "json.h" +#include "locale-util.h" +#include "memory-util.h" +#include "qrcode-util.h" +#include "recovery-key.h" +#include "terminal-util.h" + +int enroll_recovery( + struct crypt_device *cd, + const void *volume_key, + size_t volume_key_size) { + + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_(erase_and_freep) char *password = NULL; + _cleanup_free_ char *keyslot_as_string = NULL; + int keyslot, r, q; + const char *node; + + assert_se(cd); + assert_se(volume_key); + assert_se(volume_key_size > 0); + + assert_se(node = crypt_get_device_name(cd)); + + r = make_recovery_key(&password); + if (r < 0) + return log_error_errno(r, "Failed to generate recovery key: %m"); + + r = cryptsetup_set_minimal_pbkdf(cd); + if (r < 0) + return log_error_errno(r, "Failed to set minimal PBKDF: %m"); + + keyslot = crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + password, + strlen(password)); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new recovery key to %s: %m", node); + + fflush(stdout); + fprintf(stderr, + "A secret recovery key has been generated for this volume:\n\n" + " %s%s%s", + emoji_enabled() ? special_glyph(SPECIAL_GLYPH_LOCK_AND_KEY) : "", + emoji_enabled() ? " " : "", + ansi_highlight()); + fflush(stderr); + + fputs(password, stdout); + fflush(stdout); + + fputs(ansi_normal(), stderr); + fflush(stderr); + + fputc('\n', stdout); + fflush(stdout); + + fputs("\nPlease save this secret recovery key at a secure location. It may be used to\n" + "regain access to the volume if the other configured access credentials have\n" + "been lost or forgotten. The recovery key may be entered in place of a password\n" + "whenever authentication is requested.\n", stderr); + fflush(stderr); + + (void) print_qrcode(stderr, "You may optionally scan the recovery key off screen", password); + + if (asprintf(&keyslot_as_string, "%i", keyslot) < 0) { + r = log_oom(); + goto rollback; + } + + r = json_build(&v, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-recovery")), + JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))))); + if (r < 0) { + log_error_errno(r, "Failed to prepare recovery key JSON token object: %m"); + goto rollback; + } + + r = cryptsetup_add_token_json(cd, v); + if (r < 0) { + log_error_errno(r, "Failed to add recovery JSON token to LUKS2 header: %m"); + goto rollback; + } + + log_info("New recovery key enrolled as key slot %i.", keyslot); + return keyslot; + +rollback: + q = crypt_keyslot_destroy(cd, keyslot); + if (q < 0) + log_debug_errno(q, "Unable to remove key slot we just added again, can't rollback, sorry: %m"); + + return r; +} diff --git a/src/cryptenroll/cryptenroll-recovery.h b/src/cryptenroll/cryptenroll-recovery.h new file mode 100644 index 000000000..9bf4f2e48 --- /dev/null +++ b/src/cryptenroll/cryptenroll-recovery.h @@ -0,0 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" + +int enroll_recovery(struct crypt_device *cd, const void *volume_key, size_t volume_key_size); diff --git a/src/cryptenroll/cryptenroll-tpm2.c b/src/cryptenroll/cryptenroll-tpm2.c new file mode 100644 index 000000000..9c1478c47 --- /dev/null +++ b/src/cryptenroll/cryptenroll-tpm2.c @@ -0,0 +1,131 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "cryptenroll-tpm2.h" +#include "hexdecoct.h" +#include "json.h" +#include "memory-util.h" +#include "tpm2-util.h" + +static int search_policy_hash( + struct crypt_device *cd, + const void *hash, + size_t hash_size) { + + int r; + + assert(cd); + assert(hash || hash_size == 0); + + if (hash_size == 0) + return 0; + + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token ++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_free_ void *thash = NULL; + size_t thash_size = 0; + int keyslot; + JsonVariant *w; + + r = cryptsetup_get_token_as_json(cd, token, "systemd-tpm2", &v); + if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE)) + continue; + if (r < 0) + return log_error_errno(r, "Failed to read JSON token data off disk: %m"); + + keyslot = cryptsetup_get_keyslot_from_token(v); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to determine keyslot of JSON token: %m"); + + w = json_variant_by_key(v, "tpm2-policy-hash"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 token data lacks 'tpm2-policy-hash' field."); + + r = unhexmem(json_variant_string(w), SIZE_MAX, &thash, &thash_size); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid base64 data in 'tpm2-policy-hash' field."); + + if (memcmp_nn(hash, hash_size, thash, thash_size) == 0) + return keyslot; /* Found entry with same hash. */ + } + + return -ENOENT; /* Not found */ +} + +int enroll_tpm2(struct crypt_device *cd, + const void *volume_key, + size_t volume_key_size, + const char *device, + uint32_t pcr_mask) { + + _cleanup_(erase_and_freep) void *secret = NULL, *secret2 = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + size_t secret_size, secret2_size, blob_size, hash_size; + _cleanup_free_ void *blob = NULL, *hash = NULL; + const char *node; + int r, keyslot; + + assert(cd); + assert(volume_key); + assert(volume_key_size > 0); + assert(pcr_mask < (1U << TPM2_PCRS_MAX)); /* Support 24 PCR banks */ + + assert_se(node = crypt_get_device_name(cd)); + + r = tpm2_seal(device, pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size); + if (r < 0) + return r; + + /* Let's see if we already have this specific PCR policy hash enrolled, if so, exit early. */ + r = search_policy_hash(cd, hash, hash_size); + if (r == -ENOENT) + log_debug_errno(r, "PCR policy hash not yet enrolled, enrolling now."); + else if (r < 0) + return r; + else { + log_info("This PCR set is already enrolled, executing no operation."); + return r; /* return existing keyslot, so that wiping won't kill it */ + } + + /* Quick verification that everything is in order, we are not in a hurry after all. */ + log_debug("Unsealing for verification..."); + r = tpm2_unseal(device, pcr_mask, blob, blob_size, hash, hash_size, &secret2, &secret2_size); + if (r < 0) + return r; + + if (memcmp_nn(secret, secret_size, secret2, secret2_size) != 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "TPM2 seal/unseal verification failed."); + + /* let's base64 encode the key to use, for compat with homed (and it's easier to every type it in by keyboard, if that might end up being necessary. */ + r = base64mem(secret, secret_size, &base64_encoded); + if (r < 0) + return log_error_errno(r, "Failed to base64 encode secret key: %m"); + + r = cryptsetup_set_minimal_pbkdf(cd); + if (r < 0) + return log_error_errno(r, "Failed to set minimal PBKDF: %m"); + + keyslot = crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + base64_encoded, + strlen(base64_encoded)); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node); + + r = tpm2_make_luks2_json(keyslot, pcr_mask, blob, blob_size, hash, hash_size, &v); + if (r < 0) + return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); + + r = cryptsetup_add_token_json(cd, v); + if (r < 0) + return log_error_errno(r, "Failed to add TPM2 JSON token to LUKS2 header: %m"); + + log_info("New TPM2 token enrolled as key slot %i.", keyslot); + return keyslot; +} diff --git a/src/cryptenroll/cryptenroll-tpm2.h b/src/cryptenroll/cryptenroll-tpm2.h new file mode 100644 index 000000000..d5dd1b000 --- /dev/null +++ b/src/cryptenroll/cryptenroll-tpm2.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" +#include "log.h" + +#if HAVE_TPM2 +int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask); +#else +static inline int enroll_tpm2(struct crypt_device *cd, const void *volume_key, size_t volume_key_size, const char *device, uint32_t pcr_mask) { + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 key enrollment not supported."); +} +#endif diff --git a/src/cryptenroll/cryptenroll-wipe.c b/src/cryptenroll/cryptenroll-wipe.c new file mode 100644 index 000000000..225594664 --- /dev/null +++ b/src/cryptenroll/cryptenroll-wipe.c @@ -0,0 +1,445 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "cryptenroll-wipe.h" +#include "cryptenroll.h" +#include "json.h" +#include "memory-util.h" +#include "parse-util.h" +#include "set.h" +#include "sort-util.h" + +static int find_all_slots(struct crypt_device *cd, Set *wipe_slots, Set *keep_slots) { + int slot_max; + + assert(cd); + assert(wipe_slots); + assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0); + + /* Finds all currently assigned slots, and adds them to 'wipe_slots', except if listed already in 'keep_slots' */ + + for (int slot = 0; slot < slot_max; slot++) { + crypt_keyslot_info status; + + /* No need to check this slot if we already know we want to wipe it or definitely keep it. */ + if (set_contains(keep_slots, INT_TO_PTR(slot)) || + set_contains(wipe_slots, INT_TO_PTR(slot))) + continue; + + status = crypt_keyslot_status(cd, slot); + if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST)) + continue; + + if (set_put(wipe_slots, INT_TO_PTR(slot)) < 0) + return log_oom(); + } + + return 0; +} + +static int find_empty_passphrase_slots(struct crypt_device *cd, Set *wipe_slots, Set *keep_slots) { + size_t vks; + int r, slot_max; + + assert(cd); + assert(wipe_slots); + assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0); + + /* Finds all slots with an empty passphrase assigned (i.e. "") and adds them to 'wipe_slots', except + * if listed already in 'keep_slots' */ + + r = crypt_get_volume_key_size(cd); + if (r <= 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size"); + vks = (size_t) r; + + for (int slot = 0; slot < slot_max; slot++) { + _cleanup_(erase_and_freep) char *vk = NULL; + crypt_keyslot_info status; + + /* No need to check this slot if we already know we want to wipe it or definitely keep it. */ + if (set_contains(keep_slots, INT_TO_PTR(slot)) || + set_contains(wipe_slots, INT_TO_PTR(slot))) + continue; + + status = crypt_keyslot_status(cd, slot); + if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST)) + continue; + + vk = malloc(vks); + if (!vk) + return log_oom(); + + r = crypt_volume_key_get(cd, slot, vk, &vks, "", 0); + if (r < 0) { + log_debug_errno(r, "Failed to acquire volume key from slot %i with empty password, ignoring: %m", slot); + continue; + } + + if (set_put(wipe_slots, INT_TO_PTR(r)) < 0) + return log_oom(); + } + + return 0; +} + +static int find_slots_by_mask( + struct crypt_device *cd, + Set *wipe_slots, + Set *keep_slots, + unsigned by_mask) { + + _cleanup_(set_freep) Set *listed_slots = NULL; + int r; + + assert(cd); + assert(wipe_slots); + + if (by_mask == 0) + return 0; + + /* Find all slots that are associated with a token of a type in the specified token type mask */ + + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + JsonVariant *w, *z; + EnrollType t; + + r = cryptsetup_get_token_as_json(cd, token, NULL, &v); + if (IN_SET(r, -ENOENT, -EINVAL)) + continue; + if (r < 0) { + log_warning_errno(r, "Failed to read JSON token data off disk, ignoring: %m"); + continue; + } + + w = json_variant_by_key(v, "type"); + if (!w || !json_variant_is_string(w)) { + log_warning("Token JSON data lacks type field, ignoring."); + continue; + } + + t = luks2_token_type_from_string(json_variant_string(w)); + + w = json_variant_by_key(v, "keyslots"); + if (!w || !json_variant_is_array(w)) { + log_warning("Token JSON data lacks keyslots field, ignoring."); + continue; + } + + JSON_VARIANT_ARRAY_FOREACH(z, w) { + int slot; + + if (!json_variant_is_string(z)) { + log_warning("Token JSON data's keyslot field is not an array of strings, ignoring."); + continue; + } + + r = safe_atoi(json_variant_string(z), &slot); + if (r < 0) { + log_warning_errno(r, "Token JSON data's keyslot filed is not an integer formatted as string, ignoring."); + continue; + } + + if (t >= 0 && (by_mask & (1U << t)) != 0) { + /* Selected by token type */ + if (set_put(wipe_slots, INT_TO_PTR(slot)) < 0) + return log_oom(); + } else if ((by_mask & (1U << ENROLL_PASSWORD)) != 0) { + /* If we shall remove all plain password slots, let's maintain a list of + * slots that are listed in any tokens, since those are *NOT* plain + * passwords */ + if (set_ensure_allocated(&listed_slots, NULL) < 0) + return log_oom(); + + if (set_put(listed_slots, INT_TO_PTR(slot)) < 0) + return log_oom(); + } + } + } + + /* "password" slots are those which have no token assigned. If we shall remove those, iterate through + * all slots and mark those for wiping that weren't listed in any token */ + if ((by_mask & (1U << ENROLL_PASSWORD)) != 0) { + int slot_max; + + assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0); + + for (int slot = 0; slot < slot_max; slot++) { + crypt_keyslot_info status; + + /* No need to check this slot if we already know we want to wipe it or definitely keep it. */ + if (set_contains(keep_slots, INT_TO_PTR(slot)) || + set_contains(wipe_slots, INT_TO_PTR(slot))) + continue; + + if (set_contains(listed_slots, INT_TO_PTR(slot))) /* This has a token, hence is not a password. */ + continue; + + status = crypt_keyslot_status(cd, slot); + if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST)) /* Not actually assigned? */ + continue; + + /* Finally, we found a password, add it to the list of slots to wipe */ + if (set_put(wipe_slots, INT_TO_PTR(slot)) < 0) + return log_oom(); + } + } + + return 0; +} + +static int find_slot_tokens(struct crypt_device *cd, Set *wipe_slots, Set *keep_slots, Set *wipe_tokens) { + int r; + + assert(cd); + assert(wipe_slots); + assert(keep_slots); + assert(wipe_tokens); + + /* Find all tokens matching the slots we want to wipe, so that we can wipe them too. Also, for update + * the slots sets according to the token data: add any other slots listed in the tokens we act on. */ + + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + bool shall_wipe = false; + JsonVariant *w, *z; + + r = cryptsetup_get_token_as_json(cd, token, NULL, &v); + if (IN_SET(r, -ENOENT, -EINVAL)) + continue; + if (r < 0) { + log_warning_errno(r, "Failed to read JSON token data off disk, ignoring: %m"); + continue; + } + + w = json_variant_by_key(v, "keyslots"); + if (!w || !json_variant_is_array(w)) { + log_warning("Token JSON data lacks keyslots field, ignoring."); + continue; + } + + /* Go through the slots associated with this token: if we shall keep any slot of them, the token shall stay too. */ + JSON_VARIANT_ARRAY_FOREACH(z, w) { + int slot; + + if (!json_variant_is_string(z)) { + log_warning("Token JSON data's keyslot field is not an array of strings, ignoring."); + continue; + } + + r = safe_atoi(json_variant_string(z), &slot); + if (r < 0) { + log_warning_errno(r, "Token JSON data's keyslot filed is not an integer formatted as string, ignoring."); + continue; + } + + if (set_contains(keep_slots, INT_TO_PTR(slot))) { + shall_wipe = false; + break; /* If we shall keep this slot, then this is definite: we will keep its token too */ + } + + /* If there's a slot associated with this token that we shall wipe, then remove the + * token too. But we are careful here: let's continue iterating, maybe there's a slot + * that we need to keep, in which case we can reverse the decision again. */ + if (set_contains(wipe_slots, INT_TO_PTR(slot))) + shall_wipe = true; + } + + /* Go through the slots again, and this time add them to the list of slots to keep/remove */ + JSON_VARIANT_ARRAY_FOREACH(z, w) { + int slot; + + if (!json_variant_is_string(z)) + continue; + if (safe_atoi(json_variant_string(z), &slot) < 0) + continue; + + if (set_put(shall_wipe ? wipe_slots : keep_slots, INT_TO_PTR(slot)) < 0) + return log_oom(); + } + + /* And of course, also remember the tokens to remove. */ + if (shall_wipe) + if (set_put(wipe_tokens, INT_TO_PTR(token)) < 0) + return log_oom(); + } + + return 0; +} + +static bool slots_remain(struct crypt_device *cd, Set *wipe_slots, Set *keep_slots) { + int slot_max; + + assert(cd); + assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0); + + /* Checks if any slots remaining in the LUKS2 header if we remove all slots listed in 'wipe_slots' + * (keeping those listed in 'keep_slots') */ + + for (int slot = 0; slot < slot_max; slot++) { + crypt_keyslot_info status; + + status = crypt_keyslot_status(cd, slot); + if (!IN_SET(status, CRYPT_SLOT_ACTIVE, CRYPT_SLOT_ACTIVE_LAST)) + continue; + + /* The "keep" set wins if a slot is listed in both sets. This is important so that we can + * safely add a new slot and remove all others of the same type, which in a naive + * implementation might mean we remove what we just added — which we of course don't want. */ + if (set_contains(keep_slots, INT_TO_PTR(slot)) || + !set_contains(wipe_slots, INT_TO_PTR(slot))) + return true; + } + + return false; +} + +int wipe_slots(struct crypt_device *cd, + const int explicit_slots[], + size_t n_explicit_slots, + WipeScope by_scope, + unsigned by_mask, + int except_slot) { + + _cleanup_(set_freep) Set *wipe_slots = NULL, *wipe_tokens = NULL, *keep_slots = NULL; + _cleanup_free_ int *ordered_slots = NULL, *ordered_tokens = NULL; + size_t n_ordered_slots = 0, n_ordered_tokens = 0; + int r, slot_max, ret; + void *e; + + assert_se(cd); + + /* Shortcut if nothing to wipe. */ + if (n_explicit_slots == 0 && by_mask == 0 && by_scope == WIPE_EXPLICIT) + return 0; + + /* So this is a bit more complicated than I'd wish, but we want support three different axis for wiping slots: + * + * 1. Wiping by slot indexes + * 2. Wiping slots of specified token types + * 3. Wiping "all" entries, or entries with an empty password (i.e. "") + * + * (or any combination of the above) + * + * Plus: We always want to remove tokens matching the slots. + * Plus: We always want to exclude the slots/tokens we just added. + */ + + wipe_slots = set_new(NULL); + keep_slots = set_new(NULL); + wipe_tokens = set_new(NULL); + if (!wipe_slots || !keep_slots || !wipe_tokens) + return log_oom(); + + /* Let's maintain one set of slots for the slots we definitely want to keep */ + if (except_slot >= 0) + if (set_put(keep_slots, INT_TO_PTR(except_slot)) < 0) + return log_oom(); + + assert_se((slot_max = crypt_keyslot_max(CRYPT_LUKS2)) > 0); + + /* Maintain another set of the slots we intend to wipe */ + for (size_t i = 0; i < n_explicit_slots; i++) { + if (explicit_slots[i] >= slot_max) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Slot index %i out of range.", explicit_slots[i]); + + if (set_put(wipe_slots, INT_TO_PTR(explicit_slots[i])) < 0) + return log_oom(); + } + + /* Now, handle the "all" and "empty passphrase" cases. */ + switch (by_scope) { + + case WIPE_EXPLICIT: + break; /* Nothing to do here */ + + case WIPE_ALL: + r = find_all_slots(cd, wipe_slots, keep_slots); + if (r < 0) + return r; + + break; + + case WIPE_EMPTY_PASSPHRASE: + r = find_empty_passphrase_slots(cd, wipe_slots, keep_slots); + if (r < 0) + return r; + + break; + default: + assert_not_reached("Unexpected wipe scope"); + } + + /* Then add all slots that match a token type */ + r = find_slots_by_mask(cd, wipe_slots, keep_slots, by_mask); + if (r < 0) + return r; + + /* And determine tokens that we shall remove */ + r = find_slot_tokens(cd, wipe_slots, keep_slots, wipe_tokens); + if (r < 0) + return r; + + /* Safety check: let's make sure that after we are done there's at least one slot remaining */ + if (!slots_remain(cd, wipe_slots, keep_slots)) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), + "Wipe operation would leave no valid slots around, can't allow that, sorry."); + + /* Generated ordered lists of the slots and the tokens to remove */ + ordered_slots = new(int, set_size(wipe_slots)); + if (!ordered_slots) + return log_oom(); + SET_FOREACH(e, wipe_slots) { + int slot = PTR_TO_INT(e); + + if (set_contains(keep_slots, INT_TO_PTR(slot))) + continue; + + ordered_slots[n_ordered_slots++] = slot; + } + typesafe_qsort(ordered_slots, n_ordered_slots, cmp_int); + + ordered_tokens = new(int, set_size(wipe_tokens)); + if (!ordered_tokens) + return log_oom(); + SET_FOREACH(e, wipe_tokens) + ordered_tokens[n_ordered_tokens++] = PTR_TO_INT(e); + typesafe_qsort(ordered_tokens, n_ordered_tokens, cmp_int); + + if (n_ordered_slots == 0 && n_ordered_tokens == 0) { + log_full(except_slot < 0 ? LOG_NOTICE : LOG_DEBUG, + "No slots to remove selected."); + return 0; + } + + if (DEBUG_LOGGING) { + for (size_t i = 0; i < n_ordered_slots; i++) + log_debug("Going to wipe slot %i.", ordered_slots[i]); + for (size_t i = 0; i < n_ordered_tokens; i++) + log_debug("Going to wipe token %i.", ordered_tokens[i]); + } + + /* Now, let's actually start wiping things. (We go from back to front, to make space at the end + * first.) */ + ret = 0; + for (size_t i = n_ordered_slots; i > 0; i--) { + r = crypt_keyslot_destroy(cd, ordered_slots[i - 1]); + if (r < 0) { + log_warning_errno(r, "Failed to wipe slot %i, continuing: %m", ordered_slots[i - 1]); + if (ret == 0) + ret = r; + } else + log_info("Wiped slot %i.", ordered_slots[i - 1]); + } + + for (size_t i = n_ordered_tokens; i > 0; i--) { + r = crypt_token_json_set(cd, ordered_tokens[i - 1], NULL); + if (r < 0) { + log_warning_errno(r, "Failed to wipe token %i, continuing: %m", ordered_tokens[i - 1]); + if (ret == 0) + ret = r; + } + } + + return ret; +} diff --git a/src/cryptenroll/cryptenroll-wipe.h b/src/cryptenroll/cryptenroll-wipe.h new file mode 100644 index 000000000..5bcd78391 --- /dev/null +++ b/src/cryptenroll/cryptenroll-wipe.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "cryptenroll.h" +#include "cryptsetup-util.h" + +int wipe_slots(struct crypt_device *cd, + const int explicit_slots[], + size_t n_explicit_slots, + WipeScope by_scope, + unsigned by_mask, + int except_slot); diff --git a/src/cryptenroll/cryptenroll.c b/src/cryptenroll/cryptenroll.c new file mode 100644 index 000000000..a137a41c9 --- /dev/null +++ b/src/cryptenroll/cryptenroll.c @@ -0,0 +1,518 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "ask-password-api.h" +#include "cryptenroll-fido2.h" +#include "cryptenroll-list.h" +#include "cryptenroll-password.h" +#include "cryptenroll-pkcs11.h" +#include "cryptenroll-recovery.h" +#include "cryptenroll-tpm2.h" +#include "cryptenroll-wipe.h" +#include "cryptenroll.h" +#include "cryptsetup-util.h" +#include "escape.h" +#include "libfido2-util.h" +#include "main-func.h" +#include "memory-util.h" +#include "parse-argument.h" +#include "parse-util.h" +#include "path-util.h" +#include "pkcs11-util.h" +#include "pretty-print.h" +#include "string-table.h" +#include "strv.h" +#include "terminal-util.h" +#include "tpm2-util.h" + +static EnrollType arg_enroll_type = _ENROLL_TYPE_INVALID; +static char *arg_pkcs11_token_uri = NULL; +static char *arg_fido2_device = NULL; +static char *arg_tpm2_device = NULL; +static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; +static char *arg_node = NULL; +static int *arg_wipe_slots = NULL; +static size_t arg_n_wipe_slots = 0; +static WipeScope arg_wipe_slots_scope = WIPE_EXPLICIT; +static unsigned arg_wipe_slots_mask = 0; /* Bitmask of (1U << EnrollType), for wiping all slots of specific types */ + +assert_cc(sizeof(arg_wipe_slots_mask) * 8 >= _ENROLL_TYPE_MAX); + +STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_token_uri, freep); +STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep); +STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); +STATIC_DESTRUCTOR_REGISTER(arg_node, freep); + +static bool wipe_requested(void) { + return arg_n_wipe_slots > 0 || + arg_wipe_slots_scope != WIPE_EXPLICIT || + arg_wipe_slots_mask != 0; +} + +static const char* const enroll_type_table[_ENROLL_TYPE_MAX] = { + [ENROLL_PASSWORD] = "password", + [ENROLL_RECOVERY] = "recovery", + [ENROLL_PKCS11] = "pkcs11", + [ENROLL_FIDO2] = "fido2", + [ENROLL_TPM2] = "tpm2", +}; + +DEFINE_STRING_TABLE_LOOKUP(enroll_type, EnrollType); + +static const char *const luks2_token_type_table[_ENROLL_TYPE_MAX] = { + /* ENROLL_PASSWORD has no entry here, as slots of this type do not have a token in the LUKS2 header */ + [ENROLL_RECOVERY] = "systemd-recovery", + [ENROLL_PKCS11] = "systemd-pkcs11", + [ENROLL_FIDO2] = "systemd-fido2", + [ENROLL_TPM2] = "systemd-tpm2", +}; + +DEFINE_STRING_TABLE_LOOKUP(luks2_token_type, EnrollType); + +static int help(void) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-cryptenroll", "1", &link); + if (r < 0) + return log_oom(); + + printf("%s [OPTIONS...] BLOCK-DEVICE\n" + "\n%sEnroll a security token or authentication credential to a LUKS volume.%s\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " --password Enroll a user-supplied password\n" + " --recovery-key Enroll a recovery key\n" + " --pkcs11-token-uri=URI\n" + " Specify PKCS#11 security token URI\n" + " --fido2-device=PATH\n" + " Enroll a FIDO2-HMAC security token\n" + " --tpm2-device=PATH\n" + " Enroll a TPM2 device\n" + " --tpm2-pcrs=PCR1,PCR2,PCR3,…\n" + " Specify TPM2 PCRs to seal against\n" + " --wipe-slot=SLOT1,SLOT2,…\n" + " Wipe specified slots\n" + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_PASSWORD, + ARG_RECOVERY_KEY, + ARG_PKCS11_TOKEN_URI, + ARG_FIDO2_DEVICE, + ARG_TPM2_DEVICE, + ARG_TPM2_PCRS, + ARG_WIPE_SLOT, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "password", no_argument, NULL, ARG_PASSWORD }, + { "recovery-key", no_argument, NULL, ARG_RECOVERY_KEY }, + { "pkcs11-token-uri", required_argument, NULL, ARG_PKCS11_TOKEN_URI }, + { "fido2-device", required_argument, NULL, ARG_FIDO2_DEVICE }, + { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, + { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS }, + { "wipe-slot", required_argument, NULL, ARG_WIPE_SLOT }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + return help(); + + case ARG_VERSION: + return version(); + + case ARG_PASSWORD: + if (arg_enroll_type >= 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Multiple operations specified at once, refusing."); + + arg_enroll_type = ENROLL_PASSWORD; + break; + + case ARG_RECOVERY_KEY: + if (arg_enroll_type >= 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Multiple operations specified at once, refusing."); + + arg_enroll_type = ENROLL_RECOVERY; + break; + + case ARG_PKCS11_TOKEN_URI: { + _cleanup_free_ char *uri = NULL; + + if (streq(optarg, "list")) + return pkcs11_list_tokens(); + + if (arg_enroll_type >= 0 || arg_pkcs11_token_uri) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Multiple operations specified at once, refusing."); + + if (streq(optarg, "auto")) { + r = pkcs11_find_token_auto(&uri); + if (r < 0) + return r; + } else { + if (!pkcs11_uri_valid(optarg)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid PKCS#11 URI: %s", optarg); + + uri = strdup(optarg); + if (!uri) + return log_oom(); + } + + arg_enroll_type = ENROLL_PKCS11; + arg_pkcs11_token_uri = TAKE_PTR(uri); + break; + } + + case ARG_FIDO2_DEVICE: { + _cleanup_free_ char *device = NULL; + + if (streq(optarg, "list")) + return fido2_list_devices(); + + if (arg_enroll_type >= 0 || arg_fido2_device) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Multiple operations specified at once, refusing."); + + if (streq(optarg, "auto")) { + r = fido2_find_device_auto(&device); + if (r < 0) + return r; + } else { + device = strdup(optarg); + if (!device) + return log_oom(); + } + + arg_enroll_type = ENROLL_FIDO2; + arg_fido2_device = TAKE_PTR(device); + break; + } + + case ARG_TPM2_DEVICE: { + _cleanup_free_ char *device = NULL; + + if (streq(optarg, "list")) + return tpm2_list_devices(); + + if (arg_enroll_type >= 0 || arg_tpm2_device) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Multiple operations specified at once, refusing."); + + if (!streq(optarg, "auto")) { + device = strdup(optarg); + if (!device) + return log_oom(); + } + + arg_enroll_type = ENROLL_TPM2; + arg_tpm2_device = TAKE_PTR(device); + break; + } + + case ARG_TPM2_PCRS: { + uint32_t mask; + + if (isempty(optarg)) { + arg_tpm2_pcr_mask = 0; + break; + } + + r = tpm2_parse_pcrs(optarg, &mask); + if (r < 0) + return r; + + if (arg_tpm2_pcr_mask == UINT32_MAX) + arg_tpm2_pcr_mask = mask; + else + arg_tpm2_pcr_mask |= mask; + + break; + } + + case ARG_WIPE_SLOT: { + const char *p = optarg; + + if (isempty(optarg)) { + arg_wipe_slots_mask = 0; + arg_wipe_slots_scope = WIPE_EXPLICIT; + break; + } + + for (;;) { + _cleanup_free_ char *slot = NULL; + unsigned n; + + r = extract_first_word(&p, &slot, ",", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == 0) + break; + if (r < 0) + return log_error_errno(r, "Failed to parse slot list: %s", optarg); + + if (streq(slot, "all")) + arg_wipe_slots_scope = WIPE_ALL; + else if (streq(slot, "empty")) { + if (arg_wipe_slots_scope != WIPE_ALL) /* if "all" was specified before, that wins */ + arg_wipe_slots_scope = WIPE_EMPTY_PASSPHRASE; + } else if (streq(slot, "password")) + arg_wipe_slots_mask = 1U << ENROLL_PASSWORD; + else if (streq(slot, "recovery")) + arg_wipe_slots_mask = 1U << ENROLL_RECOVERY; + else if (streq(slot, "pkcs11")) + arg_wipe_slots_mask = 1U << ENROLL_PKCS11; + else if (streq(slot, "fido2")) + arg_wipe_slots_mask = 1U << ENROLL_FIDO2; + else if (streq(slot, "tpm2")) + arg_wipe_slots_mask = 1U << ENROLL_TPM2; + else { + int *a; + + r = safe_atou(slot, &n); + if (r < 0) + return log_error_errno(r, "Failed to parse slot index: %s", slot); + if (n > INT_MAX) + return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Slot index out of range: %u", n); + + a = reallocarray(arg_wipe_slots, sizeof(int), arg_n_wipe_slots + 1); + if (!a) + return log_oom(); + + arg_wipe_slots = a; + arg_wipe_slots[arg_n_wipe_slots++] = (int) n; + } + } + break; + } + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + } + + if (optind >= argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No block device node specified, refusing."); + + if (argc > optind+1) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Too many arguments, refusing."); + + r = parse_path_argument(argv[optind], false, &arg_node); + if (r < 0) + return r; + + if (arg_tpm2_pcr_mask == UINT32_MAX) + arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT; + + return 1; +} + +static int prepare_luks( + struct crypt_device **ret_cd, + void **ret_volume_key, + size_t *ret_volume_key_size) { + + _cleanup_(crypt_freep) struct crypt_device *cd = NULL; + _cleanup_(erase_and_freep) void *vk = NULL; + char *e = NULL; + size_t vks; + int r; + + assert(ret_cd); + assert(!ret_volume_key == !ret_volume_key_size); + + r = crypt_init(&cd, arg_node); + if (r < 0) + return log_error_errno(r, "Failed to allocate libcryptsetup context: %m"); + + cryptsetup_enable_logging(cd); + + r = crypt_load(cd, CRYPT_LUKS2, NULL); + if (r < 0) + return log_error_errno(r, "Failed to load LUKS2 superblock: %m"); + + if (!ret_volume_key) { + *ret_cd = TAKE_PTR(cd); + return 0; + } + + r = crypt_get_volume_key_size(cd); + if (r <= 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine LUKS volume key size"); + vks = (size_t) r; + + vk = malloc(vks); + if (!vk) + return log_oom(); + + e = getenv("PASSWORD"); + if (e) { + _cleanup_(erase_and_freep) char *password = NULL; + + password = strdup(e); + if (!password) + return log_oom(); + + string_erase(e); + assert_se(unsetenv("PASSWORD") >= 0); + + r = crypt_volume_key_get( + cd, + CRYPT_ANY_SLOT, + vk, + &vks, + password, + strlen(password)); + if (r < 0) + return log_error_errno(r, "Password from environment variable $PASSWORD did not work."); + } else { + AskPasswordFlags ask_password_flags = ASK_PASSWORD_PUSH_CACHE|ASK_PASSWORD_ACCEPT_CACHED; + _cleanup_free_ char *question = NULL, *disk_path = NULL; + unsigned i = 5; + const char *id; + + question = strjoin("Please enter current passphrase for disk ", arg_node, ":"); + if (!question) + return log_oom(); + + disk_path = cescape(arg_node); + if (!disk_path) + return log_oom(); + + id = strjoina("cryptsetup:", disk_path); + + for (;;) { + _cleanup_strv_free_erase_ char **passwords = NULL; + char **p; + + if (--i == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOKEY), + "Too many attempts, giving up:"); + + r = ask_password_auto( + question, "drive-harddisk", id, "cryptenroll", USEC_INFINITY, + ask_password_flags, + &passwords); + if (r < 0) + return log_error_errno(r, "Failed to query password: %m"); + + r = -EPERM; + STRV_FOREACH(p, passwords) { + r = crypt_volume_key_get( + cd, + CRYPT_ANY_SLOT, + vk, + &vks, + *p, + strlen(*p)); + if (r >= 0) + break; + } + if (r >= 0) + break; + + log_error_errno(r, "Password not correct, please try again."); + ask_password_flags &= ~ASK_PASSWORD_ACCEPT_CACHED; + } + } + + *ret_cd = TAKE_PTR(cd); + *ret_volume_key = TAKE_PTR(vk); + *ret_volume_key_size = vks; + + return 0; +} + +static int run(int argc, char *argv[]) { + _cleanup_(crypt_freep) struct crypt_device *cd = NULL; + _cleanup_(erase_and_freep) void *vk = NULL; + size_t vks; + int slot, r; + + log_show_color(true); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + if (arg_enroll_type < 0) + r = prepare_luks(&cd, NULL, NULL); /* No need to unlock device if we don't need the volume key because we don't need to enroll anything */ + else + r = prepare_luks(&cd, &vk, &vks); + if (r < 0) + return r; + + switch (arg_enroll_type) { + + case ENROLL_PASSWORD: + slot = enroll_password(cd, vk, vks); + break; + + case ENROLL_RECOVERY: + slot = enroll_recovery(cd, vk, vks); + break; + + case ENROLL_PKCS11: + slot = enroll_pkcs11(cd, vk, vks, arg_pkcs11_token_uri); + break; + + case ENROLL_FIDO2: + slot = enroll_fido2(cd, vk, vks, arg_fido2_device); + break; + + case ENROLL_TPM2: + slot = enroll_tpm2(cd, vk, vks, arg_tpm2_device, arg_tpm2_pcr_mask); + break; + + case _ENROLL_TYPE_INVALID: + /* List enrolled slots if we are called without anything to enroll or wipe */ + if (!wipe_requested()) + return list_enrolled(cd); + + /* Only slot wiping selected */ + return wipe_slots(cd, arg_wipe_slots, arg_n_wipe_slots, arg_wipe_slots_scope, arg_wipe_slots_mask, -1); + + default: + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Operation not implemented yet."); + } + if (slot < 0) + return slot; + + /* After we completed enrolling, remove user selected slots */ + r = wipe_slots(cd, arg_wipe_slots, arg_n_wipe_slots, arg_wipe_slots_scope, arg_wipe_slots_mask, slot); + if (r < 0) + return r; + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/cryptenroll/cryptenroll.h b/src/cryptenroll/cryptenroll.h new file mode 100644 index 000000000..b28d9db99 --- /dev/null +++ b/src/cryptenroll/cryptenroll.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +typedef enum EnrollType { + ENROLL_PASSWORD, + ENROLL_RECOVERY, + ENROLL_PKCS11, + ENROLL_FIDO2, + ENROLL_TPM2, + _ENROLL_TYPE_MAX, + _ENROLL_TYPE_INVALID = -EINVAL, +} EnrollType; + +typedef enum WipeScope { + WIPE_EXPLICIT, /* only wipe the listed slots */ + WIPE_ALL, /* wipe all slots */ + WIPE_EMPTY_PASSPHRASE, /* wipe slots with empty passphrases plus listed slots */ + _WIPE_SCOPE_MAX, + _WIPE_SCOPE_INVALID = -EINVAL, +} WipeScope; + +const char* enroll_type_to_string(EnrollType t); +EnrollType enroll_type_from_string(const char *s); + +const char* luks2_token_type_to_string(EnrollType t); +EnrollType luks2_token_type_from_string(const char *s); diff --git a/src/cryptenroll/meson.build b/src/cryptenroll/meson.build new file mode 100644 index 000000000..0a795934e --- /dev/null +++ b/src/cryptenroll/meson.build @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +systemd_cryptenroll_sources = files( + 'cryptenroll-fido2.h', + 'cryptenroll-list.c', + 'cryptenroll-list.h', + 'cryptenroll-password.c', + 'cryptenroll-password.h', + 'cryptenroll-pkcs11.h', + 'cryptenroll-recovery.c', + 'cryptenroll-recovery.h', + 'cryptenroll-tpm2.h', + 'cryptenroll-wipe.c', + 'cryptenroll-wipe.h', + 'cryptenroll.c', + 'cryptenroll.h') + +if conf.get('HAVE_P11KIT') == 1 and conf.get('HAVE_OPENSSL') == 1 + systemd_cryptenroll_sources += files('cryptenroll-pkcs11.c') +endif + +if conf.get('HAVE_LIBFIDO2') == 1 + systemd_cryptenroll_sources += files('cryptenroll-fido2.c') +endif + +if conf.get('HAVE_TPM2') == 1 + systemd_cryptenroll_sources += files('cryptenroll-tpm2.c') +endif diff --git a/src/cryptsetup/cryptsetup-fido2.c b/src/cryptsetup/cryptsetup-fido2.c new file mode 100644 index 000000000..dfdb96436 --- /dev/null +++ b/src/cryptsetup/cryptsetup-fido2.c @@ -0,0 +1,190 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "ask-password-api.h" +#include "cryptsetup-fido2.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "json.h" +#include "libfido2-util.h" +#include "parse-util.h" +#include "random-util.h" +#include "strv.h" + +int acquire_fido2_key( + const char *volume_name, + const char *friendly_name, + const char *device, + const char *rp_id, + const void *cid, + size_t cid_size, + const char *key_file, + size_t key_file_size, + uint64_t key_file_offset, + const void *key_data, + size_t key_data_size, + usec_t until, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + + AskPasswordFlags flags = ASK_PASSWORD_PUSH_CACHE | ASK_PASSWORD_ACCEPT_CACHED; + _cleanup_strv_free_erase_ char **pins = NULL; + _cleanup_free_ void *loaded_salt = NULL; + const char *salt; + size_t salt_size; + char *e; + int r; + + assert(cid); + assert(key_file || key_data); + + if (key_data) { + salt = key_data; + salt_size = key_data_size; + } else { + _cleanup_free_ char *bindname = NULL; + + /* If we read the salt via AF_UNIX, make this client recognizable */ + if (asprintf(&bindname, "@%" PRIx64"/cryptsetup-fido2/%s", random_u64(), volume_name) < 0) + return log_oom(); + + r = read_full_file_full( + AT_FDCWD, key_file, + key_file_offset == 0 ? UINT64_MAX : key_file_offset, + key_file_size == 0 ? SIZE_MAX : key_file_size, + READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) &loaded_salt, &salt_size); + if (r < 0) + return r; + + salt = loaded_salt; + } + + e = getenv("PIN"); + if (e) { + pins = strv_new(e); + if (!pins) + return log_oom(); + + string_erase(e); + if (unsetenv("PIN") < 0) + return log_error_errno(errno, "Failed to unset $PIN: %m"); + } + + for (;;) { + r = fido2_use_hmac_hash( + device, + rp_id ?: "io.systemd.cryptsetup", + salt, salt_size, + cid, cid_size, + pins, + /* up= */ true, + ret_decrypted_key, + ret_decrypted_key_size); + if (!IN_SET(r, + -ENOANO, /* needs pin */ + -ENOLCK)) /* pin incorrect */ + return r; + + pins = strv_free_erase(pins); + + r = ask_password_auto("Please enter security token PIN:", "drive-harddisk", NULL, "fido2-pin", until, flags, &pins); + if (r < 0) + return log_error_errno(r, "Failed to ask for user password: %m"); + + flags &= ~ASK_PASSWORD_ACCEPT_CACHED; + } +} + +int find_fido2_auto_data( + struct crypt_device *cd, + char **ret_rp_id, + void **ret_salt, + size_t *ret_salt_size, + void **ret_cid, + size_t *ret_cid_size, + int *ret_keyslot) { + + _cleanup_free_ void *cid = NULL, *salt = NULL; + size_t cid_size = 0, salt_size = 0; + _cleanup_free_ char *rp = NULL; + int r, keyslot = -1; + + assert(cd); + assert(ret_salt); + assert(ret_salt_size); + assert(ret_cid); + assert(ret_cid_size); + assert(ret_keyslot); + + /* Loads FIDO2 metadata from LUKS2 JSON token headers. */ + + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token ++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + JsonVariant *w; + + r = cryptsetup_get_token_as_json(cd, token, "systemd-fido2", &v); + if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE)) + continue; + if (r < 0) + return log_error_errno(r, "Failed to read JSON token data off disk: %m"); + + if (cid) + return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), + "Multiple FIDO2 tokens enrolled, cannot automatically determine token."); + + w = json_variant_by_key(v, "fido2-credential"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "FIDO2 token data lacks 'fido2-credential' field."); + + r = unbase64mem(json_variant_string(w), SIZE_MAX, &cid, &cid_size); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid base64 data in 'fido2-credential' field."); + + w = json_variant_by_key(v, "fido2-salt"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "FIDO2 token data lacks 'fido2-salt' field."); + + assert(!salt); + assert(salt_size == 0); + r = unbase64mem(json_variant_string(w), SIZE_MAX, &salt, &salt_size); + if (r < 0) + return log_error_errno(r, "Failed to decode base64 encoded salt."); + + assert(keyslot < 0); + keyslot = cryptsetup_get_keyslot_from_token(v); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to extract keyslot index from FIDO2 JSON data: %m"); + + w = json_variant_by_key(v, "fido2-rp"); + if (w) { + /* The "rp" field is optional. */ + + if (!json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "FIDO2 token data's 'fido2-rp' field is not a string."); + + assert(!rp); + rp = strdup(json_variant_string(w)); + if (!rp) + return log_oom(); + } + } + + if (!cid) + return log_error_errno(SYNTHETIC_ERRNO(ENXIO), + "No valid FIDO2 token data found."); + + log_info("Automatically discovered security FIDO2 token unlocks volume."); + + *ret_rp_id = TAKE_PTR(rp); + *ret_cid = TAKE_PTR(cid); + *ret_cid_size = cid_size; + *ret_salt = TAKE_PTR(salt); + *ret_salt_size = salt_size; + *ret_keyslot = keyslot; + return 0; +} diff --git a/src/cryptsetup/cryptsetup-fido2.h b/src/cryptsetup/cryptsetup-fido2.h new file mode 100644 index 000000000..92093ba38 --- /dev/null +++ b/src/cryptsetup/cryptsetup-fido2.h @@ -0,0 +1,71 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" +#include "log.h" +#include "time-util.h" + +#if HAVE_LIBFIDO2 + +int acquire_fido2_key( + const char *volume_name, + const char *friendly_name, + const char *device, + const char *rp_id, + const void *cid, + size_t cid_size, + const char *key_file, + size_t key_file_size, + uint64_t key_file_offset, + const void *key_data, + size_t key_data_size, + usec_t until, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size); + +int find_fido2_auto_data( + struct crypt_device *cd, + char **ret_rp_id, + void **ret_salt, + size_t *ret_salt_size, + void **ret_cid, + size_t *ret_cid_size, + int *ret_keyslot); + +#else + +static inline int acquire_fido2_key( + const char *volume_name, + const char *friendly_name, + const char *device, + const char *rp_id, + const void *cid, + size_t cid_size, + const char *key_file, + size_t key_file_size, + uint64_t key_file_offset, + const void *key_data, + size_t key_data_size, + usec_t until, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 token support not available."); +} + +static inline int find_fido2_auto_data( + struct crypt_device *cd, + char **ret_rp_id, + void **ret_salt, + size_t *ret_salt_size, + void **ret_cid, + size_t *ret_cid_size, + int *ret_keyslot) { + + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 token support not available."); +} +#endif diff --git a/src/cryptsetup/cryptsetup-generator.c b/src/cryptsetup/cryptsetup-generator.c index 68c73499c..98c8408da 100644 --- a/src/cryptsetup/cryptsetup-generator.c +++ b/src/cryptsetup/cryptsetup-generator.c @@ -301,7 +301,9 @@ static int create_disk( netdev = fstab_test_option(options, "_netdev\0"); attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0"); - keyfile_can_timeout = fstab_filter_options(options, "keyfile-timeout\0", NULL, &keyfile_timeout_value, NULL); + keyfile_can_timeout = fstab_filter_options(options, + "keyfile-timeout\0", + NULL, &keyfile_timeout_value, NULL, NULL); if (keyfile_can_timeout < 0) return log_error_errno(keyfile_can_timeout, "Failed to parse keyfile-timeout= option value: %m"); @@ -310,11 +312,12 @@ static int create_disk( "header\0", NULL, &header_path, + NULL, headerdev ? &filtered_header : NULL); if (detached_header < 0) return log_error_errno(detached_header, "Failed to parse header= option value: %m"); - tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL); + tmp = fstab_filter_options(options, "tmp\0", NULL, &tmp_fstype, NULL, NULL); if (tmp < 0) return log_error_errno(tmp, "Failed to parse tmp= option value: %m"); @@ -445,14 +448,13 @@ static int create_disk( fprintf(f, "After=%s\n" "Requires=%s\n", unit, unit); - if (umount_unit) { + if (umount_unit) fprintf(f, "Wants=%s\n" "Before=%s\n", umount_unit, umount_unit ); - } } if (!nofail) @@ -603,7 +605,7 @@ static int filter_header_device(const char *options, assert(ret_headerdev); assert(ret_filtered_headerdev_options); - r = fstab_filter_options(options, "header\0", NULL, &headerspec, &filtered_headerspec); + r = fstab_filter_options(options, "header\0", NULL, &headerspec, NULL, &filtered_headerspec); if (r < 0) return log_error_errno(r, "Failed to parse header= option value: %m"); @@ -668,7 +670,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat r = sscanf(value, "%m[0-9a-fA-F-]=%ms", &uuid, &uuid_value); if (r != 2) - return free_and_strdup(&arg_default_options, value) < 0 ? log_oom() : 0; + return free_and_strdup_warn(&arg_default_options, value); if (warn_uuid_invalid(uuid, key)) return 0; @@ -692,11 +694,8 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat return 0; n = strspn(value, ALPHANUMERICAL "-"); - if (value[n] != '=') { - if (free_and_strdup(&arg_default_keyfile, value) < 0) - return log_oom(); - return 0; - } + if (value[n] != '=') + return free_and_strdup_warn(&arg_default_keyfile, value); uuid = strndup(value, n); if (!uuid) diff --git a/src/cryptsetup/cryptsetup-keyfile.c b/src/cryptsetup/cryptsetup-keyfile.c index f84912356..a6281fbde 100644 --- a/src/cryptsetup/cryptsetup-keyfile.c +++ b/src/cryptsetup/cryptsetup-keyfile.c @@ -1,29 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include - #include "cryptsetup-keyfile.h" -#include "fd-util.h" -#include "format-util.h" -#include "memory-util.h" +#include "fileio.h" #include "path-util.h" -#include "stat-util.h" #include "strv.h" -#define KEY_FILE_SIZE_MAX (16U*1024U*1024U) /* 16 MiB */ - -int load_key_file( +int find_key_file( const char *key_file, char **search_path, - size_t key_file_size, - uint64_t key_file_offset, + const char *bindname, void **ret_key, size_t *ret_key_size) { - _cleanup_(erase_and_freep) char *buffer = NULL; - _cleanup_free_ char *discovered_path = NULL; - _cleanup_close_ int fd = -1; - ssize_t n; + char **i; int r; assert(key_file); @@ -31,80 +20,38 @@ int load_key_file( assert(ret_key_size); if (strv_isempty(search_path) || path_is_absolute(key_file)) { - fd = open(key_file, O_RDONLY|O_CLOEXEC); - if (fd < 0) - return log_error_errno(errno, "Failed to load key file '%s': %m", key_file); - } else { - char **i; - STRV_FOREACH(i, search_path) { - _cleanup_free_ char *joined; - - joined = path_join(*i, key_file); - if (!joined) - return log_oom(); - - fd = open(joined, O_RDONLY|O_CLOEXEC); - if (fd >= 0) { - discovered_path = TAKE_PTR(joined); - break; - } - if (errno != ENOENT) - return log_error_errno(errno, "Failed to load key file '%s': %m", joined); - } - - if (!discovered_path) { - /* Search path supplied, but file not found, report by returning NULL, but not failing */ - *ret_key = NULL; - *ret_key_size = 0; - return 0; - } - - assert(fd >= 0); - key_file = discovered_path; - } - - if (key_file_size == 0) { - struct stat st; - - if (fstat(fd, &st) < 0) - return log_error_errno(errno, "Failed to stat key file '%s': %m", key_file); - - r = stat_verify_regular(&st); + r = read_full_file_full( + AT_FDCWD, key_file, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) ret_key, ret_key_size); if (r < 0) - return log_error_errno(r, "Key file is not a regular file: %m"); + return log_error_errno(r, "Failed to load key file '%s': %m", key_file); - if (st.st_size == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file is empty, refusing."); - if ((uint64_t) st.st_size > KEY_FILE_SIZE_MAX) { - char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX]; - return log_error_errno(SYNTHETIC_ERRNO(ERANGE), - "Key file larger (%s) than allowed maximum size (%s), refusing.", - format_bytes(buf1, sizeof(buf1), st.st_size), - format_bytes(buf2, sizeof(buf2), KEY_FILE_SIZE_MAX)); - } - - if (key_file_offset >= (uint64_t) st.st_size) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file offset too large for file, refusing."); - - key_file_size = st.st_size - key_file_offset; + return 1; } - buffer = malloc(key_file_size); - if (!buffer) - return log_oom(); + STRV_FOREACH(i, search_path) { + _cleanup_free_ char *joined; - if (key_file_offset > 0) - n = pread(fd, buffer, key_file_size, key_file_offset); - else - n = read(fd, buffer, key_file_size); - if (n < 0) - return log_error_errno(errno, "Failed to read key file '%s': %m", key_file); - if (n == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Empty encrypted key found, refusing."); + joined = path_join(*i, key_file); + if (!joined) + return log_oom(); - *ret_key = TAKE_PTR(buffer); - *ret_key_size = (size_t) n; + r = read_full_file_full( + AT_FDCWD, joined, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) ret_key, ret_key_size); + if (r >= 0) + return 1; + if (r != -ENOENT) + return log_error_errno(r, "Failed to load key file '%s': %m", key_file); + } - return 1; + /* Search path supplied, but file not found, report by returning NULL, but not failing */ + *ret_key = NULL; + *ret_key_size = 0; + return 0; } diff --git a/src/cryptsetup/cryptsetup-keyfile.h b/src/cryptsetup/cryptsetup-keyfile.h index 308f5ebd6..83bd1fbed 100644 --- a/src/cryptsetup/cryptsetup-keyfile.h +++ b/src/cryptsetup/cryptsetup-keyfile.h @@ -4,10 +4,9 @@ #include #include -int load_key_file( +int find_key_file( const char *key_file, char **search_path, - size_t key_file_size, - uint64_t key_file_offset, + const char *bindname, void **ret_key, size_t *ret_key_size); diff --git a/src/cryptsetup/cryptsetup-pkcs11.c b/src/cryptsetup/cryptsetup-pkcs11.c index 50db46f8d..8d7d74fb7 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.c +++ b/src/cryptsetup/cryptsetup-pkcs11.c @@ -10,13 +10,17 @@ #include "alloc-util.h" #include "ask-password-api.h" #include "cryptsetup-pkcs11.h" -#include "cryptsetup-keyfile.h" #include "escape.h" #include "fd-util.h" +#include "fileio.h" #include "format-util.h" +#include "hexdecoct.h" +#include "json.h" #include "macro.h" #include "memory-util.h" +#include "parse-util.h" #include "pkcs11-util.h" +#include "random-util.h" #include "stat-util.h" #include "strv.h" @@ -95,6 +99,7 @@ static int pkcs11_callback( } int decrypt_pkcs11_key( + const char *volume_name, const char *friendly_name, const char *pkcs11_uri, const char *key_file, /* We either expect key_file and associated parameters to be set (for file keys) … */ @@ -126,7 +131,19 @@ int decrypt_pkcs11_key( data.free_encrypted_key = false; } else { - r = load_key_file(key_file, NULL, key_file_size, key_file_offset, &data.encrypted_key, &data.encrypted_key_size); + _cleanup_free_ char *bindname = NULL; + + /* If we read the key via AF_UNIX, make this client recognizable */ + if (asprintf(&bindname, "@%" PRIx64"/cryptsetup-pkcs11/%s", random_u64(), volume_name) < 0) + return log_oom(); + + r = read_full_file_full( + AT_FDCWD, key_file, + key_file_offset == 0 ? UINT64_MAX : key_file_offset, + key_file_size == 0 ? SIZE_MAX : key_file_size, + READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) &data.encrypted_key, &data.encrypted_key_size); if (r < 0) return r; @@ -142,3 +159,80 @@ int decrypt_pkcs11_key( return 0; } + +int find_pkcs11_auto_data( + struct crypt_device *cd, + char **ret_uri, + void **ret_encrypted_key, + size_t *ret_encrypted_key_size, + int *ret_keyslot) { + + _cleanup_free_ char *uri = NULL; + _cleanup_free_ void *key = NULL; + int r, keyslot = -1; + size_t key_size = 0; + + assert(cd); + assert(ret_uri); + assert(ret_encrypted_key); + assert(ret_encrypted_key_size); + assert(ret_keyslot); + + /* Loads PKCS#11 metadata from LUKS2 JSON token headers. */ + + for (int token = 0; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + JsonVariant *w; + + r = cryptsetup_get_token_as_json(cd, token, "systemd-pkcs11", &v); + if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE)) + continue; + if (r < 0) + return log_error_errno(r, "Failed to read JSON token data off disk: %m"); + + if (uri) + return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), + "Multiple PKCS#11 tokens enrolled, cannot automatically determine token."); + + w = json_variant_by_key(v, "pkcs11-uri"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "PKCS#11 token data lacks 'pkcs11-uri' field."); + + uri = strdup(json_variant_string(w)); + if (!uri) + return log_oom(); + + if (!pkcs11_uri_valid(uri)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "PKCS#11 token data contains invalid PKCS#11 URI."); + + w = json_variant_by_key(v, "pkcs11-key"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "PKCS#11 token data lacks 'pkcs11-key' field."); + + assert(!key); + assert(key_size == 0); + r = unbase64mem(json_variant_string(w), SIZE_MAX, &key, &key_size); + if (r < 0) + return log_error_errno(r, "Failed to decode base64 encoded key."); + + assert(keyslot < 0); + keyslot = cryptsetup_get_keyslot_from_token(v); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to extract keyslot index from PKCS#11 JSON data: %m"); + } + + if (!uri) + return log_error_errno(SYNTHETIC_ERRNO(ENXIO), + "No valid PKCS#11 token data found."); + + log_info("Automatically discovered security PKCS#11 token '%s' unlocks volume.", uri); + + *ret_uri = TAKE_PTR(uri); + *ret_encrypted_key = TAKE_PTR(key); + *ret_encrypted_key_size = key_size; + *ret_keyslot = keyslot; + return 0; +} diff --git a/src/cryptsetup/cryptsetup-pkcs11.h b/src/cryptsetup/cryptsetup-pkcs11.h index 266c8e1b3..4cd82e021 100644 --- a/src/cryptsetup/cryptsetup-pkcs11.h +++ b/src/cryptsetup/cryptsetup-pkcs11.h @@ -3,12 +3,14 @@ #include +#include "cryptsetup-util.h" #include "log.h" #include "time-util.h" #if HAVE_P11KIT int decrypt_pkcs11_key( + const char *volume_name, const char *friendly_name, const char *pkcs11_uri, const char *key_file, @@ -20,9 +22,17 @@ int decrypt_pkcs11_key( void **ret_decrypted_key, size_t *ret_decrypted_key_size); +int find_pkcs11_auto_data( + struct crypt_device *cd, + char **ret_uri, + void **ret_encrypted_key, + size_t *ret_encrypted_key_size, + int *ret_keyslot); + #else static inline int decrypt_pkcs11_key( + const char *volume_name, const char *friendly_name, const char *pkcs11_uri, const char *key_file, @@ -38,4 +48,15 @@ static inline int decrypt_pkcs11_key( "PKCS#11 Token support not available."); } +static inline int find_pkcs11_auto_data( + struct crypt_device *cd, + char **ret_uri, + void **ret_encrypted_key, + size_t *ret_encrypted_key_size, + int *ret_keyslot) { + + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PKCS#11 Token support not available."); +} + #endif diff --git a/src/cryptsetup/cryptsetup-tpm2.c b/src/cryptsetup/cryptsetup-tpm2.c new file mode 100644 index 000000000..4757c5882 --- /dev/null +++ b/src/cryptsetup/cryptsetup-tpm2.c @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "cryptsetup-tpm2.h" +#include "fileio.h" +#include "hexdecoct.h" +#include "json.h" +#include "parse-util.h" +#include "random-util.h" +#include "tpm2-util.h" + +int acquire_tpm2_key( + const char *volume_name, + const char *device, + uint32_t pcr_mask, + const char *key_file, + size_t key_file_size, + uint64_t key_file_offset, + const void *key_data, + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + + _cleanup_free_ void *loaded_blob = NULL; + _cleanup_free_ char *auto_device = NULL; + size_t blob_size; + const void *blob; + int r; + + if (!device) { + r = tpm2_find_device_auto(LOG_DEBUG, &auto_device); + if (r == -ENODEV) + return -EAGAIN; /* Tell the caller to wait for a TPM2 device to show up */ + if (r < 0) + return r; + + device = auto_device; + } + + if (key_data) { + blob = key_data; + blob_size = key_data_size; + } else { + _cleanup_free_ char *bindname = NULL; + + /* If we read the salt via AF_UNIX, make this client recognizable */ + if (asprintf(&bindname, "@%" PRIx64"/cryptsetup-tpm2/%s", random_u64(), volume_name) < 0) + return log_oom(); + + r = read_full_file_full( + AT_FDCWD, key_file, + key_file_offset == 0 ? UINT64_MAX : key_file_offset, + key_file_size == 0 ? SIZE_MAX : key_file_size, + READ_FULL_FILE_CONNECT_SOCKET, + bindname, + (char**) &loaded_blob, &blob_size); + if (r < 0) + return r; + + blob = loaded_blob; + } + + return tpm2_unseal(device, pcr_mask, blob, blob_size, policy_hash, policy_hash_size, ret_decrypted_key, ret_decrypted_key_size); +} + +int find_tpm2_auto_data( + struct crypt_device *cd, + uint32_t search_pcr_mask, + int start_token, + uint32_t *ret_pcr_mask, + void **ret_blob, + size_t *ret_blob_size, + void **ret_policy_hash, + size_t *ret_policy_hash_size, + int *ret_keyslot, + int *ret_token) { + + _cleanup_free_ void *blob = NULL, *policy_hash = NULL; + size_t blob_size = 0, policy_hash_size = 0; + int r, keyslot = -1, token = -1; + uint32_t pcr_mask = 0; + + assert(cd); + + for (token = start_token; token < sym_crypt_token_max(CRYPT_LUKS2); token++) { + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + JsonVariant *w, *e; + + r = cryptsetup_get_token_as_json(cd, token, "systemd-tpm2", &v); + if (IN_SET(r, -ENOENT, -EINVAL, -EMEDIUMTYPE)) + continue; + if (r < 0) + return log_error_errno(r, "Failed to read JSON token data off disk: %m"); + + w = json_variant_by_key(v, "tpm2-pcrs"); + if (!w || !json_variant_is_array(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 token data lacks 'tpm2-pcrs' field."); + + assert(pcr_mask == 0); + JSON_VARIANT_ARRAY_FOREACH(e, w) { + uintmax_t u; + + if (!json_variant_is_number(e)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 PCR is not a number."); + + u = json_variant_unsigned(e); + if (u >= TPM2_PCRS_MAX) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 PCR number out of range."); + + pcr_mask |= UINT32_C(1) << u; + } + + if (search_pcr_mask != UINT32_MAX && + search_pcr_mask != pcr_mask) /* PCR mask doesn't match what is configured, ignore this entry */ + continue; + + assert(!blob); + w = json_variant_by_key(v, "tpm2-blob"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 token data lacks 'tpm2-blob' field."); + + r = unbase64mem(json_variant_string(w), SIZE_MAX, &blob, &blob_size); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid base64 data in 'tpm2-blob' field."); + + assert(!policy_hash); + w = json_variant_by_key(v, "tpm2-policy-hash"); + if (!w || !json_variant_is_string(w)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "TPM2 token data lacks 'tpm2-policy-hash' field."); + + r = unhexmem(json_variant_string(w), SIZE_MAX, &policy_hash, &policy_hash_size); + if (r < 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Invalid base64 data in 'tpm2-policy-hash' field."); + + assert(keyslot < 0); + keyslot = cryptsetup_get_keyslot_from_token(v); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to extract keyslot index from TPM2 JSON data: %m"); + + break; + } + + if (!blob) + return log_error_errno(SYNTHETIC_ERRNO(ENXIO), + "No valid TPM2 token data found."); + + if (start_token <= 0) + log_info("Automatically discovered security TPM2 token unlocks volume."); + + *ret_pcr_mask = pcr_mask; + *ret_blob = TAKE_PTR(blob); + *ret_blob_size = blob_size; + *ret_policy_hash = TAKE_PTR(policy_hash); + *ret_policy_hash_size = policy_hash_size; + *ret_keyslot = keyslot; + *ret_token = token; + + return 0; +} diff --git a/src/cryptsetup/cryptsetup-tpm2.h b/src/cryptsetup/cryptsetup-tpm2.h new file mode 100644 index 000000000..8ddf301a6 --- /dev/null +++ b/src/cryptsetup/cryptsetup-tpm2.h @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include + +#include "cryptsetup-util.h" +#include "log.h" +#include "time-util.h" + +#if HAVE_TPM2 + +int acquire_tpm2_key( + const char *volume_name, + const char *device, + uint32_t pcr_mask, + const char *key_file, + size_t key_file_size, + uint64_t key_file_offset, + const void *key_data, + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size); + +int find_tpm2_auto_data( + struct crypt_device *cd, + uint32_t search_pcr_mask, + int start_token, + uint32_t *ret_pcr_mask, + void **ret_blob, + size_t *ret_blob_size, + void **ret_policy_hash, + size_t *ret_policy_hash_size, + int *ret_keyslot, + int *ret_token); + +#else + +static inline int acquire_tpm2_key( + const char *volume_name, + const char *device, + uint32_t pcr_mask, + const char *key_file, + size_t key_file_size, + uint64_t key_file_offset, + const void *key_data, + size_t key_data_size, + const void *policy_hash, + size_t policy_hash_size, + void **ret_decrypted_key, + size_t *ret_decrypted_key_size) { + + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 support not available."); +} + +static inline int find_tpm2_auto_data( + struct crypt_device *cd, + uint32_t search_pcr_mask, + int start_token, + uint32_t *ret_pcr_mask, + void **ret_blob, + size_t *ret_blob_size, + void **ret_policy_hash, + size_t *ret_policy_hash_size, + int *ret_keyslot, + int *ret_token) { + + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 support not available."); +} + +#endif diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c index 129f5fc3f..dba26a54a 100644 --- a/src/cryptsetup/cryptsetup.c +++ b/src/cryptsetup/cryptsetup.c @@ -11,8 +11,10 @@ #include "alloc-util.h" #include "ask-password-api.h" +#include "cryptsetup-fido2.h" #include "cryptsetup-keyfile.h" #include "cryptsetup-pkcs11.h" +#include "cryptsetup-tpm2.h" #include "cryptsetup-util.h" #include "device-util.h" #include "escape.h" @@ -20,6 +22,7 @@ #include "fs-util.h" #include "fstab-util.h" #include "hexdecoct.h" +#include "libfido2-util.h" #include "log.h" #include "main-func.h" #include "memory-util.h" @@ -29,8 +32,10 @@ #include "path-util.h" #include "pkcs11-util.h" #include "pretty-print.h" +#include "random-util.h" #include "string-util.h" #include "strv.h" +#include "tpm2-util.h" /* internal helper */ #define ANY_LUKS "LUKS" @@ -65,12 +70,25 @@ static uint64_t arg_offset = 0; static uint64_t arg_skip = 0; static usec_t arg_timeout = USEC_INFINITY; static char *arg_pkcs11_uri = NULL; +static bool arg_pkcs11_uri_auto = false; +static char *arg_fido2_device = NULL; +static bool arg_fido2_device_auto = false; +static void *arg_fido2_cid = NULL; +static size_t arg_fido2_cid_size = 0; +static char *arg_fido2_rp_id = NULL; +static char *arg_tpm2_device = NULL; +static bool arg_tpm2_device_auto = false; +static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; STATIC_DESTRUCTOR_REGISTER(arg_cipher, freep); STATIC_DESTRUCTOR_REGISTER(arg_hash, freep); STATIC_DESTRUCTOR_REGISTER(arg_header, freep); STATIC_DESTRUCTOR_REGISTER(arg_tcrypt_keyfiles, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_pkcs11_uri, freep); +STATIC_DESTRUCTOR_REGISTER(arg_fido2_device, freep); +STATIC_DESTRUCTOR_REGISTER(arg_fido2_cid, freep); +STATIC_DESTRUCTOR_REGISTER(arg_fido2_rp_id, freep); +STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); /* Options Debian's crypttab knows we don't: @@ -267,13 +285,90 @@ static int parse_one_option(const char *option) { } else if ((val = startswith(option, "pkcs11-uri="))) { - if (!pkcs11_uri_valid(val)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing"); + if (streq(val, "auto")) { + arg_pkcs11_uri = mfree(arg_pkcs11_uri); + arg_pkcs11_uri_auto = true; + } else { + if (!pkcs11_uri_valid(val)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "pkcs11-uri= parameter expects a PKCS#11 URI, refusing"); - r = free_and_strdup(&arg_pkcs11_uri, val); + r = free_and_strdup(&arg_pkcs11_uri, val); + if (r < 0) + return log_oom(); + + arg_pkcs11_uri_auto = false; + } + + } else if ((val = startswith(option, "fido2-device="))) { + + if (streq(val, "auto")) { + arg_fido2_device = mfree(arg_fido2_device); + arg_fido2_device_auto = true; + } else { + r = free_and_strdup(&arg_fido2_device, val); + if (r < 0) + return log_oom(); + + arg_fido2_device_auto = false; + } + + } else if ((val = startswith(option, "fido2-cid="))) { + + if (streq(val, "auto")) + arg_fido2_cid = mfree(arg_fido2_cid); + else { + _cleanup_free_ void *cid = NULL; + size_t cid_size; + + r = unbase64mem(val, SIZE_MAX, &cid, &cid_size); + if (r < 0) + return log_error_errno(r, "Failed to decode FIDO2 CID data: %m"); + + free(arg_fido2_cid); + arg_fido2_cid = TAKE_PTR(cid); + arg_fido2_cid_size = cid_size; + } + + /* Turn on FIDO2 as side-effect, if not turned on yet. */ + if (!arg_fido2_device && !arg_fido2_device_auto) + arg_fido2_device_auto = true; + + } else if ((val = startswith(option, "fido2-rp="))) { + + r = free_and_strdup(&arg_fido2_rp_id, val); if (r < 0) return log_oom(); + } else if ((val = startswith(option, "tpm2-device="))) { + + if (streq(val, "auto")) { + arg_tpm2_device = mfree(arg_tpm2_device); + arg_tpm2_device_auto = true; + } else { + r = free_and_strdup(&arg_tpm2_device, val); + if (r < 0) + return log_oom(); + + arg_tpm2_device_auto = false; + } + + } else if ((val = startswith(option, "tpm2-pcrs="))) { + + if (isempty(val)) + arg_tpm2_pcr_mask = 0; + else { + uint32_t mask; + + r = tpm2_parse_pcrs(val, &mask); + if (r < 0) + return r; + + if (arg_tpm2_pcr_mask == UINT32_MAX) + arg_tpm2_pcr_mask = mask; + else + arg_tpm2_pcr_mask |= mask; + } + } else if ((val = startswith(option, "try-empty-password="))) { r = parse_boolean(val); @@ -324,7 +419,6 @@ static int parse_options(const char *options) { static char* disk_description(const char *path) { static const char name_fields[] = - "ID_PART_ENTRY_NAME\0" "DM_NAME\0" "ID_MODEL_FROM_DATABASE\0" "ID_MODEL\0"; @@ -332,6 +426,7 @@ static char* disk_description(const char *path) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; const char *i, *name; struct stat st; + int r; assert(path); @@ -341,9 +436,27 @@ static char* disk_description(const char *path) { if (!S_ISBLK(st.st_mode)) return NULL; - if (sd_device_new_from_devnum(&device, 'b', st.st_rdev) < 0) + if (sd_device_new_from_stat_rdev(&device, &st) < 0) return NULL; + if (sd_device_get_property_value(device, "ID_PART_ENTRY_NAME", &name) >= 0) { + _cleanup_free_ char *unescaped = NULL; + + /* ID_PART_ENTRY_NAME uses \x style escaping, using libblkid's blkid_encode_string(). Let's + * reverse this here to make the string more human friendly in case people embed spaces or + * other weird stuff. */ + + r = cunescape(name, UNESCAPE_RELAX, &unescaped); + if (r < 0) { + log_debug_errno(r, "Failed to unescape ID_PART_ENTRY_NAME, skipping device: %m"); + return NULL; + } + + if (!isempty(unescaped) && !string_has_cc(unescaped, NULL)) + return TAKE_PTR(unescaped); + } + + /* These need no unescaping. */ NULSTR_FOREACH(i, name_fields) if (sd_device_get_property_value(device, i, &name) >= 0 && !isempty(name)) @@ -473,7 +586,8 @@ static int get_password( return log_oom(); strncpy(c, *p, arg_key_size); - free_and_replace(*p, c); + erase_and_free(*p); + *p = TAKE_PTR(c); } *ret = TAKE_PTR(passwords); @@ -491,7 +605,7 @@ static int attach_tcrypt( uint32_t flags) { int r = 0; - _cleanup_free_ char *passphrase = NULL; + _cleanup_(erase_and_freep) char *passphrase = NULL; struct crypt_params_tcrypt params = { .flags = CRYPT_TCRYPT_LEGACY_MODES, .keyfiles = (const char **)arg_tcrypt_keyfiles, @@ -502,10 +616,10 @@ static int attach_tcrypt( assert(name); assert(key_file || key_data || !strv_isempty(passwords)); - if (arg_pkcs11_uri) + if (arg_pkcs11_uri || arg_pkcs11_uri_auto || arg_fido2_device || arg_fido2_device_auto || arg_tpm2_device || arg_tpm2_device_auto) /* Ask for a regular password */ return log_error_errno(SYNTHETIC_ERRNO(EAGAIN), - "Sorry, but tcrypt devices are currently not supported in conjunction with pkcs11 support."); + "Sorry, but tcrypt devices are currently not supported in conjunction with pkcs11/fido2/tpm2 support."); if (arg_tcrypt_hidden) params.flags |= CRYPT_TCRYPT_HIDDEN_HEADER; @@ -556,6 +670,594 @@ static int attach_tcrypt( return 0; } +static char *make_bindname(const char *volume) { + char *s; + + if (asprintf(&s, "@%" PRIx64"/cryptsetup/%s", random_u64(), volume) < 0) + return NULL; + + return s; +} + +static int make_security_device_monitor(sd_event *event, sd_device_monitor **ret) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; + int r; + + assert(ret); + + r = sd_device_monitor_new(&monitor); + if (r < 0) + return log_error_errno(r, "Failed to allocate device monitor: %m"); + + r = sd_device_monitor_filter_add_match_tag(monitor, "security-device"); + if (r < 0) + return log_error_errno(r, "Failed to configure device monitor: %m"); + + r = sd_device_monitor_attach_event(monitor, event); + if (r < 0) + return log_error_errno(r, "Failed to attach device monitor: %m"); + + r = sd_device_monitor_start(monitor, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to start device monitor: %m"); + + *ret = TAKE_PTR(monitor); + return 0; +} + +static int attach_luks_or_plain_or_bitlk_by_fido2( + struct crypt_device *cd, + const char *name, + const char *key_file, + const void *key_data, + size_t key_data_size, + usec_t until, + uint32_t flags, + bool pass_volume_key) { + + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; + _cleanup_(erase_and_freep) void *decrypted_key = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_free_ void *discovered_salt = NULL, *discovered_cid = NULL; + size_t discovered_salt_size, discovered_cid_size, cid_size, decrypted_key_size; + _cleanup_free_ char *friendly = NULL, *discovered_rp_id = NULL; + int keyslot = arg_key_slot, r; + const char *rp_id; + const void *cid; + + assert(cd); + assert(name); + assert(arg_fido2_device || arg_fido2_device_auto); + + if (arg_fido2_cid) { + if (!key_file && !key_data) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "FIDO2 mode selected but no key file specified, refusing."); + + rp_id = arg_fido2_rp_id; + cid = arg_fido2_cid; + cid_size = arg_fido2_cid_size; + } else { + r = find_fido2_auto_data( + cd, + &discovered_rp_id, + &discovered_salt, + &discovered_salt_size, + &discovered_cid, + &discovered_cid_size, + &keyslot); + + if (IN_SET(r, -ENOTUNIQ, -ENXIO)) + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), + "Automatic FIDO2 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking."); + if (r < 0) + return r; + + rp_id = discovered_rp_id; + key_data = discovered_salt; + key_data_size = discovered_salt_size; + cid = discovered_cid; + cid_size = discovered_cid_size; + } + + friendly = friendly_disk_name(crypt_get_device_name(cd), name); + if (!friendly) + return log_oom(); + + for (;;) { + bool processed = false; + + r = acquire_fido2_key( + name, + friendly, + arg_fido2_device, + rp_id, + cid, cid_size, + key_file, arg_keyfile_size, arg_keyfile_offset, + key_data, key_data_size, + until, + &decrypted_key, &decrypted_key_size); + if (r >= 0) + break; + if (r != -EAGAIN) /* EAGAIN means: token not found */ + return r; + + if (!monitor) { + /* We didn't find the token. In this case, watch for it via udev. Let's + * create an event loop and monitor first. */ + + assert(!event); + + r = sd_event_default(&event); + if (r < 0) + return log_error_errno(r, "Failed to allocate event loop: %m"); + + r = make_security_device_monitor(event, &monitor); + if (r < 0) + return r; + + log_notice("Security token not present for unlocking volume %s, please plug it in.", friendly); + + /* Let's immediately rescan in case the token appeared in the time we needed + * to create and configure the monitor */ + continue; + } + + for (;;) { + /* Wait for one event, and then eat all subsequent events until there are no + * further ones */ + r = sd_event_run(event, processed ? 0 : UINT64_MAX); + if (r < 0) + return log_error_errno(r, "Failed to run event loop: %m"); + if (r == 0) + break; + + processed = true; + } + + log_debug("Got one or more potentially relevant udev events, rescanning FIDO2..."); + } + + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags); + else { + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + + /* Before using this key as passphrase we base64 encode it, for compat with homed */ + + r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); + if (r < 0) + return log_oom(); + + r = crypt_activate_by_passphrase(cd, name, keyslot, base64_encoded, strlen(base64_encoded), flags); + } + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with FIDO2 decrypted key. (Key incorrect?)"); + return -EAGAIN; /* log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate with FIDO2 acquired key: %m"); + + return 0; +} + +static int attach_luks_or_plain_or_bitlk_by_pkcs11( + struct crypt_device *cd, + const char *name, + const char *key_file, + const void *key_data, + size_t key_data_size, + usec_t until, + uint32_t flags, + bool pass_volume_key) { + + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; + _cleanup_free_ char *friendly = NULL, *discovered_uri = NULL; + size_t decrypted_key_size = 0, discovered_key_size = 0; + _cleanup_(erase_and_freep) void *decrypted_key = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_free_ void *discovered_key = NULL; + int keyslot = arg_key_slot, r; + const char *uri; + + assert(cd); + assert(name); + assert(arg_pkcs11_uri || arg_pkcs11_uri_auto); + + if (arg_pkcs11_uri_auto) { + r = find_pkcs11_auto_data(cd, &discovered_uri, &discovered_key, &discovered_key_size, &keyslot); + if (IN_SET(r, -ENOTUNIQ, -ENXIO)) + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), + "Automatic PKCS#11 metadata discovery was not possible because missing or not unique, falling back to traditional unlocking."); + if (r < 0) + return r; + + uri = discovered_uri; + key_data = discovered_key; + key_data_size = discovered_key_size; + } else { + uri = arg_pkcs11_uri; + + if (!key_file && !key_data) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing."); + } + + friendly = friendly_disk_name(crypt_get_device_name(cd), name); + if (!friendly) + return log_oom(); + + for (;;) { + bool processed = false; + + r = decrypt_pkcs11_key( + name, + friendly, + uri, + key_file, arg_keyfile_size, arg_keyfile_offset, + key_data, key_data_size, + until, + &decrypted_key, &decrypted_key_size); + if (r >= 0) + break; + if (r != -EAGAIN) /* EAGAIN means: token not found */ + return r; + + if (!monitor) { + /* We didn't find the token. In this case, watch for it via udev. Let's + * create an event loop and monitor first. */ + + assert(!event); + + r = sd_event_default(&event); + if (r < 0) + return log_error_errno(r, "Failed to allocate event loop: %m"); + + r = make_security_device_monitor(event, &monitor); + if (r < 0) + return r; + + log_notice("Security token %s not present for unlocking volume %s, please plug it in.", + uri, friendly); + + /* Let's immediately rescan in case the token appeared in the time we needed + * to create and configure the monitor */ + continue; + } + + for (;;) { + /* Wait for one event, and then eat all subsequent events until there are no + * further ones */ + r = sd_event_run(event, processed ? 0 : UINT64_MAX); + if (r < 0) + return log_error_errno(r, "Failed to run event loop: %m"); + if (r == 0) + break; + + processed = true; + } + + log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11..."); + } + + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags); + else { + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + + /* Before using this key as passphrase we base64 encode it. Why? For compatibility + * with homed's PKCS#11 hookup: there we want to use the key we acquired through + * PKCS#11 for other authentication/decryption mechanisms too, and some of them do + * not not take arbitrary binary blobs, but require NUL-terminated strings — most + * importantly UNIX password hashes. Hence, for compatibility we want to use a string + * without embedded NUL here too, and that's easiest to generate from a binary blob + * via base64 encoding. */ + + r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); + if (r < 0) + return log_oom(); + + r = crypt_activate_by_passphrase(cd, name, keyslot, base64_encoded, strlen(base64_encoded), flags); + } + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with PKCS#11 decrypted key. (Key incorrect?)"); + return -EAGAIN; /* log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m"); + + return 0; +} + +static int make_tpm2_device_monitor(sd_event *event, sd_device_monitor **ret) { + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; + int r; + + assert(ret); + + r = sd_device_monitor_new(&monitor); + if (r < 0) + return log_error_errno(r, "Failed to allocate device monitor: %m"); + + r = sd_device_monitor_filter_add_match_subsystem_devtype(monitor, "tpmrm", NULL); + if (r < 0) + return log_error_errno(r, "Failed to configure device monitor: %m"); + + r = sd_device_monitor_attach_event(monitor, event); + if (r < 0) + return log_error_errno(r, "Failed to attach device monitor: %m"); + + r = sd_device_monitor_start(monitor, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to start device monitor: %m"); + + *ret = TAKE_PTR(monitor); + return 0; +} + +static int attach_luks_or_plain_or_bitlk_by_tpm2( + struct crypt_device *cd, + const char *name, + const char *key_file, + const void *key_data, + size_t key_data_size, + usec_t until, + uint32_t flags, + bool pass_volume_key) { + + _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; + _cleanup_(erase_and_freep) void *decrypted_key = NULL; + _cleanup_(sd_event_unrefp) sd_event *event = NULL; + _cleanup_free_ char *friendly = NULL; + int keyslot = arg_key_slot, r; + size_t decrypted_key_size; + + assert(cd); + assert(name); + assert(arg_tpm2_device || arg_tpm2_device_auto); + + friendly = friendly_disk_name(crypt_get_device_name(cd), name); + if (!friendly) + return log_oom(); + + for (;;) { + bool processed = false; + + if (key_file || key_data) { + /* If key data is specified, use that */ + + r = acquire_tpm2_key( + name, + arg_tpm2_device, + arg_tpm2_pcr_mask == UINT32_MAX ? TPM2_PCR_MASK_DEFAULT : arg_tpm2_pcr_mask, + key_file, arg_keyfile_size, arg_keyfile_offset, + key_data, key_data_size, + NULL, 0, /* we don't know the policy hash */ + &decrypted_key, &decrypted_key_size); + if (r >= 0) + break; + if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */ + return r; + } else { + _cleanup_free_ void *blob = NULL, *policy_hash = NULL; + size_t blob_size, policy_hash_size; + bool found_some = false; + int token = 0; /* first token to look at */ + + /* If no key data is specified, look for it in the header. In order to support + * software upgrades we'll iterate through all suitable tokens, maybe one of them + * works. */ + + for (;;) { + uint32_t pcr_mask; + + r = find_tpm2_auto_data( + cd, + arg_tpm2_pcr_mask, /* if != UINT32_MAX we'll only look for tokens with this PCR mask */ + token, /* search for the token with this index, or any later index than this */ + &pcr_mask, + &blob, &blob_size, + &policy_hash, &policy_hash_size, + &keyslot, + &token); + if (r == -ENXIO) { + /* No further TPM2 tokens found in the LUKS2 header.*/ + if (found_some) + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), + "No TPM2 metadata matching the current system state found in LUKS2 header, falling back to traditional unlocking."); + else + return log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), + "No TPM2 metadata enrolled in LUKS2 header, falling back to traditional unlocking."); + } + if (r < 0) + return r; + + found_some = true; + + r = acquire_tpm2_key( + name, + arg_tpm2_device, + pcr_mask, + NULL, 0, 0, /* no key file */ + blob, blob_size, + policy_hash, policy_hash_size, + &decrypted_key, &decrypted_key_size); + if (r != -EPERM) + break; + + token++; /* try a different token next time */ + } + + if (r >= 0) + break; + if (r != -EAGAIN) /* EAGAIN means: no tpm2 chip found */ + return r; + } + + if (!monitor) { + /* We didn't find the TPM2 device. In this case, watch for it via udev. Let's create + * an event loop and monitor first. */ + + assert(!event); + + r = sd_event_default(&event); + if (r < 0) + return log_error_errno(r, "Failed to allocate event loop: %m"); + + r = make_tpm2_device_monitor(event, &monitor); + if (r < 0) + return r; + + log_info("TPM2 device not present for unlocking %s, waiting for it to become available.", friendly); + + /* Let's immediately rescan in case the device appeared in the time we needed + * to create and configure the monitor */ + continue; + } + + for (;;) { + /* Wait for one event, and then eat all subsequent events until there are no + * further ones */ + r = sd_event_run(event, processed ? 0 : UINT64_MAX); + if (r < 0) + return log_error_errno(r, "Failed to run event loop: %m"); + if (r == 0) + break; + + processed = true; + } + + log_debug("Got one or more potentially relevant udev events, rescanning for TPM2..."); + } + + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags); + else { + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + + /* Before using this key as passphrase we base64 encode it, for compat with homed */ + + r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); + if (r < 0) + return log_oom(); + + r = crypt_activate_by_passphrase(cd, name, keyslot, base64_encoded, strlen(base64_encoded), flags); + } + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with TPM2 decrypted key. (Key incorrect?)"); + return -EAGAIN; /* log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate with TPM2 acquired key: %m"); + + return 0; +} + +static int attach_luks_or_plain_or_bitlk_by_key_data( + struct crypt_device *cd, + const char *name, + const void *key_data, + size_t key_data_size, + uint32_t flags, + bool pass_volume_key) { + + int r; + + assert(cd); + assert(name); + assert(key_data); + + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags); + else + r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags); + if (r == -EPERM) { + log_error_errno(r, "Failed to activate. (Key incorrect?)"); + return -EAGAIN; /* Log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate: %m"); + + return 0; +} + +static int attach_luks_or_plain_or_bitlk_by_key_file( + struct crypt_device *cd, + const char *name, + const char *key_file, + uint32_t flags, + bool pass_volume_key) { + + _cleanup_(erase_and_freep) char *kfdata = NULL; + _cleanup_free_ char *bindname = NULL; + size_t kfsize; + int r; + + assert(cd); + assert(name); + assert(key_file); + + /* If we read the key via AF_UNIX, make this client recognizable */ + bindname = make_bindname(name); + if (!bindname) + return log_oom(); + + r = read_full_file_full( + AT_FDCWD, key_file, + arg_keyfile_offset == 0 ? UINT64_MAX : arg_keyfile_offset, + arg_keyfile_size == 0 ? SIZE_MAX : arg_keyfile_size, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + bindname, + &kfdata, &kfsize); + if (r == -ENOENT) { + log_error_errno(r, "Failed to activate, key file '%s' missing.", key_file); + return -EAGAIN; /* Log actual error, but return EAGAIN */ + } + + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, kfdata, kfsize, flags); + else + r = crypt_activate_by_passphrase(cd, name, arg_key_slot, kfdata, kfsize, flags); + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file); + return -EAGAIN; /* Log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file); + + return 0; +} + +static int attach_luks_or_plain_or_bitlk_by_passphrase( + struct crypt_device *cd, + const char *name, + char **passwords, + uint32_t flags, + bool pass_volume_key) { + + char **p; + int r; + + assert(cd); + assert(name); + + r = -EINVAL; + STRV_FOREACH(p, passwords) { + if (pass_volume_key) + r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags); + else + r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags); + if (r >= 0) + break; + } + if (r == -EPERM) { + log_error_errno(r, "Failed to activate with specified passphrase. (Passphrase incorrect?)"); + return -EAGAIN; /* log actual error, but return EAGAIN */ + } + if (r < 0) + return log_error_errno(r, "Failed to activate with specified passphrase: %m"); + + return 0; +} + static int attach_luks_or_plain_or_bitlk( struct crypt_device *cd, const char *name, @@ -566,8 +1268,8 @@ static int attach_luks_or_plain_or_bitlk( uint32_t flags, usec_t until) { - int r = 0; bool pass_volume_key = false; + int r; assert(cd); assert(name); @@ -581,13 +1283,14 @@ static int attach_luks_or_plain_or_bitlk( const char *cipher, *cipher_mode; _cleanup_free_ char *truncated_cipher = NULL; - if (arg_hash) { + if (streq_ptr(arg_hash, "plain")) /* plain isn't a real hash type. it just means "use no hash" */ - if (!streq(arg_hash, "plain")) - params.hash = arg_hash; - } else if (!key_file) - /* for CRYPT_PLAIN, the behaviour of cryptsetup - * package is to not hash when a key file is provided */ + params.hash = NULL; + else if (arg_hash) + params.hash = arg_hash; + else if (!key_file) + /* for CRYPT_PLAIN, the behaviour of cryptsetup package is to not hash when a key + * file is provided */ params.hash = "ripemd160"; if (arg_cipher) { @@ -615,7 +1318,7 @@ static int attach_luks_or_plain_or_bitlk( return log_error_errno(r, "Loading of cryptographic parameters failed: %m"); /* hash == NULL implies the user passed "plain" */ - pass_volume_key = (params.hash == NULL); + pass_volume_key = !params.hash; } log_info("Set cipher %s, mode %s, key size %i bits for device %s.", @@ -624,156 +1327,18 @@ static int attach_luks_or_plain_or_bitlk( crypt_get_volume_key_size(cd)*8, crypt_get_device_name(cd)); - if (arg_pkcs11_uri) { - _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *monitor = NULL; - _cleanup_(sd_event_unrefp) sd_event *event = NULL; - _cleanup_free_ void *decrypted_key = NULL; - _cleanup_free_ char *friendly = NULL; - size_t decrypted_key_size = 0; + if (arg_tpm2_device || arg_tpm2_device_auto) + return attach_luks_or_plain_or_bitlk_by_tpm2(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key); + if (arg_fido2_device || arg_fido2_device_auto) + return attach_luks_or_plain_or_bitlk_by_fido2(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key); + if (arg_pkcs11_uri || arg_pkcs11_uri_auto) + return attach_luks_or_plain_or_bitlk_by_pkcs11(cd, name, key_file, key_data, key_data_size, until, flags, pass_volume_key); + if (key_data) + return attach_luks_or_plain_or_bitlk_by_key_data(cd, name, key_data, key_data_size, flags, pass_volume_key); + if (key_file) + return attach_luks_or_plain_or_bitlk_by_key_file(cd, name, key_file, flags, pass_volume_key); - if (!key_file && !key_data) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "PKCS#11 mode selected but no key file specified, refusing."); - - friendly = friendly_disk_name(crypt_get_device_name(cd), name); - if (!friendly) - return log_oom(); - - for (;;) { - bool processed = false; - - r = decrypt_pkcs11_key( - friendly, - arg_pkcs11_uri, - key_file, arg_keyfile_size, arg_keyfile_offset, - key_data, key_data_size, - until, - &decrypted_key, &decrypted_key_size); - if (r >= 0) - break; - if (r != -EAGAIN) /* EAGAIN means: token not found */ - return r; - - if (!monitor) { - /* We didn't find the token. In this case, watch for it via udev. Let's - * create an event loop and monitor first. */ - - assert(!event); - - r = sd_event_default(&event); - if (r < 0) - return log_error_errno(r, "Failed to allocate event loop: %m"); - - r = sd_device_monitor_new(&monitor); - if (r < 0) - return log_error_errno(r, "Failed to allocate device monitor: %m"); - - r = sd_device_monitor_filter_add_match_tag(monitor, "security-device"); - if (r < 0) - return log_error_errno(r, "Failed to configure device monitor: %m"); - - r = sd_device_monitor_attach_event(monitor, event); - if (r < 0) - return log_error_errno(r, "Failed to attach device monitor: %m"); - - r = sd_device_monitor_start(monitor, NULL, NULL); - if (r < 0) - return log_error_errno(r, "Failed to start device monitor: %m"); - - log_notice("Security token %s not present for unlocking volume %s, please plug it in.", - arg_pkcs11_uri, friendly); - - /* Let's immediately rescan in case the token appeared in the time we needed - * to create and configure the monitor */ - continue; - } - - for (;;) { - /* Wait for one event, and then eat all subsequent events until there are no - * further ones */ - r = sd_event_run(event, processed ? 0 : UINT64_MAX); - if (r < 0) - return log_error_errno(r, "Failed to run event loop: %m"); - if (r == 0) - break; - - processed = true; - } - - log_debug("Got one or more potentially relevant udev events, rescanning PKCS#11..."); - } - - if (pass_volume_key) - r = crypt_activate_by_volume_key(cd, name, decrypted_key, decrypted_key_size, flags); - else { - _cleanup_free_ char *base64_encoded = NULL; - - /* Before using this key as passphrase we base64 encode it. Why? For compatibility - * with homed's PKCS#11 hookup: there we want to use the key we acquired through - * PKCS#11 for other authentication/decryption mechanisms too, and some of them do - * not not take arbitrary binary blobs, but require NUL-terminated strings — most - * importantly UNIX password hashes. Hence, for compatibility we want to use a string - * without embedded NUL here too, and that's easiest to generate from a binary blob - * via base64 encoding. */ - - r = base64mem(decrypted_key, decrypted_key_size, &base64_encoded); - if (r < 0) - return log_oom(); - - r = crypt_activate_by_passphrase(cd, name, arg_key_slot, base64_encoded, strlen(base64_encoded), flags); - } - if (r == -EPERM) { - log_error_errno(r, "Failed to activate with PKCS#11 decrypted key. (Key incorrect?)"); - return -EAGAIN; /* log actual error, but return EAGAIN */ - } - if (r < 0) - return log_error_errno(r, "Failed to activate with PKCS#11 acquired key: %m"); - - } else if (key_data) { - if (pass_volume_key) - r = crypt_activate_by_volume_key(cd, name, key_data, key_data_size, flags); - else - r = crypt_activate_by_passphrase(cd, name, arg_key_slot, key_data, key_data_size, flags); - if (r == -EPERM) { - log_error_errno(r, "Failed to activate. (Key incorrect?)"); - return -EAGAIN; /* Log actual error, but return EAGAIN */ - } - if (r < 0) - return log_error_errno(r, "Failed to activate: %m"); - - } else if (key_file) { - r = crypt_activate_by_keyfile_device_offset(cd, name, arg_key_slot, key_file, arg_keyfile_size, arg_keyfile_offset, flags); - if (r == -EPERM) { - log_error_errno(r, "Failed to activate with key file '%s'. (Key data incorrect?)", key_file); - return -EAGAIN; /* Log actual error, but return EAGAIN */ - } - if (r == -EINVAL) { - log_error_errno(r, "Failed to activate with key file '%s'. (Key file missing?)", key_file); - return -EAGAIN; /* Log actual error, but return EAGAIN */ - } - if (r < 0) - return log_error_errno(r, "Failed to activate with key file '%s': %m", key_file); - - } else { - char **p; - - r = -EINVAL; - STRV_FOREACH(p, passwords) { - if (pass_volume_key) - r = crypt_activate_by_volume_key(cd, name, *p, arg_key_size, flags); - else - r = crypt_activate_by_passphrase(cd, name, arg_key_slot, *p, strlen(*p), flags); - if (r >= 0) - break; - } - if (r == -EPERM) { - log_error_errno(r, "Failed to activate with specified passphrase. (Passphrase incorrect?)"); - return -EAGAIN; /* log actual error, but return EAGAIN */ - } - if (r < 0) - return log_error_errno(r, "Failed to activate with specified passphrase: %m"); - } - - return r; + return attach_luks_or_plain_or_bitlk_by_passphrase(cd, name, passwords, flags, pass_volume_key); } static int help(void) { @@ -787,11 +1352,10 @@ static int help(void) { printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n" "%s detach VOLUME\n\n" "Attaches or detaches an encrypted block device.\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + program_invocation_short_name, + link); return 0; } @@ -839,6 +1403,7 @@ static void remove_and_erasep(const char **p) { static int run(int argc, char *argv[]) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; + const char *verb; int r; if (argc <= 1) @@ -848,64 +1413,75 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires at least two arguments."); - log_setup_service(); + log_setup(); cryptsetup_enable_logging(cd); umask(0022); - if (streq(argv[1], "attach")) { + verb = argv[1]; + + if (streq(verb, "attach")) { + _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL; + _cleanup_(erase_and_freep) void *key_data = NULL; + const char *volume, *source, *key_file, *options; + crypt_status_info status; + size_t key_data_size = 0; uint32_t flags = 0; unsigned tries; usec_t until; - crypt_status_info status; - _cleanup_(remove_and_erasep) const char *destroy_key_file = NULL; - const char *key_file = NULL; - _cleanup_(erase_and_freep) void *key_data = NULL; - size_t key_data_size = 0; /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */ if (argc < 4) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "attach requires at least two arguments."); - if (!filename_is_valid(argv[2])) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]); + volume = argv[2]; + source = argv[3]; + key_file = argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none") ? argv[4] : NULL; + options = argc >= 6 && !STR_IN_SET(argv[5], "", "-", "none") ? argv[5] : NULL; - if (argc >= 5 && !STR_IN_SET(argv[4], "", "-", "none")) { - if (path_is_absolute(argv[4])) - key_file = argv[4]; - else - log_warning("Password file path '%s' is not absolute. Ignoring.", argv[4]); + if (!filename_is_valid(volume)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); + + if (key_file && !path_is_absolute(key_file)) { + log_warning("Password file path '%s' is not absolute. Ignoring.", key_file); + key_file = NULL; } - if (argc >= 6 && !STR_IN_SET(argv[5], "", "-", "none")) { - r = parse_options(argv[5]); + if (options) { + r = parse_options(options); if (r < 0) return r; } log_debug("%s %s ← %s type=%s cipher=%s", __func__, - argv[2], argv[3], strempty(arg_type), strempty(arg_cipher)); + volume, source, strempty(arg_type), strempty(arg_cipher)); /* A delicious drop of snake oil */ (void) mlockall(MCL_FUTURE); if (!key_file) { + _cleanup_free_ char *bindname = NULL; const char *fn; + bindname = make_bindname(volume); + if (!bindname) + return log_oom(); + /* If a key file is not explicitly specified, search for a key in a well defined * search path, and load it. */ - fn = strjoina(argv[2], ".key"); - r = load_key_file(fn, - STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"), - 0, 0, /* Note we leave arg_keyfile_offset/arg_keyfile_size as something that only applies to arg_keyfile! */ - &key_data, &key_data_size); + fn = strjoina(volume, ".key"); + r = find_key_file( + fn, + STRV_MAKE("/etc/cryptsetup-keys.d", "/run/cryptsetup-keys.d"), + bindname, + &key_data, &key_data_size); if (r < 0) return r; if (r > 0) - log_debug("Automatically discovered key for volume '%s'.", argv[2]); + log_debug("Automatically discovered key for volume '%s'.", volume); } else if (arg_keyfile_erase) destroy_key_file = key_file; /* let's get this baby erased when we leave */ @@ -913,24 +1489,23 @@ static int run(int argc, char *argv[]) { log_debug("LUKS header: %s", arg_header); r = crypt_init(&cd, arg_header); } else - r = crypt_init(&cd, argv[3]); + r = crypt_init(&cd, source); if (r < 0) return log_error_errno(r, "crypt_init() failed: %m"); cryptsetup_enable_logging(cd); - status = crypt_status(cd, argv[2]); + status = crypt_status(cd, volume); if (IN_SET(status, CRYPT_ACTIVE, CRYPT_BUSY)) { - log_info("Volume %s already active.", argv[2]); + log_info("Volume %s already active.", volume); return 0; } flags = determine_flags(); - if (arg_timeout == USEC_INFINITY) + until = usec_add(now(CLOCK_MONOTONIC), arg_timeout); + if (until == USEC_INFINITY) until = 0; - else - until = now(CLOCK_MONOTONIC) + arg_timeout; arg_key_size = (arg_key_size > 0 ? arg_key_size : (256 / 8)); @@ -949,16 +1524,16 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to load LUKS superblock on device %s: %m", crypt_get_device_name(cd)); if (arg_header) { - r = crypt_set_data_device(cd, argv[3]); + r = crypt_set_data_device(cd, source); if (r < 0) - return log_error_errno(r, "Failed to set LUKS data device %s: %m", argv[3]); + return log_error_errno(r, "Failed to set LUKS data device %s: %m", source); } /* Tokens are available in LUKS2 only, but it is ok to call (and fail) with LUKS1. */ if (!key_file && !key_data) { - r = crypt_activate_by_token(cd, argv[2], CRYPT_ANY_TOKEN, NULL, flags); + r = crypt_activate_by_token(cd, volume, CRYPT_ANY_TOKEN, NULL, flags); if (r >= 0) { - log_debug("Volume %s activated with LUKS token id %i.", argv[2], r); + log_debug("Volume %s activated with LUKS token id %i.", volume, r); return 0; } @@ -980,14 +1555,14 @@ static int run(int argc, char *argv[]) { /* When we were able to acquire multiple keys, let's always process them in this order: * - * 1. A key acquired via PKCS#11 token + * 1. A key acquired via PKCS#11 or FIDO2 token, or TPM2 chip * 2. The discovered key: i.e. key_data + key_data_size * 3. The configured key: i.e. key_file + arg_keyfile_offset + arg_keyfile_size * 4. The empty password, in case arg_try_empty_password is set * 5. We enquire the user for a password */ - if (!key_file && !key_data && !arg_pkcs11_uri) { + if (!key_file && !key_data && !arg_pkcs11_uri && !arg_pkcs11_uri_auto && !arg_fido2_device && !arg_fido2_device_auto && !arg_tpm2_device && !arg_tpm2_device_auto) { if (arg_try_empty_password) { /* Hmm, let's try an empty password now, but only once */ @@ -1002,7 +1577,7 @@ static int run(int argc, char *argv[]) { /* Ask the user for a passphrase only as last resort, if we have * nothing else to check for */ - r = get_password(argv[2], argv[3], until, tries == 0 && !arg_verify, &passwords); + r = get_password(volume, source, until, tries == 0 && !arg_verify, &passwords); if (r == -EAGAIN) continue; if (r < 0) @@ -1011,9 +1586,9 @@ static int run(int argc, char *argv[]) { } if (streq_ptr(arg_type, CRYPT_TCRYPT)) - r = attach_tcrypt(cd, argv[2], key_file, key_data, key_data_size, passwords, flags); + r = attach_tcrypt(cd, volume, key_file, key_data, key_data_size, passwords, flags); else - r = attach_luks_or_plain_or_bitlk(cd, argv[2], key_file, key_data, key_data_size, passwords, flags, until); + r = attach_luks_or_plain_or_bitlk(cd, volume, key_file, key_data, key_data_size, passwords, flags, until); if (r >= 0) break; if (r != -EAGAIN) @@ -1025,19 +1600,27 @@ static int run(int argc, char *argv[]) { key_data = erase_and_free(key_data); key_data_size = 0; arg_pkcs11_uri = mfree(arg_pkcs11_uri); + arg_pkcs11_uri_auto = false; + arg_fido2_device = mfree(arg_fido2_device); + arg_fido2_device_auto = false; + arg_tpm2_device = mfree(arg_tpm2_device); + arg_tpm2_device_auto = false; } if (arg_tries != 0 && tries >= arg_tries) return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Too many attempts to activate; giving up."); - } else if (streq(argv[1], "detach")) { + } else if (streq(verb, "detach")) { + const char *volume; - if (!filename_is_valid(argv[2])) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", argv[2]); + volume = argv[2]; - r = crypt_init_by_name(&cd, argv[2]); + if (!filename_is_valid(volume)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Volume name '%s' is not valid.", volume); + + r = crypt_init_by_name(&cd, volume); if (r == -ENODEV) { - log_info("Volume %s already inactive.", argv[2]); + log_info("Volume %s already inactive.", volume); return 0; } if (r < 0) @@ -1045,12 +1628,12 @@ static int run(int argc, char *argv[]) { cryptsetup_enable_logging(cd); - r = crypt_deactivate(cd, argv[2]); + r = crypt_deactivate(cd, volume); if (r < 0) return log_error_errno(r, "Failed to deactivate: %m"); } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", argv[1]); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown verb %s.", verb); return 0; } diff --git a/src/cryptsetup/meson.build b/src/cryptsetup/meson.build new file mode 100644 index 000000000..26267fba5 --- /dev/null +++ b/src/cryptsetup/meson.build @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +systemd_cryptsetup_sources = files( + 'cryptsetup-fido2.h', + 'cryptsetup-keyfile.c', + 'cryptsetup-keyfile.h', + 'cryptsetup-pkcs11.h', + 'cryptsetup-tpm2.h', + 'cryptsetup.c') + +if conf.get('HAVE_P11KIT') == 1 + systemd_cryptsetup_sources += files('cryptsetup-pkcs11.c') +endif + +if conf.get('HAVE_LIBFIDO2') == 1 + systemd_cryptsetup_sources += files('cryptsetup-fido2.c') +endif + +if conf.get('HAVE_TPM2') == 1 + systemd_cryptsetup_sources += files('cryptsetup-tpm2.c') +endif diff --git a/src/debug-generator/debug-generator.c b/src/debug-generator/debug-generator.c index c6e4d79e3..d9fccea5c 100644 --- a/src/debug-generator/debug-generator.c +++ b/src/debug-generator/debug-generator.c @@ -68,27 +68,21 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat else if (r > 0) t = skip_dev_prefix(DEBUGTTY); - if (free_and_strdup(&arg_debug_shell, t) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_debug_shell, t); } else if (streq(key, "systemd.unit")) { if (proc_cmdline_value_missing(key, value)) return 0; - r = free_and_strdup(&arg_default_unit, value); - if (r < 0) - return log_error_errno(r, "Failed to set default unit %s: %m", value); + return free_and_strdup_warn(&arg_default_unit, value); } else if (!value) { const char *target; target = runlevel_to_target(key); - if (target) { - r = free_and_strdup(&arg_default_unit, target); - if (r < 0) - return log_error_errno(r, "Failed to set default unit %s: %m", target); - } + if (target) + return free_and_strdup_warn(&arg_default_unit, target); } return 0; diff --git a/src/delta/delta.c b/src/delta/delta.c index 4295abdc3..bb38db54a 100644 --- a/src/delta/delta.c +++ b/src/delta/delta.c @@ -15,6 +15,7 @@ #include "main-func.h" #include "nulstr-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -532,10 +533,9 @@ static int help(void) { " --no-pager Do not pipe output into a pager\n" " --diff[=1|0] Show a diff when overridden files differ\n" " -t --type=LIST... Only display a selected set of override types\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -587,7 +587,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 1); assert(argv); @@ -617,18 +617,10 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_DIFF: - if (!optarg) - arg_diff = 1; - else { - int b; - - b = parse_boolean(optarg); - if (b < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse diff boolean."); - - arg_diff = b; - } + r = parse_boolean_argument("--diff", optarg, NULL); + if (r < 0) + return r; + arg_diff = r; break; case '?': @@ -644,7 +636,7 @@ static int parse_argv(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r, k, n_found = 0; - log_setup_cli(); + log_setup(); 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 14d649c6e..bfdede6ce 100644 --- a/src/detect-virt/detect-virt.c +++ b/src/detect-virt/detect-virt.c @@ -39,10 +39,9 @@ static int help(void) { " --private-users Only detect whether we are running in a user namespace\n" " -q --quiet Don't output anything, just set return value\n" " --list List all known and detectable types of virtualization\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -128,7 +127,7 @@ static int run(int argc, char *argv[]) { * to detect whether we are being run in a virtualized * environment or not */ - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/dissect/dissect.c b/src/dissect/dissect.c index dc7e9dc62..cb96a57ab 100644 --- a/src/dissect/dissect.c +++ b/src/dissect/dissect.c @@ -22,6 +22,7 @@ #include "mkdir.h" #include "mount-util.h" #include "namespace-util.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -45,8 +46,9 @@ static const char *arg_source = NULL; static const char *arg_target = NULL; static DissectImageFlags arg_flags = DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_DISCARD_ON_LOOP|DISSECT_IMAGE_RELAX_VAR_CHECK|DISSECT_IMAGE_FSCK; static VeritySettings arg_verity_settings = VERITY_SETTINGS_DEFAULT; -static bool arg_json = false; -static JsonFormatFlags arg_json_format_flags = 0; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; +static PagerFlags arg_pager_flags = 0; +static bool arg_legend = true; STATIC_DESTRUCTOR_REGISTER(arg_verity_settings, verity_settings_done); @@ -64,6 +66,8 @@ static int help(void) { "%1$s [OPTIONS...] --copy-to IMAGE [SOURCE] PATH\n\n" "%5$sDissect a file system OS image.%6$s\n\n" "%3$sOptions:%4$s\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" " -r --read-only Mount read-only\n" " --fsck=BOOL Run fsck before mounting\n" " --mkdir Make mount directory before mounting, if missing\n" @@ -84,11 +88,13 @@ static int help(void) { " -M Shortcut for --mount --mkdir\n" " -x --copy-from Copy files from image to host\n" " -a --copy-to Copy files from host to image\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - , ansi_underline(), ansi_normal() - , ansi_highlight(), ansi_normal()); + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); return 0; } @@ -97,6 +103,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, ARG_DISCARD, ARG_FSCK, ARG_ROOT_HASH, @@ -109,6 +117,8 @@ static int parse_argv(int argc, char *argv[]) { static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, { "mount", no_argument, NULL, 'm' }, { "read-only", no_argument, NULL, 'r' }, { "discard", required_argument, NULL, ARG_DISCARD }, @@ -138,6 +148,14 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); + case ARG_NO_PAGER: + arg_pager_flags |= PAGER_DISABLE; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + case 'm': arg_action = ACTION_MOUNT; break; @@ -228,7 +246,7 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_VERITY_DATA: - r = parse_path_argument_and_warn(optarg, false, &arg_verity_settings.data_path); + r = parse_path_argument(optarg, false, &arg_verity_settings.data_path); if (r < 0) return r; break; @@ -242,22 +260,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_JSON: - if (streq(optarg, "pretty")) { - arg_json = true; - arg_json_format_flags = JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR_AUTO; - } else if (streq(optarg, "short")) { - arg_json = true; - arg_json_format_flags = JSON_FORMAT_NEWLINE; - } else if (streq(optarg, "off")) { - arg_json = false; - arg_json_format_flags = 0; - } else if (streq(optarg, "help")) { - puts("pretty\n" - "short\n" - "off"); - return 0; - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown argument to --json=: %s", optarg); + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; break; @@ -353,17 +358,20 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { assert(m); assert(d); - if (!arg_json) + if (arg_json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) + (void) pager_open(arg_pager_flags); + + if (arg_json_format_flags & JSON_FORMAT_OFF) printf(" Name: %s\n", basename(arg_image)); if (ioctl(d->fd, BLKGETSIZE64, &size) < 0) log_debug_errno(errno, "Failed to query size of loopback device: %m"); - else if (!arg_json) { + else if (arg_json_format_flags & JSON_FORMAT_OFF) { char s[FORMAT_BYTES_MAX]; printf(" Size: %s\n", format_bytes(s, sizeof(s), size)); } - if (!arg_json) + if (arg_json_format_flags & JSON_FORMAT_OFF) putc('\n', stdout); r = dissected_image_acquire_metadata(m); @@ -379,7 +387,7 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { log_warning_errno(r, "OS image is currently in use, proceeding without showing OS image metadata."); else if (r < 0) return log_error_errno(r, "Failed to acquire image metadata: %m"); - else if (!arg_json) { + else if (arg_json_format_flags & JSON_FORMAT_OFF) { if (m->hostname) printf(" Hostname: %s\n", m->hostname); @@ -404,13 +412,23 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { *p, *q); } + if (!strv_isempty(m->extension_release)) { + char **p, **q; + + STRV_FOREACH_PAIR(p, q, m->extension_release) + printf("%s %s=%s\n", + p == m->extension_release ? "Extension Release:" : " ", + *p, *q); + } + if (m->hostname || !sd_id128_is_null(m->machine_id) || !strv_isempty(m->machine_info) || + !strv_isempty(m->extension_release) || !strv_isempty(m->os_release)) putc('\n', stdout); } else { - _cleanup_(json_variant_unrefp) JsonVariant *mi = NULL, *osr = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *mi = NULL, *osr = NULL, *exr = NULL; if (!strv_isempty(m->machine_info)) { r = strv_pair_to_json(m->machine_info, &mi); @@ -424,13 +442,20 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { return log_oom(); } + if (!strv_isempty(m->extension_release)) { + r = strv_pair_to_json(m->extension_release, &exr); + if (r < 0) + return log_oom(); + } + r = json_build(&v, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("name", JSON_BUILD_STRING(basename(arg_image))), JSON_BUILD_PAIR("size", JSON_BUILD_INTEGER(size)), JSON_BUILD_PAIR_CONDITION(m->hostname, "hostname", JSON_BUILD_STRING(m->hostname)), JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->machine_id), "machineId", JSON_BUILD_ID128(m->machine_id)), JSON_BUILD_PAIR_CONDITION(mi, "machineInfo", JSON_BUILD_VARIANT(mi)), - JSON_BUILD_PAIR_CONDITION(osr, "osRelease", JSON_BUILD_VARIANT(osr)))); + JSON_BUILD_PAIR_CONDITION(osr, "osRelease", JSON_BUILD_VARIANT(osr)), + JSON_BUILD_PAIR_CONDITION(exr, "extensionRelease", JSON_BUILD_VARIANT(exr)))); if (r < 0) return log_oom(); } @@ -495,7 +520,13 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { return table_log_add_error(r); } - if (arg_json) { + if (arg_json_format_flags & JSON_FORMAT_OFF) { + (void) table_set_header(t, arg_legend); + + r = table_print(t, NULL); + if (r < 0) + return table_log_print_error(r); + } else { _cleanup_(json_variant_unrefp) JsonVariant *jt = NULL; r = table_to_json(t, &jt); @@ -507,10 +538,6 @@ static int action_dissect(DissectedImage *m, LoopDevice *d) { return log_oom(); json_variant_dump(v, arg_json_format_flags, stdout, NULL); - } else { - r = table_print(t, stdout); - if (r < 0) - return log_error_errno(r, "Failed to dump table: %m"); } return 0; @@ -600,11 +627,11 @@ static int action_copy(DissectedImage *m, LoopDevice *d) { /* Copying to stdout? */ if (streq(arg_target, "-")) { - r = copy_bytes(source_fd, STDOUT_FILENO, (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(source_fd, STDOUT_FILENO, UINT64_MAX, COPY_REFLINK); if (r < 0) return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to stdout: %m", arg_source, arg_image); - /* When we copy to stdou we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */ + /* When we copy to stdout we don't copy any attributes (i.e. no access mode, no ownership, no xattr, no times) */ return 0; } @@ -626,7 +653,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) { if (target_fd < 0) return log_error_errno(errno, "Failed to create regular file at target path '%s': %m", arg_target); - r = copy_bytes(source_fd, target_fd, (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(source_fd, target_fd, UINT64_MAX, COPY_REFLINK); if (r < 0) return log_error_errno(r, "Failed to copy bytes from %s in mage '%s' to '%s': %m", arg_source, arg_image, arg_target); @@ -657,7 +684,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) { if (target_fd < 0) return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target); - r = copy_bytes(STDIN_FILENO, target_fd, (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(STDIN_FILENO, target_fd, UINT64_MAX, COPY_REFLINK); if (r < 0) return log_error_errno(r, "Failed to copy bytes from stdin to '%s' in image '%s': %m", arg_target, arg_image); @@ -695,7 +722,7 @@ static int action_copy(DissectedImage *m, LoopDevice *d) { if (target_fd < 0) return log_error_errno(errno, "Failed to open target file '%s': %m", arg_target); - r = copy_bytes(source_fd, target_fd, (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(source_fd, target_fd, UINT64_MAX, COPY_REFLINK); if (r < 0) return log_error_errno(r, "Failed to copy bytes from '%s' to '%s' in image '%s': %m", arg_source, arg_target, arg_image); diff --git a/src/escape/escape.c b/src/escape/escape.c index 05d03ad76..3178f9b17 100644 --- a/src/escape/escape.c +++ b/src/escape/escape.c @@ -40,10 +40,9 @@ static int help(void) { " -u --unescape Unescape strings\n" " -m --mangle Mangle strings\n" " -p --path When escaping/unescaping assume the string is a path\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -83,17 +82,16 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); - case ARG_SUFFIX: - - if (unit_type_from_string(optarg) < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid unit suffix type %s.", optarg); + case ARG_SUFFIX: { + UnitType t = unit_type_from_string(optarg); + if (t < 0) + return log_error_errno(t, "Invalid unit suffix type \"%s\".", optarg); arg_suffix = optarg; break; + } case ARG_TEMPLATE: - if (!unit_name_is_valid(optarg, UNIT_NAME_TEMPLATE)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Template name %s is not valid.", optarg); @@ -159,7 +157,7 @@ static int run(int argc, char *argv[]) { char **i; int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/firstboot/firstboot.c b/src/firstboot/firstboot.c index 742b43f9f..8e3028717 100644 --- a/src/firstboot/firstboot.c +++ b/src/firstboot/firstboot.c @@ -24,6 +24,7 @@ #include "mkdir.h" #include "mount-util.h" #include "os-util.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -105,8 +106,7 @@ static void print_welcome(void) { r = parse_os_release( arg_root, "PRETTY_NAME", &pretty_name, - "ANSI_COLOR", &ansi_color, - NULL); + "ANSI_COLOR", &ansi_color); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to read os-release file, ignoring: %m"); @@ -210,10 +210,7 @@ static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*i } log_info("Selected '%s'.", l[u-1]); - if (free_and_strdup(ret, l[u-1]) < 0) - return log_oom(); - - return 0; + return free_and_strdup_warn(ret, l[u-1]); } if (!is_valid(p)) { @@ -493,7 +490,7 @@ static int prompt_hostname(void) { break; } - if (!hostname_is_valid(h, true)) { + if (!hostname_is_valid(h, VALID_HOSTNAME_TRAILING_DOT)) { log_error("Specified hostname invalid."); continue; } @@ -678,7 +675,7 @@ static int write_root_passwd(const char *passwd_path, const char *password, cons if (original) { struct passwd *i; - r = sync_rights(fileno(original), fileno(passwd)); + r = copy_rights(fileno(original), fileno(passwd)); if (r < 0) return r; @@ -746,7 +743,7 @@ static int write_root_shadow(const char *shadow_path, const char *hashed_passwor if (original) { struct spwd *i; - r = sync_rights(fileno(original), fileno(shadow)); + r = copy_rights(fileno(original), fileno(shadow)); if (r < 0) return r; @@ -774,7 +771,7 @@ static int write_root_shadow(const char *shadow_path, const char *hashed_passwor .sp_warn = -1, .sp_inact = -1, .sp_expire = -1, - .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ + .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */ }; if (errno != ENOENT) @@ -954,10 +951,9 @@ static int help(void) { " --force Overwrite existing files\n" " --delete-root-password Delete root password\n" " --welcome=no Disable the welcome text\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -1050,13 +1046,13 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, true, &arg_root); + r = parse_path_argument(optarg, true, &arg_root); if (r < 0) return r; break; case ARG_IMAGE: - r = parse_path_argument_and_warn(optarg, false, &arg_image); + r = parse_path_argument(optarg, false, &arg_image); if (r < 0) return r; break; @@ -1135,21 +1131,21 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_HOSTNAME: - if (!hostname_is_valid(optarg, true)) + if (!hostname_is_valid(optarg, VALID_HOSTNAME_TRAILING_DOT)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Host name %s is not valid.", optarg); - hostname_cleanup(optarg); r = free_and_strdup(&arg_hostname, optarg); if (r < 0) return log_oom(); + hostname_cleanup(arg_hostname); break; case ARG_MACHINE_ID: - if (sd_id128_from_string(optarg, &arg_machine_id) < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse machine id %s.", optarg); + r = sd_id128_from_string(optarg, &arg_machine_id); + if (r < 0) + return log_error_errno(r, "Failed to parse machine id %s.", optarg); break; @@ -1272,7 +1268,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/fsck/fsck.c b/src/fsck/fsck.c index 04752fe9d..cd7adfaeb 100644 --- a/src/fsck/fsck.c +++ b/src/fsck/fsck.c @@ -172,7 +172,7 @@ static int process_progress(int fd, FILE* console) { } for (;;) { - int pass, m; + int pass; unsigned long cur, max; _cleanup_free_ char *device = NULL; double p; @@ -206,18 +206,17 @@ static int process_progress(int fd, FILE* console) { last = t; p = percent(pass, cur, max); - fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m); - fflush(console); + r = fprintf(console, "\r%s: fsck %3.1f%% complete...\r", device, p); + if (r < 0) + return -EIO; /* No point in continuing if something happened to our output stream */ - if (m > clear) - clear = m; + fflush(console); + clear = MAX(clear, r); } if (clear > 0) { - unsigned j; - fputc('\r', console); - for (j = 0; j < (unsigned) clear; j++) + for (int j = 0; j < clear; j++) fputc(' ', console); fputc('\r', console); fflush(console); @@ -256,7 +255,7 @@ static int run(int argc, char *argv[]) { int r, exit_status; pid_t pid; - log_setup_service(); + log_setup(); if (argc > 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -288,7 +287,7 @@ static int run(int argc, char *argv[]) { "%s is not a block device.", device); - r = sd_device_new_from_devnum(&dev, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(&dev, &st); if (r < 0) return log_error_errno(r, "Failed to detect device %s: %m", device); diff --git a/src/fstab-generator/fstab-generator.c b/src/fstab-generator/fstab-generator.c index 15f589222..8c1087a9a 100644 --- a/src/fstab-generator/fstab-generator.c +++ b/src/fstab-generator/fstab-generator.c @@ -200,7 +200,7 @@ static int write_timeout( usec_t u; int r; - r = fstab_filter_options(opts, filter, NULL, &timeout, NULL); + r = fstab_filter_options(opts, filter, NULL, &timeout, NULL, NULL); if (r < 0) return log_warning_errno(r, "Failed to parse options: %m"); if (r == 0) @@ -241,7 +241,7 @@ static int write_dependency( assert(f); assert(opts); - r = fstab_extract_values(opts, filter, &names); + r = fstab_filter_options(opts, filter, NULL, NULL, &names, NULL); if (r < 0) return log_warning_errno(r, "Failed to parse options: %m"); if (r == 0) @@ -274,17 +274,17 @@ static int write_dependency( static int write_after(FILE *f, const char *opts) { return write_dependency(f, opts, - "x-systemd.after", "After=%1$s\n"); + "x-systemd.after\0", "After=%1$s\n"); } static int write_requires_after(FILE *f, const char *opts) { return write_dependency(f, opts, - "x-systemd.requires", "After=%1$s\nRequires=%1$s\n"); + "x-systemd.requires\0", "After=%1$s\nRequires=%1$s\n"); } static int write_before(FILE *f, const char *opts) { return write_dependency(f, opts, - "x-systemd.before", "Before=%1$s\n"); + "x-systemd.before\0", "Before=%1$s\n"); } static int write_requires_mounts_for(FILE *f, const char *opts) { @@ -295,7 +295,7 @@ static int write_requires_mounts_for(FILE *f, const char *opts) { assert(f); assert(opts); - r = fstab_extract_values(opts, "x-systemd.requires-mounts-for", &paths); + r = fstab_filter_options(opts, "x-systemd.requires-mounts-for\0", NULL, NULL, &paths, NULL); if (r < 0) return log_warning_errno(r, "Failed to parse options: %m"); if (r == 0) @@ -376,11 +376,11 @@ static int add_mount( mount_point_ignore(where)) return 0; - r = fstab_extract_values(opts, "x-systemd.wanted-by", &wanted_by); + r = fstab_filter_options(opts, "x-systemd.wanted-by\0", NULL, NULL, &wanted_by, NULL); if (r < 0) return r; - r = fstab_extract_values(opts, "x-systemd.required-by", &required_by); + r = fstab_filter_options(opts, "x-systemd.required-by\0", NULL, NULL, &required_by, NULL); if (r < 0) return r; @@ -423,7 +423,7 @@ static int add_mount( * mount.nfs (so systemd can manage the job-control aspects of 'bg'), * we need to explicitly preserve that default, and also ensure * the systemd mount-timeout doesn't interfere. - * By placing these options first, they can be over-ridden by + * By placing these options first, they can be overridden by * settings in /etc/fstab. */ opts = strjoina("x-systemd.mount-timeout=infinity,retry=10000,nofail,", opts, ",fg"); SET_FLAG(flags, NOFAIL, true); @@ -611,11 +611,11 @@ static int parse_fstab(bool initrd) { * /etc/fstab. So we canonicalize here. Note that we use CHASE_NONEXISTENT to handle the case * where a symlink refers to another mount target; this works assuming the sub-mountpoint * target is the final directory. */ - r = chase_symlinks(where, initrd ? "/sysroot" : NULL, + k = chase_symlinks(where, initrd ? "/sysroot" : NULL, CHASE_PREFIX_ROOT | CHASE_NONEXISTENT, &canonical_where, NULL); - if (r < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */ - log_debug_errno(r, "Failed to read symlink target for %s, ignoring: %m", where); + if (k < 0) /* If we can't canonicalize we continue on as if it wasn't a symlink */ + log_debug_errno(k, "Failed to read symlink target for %s, ignoring: %m", where); else if (streq(canonical_where, where)) /* If it was fully canonicalized, suppress the change */ canonical_where = mfree(canonical_where); else @@ -671,7 +671,8 @@ static int parse_fstab(bool initrd) { static int add_sysroot_mount(void) { _cleanup_free_ char *what = NULL; - const char *opts; + const char *opts, *fstype; + bool default_rw; int r; if (isempty(arg_root_what)) { @@ -691,12 +692,29 @@ static int add_sysroot_mount(void) { return 0; } - what = fstab_node_to_udev_node(arg_root_what); - if (!what) - return log_oom(); + if (streq(arg_root_what, "tmpfs")) { + /* If root=tmpfs is specified, then take this as shortcut for a writable tmpfs mount as root */ + + what = strdup("rootfs"); /* just a pretty name, to show up in /proc/self/mountinfo */ + if (!what) + return log_oom(); + + fstype = arg_root_fstype ?: "tmpfs"; /* tmpfs, unless overridden */ + + default_rw = true; /* writable, unless overridden */; + } else { + + what = fstab_node_to_udev_node(arg_root_what); + if (!what) + return log_oom(); + + fstype = arg_root_fstype; /* if not specified explicitly, don't default to anything here */ + + default_rw = false; /* read-only, unless overridden */ + } if (!arg_root_options) - opts = arg_root_rw > 0 ? "rw" : "ro"; + opts = arg_root_rw > 0 || (arg_root_rw < 0 && default_rw) ? "rw" : "ro"; else if (arg_root_rw >= 0 || !fstab_test_option(arg_root_options, "ro\0" "rw\0")) opts = strjoina(arg_root_options, ",", arg_root_rw > 0 ? "rw" : "ro"); @@ -715,7 +733,7 @@ static int add_sysroot_mount(void) { what, "/sysroot", NULL, - arg_root_fstype, + fstype, opts, is_device_path(what) ? 1 : 0, /* passno */ 0, /* makefs off, growfs off, noauto off, nofail off, automount off */ @@ -827,23 +845,21 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_root_what, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_root_what, value); } else if (streq(key, "rootfstype")) { if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_root_fstype, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_root_fstype, value); } else if (streq(key, "rootflags")) { if (proc_cmdline_value_missing(key, value)) return 0; - if (!strextend_with_separator(&arg_root_options, ",", value, NULL)) + if (!strextend_with_separator(&arg_root_options, ",", value)) return log_oom(); } else if (streq(key, "roothash")) { @@ -851,31 +867,28 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_root_hash, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_root_hash, value); } else if (streq(key, "mount.usr")) { if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_usr_what, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_usr_what, value); } else if (streq(key, "mount.usrfstype")) { if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_usr_fstype, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_usr_fstype, value); } else if (streq(key, "mount.usrflags")) { if (proc_cmdline_value_missing(key, value)) return 0; - if (!strextend_with_separator(&arg_usr_options, ",", value, NULL)) + if (!strextend_with_separator(&arg_usr_options, ",", value)) return log_oom(); } else if (streq(key, "rw") && !value) @@ -888,7 +901,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (value) { m = volatile_mode_from_string(value); if (m < 0) - log_warning("Failed to parse systemd.volatile= argument: %s", value); + log_warning_errno(m, "Failed to parse systemd.volatile= argument: %s", value); else arg_volatile_mode = m; } else diff --git a/src/boot/efi/loader-features.h b/src/fundamental/efi-loader-features.h similarity index 100% rename from src/boot/efi/loader-features.h rename to src/fundamental/efi-loader-features.h diff --git a/src/fundamental/macro-fundamental.h b/src/fundamental/macro-fundamental.h new file mode 100644 index 000000000..790920eb2 --- /dev/null +++ b/src/fundamental/macro-fundamental.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#ifndef SD_BOOT +#include +#endif + +#include "type.h" + +#define _const_ __attribute__((__const__)) +#define _pure_ __attribute__((__pure__)) +#define _unused_ __attribute__((__unused__)) +#define _cleanup_(x) __attribute__((__cleanup__(x))) + +#ifndef __COVERITY__ +# define VOID_0 ((void)0) +#else +# define VOID_0 ((void*)0) +#endif + +#define ELEMENTSOF(x) \ + (__builtin_choose_expr( \ + !__builtin_types_compatible_p(typeof(x), typeof(&*(x))), \ + sizeof(x)/sizeof((x)[0]), \ + VOID_0)) + +#define XCONCATENATE(x, y) x ## y +#define CONCATENATE(x, y) XCONCATENATE(x, y) + +#ifdef SD_BOOT +#define assert(expr) do {} while (false) +#endif + +#if defined(static_assert) +#define assert_cc(expr) \ + static_assert(expr, #expr) +#else +#define assert_cc(expr) \ + struct CONCATENATE(_assert_struct_, __COUNTER__) { \ + char x[(expr) ? 0 : -1]; \ + } +#endif + +#define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) +#define UNIQ __COUNTER__ + +#undef MAX +#define MAX(a, b) __MAX(UNIQ, (a), UNIQ, (b)) +#define __MAX(aq, a, bq, b) \ + ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ + }) + +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define CONST_MAX(_A, _B) \ + (__builtin_choose_expr( \ + __builtin_constant_p(_A) && \ + __builtin_constant_p(_B) && \ + __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ + ((_A) > (_B)) ? (_A) : (_B), \ + VOID_0)) + +/* takes two types and returns the size of the larger one */ +#define MAXSIZE(A, B) (sizeof(union _packed_ { typeof(A) a; typeof(B) b; })) + +#define MAX3(x, y, z) \ + ({ \ + const typeof(x) _c = MAX(x, y); \ + MAX(_c, z); \ + }) + +#define MAX4(x, y, z, a) \ + ({ \ + const typeof(x) _d = MAX3(x, y, z); \ + MAX(_d, a); \ + }) + +#undef MIN +#define MIN(a, b) __MIN(UNIQ, (a), UNIQ, (b)) +#define __MIN(aq, a, bq, b) \ + ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A, aq) < UNIQ_T(B, bq) ? UNIQ_T(A, aq) : UNIQ_T(B, bq); \ + }) + +/* evaluates to (void) if _A or _B are not constant or of different types */ +#define CONST_MIN(_A, _B) \ + (__builtin_choose_expr( \ + __builtin_constant_p(_A) && \ + __builtin_constant_p(_B) && \ + __builtin_types_compatible_p(typeof(_A), typeof(_B)), \ + ((_A) < (_B)) ? (_A) : (_B), \ + VOID_0)) + +#define MIN3(x, y, z) \ + ({ \ + const typeof(x) _c = MIN(x, y); \ + MIN(_c, z); \ + }) + +#define LESS_BY(a, b) __LESS_BY(UNIQ, (a), UNIQ, (b)) +#define __LESS_BY(aq, a, bq, b) \ + ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A, aq) > UNIQ_T(B, bq) ? UNIQ_T(A, aq) - UNIQ_T(B, bq) : 0; \ + }) + +#define CMP(a, b) __CMP(UNIQ, (a), UNIQ, (b)) +#define __CMP(aq, a, bq, b) \ + ({ \ + const typeof(a) UNIQ_T(A, aq) = (a); \ + const typeof(b) UNIQ_T(B, bq) = (b); \ + UNIQ_T(A, aq) < UNIQ_T(B, bq) ? -1 : \ + UNIQ_T(A, aq) > UNIQ_T(B, bq) ? 1 : 0; \ + }) + +#undef CLAMP +#define CLAMP(x, low, high) __CLAMP(UNIQ, (x), UNIQ, (low), UNIQ, (high)) +#define __CLAMP(xq, x, lowq, low, highq, high) \ + ({ \ + const typeof(x) UNIQ_T(X, xq) = (x); \ + const typeof(low) UNIQ_T(LOW, lowq) = (low); \ + const typeof(high) UNIQ_T(HIGH, highq) = (high); \ + UNIQ_T(X, xq) > UNIQ_T(HIGH, highq) ? \ + UNIQ_T(HIGH, highq) : \ + UNIQ_T(X, xq) < UNIQ_T(LOW, lowq) ? \ + UNIQ_T(LOW, lowq) : \ + UNIQ_T(X, xq); \ + }) + +/* [(x + y - 1) / y] suffers from an integer overflow, even though the + * computation should be possible in the given type. Therefore, we use + * [x / y + !!(x % y)]. Note that on "Real CPUs" a division returns both the + * quotient and the remainder, so both should be equally fast. */ +#define DIV_ROUND_UP(x, y) __DIV_ROUND_UP(UNIQ, (x), UNIQ, (y)) +#define __DIV_ROUND_UP(xq, x, yq, y) \ + ({ \ + const typeof(x) UNIQ_T(X, xq) = (x); \ + const typeof(y) UNIQ_T(Y, yq) = (y); \ + (UNIQ_T(X, xq) / UNIQ_T(Y, yq) + !!(UNIQ_T(X, xq) % UNIQ_T(Y, yq))); \ + }) + +#define CASE_F(X) case X: +#define CASE_F_1(CASE, X) CASE_F(X) +#define CASE_F_2(CASE, X, ...) CASE(X) CASE_F_1(CASE, __VA_ARGS__) +#define CASE_F_3(CASE, X, ...) CASE(X) CASE_F_2(CASE, __VA_ARGS__) +#define CASE_F_4(CASE, X, ...) CASE(X) CASE_F_3(CASE, __VA_ARGS__) +#define CASE_F_5(CASE, X, ...) CASE(X) CASE_F_4(CASE, __VA_ARGS__) +#define CASE_F_6(CASE, X, ...) CASE(X) CASE_F_5(CASE, __VA_ARGS__) +#define CASE_F_7(CASE, X, ...) CASE(X) CASE_F_6(CASE, __VA_ARGS__) +#define CASE_F_8(CASE, X, ...) CASE(X) CASE_F_7(CASE, __VA_ARGS__) +#define CASE_F_9(CASE, X, ...) CASE(X) CASE_F_8(CASE, __VA_ARGS__) +#define CASE_F_10(CASE, X, ...) CASE(X) CASE_F_9(CASE, __VA_ARGS__) +#define CASE_F_11(CASE, X, ...) CASE(X) CASE_F_10(CASE, __VA_ARGS__) +#define CASE_F_12(CASE, X, ...) CASE(X) CASE_F_11(CASE, __VA_ARGS__) +#define CASE_F_13(CASE, X, ...) CASE(X) CASE_F_12(CASE, __VA_ARGS__) +#define CASE_F_14(CASE, X, ...) CASE(X) CASE_F_13(CASE, __VA_ARGS__) +#define CASE_F_15(CASE, X, ...) CASE(X) CASE_F_14(CASE, __VA_ARGS__) +#define CASE_F_16(CASE, X, ...) CASE(X) CASE_F_15(CASE, __VA_ARGS__) +#define CASE_F_17(CASE, X, ...) CASE(X) CASE_F_16(CASE, __VA_ARGS__) +#define CASE_F_18(CASE, X, ...) CASE(X) CASE_F_17(CASE, __VA_ARGS__) +#define CASE_F_19(CASE, X, ...) CASE(X) CASE_F_18(CASE, __VA_ARGS__) +#define CASE_F_20(CASE, X, ...) CASE(X) CASE_F_19(CASE, __VA_ARGS__) + +#define GET_CASE_F(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,NAME,...) NAME +#define FOR_EACH_MAKE_CASE(...) \ + GET_CASE_F(__VA_ARGS__,CASE_F_20,CASE_F_19,CASE_F_18,CASE_F_17,CASE_F_16,CASE_F_15,CASE_F_14,CASE_F_13,CASE_F_12,CASE_F_11, \ + CASE_F_10,CASE_F_9,CASE_F_8,CASE_F_7,CASE_F_6,CASE_F_5,CASE_F_4,CASE_F_3,CASE_F_2,CASE_F_1) \ + (CASE_F,__VA_ARGS__) + +#define IN_SET(x, ...) \ + ({ \ + sd_bool _found = false; \ + /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \ + * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \ + * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \ + * doesn't work, as we want to use this on bitfields and gcc refuses typeof() on bitfields.) */ \ + static const long double __assert_in_set[] _unused_ = { __VA_ARGS__ }; \ + assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ + switch(x) { \ + FOR_EACH_MAKE_CASE(__VA_ARGS__) \ + _found = true; \ + break; \ + default: \ + break; \ + } \ + _found; \ + }) + +/* Takes inspiration from Rust's Option::take() method: reads and returns a pointer, but at the same time + * resets it to NULL. See: https://doc.rust-lang.org/std/option/enum.Option.html#method.take */ +#define TAKE_PTR(ptr) \ + ({ \ + typeof(ptr) _ptr_ = (ptr); \ + (ptr) = NULL; \ + _ptr_; \ + }) diff --git a/src/fundamental/meson.build b/src/fundamental/meson.build new file mode 100644 index 000000000..40b9ab8e2 --- /dev/null +++ b/src/fundamental/meson.build @@ -0,0 +1,22 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +fundamental_path = meson.current_source_dir() + +fundamental_headers = files( + 'efi-loader-features.h', + 'macro-fundamental.h', + 'string-util-fundamental.h', + 'type.h') + +sources = ''' + string-util-fundamental.c +'''.split() + +# for sd-boot +fundamental_source_paths = [] +foreach s : sources + fundamental_source_paths += join_paths(meson.current_source_dir(), s) +endforeach + +# for libbasic +fundamental_sources = files(sources) + fundamental_headers diff --git a/src/fundamental/string-util-fundamental.c b/src/fundamental/string-util-fundamental.c new file mode 100644 index 000000000..9f14597fe --- /dev/null +++ b/src/fundamental/string-util-fundamental.c @@ -0,0 +1,234 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef SD_BOOT +#include + +#include "macro.h" +#endif +#include "string-util-fundamental.h" + +sd_char *startswith(const sd_char *s, const sd_char *prefix) { + sd_size_t l; + + assert(s); + assert(prefix); + + l = strlen(prefix); + if (!strneq(s, prefix, l)) + return NULL; + + return (sd_char*) s + l; +} + +#ifndef SD_BOOT +sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) { + sd_size_t l; + + assert(s); + assert(prefix); + + l = strlen(prefix); + if (!strncaseeq(s, prefix, l)) + return NULL; + + return (sd_char*) s + l; +} +#endif + +sd_char* endswith(const sd_char *s, const sd_char *postfix) { + sd_size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (sd_char*) s + sl; + + if (sl < pl) + return NULL; + + if (strcmp(s + sl - pl, postfix) != 0) + return NULL; + + return (sd_char*) s + sl - pl; +} + +sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) { + sd_size_t sl, pl; + + assert(s); + assert(postfix); + + sl = strlen(s); + pl = strlen(postfix); + + if (pl == 0) + return (sd_char*) s + sl; + + if (sl < pl) + return NULL; + + if (strcasecmp(s + sl - pl, postfix) != 0) + return NULL; + + return (sd_char*) s + sl - pl; +} + +#ifdef SD_BOOT +static sd_bool isdigit(sd_char a) { + return a >= '0' && a <= '9'; +} +#endif + +static sd_bool is_alpha(sd_char a) { + /* Locale independent version of isalpha(). */ + return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); +} + +static sd_bool is_valid_version_char(sd_char a) { + return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.'); +} + +sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { + + /* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually + * want to directly compare strings which contain both version and release; e.g. + * '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'. + * Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer. + * + * This splits the input strings into segments. Each segment is numeric or alpha, and may be + * prefixed with the following: + * '~' : used for pre-releases, a segment prefixed with this is the oldest, + * '-' : used for the separator between version and release, + * '^' : used for patched releases, a segment with this is newer than one with '-'. + * '.' : used for point releases. + * Note, no prefix segment is the newest. All non-supported characters are dropped, and + * handled as a separator of segments, e.g., 123_a is equivalent to 123a. + * + * By using this, version strings can be sorted like following: + * (older) 122.1 + * ^ 123~rc1-1 + * | 123 + * | 123-a + * | 123-a.1 + * | 123-1 + * | 123-1.1 + * | 123^post1 + * | 123.a-1 + * | 123.1-1 + * v 123a-1 + * (newer) 124-1 + */ + + if (isempty(a) || isempty(b)) + return strcmp_ptr(a, b); + + for (;;) { + const sd_char *aa, *bb; + sd_int r; + + /* Drop leading invalid characters. */ + while (*a != '\0' && !is_valid_version_char(*a)) + a++; + while (*b != '\0' && !is_valid_version_char(*b)) + b++; + + /* Handle '~'. Used for pre-releases, e.g. 123~rc1, or 4.5~alpha1 */ + if (*a == '~' || *b == '~') { + /* The string prefixed with '~' is older. */ + r = CMP(*a != '~', *b != '~'); + if (r != 0) + return r; + + /* Now both strings are prefixed with '~'. Compare remaining strings. */ + a++; + b++; + } + + /* If at least one string reaches the end, then longer is newer. + * Note that except for '~' prefixed segments, a string has more segments is newer. + * So, this check must be after the '~' check. */ + if (*a == '\0' || *b == '\0') + return strcmp(a, b); + + /* Handle '-', which separates version and release, e.g 123.4-3.1.fc33.x86_64 */ + if (*a == '-' || *b == '-') { + /* The string prefixed with '-' is older (e.g., 123-9 vs 123.1-1) */ + r = CMP(*a != '-', *b != '-'); + if (r != 0) + return r; + + a++; + b++; + } + + /* Handle '^'. Used for patched release. */ + if (*a == '^' || *b == '^') { + r = CMP(*a != '^', *b != '^'); + if (r != 0) + return r; + + a++; + b++; + } + + /* Handle '.'. Used for point releases. */ + if (*a == '.' || *b == '.') { + r = CMP(*a != '.', *b != '.'); + if (r != 0) + return r; + + a++; + b++; + } + + if (isdigit(*a) || isdigit(*b)) { + /* Skip leading '0', to make 00123 equivalent to 123. */ + while (*a == '0') + a++; + while (*b == '0') + b++; + + /* Find the leading numeric segments. One may be an empty string. So, + * numeric segments are always newer than alpha segments. */ + for (aa = a; *aa != '\0' && isdigit(*aa); aa++) + ; + for (bb = b; *bb != '\0' && isdigit(*bb); bb++) + ; + + /* To compare numeric segments without parsing their values, first compare the + * lengths of the segments. Eg. 12345 vs 123, longer is newer. */ + r = CMP(aa - a, bb - b); + if (r != 0) + return r; + + /* Then, compare them as strings. */ + r = strncmp(a, b, aa - a); + if (r != 0) + return r; + } else { + /* Find the leading non-numeric segments. */ + for (aa = a; *aa != '\0' && is_alpha(*aa); aa++) + ; + for (bb = b; *bb != '\0' && is_alpha(*bb); bb++) + ; + + /* Note that the segments are usually not NUL-terminated. */ + r = strncmp(a, b, MIN(aa - a, bb - b)); + if (r != 0) + return r; + + /* Longer is newer, e.g. abc vs abcde. */ + r = CMP(aa - a, bb - b); + if (r != 0) + return r; + } + + /* The current segments are equivalent. Let's compare the next one. */ + a = aa; + b = bb; + } +} diff --git a/src/fundamental/string-util-fundamental.h b/src/fundamental/string-util-fundamental.h new file mode 100644 index 000000000..407cede48 --- /dev/null +++ b/src/fundamental/string-util-fundamental.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#ifdef SD_BOOT +#include +#include +#else +#include +#endif + +#include "macro-fundamental.h" + +#ifdef SD_BOOT +#define strlen(a) StrLen((a)) +#define strcmp(a, b) StrCmp((a), (b)) +#define strncmp(a, b, n) StrnCmp((a), (b), (n)) +#define strcasecmp(a, b) StriCmp((a), (b)) +#define STR_C(str) (L ## str) +#else +#define STR_C(str) (str) +#endif + +#define streq(a,b) (strcmp((a),(b)) == 0) +#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) +#define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) +#ifndef SD_BOOT +#define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) +#endif + +static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) { + if (a && b) + return strcmp(a, b); + + return CMP(a, b); +} + +static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) { + if (a && b) + return strcasecmp(a, b); + + return CMP(a, b); +} + +static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) { + return strcmp_ptr(a, b) == 0; +} + +static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { + return strcasecmp_ptr(a, b) == 0; +} + +sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_; +#ifndef SD_BOOT +sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_; +#endif +sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_; +sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_; + +static inline sd_bool isempty(const sd_char *a) { + return !a || a[0] == '\0'; +} + +static inline const sd_char *yes_no(sd_bool b) { + return b ? STR_C("yes") : STR_C("no"); +} + +sd_int strverscmp_improved(const sd_char *a, const sd_char *b); diff --git a/src/fundamental/type.h b/src/fundamental/type.h new file mode 100644 index 000000000..f645d2de7 --- /dev/null +++ b/src/fundamental/type.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#ifdef SD_BOOT +#include + +typedef BOOLEAN sd_bool; +typedef CHAR16 sd_char; +typedef INTN sd_int; +typedef UINTN sd_size_t; + +#define true TRUE +#define false FALSE +#else +#include +#include + +typedef bool sd_bool; +typedef char sd_char; +typedef int sd_int; +typedef size_t sd_size_t; +#endif diff --git a/src/fuzz/fuzz-hostname-util.c b/src/fuzz/fuzz-hostname-setup.c similarity index 96% rename from src/fuzz/fuzz-hostname-util.c rename to src/fuzz/fuzz-hostname-setup.c index 0a81e7442..b8d36da54 100644 --- a/src/fuzz/fuzz-hostname-util.c +++ b/src/fuzz/fuzz-hostname-setup.c @@ -4,7 +4,7 @@ #include "fd-util.h" #include "fileio.h" #include "fuzz.h" -#include "hostname-util.h" +#include "hostname-setup.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { _cleanup_fclose_ FILE *f = NULL; diff --git a/src/fuzz/fuzz-main.c b/src/fuzz/fuzz-main.c index 2df2993cb..cf70424c1 100644 --- a/src/fuzz/fuzz-main.c +++ b/src/fuzz/fuzz-main.c @@ -1,9 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "alloc-util.h" -#include "log.h" #include "fileio.h" #include "fuzz.h" +#include "log.h" +#include "parse-util.h" +#include "string-util.h" #include "tests.h" /* This is a test driver for the systemd fuzzers that provides main function @@ -15,17 +17,26 @@ /* This one was borrowed from * https://github.com/google/oss-fuzz/blob/646fca1b506b056db3a60d32c4a1a7398f171c94/infra/base-images/base-runner/bad_build_check#L19 */ -#define MIN_NUMBER_OF_RUNS 4 +#define NUMBER_OF_RUNS 4 int main(int argc, char **argv) { - int i, r; - size_t size; - char *name; + int r; test_setup_logging(LOG_DEBUG); - for (i = 1; i < argc; i++) { + unsigned number_of_runs = NUMBER_OF_RUNS; + + const char *v = getenv("SYSTEMD_FUZZ_RUNS"); + if (!isempty(v)) { + r = safe_atou(v, &number_of_runs); + if (r < 0) + return log_error_errno(r, "Failed to parse SYSTEMD_FUZZ_RUNS=%s: %m", v); + } + + for (int i = 1; i < argc; i++) { _cleanup_free_ char *buf = NULL; + size_t size; + char *name; name = argv[i]; r = read_full_file(name, &buf, &size); @@ -35,7 +46,7 @@ int main(int argc, char **argv) { } printf("%s... ", name); fflush(stdout); - for (int j = 0; j < MIN_NUMBER_OF_RUNS; j++) + for (unsigned j = 0; j < number_of_runs; j++) if (LLVMFuzzerTestOneInput((uint8_t*)buf, size) == EXIT_TEST_SKIP) return EXIT_TEST_SKIP; printf("ok\n"); diff --git a/src/fuzz/meson.build b/src/fuzz/meson.build index a5fac5980..1ed1dd825 100644 --- a/src/fuzz/meson.build +++ b/src/fuzz/meson.build @@ -1,159 +1,23 @@ # SPDX-License-Identifier: LGPL-2.1-or-later fuzzers += [ - [['src/fuzz/fuzz-bus-message.c'], - [libshared], - []], + [['src/fuzz/fuzz-catalog.c']], - [['src/fuzz/fuzz-catalog.c'], - [libjournal_core, - libshared], - []], + [['src/fuzz/fuzz-json.c']], - [['src/fuzz/fuzz-dns-packet.c', - dns_type_headers], - [libsystemd_resolve_core, - libshared], - [libgcrypt, - libgpg_error, - libm]], + [['src/fuzz/fuzz-varlink.c']], - [['src/fuzz/fuzz-dhcp6-client.c', - 'src/libsystemd-network/dhcp-identifier.h', - 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/dhcp6-internal.h', - 'src/systemd/sd-dhcp6-client.h'], - [libshared, - libsystemd_network], - []], + [['src/fuzz/fuzz-udev-database.c']], - [['src/fuzz/fuzz-dhcp-server.c'], - [libsystemd_network, - libshared], - []], + [['src/fuzz/fuzz-compress.c']], - [['src/fuzz/fuzz-lldp.c'], - [libshared, - libsystemd_network], - []], + [['src/fuzz/fuzz-bus-label.c']], - [['src/fuzz/fuzz-ndisc-rs.c', - 'src/libsystemd-network/dhcp-identifier.h', - 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/icmp6-util.h', - 'src/systemd/sd-dhcp6-client.h', - 'src/systemd/sd-ndisc.h'], - [libshared, - libsystemd_network], - []], + [['src/fuzz/fuzz-env-file.c']], - [['src/fuzz/fuzz-json.c'], - [libshared], - []], + [['src/fuzz/fuzz-hostname-setup.c']], - [['src/fuzz/fuzz-varlink.c'], - [libshared], - []], + [['src/fuzz/fuzz-calendarspec.c']], - [['src/fuzz/fuzz-unit-file.c'], - [libcore, - libshared], - [libmount]], - - [['src/fuzz/fuzz-journald-audit.c', - 'src/fuzz/fuzz-journald.c'], - [libjournal_core, - libshared], - [libselinux]], - - [['src/fuzz/fuzz-journald-kmsg.c', - 'src/fuzz/fuzz-journald.c'], - [libjournal_core, - libshared], - [libselinux]], - - [['src/fuzz/fuzz-journald-native.c', - 'src/fuzz/fuzz-journald.c'], - [libjournal_core, - libshared], - [libselinux]], - - [['src/fuzz/fuzz-journald-native-fd.c', - 'src/fuzz/fuzz-journald.c'], - [libjournal_core, - libshared], - [libselinux]], - - [['src/fuzz/fuzz-journald-stream.c', - 'src/fuzz/fuzz-journald.c'], - [libjournal_core, - libshared], - [libselinux]], - - [['src/fuzz/fuzz-journald-syslog.c', - 'src/fuzz/fuzz-journald.c'], - [libjournal_core, - libshared], - [libselinux]], - - [['src/fuzz/fuzz-journal-remote.c'], - [libsystemd_journal_remote, - libshared], - []], - - [['src/fuzz/fuzz-udev-database.c'], - [libshared], - []], - - [['src/fuzz/fuzz-udev-rules.c'], - [libudev_core, - libudev_static, - libsystemd_network, - libshared], - [threads, - libacl]], - - [['src/fuzz/fuzz-compress.c'], - [libshared], - []], - - [['src/fuzz/fuzz-bus-label.c'], - [libshared], - []], - - [['src/fuzz/fuzz-env-file.c'], - [libshared], - []], - - [['src/fuzz/fuzz-hostname-util.c'], - [libshared], - []], - - [['src/fuzz/fuzz-nspawn-settings.c'], - [libshared, - libnspawn_core], - [libseccomp]], - - [['src/fuzz/fuzz-nspawn-oci.c'], - [libshared, - libnspawn_core], - [libseccomp]], - - [['src/fuzz/fuzz-calendarspec.c'], - [libshared], - []], - - [['src/fuzz/fuzz-time-util.c'], - [libshared], - []], - - [['src/fuzz/fuzz-xdg-desktop.c', - 'src/xdg-autostart-generator/xdg-autostart-service.h', - 'src/xdg-autostart-generator/xdg-autostart-service.c'], - [], - []], - - [['src/fuzz/fuzz-udev-rule-parse-value.c'], - [libshared], - []], + [['src/fuzz/fuzz-time-util.c']], ] diff --git a/src/hibernate-resume/hibernate-resume-generator.c b/src/hibernate-resume/hibernate-resume-generator.c index 04a28c905..b1e5452bb 100644 --- a/src/hibernate-resume/hibernate-resume-generator.c +++ b/src/hibernate-resume/hibernate-resume-generator.c @@ -45,7 +45,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - if (!strextend_with_separator(&arg_resume_options, ",", value, NULL)) + if (!strextend_with_separator(&arg_resume_options, ",", value)) return log_oom(); } else if (streq(key, "rootflags")) { @@ -53,7 +53,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat if (proc_cmdline_value_missing(key, value)) return 0; - if (!strextend_with_separator(&arg_root_options, ",", value, NULL)) + if (!strextend_with_separator(&arg_root_options, ",", value)) return log_oom(); } else if (streq(key, "noresume")) { diff --git a/src/hibernate-resume/hibernate-resume.c b/src/hibernate-resume/hibernate-resume.c index d8f91f4e6..58e35e403 100644 --- a/src/hibernate-resume/hibernate-resume.c +++ b/src/hibernate-resume/hibernate-resume.c @@ -20,7 +20,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/home/homectl-fido2.c b/src/home/homectl-fido2.c index 5557b70e6..d5edec1bc 100644 --- a/src/home/homectl-fido2.c +++ b/src/home/homectl-fido2.c @@ -11,6 +11,7 @@ #include "homectl-fido2.h" #include "homectl-pkcs11.h" #include "libcrypt-util.h" +#include "libfido2-util.h" #include "locale-util.h" #include "memory-util.h" #include "random-util.h" @@ -109,105 +110,22 @@ static int add_fido2_salt( } #endif -#define FIDO2_SALT_SIZE 32 - int identity_add_fido2_parameters( JsonVariant **v, const char *device) { #if HAVE_LIBFIDO2 - _cleanup_(fido_cbor_info_free) fido_cbor_info_t *di = NULL; - _cleanup_(fido_assert_free) fido_assert_t *a = NULL; - _cleanup_(erase_and_freep) char *used_pin = NULL; - _cleanup_(fido_cred_free) fido_cred_t *c = NULL; - _cleanup_(fido_dev_free) fido_dev_t *d = NULL; - _cleanup_(erase_and_freep) void *salt = NULL; JsonVariant *un, *realm, *rn; - bool found_extension = false; - const void *cid, *secret; + _cleanup_(erase_and_freep) void *secret = NULL, *salt = NULL; + _cleanup_(erase_and_freep) char *used_pin = NULL; + size_t cid_size, salt_size, secret_size; + _cleanup_free_ void *cid = NULL; const char *fido_un; - size_t n, cid_size, secret_size; - char **e; int r; - /* Construction is like this: we generate a salt of 32 bytes. We then ask the FIDO2 device to - * HMAC-SHA256 it for us with its internal key. The result is the key used by LUKS and account - * authentication. LUKS and UNIX password auth all do their own salting before hashing, so that FIDO2 - * device never sees the volume key. - * - * S = HMAC-SHA256(I, D) - * - * with: S → LUKS/account authentication key (never stored) - * I → internal key on FIDO2 device (stored in the FIDO2 device) - * D → salt we generate here (stored in the privileged part of the JSON record) - * - */ - assert(v); assert(device); - salt = malloc(FIDO2_SALT_SIZE); - if (!salt) - return log_oom(); - - r = genuine_random_bytes(salt, FIDO2_SALT_SIZE, RANDOM_BLOCK); - if (r < 0) - return log_error_errno(r, "Failed to generate salt: %m"); - - d = fido_dev_new(); - if (!d) - return log_oom(); - - r = fido_dev_open(d, device); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to open FIDO2 device %s: %s", device, fido_strerr(r)); - - if (!fido_dev_is_fido2(d)) - return log_error_errno(SYNTHETIC_ERRNO(ENODEV), - "Specified device %s is not a FIDO2 device.", device); - - di = fido_cbor_info_new(); - if (!di) - return log_oom(); - - r = fido_dev_get_cbor_info(d, di); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get CBOR device info for %s: %s", device, fido_strerr(r)); - - e = fido_cbor_info_extensions_ptr(di); - n = fido_cbor_info_extensions_len(di); - - for (size_t i = 0; i < n; i++) - if (streq(e[i], "hmac-secret")) { - found_extension = true; - break; - } - - if (!found_extension) - return log_error_errno(SYNTHETIC_ERRNO(ENODEV), - "Specified device %s is a FIDO2 device, but does not support the required HMAC-SECRET extension.", device); - - c = fido_cred_new(); - if (!c) - return log_oom(); - - r = fido_cred_set_extensions(c, FIDO_EXT_HMAC_SECRET); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to enable HMAC-SECRET extension on FIDO2 credential: %s", fido_strerr(r)); - - r = fido_cred_set_rp(c, "io.systemd.home", "Home Directory"); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 credential relying party ID/name: %s", fido_strerr(r)); - - r = fido_cred_set_type(c, COSE_ES256); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 credential type to ES256: %s", fido_strerr(r)); - un = json_variant_by_key(*v, "userName"); if (!un) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -231,164 +149,37 @@ int identity_add_fido2_parameters( return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "realName field of user record is not a string"); - r = fido_cred_set_user(c, - (const unsigned char*) fido_un, strlen(fido_un), /* We pass the user ID and name as the same */ - fido_un, - rn ? json_variant_string(rn) : NULL, - NULL /* icon URL */); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 credential user data: %s", fido_strerr(r)); - - r = fido_cred_set_clientdata_hash(c, (const unsigned char[32]) {}, 32); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 client data hash: %s", fido_strerr(r)); - - r = fido_cred_set_rk(c, FIDO_OPT_FALSE); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to turn off FIDO2 resident key option of credential: %s", fido_strerr(r)); - - r = fido_cred_set_uv(c, FIDO_OPT_FALSE); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to turn off FIDO2 user verification option of credential: %s", fido_strerr(r)); - - log_info("Initializing FIDO2 credential on security token."); - - log_notice("%s%s(Hint: This might require verification of user presence on security token.)", - emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", - emoji_enabled() ? " " : ""); - - r = fido_dev_make_cred(d, c, NULL); - if (r == FIDO_ERR_PIN_REQUIRED) { - _cleanup_free_ char *text = NULL; - - if (asprintf(&text, "Please enter security token PIN:") < 0) - return log_oom(); - - for (;;) { - _cleanup_(strv_free_erasep) char **pin = NULL; - char **i; - - r = ask_password_auto(text, "user-home", NULL, "fido2-pin", USEC_INFINITY, 0, &pin); - if (r < 0) - return log_error_errno(r, "Failed to acquire user PIN: %m"); - - r = FIDO_ERR_PIN_INVALID; - STRV_FOREACH(i, pin) { - if (isempty(*i)) { - log_info("PIN may not be empty."); - continue; - } - - r = fido_dev_make_cred(d, c, *i); - if (r == FIDO_OK) { - used_pin = strdup(*i); - if (!used_pin) - return log_oom(); - break; - } - if (r != FIDO_ERR_PIN_INVALID) - break; - } - - if (r != FIDO_ERR_PIN_INVALID) - break; - - log_notice("PIN incorrect, please try again."); - } - } - if (r == FIDO_ERR_PIN_AUTH_BLOCKED) - return log_notice_errno(SYNTHETIC_ERRNO(EPERM), - "Token PIN is currently blocked, please remove and reinsert token."); - if (r == FIDO_ERR_ACTION_TIMEOUT) - return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), - "Token action timeout. (User didn't interact with token quickly enough.)"); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to generate FIDO2 credential: %s", fido_strerr(r)); - - cid = fido_cred_id_ptr(c); - if (!cid) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get FIDO2 credential ID."); - - cid_size = fido_cred_id_len(c); - - a = fido_assert_new(); - if (!a) - return log_oom(); - - r = fido_assert_set_extensions(a, FIDO_EXT_HMAC_SECRET); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", fido_strerr(r)); - - r = fido_assert_set_hmac_salt(a, salt, FIDO2_SALT_SIZE); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set salt on FIDO2 assertion: %s", fido_strerr(r)); - - r = fido_assert_set_rp(a, "io.systemd.home"); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion ID: %s", fido_strerr(r)); - - r = fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion client data hash: %s", fido_strerr(r)); - - r = fido_assert_allow_cred(a, cid, cid_size); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to add FIDO2 assertion credential ID: %s", fido_strerr(r)); - - r = fido_assert_set_up(a, FIDO_OPT_FALSE); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to turn off FIDO2 assertion user presence: %s", fido_strerr(r)); - - log_info("Generating secret key on FIDO2 security token."); - - r = fido_dev_get_assert(d, a, used_pin); - if (r == FIDO_ERR_UP_REQUIRED) { - r = fido_assert_set_up(a, FIDO_OPT_TRUE); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to turn on FIDO2 assertion user presence: %s", fido_strerr(r)); - - log_notice("%s%sIn order to allow secret key generation, please verify presence on security token.", - emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", - emoji_enabled() ? " " : ""); - - r = fido_dev_get_assert(d, a, used_pin); - } - if (r == FIDO_ERR_ACTION_TIMEOUT) - return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), - "Token action timeout. (User didn't interact with token quickly enough.)"); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to ask token for assertion: %s", fido_strerr(r)); - - secret = fido_assert_hmac_secret_ptr(a, 0); - if (!secret) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve HMAC secret."); - - secret_size = fido_assert_hmac_secret_len(a, 0); - - r = add_fido2_credential_id(v, cid, cid_size); + r = fido2_generate_hmac_hash( + device, + /* rp_id= */ "io.systemd.home", + /* rp_name= */ "Home Directory", + /* user_id= */ fido_un, strlen(fido_un), /* We pass the user ID and name as the same */ + /* user_name= */ fido_un, + /* user_display_name= */ rn ? json_variant_string(rn) : NULL, + /* user_icon_name= */ NULL, + /* askpw_icon_name= */ "user-home", + &cid, &cid_size, + &salt, &salt_size, + &secret, &secret_size, + &used_pin); if (r < 0) return r; - r = add_fido2_salt(v, - cid, - cid_size, - salt, - FIDO2_SALT_SIZE, - secret, - secret_size); + r = add_fido2_credential_id( + v, + cid, + cid_size); + if (r < 0) + return r; + + r = add_fido2_salt( + v, + cid, + cid_size, + salt, + salt_size, + secret, + secret_size); if (r < 0) return r; @@ -405,130 +196,3 @@ int identity_add_fido2_parameters( "FIDO2 tokens not supported on this build."); #endif } - -int list_fido2_devices(void) { -#if HAVE_LIBFIDO2 - _cleanup_(table_unrefp) Table *t = NULL; - size_t allocated = 64, found = 0; - fido_dev_info_t *di = NULL; - int r; - - di = fido_dev_info_new(allocated); - if (!di) - return log_oom(); - - r = fido_dev_info_manifest(di, allocated, &found); - if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { - /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ - log_info("No FIDO2 devices found."); - r = 0; - goto finish; - } - if (r != FIDO_OK) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", fido_strerr(r)); - goto finish; - } - - t = table_new("path", "manufacturer", "product"); - if (!t) { - r = log_oom(); - goto finish; - } - - for (size_t i = 0; i < found; i++) { - const fido_dev_info_t *entry; - - entry = fido_dev_info_ptr(di, i); - if (!entry) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get device information for FIDO device %zu.", i); - goto finish; - } - - r = table_add_many( - t, - TABLE_PATH, fido_dev_info_path(entry), - TABLE_STRING, fido_dev_info_manufacturer_string(entry), - TABLE_STRING, fido_dev_info_product_string(entry)); - if (r < 0) { - table_log_add_error(r); - goto finish; - } - } - - r = table_print(t, stdout); - if (r < 0) { - log_error_errno(r, "Failed to show device table: %m"); - goto finish; - } - - r = 0; - -finish: - fido_dev_info_free(&di, allocated); - return r; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "FIDO2 tokens not supported on this build."); -#endif -} - -int find_fido2_auto(char **ret) { -#if HAVE_LIBFIDO2 - _cleanup_free_ char *copy = NULL; - size_t di_size = 64, found = 0; - const fido_dev_info_t *entry; - fido_dev_info_t *di = NULL; - const char *path; - int r; - - di = fido_dev_info_new(di_size); - if (!di) - return log_oom(); - - r = fido_dev_info_manifest(di, di_size, &found); - if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { - /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ - r = log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No FIDO2 devices found."); - goto finish; - } - if (r != FIDO_OK) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", fido_strerr(r)); - goto finish; - } - if (found > 1) { - r = log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "More than one FIDO2 device found."); - goto finish; - } - - entry = fido_dev_info_ptr(di, 0); - if (!entry) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get device information for FIDO device 0."); - goto finish; - } - - path = fido_dev_info_path(entry); - if (!path) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to query FIDO device path."); - goto finish; - } - - copy = strdup(path); - if (!copy) { - r = log_oom(); - goto finish; - } - - *ret = TAKE_PTR(copy); - r = 0; - -finish: - fido_dev_info_free(&di, di_size); - return r; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "FIDO2 tokens not supported on this build."); -#endif -} diff --git a/src/home/homectl-fido2.h b/src/home/homectl-fido2.h index d0349f540..7b8d9f60a 100644 --- a/src/home/homectl-fido2.h +++ b/src/home/homectl-fido2.h @@ -4,7 +4,3 @@ #include "json.h" int identity_add_fido2_parameters(JsonVariant **v, const char *device); - -int list_fido2_devices(void); - -int find_fido2_auto(char **ret); diff --git a/src/home/homectl-pkcs11.c b/src/home/homectl-pkcs11.c index 4b7f8336a..52cee9a17 100644 --- a/src/home/homectl-pkcs11.c +++ b/src/home/homectl-pkcs11.c @@ -11,125 +11,6 @@ #include "random-util.h" #include "strv.h" -struct pkcs11_callback_data { - char *pin_used; - X509 *cert; -}; - -#if HAVE_P11KIT -static void pkcs11_callback_data_release(struct pkcs11_callback_data *data) { - erase_and_free(data->pin_used); - X509_free(data->cert); -} - -static int pkcs11_callback( - CK_FUNCTION_LIST *m, - CK_SESSION_HANDLE session, - CK_SLOT_ID slot_id, - const CK_SLOT_INFO *slot_info, - const CK_TOKEN_INFO *token_info, - P11KitUri *uri, - void *userdata) { - - _cleanup_(erase_and_freep) char *pin_used = NULL; - struct pkcs11_callback_data *data = userdata; - CK_OBJECT_HANDLE object; - int r; - - assert(m); - assert(slot_info); - assert(token_info); - assert(uri); - assert(data); - - /* Called for every token matching our URI */ - - r = pkcs11_token_login(m, session, slot_id, token_info, "home directory operation", "user-home", "pkcs11-pin", UINT64_MAX, &pin_used); - if (r < 0) - return r; - - r = pkcs11_token_find_x509_certificate(m, session, uri, &object); - if (r < 0) - return r; - - r = pkcs11_token_read_x509_certificate(m, session, object, &data->cert); - if (r < 0) - return r; - - /* Let's read some random data off the token and write it to the kernel pool before we generate our - * random key from it. This way we can claim the quality of the RNG is at least as good as the - * kernel's and the token's pool */ - (void) pkcs11_token_acquire_rng(m, session); - - data->pin_used = TAKE_PTR(pin_used); - return 1; -} -#endif - -static int acquire_pkcs11_certificate( - const char *uri, - X509 **ret_cert, - char **ret_pin_used) { - -#if HAVE_P11KIT - _cleanup_(pkcs11_callback_data_release) struct pkcs11_callback_data data = {}; - int r; - - r = pkcs11_find_token(uri, pkcs11_callback, &data); - if (r == -EAGAIN) /* pkcs11_find_token() doesn't log about this error, but all others */ - return log_error_errno(SYNTHETIC_ERRNO(ENXIO), - "Specified PKCS#11 token with URI '%s' not found.", - uri); - if (r < 0) - return r; - - *ret_cert = TAKE_PTR(data.cert); - *ret_pin_used = TAKE_PTR(data.pin_used); - - return 0; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "PKCS#11 tokens not supported on this build."); -#endif -} - -static int encrypt_bytes( - EVP_PKEY *pkey, - const void *decrypted_key, - size_t decrypted_key_size, - void **ret_encrypt_key, - size_t *ret_encrypt_key_size) { - - _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL; - _cleanup_free_ void *b = NULL; - size_t l; - - ctx = EVP_PKEY_CTX_new(pkey, NULL); - if (!ctx) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to allocate public key context"); - - if (EVP_PKEY_encrypt_init(ctx) <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize public key context"); - - if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to configure PKCS#1 padding"); - - if (EVP_PKEY_encrypt(ctx, NULL, &l, decrypted_key, decrypted_key_size) <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine encrypted key size"); - - b = malloc(l); - if (!b) - return log_oom(); - - if (EVP_PKEY_encrypt(ctx, b, &l, decrypted_key, decrypted_key_size) <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine encrypted key size"); - - *ret_encrypt_key = TAKE_PTR(b); - *ret_encrypt_key_size = l; - - return 0; -} - static int add_pkcs11_encrypted_key( JsonVariant **v, const char *uri, @@ -261,19 +142,31 @@ int identity_add_token_pin(JsonVariant **v, const char *pin) { return 1; } +static int acquire_pkcs11_certificate( + const char *uri, + const char *askpw_friendly_name, + const char *askpw_icon_name, + X509 **ret_cert, + char **ret_pin_used) { +#if HAVE_P11KIT + return pkcs11_acquire_certificate(uri, askpw_friendly_name, askpw_icon_name, ret_cert, ret_pin_used); +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PKCS#11 tokens not supported on this build."); +#endif +} + int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { _cleanup_(erase_and_freep) void *decrypted_key = NULL, *encrypted_key = NULL; _cleanup_(erase_and_freep) char *pin = NULL; size_t decrypted_key_size, encrypted_key_size; _cleanup_(X509_freep) X509 *cert = NULL; EVP_PKEY *pkey; - RSA *rsa; - int bits; int r; assert(v); - r = acquire_pkcs11_certificate(uri, &cert, &pin); + r = acquire_pkcs11_certificate(uri, "home directory operation", "user-home", &cert, &pin); if (r < 0) return r; @@ -281,22 +174,9 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { if (!pkey) return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to extract public key from X.509 certificate."); - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key."); - - rsa = EVP_PKEY_get0_RSA(pkey); - if (!rsa) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire RSA public key from X.509 certificate."); - - bits = RSA_bits(rsa); - log_debug("Bits in RSA key: %i", bits); - - /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only - * generate a random key half the size of the RSA length */ - decrypted_key_size = bits / 8 / 2; - - if (decrypted_key_size < 1) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Uh, RSA key size too short?"); + r = rsa_pkey_to_suitable_key_size(pkey, &decrypted_key_size); + if (r < 0) + return log_error_errno(r, "Failed to extract RSA key size from X509 certificate."); log_debug("Generating %zu bytes random key.", decrypted_key_size); @@ -308,7 +188,7 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { if (r < 0) return log_error_errno(r, "Failed to generate random key: %m"); - r = encrypt_bytes(pkey, decrypted_key, decrypted_key_size, &encrypted_key, &encrypted_key_size); + r = rsa_encrypt_bytes(pkey, decrypted_key, decrypted_key_size, &encrypted_key, &encrypted_key_size); if (r < 0) return log_error_errno(r, "Failed to encrypt key: %m"); @@ -335,143 +215,3 @@ int identity_add_pkcs11_key_data(JsonVariant **v, const char *uri) { return 0; } - -#if HAVE_P11KIT -static int list_callback( - CK_FUNCTION_LIST *m, - CK_SESSION_HANDLE session, - CK_SLOT_ID slot_id, - const CK_SLOT_INFO *slot_info, - const CK_TOKEN_INFO *token_info, - P11KitUri *uri, - void *userdata) { - - _cleanup_free_ char *token_uri_string = NULL, *token_label = NULL, *token_manufacturer_id = NULL, *token_model = NULL; - _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; - Table *t = userdata; - int uri_result, r; - - assert(slot_info); - assert(token_info); - - /* We only care about hardware devices here with a token inserted. Let's filter everything else - * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during - * enumeration we'll filter those, since software tokens are typically the system certificate store - * and such, and it's typically not what people want to bind their home directories to.) */ - if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT)) - return -EAGAIN; - - token_label = pkcs11_token_label(token_info); - if (!token_label) - return log_oom(); - - token_manufacturer_id = pkcs11_token_manufacturer_id(token_info); - if (!token_manufacturer_id) - return log_oom(); - - token_model = pkcs11_token_model(token_info); - if (!token_model) - return log_oom(); - - token_uri = uri_from_token_info(token_info); - if (!token_uri) - return log_oom(); - - uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string); - if (uri_result != P11_KIT_URI_OK) - return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result)); - - r = table_add_many( - t, - TABLE_STRING, token_uri_string, - TABLE_STRING, token_label, - TABLE_STRING, token_manufacturer_id, - TABLE_STRING, token_model); - if (r < 0) - return table_log_add_error(r); - - return -EAGAIN; /* keep scanning */ -} -#endif - -int list_pkcs11_tokens(void) { -#if HAVE_P11KIT - _cleanup_(table_unrefp) Table *t = NULL; - int r; - - t = table_new("uri", "label", "manufacturer", "model"); - if (!t) - return log_oom(); - - r = pkcs11_find_token(NULL, list_callback, t); - if (r < 0 && r != -EAGAIN) - return r; - - if (table_get_rows(t) <= 1) { - log_info("No suitable PKCS#11 tokens found."); - return 0; - } - - r = table_print(t, stdout); - if (r < 0) - return log_error_errno(r, "Failed to show device table: %m"); - - return 0; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "PKCS#11 tokens not supported on this build."); -#endif -} - -#if HAVE_P11KIT -static int auto_callback( - CK_FUNCTION_LIST *m, - CK_SESSION_HANDLE session, - CK_SLOT_ID slot_id, - const CK_SLOT_INFO *slot_info, - const CK_TOKEN_INFO *token_info, - P11KitUri *uri, - void *userdata) { - - _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; - char **t = userdata; - int uri_result; - - assert(slot_info); - assert(token_info); - - if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT)) - return -EAGAIN; - - if (*t) - return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), - "More than one suitable PKCS#11 token found."); - - token_uri = uri_from_token_info(token_info); - if (!token_uri) - return log_oom(); - - uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t); - if (uri_result != P11_KIT_URI_OK) - return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result)); - - return 0; -} -#endif - -int find_pkcs11_token_auto(char **ret) { -#if HAVE_P11KIT - int r; - - r = pkcs11_find_token(NULL, auto_callback, ret); - if (r == -EAGAIN) - return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No suitable PKCS#11 tokens found."); - if (r < 0) - return r; - - return 0; -#else - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "PKCS#11 tokens not supported on this build."); -#endif -} diff --git a/src/home/homectl-recovery-key.c b/src/home/homectl-recovery-key.c index 4a6649d25..f1a180bac 100644 --- a/src/home/homectl-recovery-key.c +++ b/src/home/homectl-recovery-key.c @@ -5,46 +5,12 @@ #include "libcrypt-util.h" #include "locale-util.h" #include "memory-util.h" -#include "modhex.h" #include "qrcode-util.h" #include "random-util.h" +#include "recovery-key.h" #include "strv.h" #include "terminal-util.h" -static int make_recovery_key(char **ret) { - _cleanup_(erase_and_freep) char *formatted = NULL; - _cleanup_(erase_and_freep) uint8_t *key = NULL; - int r; - - assert(ret); - - key = new(uint8_t, MODHEX_RAW_LENGTH); - if (!key) - return log_oom(); - - r = genuine_random_bytes(key, MODHEX_RAW_LENGTH, RANDOM_BLOCK); - if (r < 0) - return log_error_errno(r, "Failed to gather entropy for recovery key: %m"); - - /* Let's now format it as 64 modhex chars, and after each 8 chars insert a dash */ - formatted = new(char, MODHEX_FORMATTED_LENGTH); - if (!formatted) - return log_oom(); - - for (size_t i = 0, j = 0; i < MODHEX_RAW_LENGTH; i++) { - formatted[j++] = modhex_alphabet[key[i] >> 4]; - formatted[j++] = modhex_alphabet[key[i] & 0xF]; - - if (i % 4 == 3) - formatted[j++] = '-'; - } - - formatted[MODHEX_FORMATTED_LENGTH-1] = 0; - - *ret = TAKE_PTR(formatted); - return 0; -} - static int add_privileged(JsonVariant **v, const char *hashed) { _cleanup_(json_variant_unrefp) JsonVariant *e = NULL, *w = NULL, *l = NULL; int r; @@ -144,7 +110,7 @@ int identity_add_recovery_key(JsonVariant **v) { /* First, let's generate a secret key */ r = make_recovery_key(&password); if (r < 0) - return r; + return log_error_errno(r, "Failed to generate recovery key: %m"); /* Let's UNIX hash it */ r = hash_password(password, &hashed); diff --git a/src/home/homectl.c b/src/home/homectl.c index 7cfda7ed2..9d12b9aba 100644 --- a/src/home/homectl.c +++ b/src/home/homectl.c @@ -18,12 +18,15 @@ #include "homectl-fido2.h" #include "homectl-pkcs11.h" #include "homectl-recovery-key.h" +#include "libfido2-util.h" #include "locale-util.h" #include "main-func.h" #include "memory-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "pkcs11-util.h" #include "pretty-print.h" #include "process-util.h" @@ -55,8 +58,7 @@ static uint64_t arg_disk_size_relative = UINT64_MAX; static char **arg_pkcs11_token_uri = NULL; static char **arg_fido2_device = NULL; static bool arg_recovery_key = false; -static bool arg_json = false; -static JsonFormatFlags arg_json_format_flags = 0; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; static bool arg_and_resize = false; static bool arg_and_change_password = false; static enum { @@ -113,8 +115,6 @@ static int list_homes(int argc, char *argv[], void *userdata) { _cleanup_(table_unrefp) Table *table = NULL; int r; - (void) pager_open(arg_pager_flags); - r = acquire_bus(&bus); if (r < 0) return r; @@ -170,22 +170,17 @@ static int list_homes(int argc, char *argv[], void *userdata) { if (r < 0) return bus_log_parse_error(r); - if (table_get_rows(table) > 1 || arg_json) { - r = table_set_sort(table, (size_t) 0, (size_t) -1); + if (table_get_rows(table) > 1 || !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) { + r = table_set_sort(table, (size_t) 0); if (r < 0) return table_log_sort_error(r); - table_set_header(table, arg_legend); - - if (arg_json) - r = table_print_json(table, stdout, arg_json_format_flags); - else - r = table_print(table, NULL); + r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); if (r < 0) - return table_log_print_error(r); + return r; } - if (arg_legend && !arg_json) { + if (arg_legend && (arg_json_format_flags & JSON_FORMAT_OFF)) { if (table_get_rows(table) > 1) printf("\n%zu home areas listed.\n", table_get_rows(table) - 1); else @@ -461,7 +456,9 @@ static void dump_home_record(UserRecord *hr) { log_warning("Warning: lacking rights to acquire privileged fields of user record of '%s', output incomplete.", hr->user_name); } - if (arg_json) { + if (arg_json_format_flags & JSON_FORMAT_OFF) + user_record_show(hr, true); + else { _cleanup_(user_record_unrefp) UserRecord *stripped = NULL; if (arg_export_format == EXPORT_FORMAT_STRIPPED) @@ -476,8 +473,7 @@ static void dump_home_record(UserRecord *hr) { hr = stripped; json_variant_dump(hr->json, arg_json_format_flags, stdout, NULL); - } else - user_record_show(hr, true); + } } static char **mangle_user_list(char **list, char ***ret_allocated) { @@ -1572,7 +1568,7 @@ static int resize_home(int argc, char *argv[], void *userdata) { (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); if (arg_disk_size_relative != UINT64_MAX || - (argc > 2 && parse_percent(argv[2]) >= 0)) + (argc > 2 && parse_permyriad(argv[2]) >= 0)) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Relative disk size specification currently not supported when resizing."); @@ -2032,12 +2028,13 @@ static int help(int argc, char *argv[], void *userdata) { " --kill-processes=BOOL Whether to kill user processes when sessions\n" " terminate\n" " --auto-login=BOOL Try to log this user in automatically\n" - "\nSee the %6$s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , ansi_underline(), ansi_normal() - , link - ); + "\nSee the %6$s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + ansi_underline(), + ansi_normal(), + link); return 0; } @@ -2265,7 +2262,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - r = parse_path_argument_and_warn(optarg, false, &hd); + r = parse_path_argument(optarg, false, &hd); if (r < 0) return r; @@ -2398,7 +2395,7 @@ static int parse_argv(int argc, char *argv[]) { l = rlimit_from_string_harder(field); if (l < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown resource limit type: %s", field); + return log_error_errno(l, "Unknown resource limit type: %s", field); if (isempty(eq + 1)) { /* Remove only the specific rlimit */ @@ -2486,7 +2483,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - r = parse_path_argument_and_warn(optarg, false, &v); + r = parse_path_argument(optarg, false, &v); if (r < 0) return r; @@ -2516,7 +2513,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_SETENV: { - _cleanup_free_ char **l = NULL, **k = NULL; + _cleanup_free_ char **l = NULL; _cleanup_(json_variant_unrefp) JsonVariant *ne = NULL; JsonVariant *e; @@ -2529,7 +2526,8 @@ static int parse_argv(int argc, char *argv[]) { } if (!env_assignment_is_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Environment assignment '%s' not valid.", optarg); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Environment assignment '%s' not valid.", optarg); e = json_variant_by_key(arg_identity_extra, "environment"); if (e) { @@ -2538,13 +2536,13 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(r, "Failed to parse JSON environment field: %m"); } - k = strv_env_set(l, optarg); - if (!k) - return log_oom(); + r = strv_env_replace_strdup(&l, optarg); + if (r < 0) + return log_error_errno(r, "Failed to replace JSON environment field: %m"); - strv_sort(k); + strv_sort(l); - r = json_variant_new_array_strv(&ne, k); + r = json_variant_new_array_strv(&ne, l); if (r < 0) return log_error_errno(r, "Failed to allocate environment list JSON: %m"); @@ -2656,7 +2654,7 @@ static int parse_argv(int argc, char *argv[]) { break; } - r = parse_permille(optarg); + r = parse_permyriad(optarg); if (r < 0) { r = parse_size(optarg, 1024, &arg_disk_size); if (r < 0) @@ -2673,7 +2671,7 @@ static int parse_argv(int argc, char *argv[]) { arg_disk_size_relative = UINT64_MAX; } else { /* Normalize to UINT32_MAX == 100% */ - arg_disk_size_relative = (uint64_t) r * UINT32_MAX / 1000U; + arg_disk_size_relative = UINT32_SCALE_FROM_PERMYRIAD(r); r = drop_from_identity("diskSize"); if (r < 0) @@ -3146,7 +3144,7 @@ static int parse_argv(int argc, char *argv[]) { const char *p; if (streq(optarg, "list")) - return list_pkcs11_tokens(); + return pkcs11_list_tokens(); /* If --pkcs11-token-uri= is specified we always drop everything old */ FOREACH_STRING(p, "pkcs11TokenUri", "pkcs11EncryptedKey") { @@ -3163,7 +3161,7 @@ static int parse_argv(int argc, char *argv[]) { if (streq(optarg, "auto")) { _cleanup_free_ char *found = NULL; - r = find_pkcs11_token_auto(&found); + r = pkcs11_find_token_auto(&found); if (r < 0) return r; r = strv_consume(&arg_pkcs11_token_uri, TAKE_PTR(found)); @@ -3184,7 +3182,7 @@ static int parse_argv(int argc, char *argv[]) { const char *p; if (streq(optarg, "list")) - return list_fido2_devices(); + return fido2_list_devices(); FOREACH_STRING(p, "fido2HmacCredential", "fido2HmacSalt") { r = drop_from_identity(p); @@ -3200,7 +3198,7 @@ static int parse_argv(int argc, char *argv[]) { if (streq(optarg, "auto")) { _cleanup_free_ char *found = NULL; - r = find_fido2_auto(&found); + r = fido2_find_device_auto(&found); if (r < 0) return r; @@ -3234,27 +3232,13 @@ static int parse_argv(int argc, char *argv[]) { } case 'j': - arg_json = true; arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO; break; case ARG_JSON: - if (streq(optarg, "pretty")) { - arg_json = true; - arg_json_format_flags = JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR_AUTO; - } else if (streq(optarg, "short")) { - arg_json = true; - arg_json_format_flags = JSON_FORMAT_NEWLINE; - } else if (streq(optarg, "off")) { - arg_json = false; - arg_json_format_flags = 0; - } else if (streq(optarg, "help")) { - puts("pretty\n" - "short\n" - "off"); - return 0; - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown argument to --json=: %s", optarg); + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; break; @@ -3266,7 +3250,7 @@ static int parse_argv(int argc, char *argv[]) { else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Specifying -E more than twice is not supported."); - arg_json = true; + arg_json_format_flags &= ~JSON_FORMAT_OFF; if (arg_json_format_flags == 0) arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO; break; @@ -3365,7 +3349,7 @@ static int run(int argc, char *argv[]) { int r; - log_setup_cli(); + log_setup(); r = redirect_bus_mgr(); if (r < 0) diff --git a/src/home/homed-gperf.gperf b/src/home/homed-gperf.gperf index 970da5f79..39aca35b0 100644 --- a/src/home/homed-gperf.gperf +++ b/src/home/homed-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") diff --git a/src/home/homed-home-bus.c b/src/home/homed-home-bus.c index 5643a9a6e..2a58ecbc1 100644 --- a/src/home/homed-home-bus.c +++ b/src/home/homed-home-bus.c @@ -885,7 +885,7 @@ static int on_deferred_change(sd_event_source *s, void *userdata) { assert(h); - h->deferred_change_event_source = sd_event_source_unref(h->deferred_change_event_source); + h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source); r = bus_home_path(h, &path); if (r < 0) { diff --git a/src/home/homed-home.c b/src/home/homed-home.c index 7f4532e0c..b0c5ce423 100644 --- a/src/home/homed-home.c +++ b/src/home/homed-home.c @@ -188,17 +188,17 @@ Home *home_free(Home *h) { user_record_unref(h->record); user_record_unref(h->secret); - h->worker_event_source = sd_event_source_unref(h->worker_event_source); + h->worker_event_source = sd_event_source_disable_unref(h->worker_event_source); safe_close(h->worker_stdout_fd); free(h->user_name); free(h->sysfs); - h->ref_event_source_please_suspend = sd_event_source_unref(h->ref_event_source_please_suspend); - h->ref_event_source_dont_suspend = sd_event_source_unref(h->ref_event_source_dont_suspend); + h->ref_event_source_please_suspend = sd_event_source_disable_unref(h->ref_event_source_please_suspend); + h->ref_event_source_dont_suspend = sd_event_source_disable_unref(h->ref_event_source_dont_suspend); h->pending_operations = ordered_set_free(h->pending_operations); - h->pending_event_source = sd_event_source_unref(h->pending_event_source); - h->deferred_change_event_source = sd_event_source_unref(h->deferred_change_event_source); + h->pending_event_source = sd_event_source_disable_unref(h->pending_event_source); + h->deferred_change_event_source = sd_event_source_disable_unref(h->deferred_change_event_source); h->current_operation = operation_unref(h->current_operation); @@ -888,7 +888,7 @@ static int home_on_worker_process(sd_event_source *s, const siginfo_t *si, void (void) hashmap_remove_value(h->manager->homes_by_worker_pid, PID_TO_PTR(h->worker_pid), h); h->worker_pid = 0; - h->worker_event_source = sd_event_source_unref(h->worker_event_source); + h->worker_event_source = sd_event_source_disable_unref(h->worker_event_source); if (si->si_code != CLD_EXITED) { assert(IN_SET(si->si_code, CLD_KILLED, CLD_DUMPED)); @@ -1007,7 +1007,7 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord r = safe_fork_full("(sd-homework)", (int[]) { stdin_fd, stdout_fd }, 2, - FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG, &pid); + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG|FORK_REOPEN_LOG, &pid); if (r < 0) return r; if (r == 0) { @@ -1038,6 +1038,10 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord _exit(EXIT_FAILURE); } + r = setenv_systemd_exec_pid(true); + if (r < 0) + log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m"); + r = rearrange_stdio(stdin_fd, stdout_fd, STDERR_FILENO); if (r < 0) { log_error_errno(r, "Failed to rearrange stdin/stdout/stderr: %m"); @@ -1063,7 +1067,7 @@ static int home_start_work(Home *h, const char *verb, UserRecord *hr, UserRecord r = hashmap_put(h->manager->homes_by_worker_pid, PID_TO_PTR(pid), h); if (r < 0) { - h->worker_event_source = sd_event_source_unref(h->worker_event_source); + h->worker_event_source = sd_event_source_disable_unref(h->worker_event_source); return r; } @@ -1834,7 +1838,9 @@ int home_killall(Home *h) { assert(h->uid > 0); /* We never should be UID 0 */ /* Let's kill everything matching the specified UID */ - r = safe_fork("(sd-killer)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT|FORK_LOG, NULL); + r = safe_fork("(sd-killer)", + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, + NULL); if (r < 0) return r; if (r == 0) { @@ -2656,11 +2662,7 @@ int home_schedule_operation(Home *h, Operation *o, sd_bus_error *error) { if (ordered_set_size(h->pending_operations) >= PENDING_OPERATIONS_MAX) return sd_bus_error_setf(error, BUS_ERROR_TOO_MANY_OPERATIONS, "Too many client operations requested"); - r = ordered_set_ensure_allocated(&h->pending_operations, &operation_hash_ops); - if (r < 0) - return r; - - r = ordered_set_put(h->pending_operations, o); + r = ordered_set_ensure_put(&h->pending_operations, &operation_hash_ops, o); if (r < 0) return r; @@ -2711,7 +2713,7 @@ static int home_get_image_path_seat(Home *h, char **ret) { if (!S_ISBLK(st.st_mode)) return -ENOTBLK; - r = sd_device_new_from_devnum(&d, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) return r; diff --git a/src/home/homed-home.h b/src/home/homed-home.h index 4c24ee72a..2afff0c02 100644 --- a/src/home/homed-home.h +++ b/src/home/homed-home.h @@ -37,7 +37,7 @@ typedef enum HomeState { HOME_AUTHENTICATING_WHILE_ACTIVE, HOME_AUTHENTICATING_FOR_ACQUIRE, /* authenticating because Acquire() was called */ _HOME_STATE_MAX, - _HOME_STATE_INVALID = -1 + _HOME_STATE_INVALID = -EINVAL, } HomeState; static inline bool HOME_STATE_IS_ACTIVE(HomeState state) { diff --git a/src/home/homed-manager-bus.c b/src/home/homed-manager-bus.c index d3ac98f90..8a06bb62b 100644 --- a/src/home/homed-manager-bus.c +++ b/src/home/homed-manager-bus.c @@ -860,7 +860,7 @@ static int on_deferred_auto_login(sd_event_source *s, void *userdata) { assert(m); - m->deferred_auto_login_event_source = sd_event_source_unref(m->deferred_auto_login_event_source); + m->deferred_auto_login_event_source = sd_event_source_disable_unref(m->deferred_auto_login_event_source); r = sd_bus_emit_properties_changed( m->bus, diff --git a/src/home/homed-manager.c b/src/home/homed-manager.c index 365ea4d23..85fdc8896 100644 --- a/src/home/homed-manager.c +++ b/src/home/homed-manager.c @@ -79,7 +79,7 @@ static void manager_watch_home(Manager *m) { assert(m); - m->inotify_event_source = sd_event_source_unref(m->inotify_event_source); + m->inotify_event_source = sd_event_source_disable_unref(m->inotify_event_source); m->scan_slash_home = false; if (statfs("/home/", &sfs) < 0) { @@ -100,7 +100,9 @@ static void manager_watch_home(Manager *m) { m->scan_slash_home = true; - r = sd_event_add_inotify(m->event, &m->inotify_event_source, "/home/", IN_CREATE|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ONLYDIR|IN_MOVED_TO|IN_MOVED_FROM|IN_DELETE, on_home_inotify, m); + r = sd_event_add_inotify(m->event, &m->inotify_event_source, "/home/", + IN_CREATE|IN_CLOSE_WRITE|IN_DELETE_SELF|IN_MOVE_SELF|IN_ONLYDIR|IN_MOVED_TO|IN_MOVED_FROM|IN_DELETE, + on_home_inotify, m); if (r < 0) log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r, "Failed to create inotify watch on /home/, ignoring."); @@ -239,25 +241,24 @@ Manager* manager_free(Manager *m) { HASHMAP_FOREACH(h, m->homes_by_worker_pid) (void) home_wait_for_worker(h); + sd_bus_flush_close_unref(m->bus); + bus_verify_polkit_async_registry_free(m->polkit_registry); + + m->device_monitor = sd_device_monitor_unref(m->device_monitor); + + m->inotify_event_source = sd_event_source_unref(m->inotify_event_source); + m->notify_socket_event_source = sd_event_source_unref(m->notify_socket_event_source); + m->deferred_rescan_event_source = sd_event_source_unref(m->deferred_rescan_event_source); + m->deferred_gc_event_source = sd_event_source_unref(m->deferred_gc_event_source); + m->deferred_auto_login_event_source = sd_event_source_unref(m->deferred_auto_login_event_source); + + sd_event_unref(m->event); + hashmap_free(m->homes_by_uid); hashmap_free(m->homes_by_name); hashmap_free(m->homes_by_worker_pid); hashmap_free(m->homes_by_sysfs); - m->inotify_event_source = sd_event_source_unref(m->inotify_event_source); - - bus_verify_polkit_async_registry_free(m->polkit_registry); - - sd_bus_flush_close_unref(m->bus); - sd_event_unref(m->event); - - m->notify_socket_event_source = sd_event_source_unref(m->notify_socket_event_source); - m->device_monitor = sd_device_monitor_unref(m->device_monitor); - - m->deferred_rescan_event_source = sd_event_source_unref(m->deferred_rescan_event_source); - m->deferred_gc_event_source = sd_event_source_unref(m->deferred_gc_event_source); - m->deferred_auto_login_event_source = sd_event_source_unref(m->deferred_auto_login_event_source); - if (m->private_key) EVP_PKEY_free(m->private_key); @@ -368,7 +369,9 @@ static int manager_add_home_by_record( return r; if (!streq_ptr(hr->user_name, name)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Identity's user name %s does not match file name %s, refusing.", hr->user_name, name); + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Identity's user name %s does not match file name %s, refusing.", + hr->user_name, name); is_signed = manager_verify_user_record(m, hr); switch (is_signed) { @@ -599,19 +602,22 @@ static int manager_acquire_uid( other = hashmap_get(m->homes_by_uid, UID_TO_PTR(candidate)); if (other) { - log_debug("Candidate UID " UID_FMT " already used by another home directory (%s), let's try another.", candidate, other->user_name); + log_debug("Candidate UID " UID_FMT " already used by another home directory (%s), let's try another.", + candidate, other->user_name); continue; } pw = getpwuid(candidate); if (pw) { - log_debug("Candidate UID " UID_FMT " already registered by another user in NSS (%s), let's try another.", candidate, pw->pw_name); + log_debug("Candidate UID " UID_FMT " already registered by another user in NSS (%s), let's try another.", + candidate, pw->pw_name); continue; } gr = getgrgid((gid_t) candidate); if (gr) { - log_debug("Candidate UID " UID_FMT " already registered by another group in NSS (%s), let's try another.", candidate, gr->gr_name); + log_debug("Candidate UID " UID_FMT " already registered by another group in NSS (%s), let's try another.", + candidate, gr->gr_name); continue; } @@ -619,7 +625,8 @@ static int manager_acquire_uid( if (r < 0) continue; if (r > 0) { - log_debug_errno(r, "Candidate UID " UID_FMT " already owns IPC objects, let's try another: %m", candidate); + log_debug_errno(r, "Candidate UID " UID_FMT " already owns IPC objects, let's try another: %m", + candidate); continue; } @@ -692,7 +699,9 @@ static int manager_add_home_by_image( if (h && uid_is_valid(h->uid)) uid = h->uid; else { - r = manager_acquire_uid(m, start_uid, user_name, IN_SET(storage, USER_SUBVOLUME, USER_DIRECTORY, USER_FSCRYPT) ? image_path : NULL, &uid); + r = manager_acquire_uid(m, start_uid, user_name, + IN_SET(storage, USER_SUBVOLUME, USER_DIRECTORY, USER_FSCRYPT) ? image_path : NULL, + &uid); if (r < 0) return log_warning_errno(r, "Failed to acquire unused UID for %s: %m", user_name); } @@ -956,7 +965,7 @@ static int manager_bind_varlink(Manager *m) { assert(m); assert(!m->varlink_server); - r = varlink_server_new(&m->varlink_server, VARLINK_SERVER_ACCOUNT_UID); + r = varlink_server_new(&m->varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); if (r < 0) return log_error_errno(r, "Failed to allocate varlink server object: %m"); @@ -1234,7 +1243,7 @@ static int manager_on_device(sd_device_monitor *monitor, sd_device *d, void *use assert(m); assert(d); - if (device_for_action(d, DEVICE_ACTION_REMOVE)) { + if (device_for_action(d, SD_DEVICE_REMOVE)) { const char *sysfs; Home *h; @@ -1343,7 +1352,7 @@ static int manager_load_key_pair(Manager *m) { return 1; } -DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_PKEY_CTX*, EVP_PKEY_CTX_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL); static int manager_generate_key_pair(Manager *m) { _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL; @@ -1454,7 +1463,7 @@ int manager_sign_user_record(Manager *m, UserRecord *u, UserRecord **ret, sd_bus } DEFINE_PRIVATE_HASH_OPS_FULL(public_key_hash_ops, char, string_hash_func, string_compare_func, free, EVP_PKEY, EVP_PKEY_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_PKEY*, EVP_PKEY_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY*, EVP_PKEY_free, NULL); static int manager_load_public_key_one(Manager *m, const char *path) { _cleanup_(EVP_PKEY_freep) EVP_PKEY *pkey = NULL; @@ -1660,7 +1669,7 @@ static int on_deferred_rescan(sd_event_source *s, void *userdata) { assert(m); - m->deferred_rescan_event_source = sd_event_source_unref(m->deferred_rescan_event_source); + m->deferred_rescan_event_source = sd_event_source_disable_unref(m->deferred_rescan_event_source); manager_enumerate_devices(m); manager_enumerate_images(m); @@ -1698,7 +1707,7 @@ static int on_deferred_gc(sd_event_source *s, void *userdata) { assert(m); - m->deferred_gc_event_source = sd_event_source_unref(m->deferred_gc_event_source); + m->deferred_gc_event_source = sd_event_source_disable_unref(m->deferred_gc_event_source); manager_gc_images(m); return 0; diff --git a/src/home/homed-operation.h b/src/home/homed-operation.h index 6721363b2..004246a4e 100644 --- a/src/home/homed-operation.h +++ b/src/home/homed-operation.h @@ -14,7 +14,7 @@ typedef enum OperationType { OPERATION_DEACTIVATE_FORCE, /* enqueued on hard $HOME unplug */ OPERATION_IMMEDIATE, /* this is never enqueued, it's just a marker we immediately started executing an operation without enqueuing anything first. */ _OPERATION_MAX, - _OPERATION_INVALID = -1, + _OPERATION_INVALID = -EINVAL, } OperationType; /* Encapsulates an operation on one or more home directories. This has two uses: diff --git a/src/home/homed.c b/src/home/homed.c index e4d64bdfd..807d25e27 100644 --- a/src/home/homed.c +++ b/src/home/homed.c @@ -17,7 +17,7 @@ static int run(int argc, char *argv[]) { _cleanup_(notify_on_cleanup) const char *notify_stop = NULL; int r; - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-homed.service", "A service to create, remove, change or inspect home areas.", diff --git a/src/home/homed.conf b/src/home/homed.conf index 1b5dbedab..ba854641d 100644 --- a/src/home/homed.conf +++ b/src/home/homed.conf @@ -1,15 +1,18 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See homed.conf(5) for details +# Use 'systemd-analyze cat-config systemd/homed.conf' to display the full config. +# +# See homed.conf(5) for details. [Home] #DefaultStorage= diff --git a/src/home/homework-fido2.c b/src/home/homework-fido2.c index 2f717a593..87d301c5b 100644 --- a/src/home/homework-fido2.c +++ b/src/home/homework-fido2.c @@ -4,138 +4,35 @@ #include "hexdecoct.h" #include "homework-fido2.h" -#include "strv.h" +#include "libfido2-util.h" +#include "memory-util.h" -static int fido2_use_specific_token( - const char *path, +int fido2_use_token( UserRecord *h, UserRecord *secret, const Fido2HmacSalt *salt, char **ret) { - _cleanup_(fido_cbor_info_free) fido_cbor_info_t *di = NULL; - _cleanup_(fido_assert_free) fido_assert_t *a = NULL; - _cleanup_(fido_dev_free) fido_dev_t *d = NULL; - bool found_extension = false; - size_t n, hmac_size; - const void *hmac; - char **e; + _cleanup_(erase_and_freep) void *hmac = NULL; + size_t hmac_size; int r; - d = fido_dev_new(); - if (!d) - return log_oom(); + assert(h); + assert(secret); + assert(salt); + assert(ret); - r = fido_dev_open(d, path); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to open FIDO2 device %s: %s", path, fido_strerr(r)); - - if (!fido_dev_is_fido2(d)) - return log_error_errno(SYNTHETIC_ERRNO(ENODEV), - "Specified device %s is not a FIDO2 device.", path); - - di = fido_cbor_info_new(); - if (!di) - return log_oom(); - - r = fido_dev_get_cbor_info(d, di); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get CBOR device info for %s: %s", path, fido_strerr(r)); - - e = fido_cbor_info_extensions_ptr(di); - n = fido_cbor_info_extensions_len(di); - - for (size_t i = 0; i < n; i++) - if (streq(e[i], "hmac-secret")) { - found_extension = true; - break; - } - - if (!found_extension) - return log_error_errno(SYNTHETIC_ERRNO(ENODEV), - "Specified device %s is a FIDO2 device, but does not support the required HMAC-SECRET extension.", path); - - a = fido_assert_new(); - if (!a) - return log_oom(); - - r = fido_assert_set_extensions(a, FIDO_EXT_HMAC_SECRET); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", fido_strerr(r)); - - r = fido_assert_set_hmac_salt(a, salt->salt, salt->salt_size); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set salt on FIDO2 assertion: %s", fido_strerr(r)); - - r = fido_assert_set_rp(a, "io.systemd.home"); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion ID: %s", fido_strerr(r)); - - r = fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion client data hash: %s", fido_strerr(r)); - - r = fido_assert_allow_cred(a, salt->credential.id, salt->credential.size); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to add FIDO2 assertion credential ID: %s", fido_strerr(r)); - - r = fido_assert_set_up(a, h->fido2_user_presence_permitted <= 0 ? FIDO_OPT_FALSE : FIDO_OPT_TRUE); - if (r != FIDO_OK) - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to set FIDO2 assertion user presence: %s", fido_strerr(r)); - - log_info("Asking FIDO2 token for authentication."); - - r = fido_dev_get_assert(d, a, NULL); /* try without pin first */ - if (r == FIDO_ERR_PIN_REQUIRED) { - char **i; - - /* OK, we needed a pin, try with all pins in turn */ - STRV_FOREACH(i, secret->token_pin) { - r = fido_dev_get_assert(d, a, *i); - if (r != FIDO_ERR_PIN_INVALID) - break; - } - } - - switch (r) { - case FIDO_OK: - break; - case FIDO_ERR_NO_CREDENTIALS: - return log_error_errno(SYNTHETIC_ERRNO(EBADSLT), - "Wrong security token; needed credentials not present on token."); - case FIDO_ERR_PIN_REQUIRED: - return log_error_errno(SYNTHETIC_ERRNO(ENOANO), - "Security token requires PIN."); - case FIDO_ERR_PIN_AUTH_BLOCKED: - return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD), - "PIN of security token is blocked, please remove/reinsert token."); - case FIDO_ERR_PIN_INVALID: - return log_error_errno(SYNTHETIC_ERRNO(ENOLCK), - "PIN of security token incorrect."); - case FIDO_ERR_UP_REQUIRED: - return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), - "User presence required."); - case FIDO_ERR_ACTION_TIMEOUT: - return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), - "Token action timeout. (User didn't interact with token quickly enough.)"); - default: - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to ask token for assertion: %s", fido_strerr(r)); - } - - hmac = fido_assert_hmac_secret_ptr(a, 0); - if (!hmac) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve HMAC secret."); - - hmac_size = fido_assert_hmac_secret_len(a, 0); + r = fido2_use_hmac_hash( + NULL, + "io.systemd.home", + salt->salt, salt->salt_size, + salt->credential.id, salt->credential.size, + secret->token_pin, + h->fido2_user_presence_permitted > 0, + &hmac, + &hmac_size); + if (r < 0) + return r; r = base64mem(hmac, hmac_size, ret); if (r < 0) @@ -143,55 +40,3 @@ static int fido2_use_specific_token( return 0; } - -int fido2_use_token(UserRecord *h, UserRecord *secret, const Fido2HmacSalt *salt, char **ret) { - size_t allocated = 64, found = 0; - fido_dev_info_t *di = NULL; - int r; - - di = fido_dev_info_new(allocated); - if (!di) - return log_oom(); - - r = fido_dev_info_manifest(di, allocated, &found); - if (r == FIDO_ERR_INTERNAL) { - /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ - r = log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "Got FIDO_ERR_INTERNAL, assuming no devices."); - goto finish; - } - if (r != FIDO_OK) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", fido_strerr(r)); - goto finish; - } - - for (size_t i = 0; i < found; i++) { - const fido_dev_info_t *entry; - const char *path; - - entry = fido_dev_info_ptr(di, i); - if (!entry) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to get device information for FIDO device %zu.", i); - goto finish; - } - - path = fido_dev_info_path(entry); - if (!path) { - r = log_error_errno(SYNTHETIC_ERRNO(EIO), - "Failed to query FIDO device path."); - goto finish; - } - - r = fido2_use_specific_token(path, h, secret, salt, ret); - if (!IN_SET(r, - -EBADSLT, /* device doesn't understand our credential hash */ - -ENODEV /* device is not a FIDO2 device with HMAC-SECRET */)) - goto finish; - } - - r = -EAGAIN; - -finish: - fido_dev_info_free(&di, allocated); - return r; -} diff --git a/src/home/homework-fscrypt.c b/src/home/homework-fscrypt.c index d0676f8ae..037e4853f 100644 --- a/src/home/homework-fscrypt.c +++ b/src/home/homework-fscrypt.c @@ -324,7 +324,9 @@ int home_prepare_fscrypt( /* Also install the access key in the user's own keyring */ if (uid_is_valid(h->uid)) { - r = safe_fork("(sd-addkey)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + r = safe_fork("(sd-addkey)", + FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_REOPEN_LOG, + NULL); if (r < 0) return log_error_errno(r, "Failed install encryption key in user's keyring: %m"); if (r == 0) { diff --git a/src/home/homework-luks.c b/src/home/homework-luks.c index b0b2d8029..07d5bcfdb 100644 --- a/src/home/homework-luks.c +++ b/src/home/homework-luks.c @@ -199,12 +199,15 @@ static int run_fsck(const char *node, const char *fstype) { return 0; } - r = safe_fork("(fsck)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR, &fsck_pid); + r = safe_fork("(fsck)", + FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS, + &fsck_pid); if (r < 0) return r; if (r == 0) { /* Child */ execl("/sbin/fsck", "/sbin/fsck", "-aTl", node, NULL); + log_open(); log_error_errno(errno, "Failed to execute fsck: %m"); _exit(FSCK_OPERATIONAL_ERROR); } @@ -518,7 +521,7 @@ static int luks_validate( blkid_loff_t offset = 0, size = 0; blkid_partlist pl; bool found = false; - int r, i, n; + int r, n; assert(fd >= 0); assert(label); @@ -570,9 +573,9 @@ static int luks_validate( if (n < 0) return errno > 0 ? -errno : -EIO; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { blkid_partition pp; - sd_id128_t id; + sd_id128_t id = SD_ID128_NULL; const char *sid; errno = 0; @@ -681,12 +684,12 @@ static int luks_validate_home_record( PasswordCache *cache, UserRecord **ret_luks_home_record) { - int r, token; + int r; assert(cd); assert(h); - for (token = 0;; token++) { + for (int token = 0;; token++) { _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *rr = NULL; _cleanup_(EVP_CIPHER_CTX_freep) EVP_CIPHER_CTX *context = NULL; _cleanup_(user_record_unrefp) UserRecord *lhr = NULL; @@ -1592,10 +1595,10 @@ static int luks_format( return 0; } -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_context*, fdisk_unref_context); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_partition*, fdisk_unref_partition); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_parttype*, fdisk_unref_parttype); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_table*, fdisk_unref_table); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_context*, fdisk_unref_context, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_partition*, fdisk_unref_partition, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_parttype*, fdisk_unref_parttype, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_table*, fdisk_unref_table, NULL); static int make_partition_table( int fd, @@ -2351,12 +2354,15 @@ static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool disc log_info("Temporary unmounting of file system completed."); /* resize2fs requires that the file system is force checked first, do so. */ - r = safe_fork("(e2fsck)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR, &fsck_pid); + r = safe_fork("(e2fsck)", + FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS, + &fsck_pid); if (r < 0) return r; if (r == 0) { /* Child */ execlp("e2fsck" ,"e2fsck", "-fp", setup->dm_node, NULL); + log_open(); log_error_errno(errno, "Failed to execute e2fsck: %m"); _exit(EXIT_FAILURE); } @@ -2380,12 +2386,15 @@ static int ext4_offline_resize_fs(HomeSetup *setup, uint64_t new_size, bool disc return log_oom(); /* Resize the thing */ - r = safe_fork("(e2resize)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR, &resize_pid); + r = safe_fork("(e2resize)", + FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_DEATHSIG|FORK_LOG|FORK_WAIT|FORK_STDOUT_TO_STDERR|FORK_CLOSE_ALL_FDS, + &resize_pid); if (r < 0) return r; if (r == 0) { /* Child */ execlp("resize2fs" ,"resize2fs", setup->dm_node, size_str, NULL); + log_open(); log_error_errno(errno, "Failed to execute resize2fs: %m"); _exit(EXIT_FAILURE); } @@ -2423,7 +2432,7 @@ static int prepare_resize_partition( _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL; _cleanup_(fdisk_unref_tablep) struct fdisk_table *t = NULL; _cleanup_free_ char *path = NULL, *disk_uuid_as_string = NULL; - size_t n_partitions, i; + size_t n_partitions; sd_id128_t disk_uuid; bool found = false; int r; @@ -2473,7 +2482,7 @@ static int prepare_resize_partition( return log_error_errno(r, "Failed to acquire partition table: %m"); n_partitions = fdisk_table_get_nents(t); - for (i = 0; i < n_partitions; i++) { + for (size_t i = 0; i < n_partitions; i++) { struct fdisk_partition *p; p = fdisk_table_get_partition(t, i); @@ -2898,7 +2907,7 @@ int home_passwd_luks( PasswordCache *cache, /* the passwords acquired via PKCS#11/FIDO2 security tokens */ char **effective_passwords /* new passwords */) { - size_t volume_key_size, i, max_key_slots, n_effective; + size_t volume_key_size, max_key_slots, n_effective; _cleanup_(erase_and_freep) void *volume_key = NULL; struct crypt_pbkdf_type good_pbkdf, minimal_pbkdf; const char *type; @@ -2943,7 +2952,7 @@ int home_passwd_luks( build_good_pbkdf(&good_pbkdf, h); build_minimal_pbkdf(&minimal_pbkdf, h); - for (i = 0; i < max_key_slots; i++) { + for (size_t i = 0; i < max_key_slots; i++) { r = crypt_keyslot_destroy(setup->crypt_device, i); if (r < 0 && !IN_SET(r, -ENOENT, -EINVAL)) /* Returns EINVAL or ENOENT if there's no key in this slot already */ return log_error_errno(r, "Failed to destroy LUKS password: %m"); diff --git a/src/home/homework.c b/src/home/homework.c index b61f65066..bb5a774f8 100644 --- a/src/home/homework.c +++ b/src/home/homework.c @@ -21,9 +21,9 @@ #include "main-func.h" #include "memory-util.h" #include "missing_magic.h" -#include "modhex.h" #include "mount-util.h" #include "path-util.h" +#include "recovery-key.h" #include "rm-rf.h" #include "stat-util.h" #include "strv.h" @@ -1633,7 +1633,7 @@ static int run(int argc, char *argv[]) { start = now(CLOCK_MONOTONIC); - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/home/meson.build b/src/home/meson.build index 444dc4761..53a387fd9 100644 --- a/src/home/meson.build +++ b/src/home/meson.build @@ -1,5 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +home_includes = [includes, include_directories('.')] + systemd_homework_sources = files(''' home-util.c home-util.h @@ -19,8 +21,6 @@ systemd_homework_sources = files(''' homework-quota.h homework.c homework.h - modhex.c - modhex.h user-record-util.c user-record-util.h '''.split()) @@ -52,8 +52,6 @@ systemd_homed_sources = files(''' homed-varlink.c homed-varlink.h homed.c - modhex.c - modhex.h user-record-pwquality.c user-record-pwquality.h user-record-sign.c @@ -80,8 +78,6 @@ homectl_sources = files(''' homectl-recovery-key.c homectl-recovery-key.h homectl.c - modhex.c - modhex.h user-record-pwquality.c user-record-pwquality.h user-record-util.c @@ -92,8 +88,6 @@ pam_systemd_home_sym = 'src/home/pam_systemd_home.sym' pam_systemd_home_c = files(''' home-util.c home-util.h - modhex.c - modhex.h pam_systemd_home.c user-record-util.c user-record-util.h @@ -107,16 +101,8 @@ if conf.get('ENABLE_HOMED') == 1 install_data('org.freedesktop.home1.policy', install_dir : polkitpolicydir) - if install_sysconfdir + if install_sysconfdir_samples install_data('homed.conf', install_dir : pkgsysconfdir) endif endif - -tests += [ - [['src/home/test-modhex.c', - 'src/home/modhex.c', - 'src/home/modhex.h'], - [], - []], -] diff --git a/src/home/pam_systemd_home.c b/src/home/pam_systemd_home.c index a91df9144..64dc53257 100644 --- a/src/home/pam_systemd_home.c +++ b/src/home/pam_systemd_home.c @@ -898,7 +898,7 @@ _public_ PAM_EXTERN int pam_sm_acct_mgmt( return PAM_NEW_AUTHTOK_REQD; case -EOWNERDEAD: - (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password expired, change requird."); + (void) pam_prompt(handle, PAM_ERROR_MSG, NULL, "Password expired, change required."); return PAM_NEW_AUTHTOK_REQD; case -EKEYREJECTED: diff --git a/src/home/user-record-sign.c b/src/home/user-record-sign.c index 8cd3a4625..5ac92255c 100644 --- a/src/home/user-record-sign.c +++ b/src/home/user-record-sign.c @@ -27,7 +27,7 @@ static int user_record_signable_json(UserRecord *ur, char **ret) { return json_variant_format(j, 0, ret); } -DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_MD_CTX*, EVP_MD_CTX_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_MD_CTX*, EVP_MD_CTX_free, NULL); int user_record_sign(UserRecord *ur, EVP_PKEY *private_key, UserRecord **ret) { _cleanup_(json_variant_unrefp) JsonVariant *encoded = NULL, *v = NULL; diff --git a/src/home/user-record-util.c b/src/home/user-record-util.c index 6bcbb56aa..b8f59c55e 100644 --- a/src/home/user-record-util.c +++ b/src/home/user-record-util.c @@ -7,7 +7,7 @@ #include "id128-util.h" #include "libcrypt-util.h" #include "memory-util.h" -#include "modhex.h" +#include "recovery-key.h" #include "mountpoint-util.h" #include "path-util.h" #include "stat-util.h" diff --git a/src/home/user-record-util.h b/src/home/user-record-util.h index 302e7a5df..f7cc4e04e 100644 --- a/src/home/user-record-util.h +++ b/src/home/user-record-util.h @@ -14,7 +14,7 @@ typedef enum UserReconcileMode { USER_RECONCILE_REQUIRE_NEWER, /* host version must be newer than embedded version */ USER_RECONCILE_REQUIRE_NEWER_OR_EQUAL, /* similar, but may also be equal */ _USER_RECONCILE_MODE_MAX, - _USER_RECONCILE_MODE_INVALID = -1, + _USER_RECONCILE_MODE_INVALID = -EINVAL, } UserReconcileMode; enum { /* return values */ diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c index 0d39e9176..e7cb015ef 100644 --- a/src/hostname/hostnamectl.c +++ b/src/hostname/hostnamectl.c @@ -11,8 +11,11 @@ #include "alloc-util.h" #include "architecture.h" +#include "bus-common-errors.h" #include "bus-error.h" #include "bus-map-properties.h" +#include "format-table.h" +#include "hostname-setup.h" #include "hostname-util.h" #include "main-func.h" #include "pretty-print.h" @@ -43,48 +46,113 @@ typedef struct StatusInfo { const char *virtualization; const char *architecture; const char *home_url; + const char *hardware_vendor; + const char *hardware_model; } StatusInfo; -static void print_status_info(StatusInfo *i) { +static int print_status_info(StatusInfo *i) { + _cleanup_(table_unrefp) Table *table = NULL; sd_id128_t mid = {}, bid = {}; + TableCell *cell; int r; assert(i); - printf(" Static hostname: %s\n", strna(i->static_hostname)); + table = table_new("key", "value"); + if (!table) + return log_oom(); + + assert_se(cell = table_get_cell(table, 0, 0)); + (void) table_set_ellipsize_percent(table, cell, 100); + (void) table_set_align_percent(table, cell, 100); + + table_set_header(table, false); + + r = table_set_empty_string(table, "n/a"); + if (r < 0) + return log_oom(); + + r = table_add_many(table, + TABLE_STRING, "Static hostname:", + TABLE_STRING, i->static_hostname); + if (r < 0) + return table_log_add_error(r); if (!isempty(i->pretty_hostname) && - !streq_ptr(i->pretty_hostname, i->static_hostname)) - printf(" Pretty hostname: %s\n", i->pretty_hostname); + !streq_ptr(i->pretty_hostname, i->static_hostname)) { + r = table_add_many(table, + TABLE_STRING, "Pretty hostname:", + TABLE_STRING, i->pretty_hostname); + if (r < 0) + return table_log_add_error(r); + } if (!isempty(i->hostname) && - !streq_ptr(i->hostname, i->static_hostname)) - printf("Transient hostname: %s\n", i->hostname); + !streq_ptr(i->hostname, i->static_hostname)) { + r = table_add_many(table, + TABLE_STRING, "Transient hostname:", + TABLE_STRING, i->hostname); + if (r < 0) + return table_log_add_error(r); + } - if (!isempty(i->icon_name)) - printf(" Icon name: %s\n", - strna(i->icon_name)); + if (!isempty(i->icon_name)) { + r = table_add_many(table, + TABLE_STRING, "Icon name:", + TABLE_STRING, i->icon_name); + if (r < 0) + return table_log_add_error(r); + } - if (!isempty(i->chassis)) - printf(" Chassis: %s\n", - strna(i->chassis)); + if (!isempty(i->chassis)) { + r = table_add_many(table, + TABLE_STRING, "Chassis:", + TABLE_STRING, i->chassis); + if (r < 0) + return table_log_add_error(r); + } - if (!isempty(i->deployment)) - printf(" Deployment: %s\n", i->deployment); + if (!isempty(i->deployment)) { + r = table_add_many(table, + TABLE_STRING, "Deployment:", + TABLE_STRING, i->deployment); + if (r < 0) + return table_log_add_error(r); + } - if (!isempty(i->location)) - printf(" Location: %s\n", i->location); + if (!isempty(i->location)) { + r = table_add_many(table, + TABLE_STRING, "Location:", + TABLE_STRING, i->location); + if (r < 0) + return table_log_add_error(r); + } r = sd_id128_get_machine(&mid); - if (r >= 0) - printf(" Machine ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(mid)); + if (r >= 0) { + r = table_add_many(table, + TABLE_STRING, "Machine ID:", + TABLE_ID128, mid); + if (r < 0) + return table_log_add_error(r); + } r = sd_id128_get_boot(&bid); - if (r >= 0) - printf(" Boot ID: " SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(bid)); + if (r >= 0) { + r = table_add_many(table, + TABLE_STRING, "Boot ID:", + TABLE_ID128, bid); + if (r < 0) + return table_log_add_error(r); + } - if (!isempty(i->virtualization)) - printf(" Virtualization: %s\n", i->virtualization); + if (!isempty(i->virtualization)) { + r = table_add_many(table, + TABLE_STRING, "Virtualization:", + TABLE_STRING, i->virtualization); + if (r < 0) + return table_log_add_error(r); + } if (!isempty(i->os_pretty_name)) { _cleanup_free_ char *formatted = NULL; @@ -95,26 +163,74 @@ static void print_status_info(StatusInfo *i) { t = formatted; } - printf(" Operating System: %s\n", t); + r = table_add_many(table, + TABLE_STRING, "Operating System:", + TABLE_STRING, t); + if (r < 0) + return table_log_add_error(r); } - if (!isempty(i->os_cpe_name)) - printf(" CPE OS Name: %s\n", i->os_cpe_name); + if (!isempty(i->os_cpe_name)) { + r = table_add_many(table, + TABLE_STRING, "CPE OS Name:", + TABLE_STRING, i->os_cpe_name); + if (r < 0) + return table_log_add_error(r); + } - if (!isempty(i->kernel_name) && !isempty(i->kernel_release)) - printf(" Kernel: %s %s\n", i->kernel_name, i->kernel_release); + if (!isempty(i->kernel_name) && !isempty(i->kernel_release)) { + const char *v; - if (!isempty(i->architecture)) - printf(" Architecture: %s\n", i->architecture); + v = strjoina(i->kernel_name, " ", i->kernel_release); + r = table_add_many(table, + TABLE_STRING, "Kernel:", + TABLE_STRING, v); + if (r < 0) + return table_log_add_error(r); + } + if (!isempty(i->architecture)) { + r = table_add_many(table, + TABLE_STRING, "Architecture:", + TABLE_STRING, i->architecture); + if (r < 0) + return table_log_add_error(r); + } + + if (!isempty(i->hardware_vendor)) { + r = table_add_many(table, + TABLE_STRING, "Hardware Vendor:", + TABLE_STRING, i->hardware_vendor); + if (r < 0) + return table_log_add_error(r); + } + + if (!isempty(i->hardware_model)) { + r = table_add_many(table, + TABLE_STRING, "Hardware Model:", + TABLE_STRING, i->hardware_model); + if (r < 0) + return table_log_add_error(r); + } + + r = table_print(table, NULL); + if (r < 0) + return table_log_print_error(r); + + return 0; } -static int show_one_name(sd_bus *bus, const char* attr) { +static int get_one_name(sd_bus *bus, const char* attr, char **ret) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *s; int r; + assert(bus); + assert(attr); + + /* This obtains one string property, and copy it if 'ret' is set, or print it otherwise. */ + r = sd_bus_get_property( bus, "org.freedesktop.hostname1", @@ -129,12 +245,21 @@ static int show_one_name(sd_bus *bus, const char* attr) { if (r < 0) return bus_log_parse_error(r); - printf("%s\n", s); + if (ret) { + char *str; + + str = strdup(s); + if (!str) + return log_oom(); + + *ret = str; + } else + printf("%s\n", s); return 0; } -static int show_all_names(sd_bus *bus, sd_bus_error *error) { +static int show_all_names(sd_bus *bus) { StatusInfo info = {}; static const struct bus_properties_map hostname_map[] = { @@ -150,6 +275,8 @@ static int show_all_names(sd_bus *bus, sd_bus_error *error) { { "OperatingSystemPrettyName", "s", NULL, offsetof(StatusInfo, os_pretty_name) }, { "OperatingSystemCPEName", "s", NULL, offsetof(StatusInfo, os_cpe_name) }, { "HomeURL", "s", NULL, offsetof(StatusInfo, home_url) }, + { "HardwareVendor", "s", NULL, offsetof(StatusInfo, hardware_vendor) }, + { "HardwareModel", "s", NULL, offsetof(StatusInfo, hardware_model) }, {} }; @@ -160,6 +287,7 @@ static int show_all_names(sd_bus *bus, sd_bus_error *error) { }; _cleanup_(sd_bus_message_unrefp) sd_bus_message *host_message = NULL, *manager_message = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; int r; r = bus_map_all_properties(bus, @@ -167,29 +295,28 @@ static int show_all_names(sd_bus *bus, sd_bus_error *error) { "/org/freedesktop/hostname1", hostname_map, 0, - error, + &error, &host_message, &info); if (r < 0) - return r; + return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r)); r = bus_map_all_properties(bus, "org.freedesktop.systemd1", "/org/freedesktop/systemd1", manager_map, 0, - error, + &error, &manager_message, &info); + if (r < 0) + return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r)); - print_status_info(&info); - - return r; + return print_status_info(&info); } static int show_status(int argc, char **argv, void *userdata) { sd_bus *bus = userdata; - int r; if (arg_pretty || arg_static || arg_transient) { const char *attr; @@ -201,61 +328,83 @@ static int show_status(int argc, char **argv, void *userdata) { attr = arg_pretty ? "PrettyHostname" : arg_static ? "StaticHostname" : "Hostname"; - return show_one_name(bus, attr); - } else { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - - r = show_all_names(bus, &error); - if (r < 0) - return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r)); - - return 0; + return get_one_name(bus, attr, NULL); } + + return show_all_names(bus); } -static int set_simple_string(sd_bus *bus, const char *method, const char *value) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - int r = 0; +static int set_simple_string_internal(sd_bus *bus, sd_bus_error *error, const char *target, const char *method, const char *value) { + _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; + int r; polkit_agent_open_if_enabled(arg_transport, arg_ask_password); + if (!error) + error = &e; + r = sd_bus_call_method( bus, "org.freedesktop.hostname1", "/org/freedesktop/hostname1", "org.freedesktop.hostname1", method, - &error, NULL, + error, NULL, "sb", value, arg_ask_password); if (r < 0) - return log_error_errno(r, "Could not set property: %s", bus_error_message(&error, r)); + return log_error_errno(r, "Could not set %s: %s", target, bus_error_message(error, r)); return 0; } +static int set_simple_string(sd_bus *bus, const char *target, const char *method, const char *value) { + return set_simple_string_internal(bus, NULL, target, method, value); +} + static int set_hostname(int argc, char **argv, void *userdata) { _cleanup_free_ char *h = NULL; const char *hostname = argv[1]; sd_bus *bus = userdata; - int r; + bool implicit = false, show_hint = false; + int r, ret = 0; if (!arg_pretty && !arg_static && !arg_transient) - arg_pretty = arg_static = arg_transient = true; + arg_pretty = arg_static = arg_transient = implicit = true; + + if (!implicit && !arg_static && arg_transient) { + _cleanup_free_ char *source = NULL; + + r = get_one_name(bus, "HostnameSource", &source); + if (r < 0) + return r; + + if (hostname_source_from_string(source) == HOSTNAME_STATIC) + log_info("Hint: static hostname is already set, so the specified transient hostname will not be used."); + } if (arg_pretty) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; const char *p; /* If the passed hostname is already valid, then assume the user doesn't know anything about pretty * hostnames, so let's unset the pretty hostname, and just set the passed hostname as static/dynamic * hostname. */ - if (arg_static && hostname_is_valid(hostname, true)) + if (implicit && hostname_is_valid(hostname, VALID_HOSTNAME_TRAILING_DOT)) p = ""; /* No pretty hostname (as it is redundant), just a static one */ else p = hostname; /* Use the passed name as pretty hostname */ - r = set_simple_string(bus, "SetPrettyHostname", p); - if (r < 0) - return r; + r = set_simple_string_internal(bus, &error, "pretty hostname", "SetPrettyHostname", p); + if (r < 0) { + if (implicit && + sd_bus_error_has_names(&error, + BUS_ERROR_FILE_IS_PROTECTED, + BUS_ERROR_READ_ONLY_FILESYSTEM)) { + show_hint = true; + ret = r; + } else + return r; + } /* Now that we set the pretty hostname, let's clean up the parameter and use that as static * hostname. If the hostname was already valid as static hostname, this will only chop off the trailing @@ -271,34 +420,47 @@ static int set_hostname(int argc, char **argv, void *userdata) { } if (arg_static) { - r = set_simple_string(bus, "SetStaticHostname", hostname); - if (r < 0) - return r; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + + r = set_simple_string_internal(bus, &error, "static hostname", "SetStaticHostname", hostname); + if (r < 0) { + if (implicit && + sd_bus_error_has_names(&error, + BUS_ERROR_FILE_IS_PROTECTED, + BUS_ERROR_READ_ONLY_FILESYSTEM)) { + show_hint = true; + ret = r; + } else + return r; + } } if (arg_transient) { - r = set_simple_string(bus, "SetHostname", hostname); + r = set_simple_string(bus, "transient hostname", "SetHostname", hostname); if (r < 0) return r; } - return 0; + if (show_hint) + log_info("Hint: use --transient option when /etc/machine-info or /etc/hostname cannot be modified (e.g. located in read-only filesystem)."); + + return ret; } static int set_icon_name(int argc, char **argv, void *userdata) { - return set_simple_string(userdata, "SetIconName", argv[1]); + return set_simple_string(userdata, "icon", "SetIconName", argv[1]); } static int set_chassis(int argc, char **argv, void *userdata) { - return set_simple_string(userdata, "SetChassis", argv[1]); + return set_simple_string(userdata, "chassis", "SetChassis", argv[1]); } static int set_deployment(int argc, char **argv, void *userdata) { - return set_simple_string(userdata, "SetDeployment", argv[1]); + return set_simple_string(userdata, "deployment", "SetDeployment", argv[1]); } static int set_location(int argc, char **argv, void *userdata) { - return set_simple_string(userdata, "SetLocation", argv[1]); + return set_simple_string(userdata, "location", "SetLocation", argv[1]); } static int help(void) { @@ -327,12 +489,11 @@ static int help(void) { " --transient Only set transient hostname\n" " --static Only set static hostname\n" " --pretty Only set pretty hostname\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -435,7 +596,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index a1794bdab..2ece8b2fb 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "bus-common-errors.h" +#include "bus-get-properties.h" #include "bus-log-control-api.h" #include "bus-polkit.h" #include "def.h" @@ -16,6 +17,7 @@ #include "env-util.h" #include "fileio-label.h" #include "fileio.h" +#include "hostname-setup.h" #include "hostname-util.h" #include "id128-util.h" #include "main-func.h" @@ -25,10 +27,12 @@ #include "os-util.h" #include "parse-util.h" #include "path-util.h" +#include "sd-device.h" #include "selinux-util.h" #include "service-util.h" #include "signal-util.h" #include "stat-util.h" +#include "string-table.h" #include "strv.h" #include "user-util.h" #include "util.h" @@ -47,17 +51,22 @@ enum { PROP_DEPLOYMENT, PROP_LOCATION, + PROP_HARDWARE_VENDOR, + PROP_HARDWARE_MODEL, + /* Read from /etc/os-release (or /usr/lib/os-release) */ PROP_OS_PRETTY_NAME, PROP_OS_CPE_NAME, PROP_OS_HOME_URL, _PROP_MAX, - _PROP_INVALID = -1, + _PROP_INVALID = -EINVAL, }; typedef struct Context { char *data[_PROP_MAX]; + HostnameSource hostname_source; + struct stat etc_hostname_stat; struct stat etc_os_release_stat; struct stat etc_machine_info_stat; @@ -66,11 +75,9 @@ typedef struct Context { } Context; static void context_reset(Context *c, uint64_t mask) { - int p; - assert(c); - for (p = 0; p < _PROP_MAX; p++) { + for (int p = 0; p < _PROP_MAX; p++) { if (!FLAGS_SET(mask, UINT64_C(1) << p)) continue; @@ -152,8 +159,7 @@ static void context_read_os_release(Context *c) { r = parse_os_release(NULL, "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME], "CPE_NAME", &c->data[PROP_OS_CPE_NAME], - "HOME_URL", &c->data[PROP_OS_HOME_URL], - NULL); + "HOME_URL", &c->data[PROP_OS_HOME_URL]); if (r < 0 && r != -ENOENT) log_warning_errno(r, "Failed to read os-release file, ignoring: %m"); @@ -312,68 +318,93 @@ static char* context_fallback_icon_name(Context *c) { return strdup("computer"); } -static bool hostname_is_useful(const char *hn) { - return !isempty(hn) && !is_localhost(hn); -} - static int context_update_kernel_hostname( Context *c, const char *transient_hn) { - const char *static_hn, *hn; - struct utsname u; + _cleanup_free_ char *_hn_free = NULL; + const char *hn; + HostnameSource hns; + int r; assert(c); - if (!transient_hn) { - /* If no transient hostname is passed in, then let's check what is currently set. */ - assert_se(uname(&u) >= 0); - transient_hn = - isempty(u.nodename) || streq(u.nodename, "(none)") ? NULL : u.nodename; - } - - static_hn = c->data[PROP_STATIC_HOSTNAME]; - - /* /etc/hostname with something other than "localhost" - * has the highest preference ... */ - if (hostname_is_useful(static_hn)) - hn = static_hn; + /* /etc/hostname has the highest preference ... */ + if (c->data[PROP_STATIC_HOSTNAME]) { + hn = c->data[PROP_STATIC_HOSTNAME]; + hns = HOSTNAME_STATIC; /* ... the transient hostname, (ie: DHCP) comes next ... */ - else if (!isempty(transient_hn)) + } else if (transient_hn) { hn = transient_hn; - - /* ... fallback to static "localhost.*" ignored above ... */ - else if (!isempty(static_hn)) - hn = static_hn; + hns = HOSTNAME_TRANSIENT; /* ... and the ultimate fallback */ - else - hn = FALLBACK_HOSTNAME; + } else { + hn = _hn_free = get_default_hostname(); + if (!hn) + return log_oom(); - if (sethostname_idempotent(hn) < 0) - return -errno; + hns = HOSTNAME_DEFAULT; + } + + r = sethostname_idempotent(hn); + if (r < 0) + return log_error_errno(r, "Failed to set hostname: %m"); + + if (c->hostname_source != hns) { + c->hostname_source = hns; + r = 1; + } (void) nscd_flush_cache(STRV_MAKE("hosts")); - return 0; + if (r == 0) + log_debug("Hostname was already set to <%s>.", hn); + else { + log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns)); + + hostname_update_source_hint(hn, hns); + } + + return r; /* 0 if no change, 1 if something was done */ +} + +static void unset_statp(struct stat **p) { + if (!*p) + return; + + **p = (struct stat) {}; } static int context_write_data_static_hostname(Context *c) { + _cleanup_(unset_statp) struct stat *s = NULL; + int r; + assert(c); + /* Make sure that if we fail here, we invalidate the cached information, since it was updated + * already, even if we can't make it hit the disk. */ + s = &c->etc_hostname_stat; + if (isempty(c->data[PROP_STATIC_HOSTNAME])) { + if (unlink("/etc/hostname") < 0 && errno != ENOENT) + return -errno; - if (unlink("/etc/hostname") < 0) - return errno == ENOENT ? 0 : -errno; - + TAKE_PTR(s); return 0; } - return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]); + + r = write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]); + if (r < 0) + return r; + + TAKE_PTR(s); + return 0; } static int context_write_data_machine_info(Context *c) { - + _cleanup_(unset_statp) struct stat *s = NULL; static const char * const name[_PROP_MAX] = { [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME", [PROP_ICON_NAME] = "ICON_NAME", @@ -381,46 +412,89 @@ static int context_write_data_machine_info(Context *c) { [PROP_DEPLOYMENT] = "DEPLOYMENT", [PROP_LOCATION] = "LOCATION", }; - _cleanup_strv_free_ char **l = NULL; - int r, p; + int r; assert(c); + /* Make sure that if we fail here, we invalidate the cached information, since it was updated + * already, even if we can't make it hit the disk. */ + s = &c->etc_machine_info_stat; + r = load_env_file(NULL, "/etc/machine-info", &l); if (r < 0 && r != -ENOENT) return r; - for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) { - _cleanup_free_ char *t = NULL; - char **u; - + for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) { assert(name[p]); - if (isempty(c->data[p])) { - strv_env_unset(l, name[p]); - continue; - } - - t = strjoin(name[p], "=", c->data[p]); - if (!t) - return -ENOMEM; - - u = strv_env_set(l, t); - if (!u) - return -ENOMEM; - - strv_free_and_replace(l, u); + r = strv_env_assign(&l, name[p], empty_to_null(c->data[p])); + if (r < 0) + return r; } if (strv_isempty(l)) { - if (unlink("/etc/machine-info") < 0) - return errno == ENOENT ? 0 : -errno; + if (unlink("/etc/machine-info") < 0 && errno != ENOENT) + return -errno; + TAKE_PTR(s); return 0; } - return write_env_file_label("/etc/machine-info", l); + r = write_env_file_label("/etc/machine-info", l); + if (r < 0) + return r; + + TAKE_PTR(s); + return 0; +} + +static int property_get_hardware_vendor( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + const char *hardware_vendor = NULL; + int r; + + r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id"); + if (r < 0) { + log_warning_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m"); + return sd_bus_message_append(reply, "s", NULL); + } + + if (sd_device_get_property_value(device, "ID_VENDOR_FROM_DATABASE", &hardware_vendor) < 0) + (void) sd_device_get_property_value(device, "ID_VENDOR", &hardware_vendor); + + return sd_bus_message_append(reply, "s", hardware_vendor); +} + +static int property_get_hardware_model( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + _cleanup_(sd_device_unrefp) sd_device *device = NULL; + const char *hardware_model = NULL; + int r; + + r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id"); + if (r < 0) { + log_warning_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m"); + return sd_bus_message_append(reply, "s", NULL); + } + + if (sd_device_get_property_value(device, "ID_MODEL_FROM_DATABASE", &hardware_model) < 0) + (void) sd_device_get_property_value(device, "ID_MODEL", &hardware_model); + + return sd_bus_message_append(reply, "s", hardware_model); } static int property_get_hostname( @@ -432,16 +506,20 @@ static int property_get_hostname( void *userdata, sd_bus_error *error) { - _cleanup_free_ char *current = NULL; + _cleanup_free_ char *hn = NULL; int r; - r = gethostname_strict(¤t); - if (r == -ENXIO) - return sd_bus_message_append(reply, "s", FALLBACK_HOSTNAME); - if (r < 0) - return r; + r = gethostname_strict(&hn); + if (r < 0) { + if (r != -ENXIO) + return r; - return sd_bus_message_append(reply, "s", current); + hn = get_default_hostname(); + if (!hn) + return -ENOMEM; + } + + return sd_bus_message_append(reply, "s", hn); } static int property_get_static_hostname( @@ -461,6 +539,66 @@ static int property_get_static_hostname( return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]); } +static int property_get_default_hostname( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + _cleanup_free_ char *hn = get_default_hostname(); + if (!hn) + return log_oom(); + + return sd_bus_message_append(reply, "s", hn); +} + +static int property_get_hostname_source( + sd_bus *bus, + const char *path, + const char *interface, + const char *property, + sd_bus_message *reply, + void *userdata, + sd_bus_error *error) { + + Context *c = userdata; + int r; + assert(c); + + context_read_etc_hostname(c); + + if (c->hostname_source < 0) { + char hostname[HOST_NAME_MAX + 1] = {}; + _cleanup_free_ char *fallback = NULL; + + (void) get_hostname_filtered(hostname); + + if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME])) + c->hostname_source = HOSTNAME_STATIC; + + else { + /* If the hostname was not set by us, try to figure out where it came from. If we set + * it to the default hostname, the file will tell us. We compare the string because + * it is possible that the hostname was set by an older version that had a different + * fallback, in the initramfs or before we reexecuted. */ + + r = read_one_line_file("/run/systemd/default-hostname", &fallback); + if (r < 0 && r != -ENOENT) + log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m"); + + if (streq_ptr(fallback, hostname)) + c->hostname_source = HOSTNAME_DEFAULT; + else + c->hostname_source = HOSTNAME_TRANSIENT; + } + } + + return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source)); +} + static int property_get_machine_info_field( sd_bus *bus, const char *path, @@ -579,7 +717,6 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error * Context *c = userdata; const char *name; int interactive, r; - struct utsname u; assert(m); assert(c); @@ -588,20 +725,15 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error * if (r < 0) return r; - context_read_etc_hostname(c); + name = empty_to_null(name); - if (isempty(name)) - name = c->data[PROP_STATIC_HOSTNAME]; + /* We always go through with the procedure below without comparing to the current hostname, because + * we might want to adjust hostname source information even if the actual hostname is unchanged. */ - if (isempty(name)) - name = FALLBACK_HOSTNAME; - - if (!hostname_is_valid(name, false)) + if (name && !hostname_is_valid(name, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name); - assert_se(uname(&u) >= 0); - if (streq_ptr(name, u.nodename)) - return sd_bus_reply_method_return(m, NULL); + context_read_etc_hostname(c); r = bus_verify_polkit_async( m, @@ -618,14 +750,12 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error * return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ r = context_update_kernel_hostname(c, name); - if (r < 0) { - log_error_errno(r, "Failed to set hostname: %m"); + if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m"); - } - - log_info("Changed hostname to '%s'", name); - - (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL); + else if (r > 0) + (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), + "/org/freedesktop/hostname1", "org.freedesktop.hostname1", + "Hostname", "HostnameSource", NULL); return sd_bus_reply_method_return(m, NULL); } @@ -650,7 +780,7 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_ if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME])) return sd_bus_reply_method_return(m, NULL); - if (!isempty(name) && !hostname_is_valid(name, false)) + if (name && !hostname_is_valid(name, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name); r = bus_verify_polkit_async( @@ -667,25 +797,29 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_ if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = free_and_strdup(&c->data[PROP_STATIC_HOSTNAME], name); + r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name); if (r < 0) return r; + r = context_write_data_static_hostname(c); + if (r < 0) { + log_error_errno(r, "Failed to write static hostname: %m"); + if (ERRNO_IS_PRIVILEGE(r)) + return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname."); + if (r == -EROFS) + return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem."); + return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m"); + } + r = context_update_kernel_hostname(c, NULL); if (r < 0) { log_error_errno(r, "Failed to set hostname: %m"); return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m"); } - r = context_write_data_static_hostname(c); - if (r < 0) { - log_error_errno(r, "Failed to write static hostname: %m"); - return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m"); - } - - log_info("Changed static hostname to '%s'", strna(c->data[PROP_STATIC_HOSTNAME])); - - (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL); + (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), + "/org/freedesktop/hostname1", "org.freedesktop.hostname1", + "StaticHostname", "Hostname", "HostnameSource", NULL); return sd_bus_reply_method_return(m, NULL); } @@ -743,13 +877,17 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ - r = free_and_strdup(&c->data[prop], name); + r = free_and_strdup_warn(&c->data[prop], name); if (r < 0) return r; r = context_write_data_machine_info(c); if (r < 0) { log_error_errno(r, "Failed to write machine info: %m"); + if (ERRNO_IS_PRIVILEGE(r)) + return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info."); + if (r == -EROFS) + return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem."); return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m"); } @@ -850,6 +988,8 @@ static const sd_bus_vtable hostname_vtable[] = { SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), + SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), @@ -860,6 +1000,8 @@ static const sd_bus_vtable hostname_vtable[] = { SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD_WITH_NAMES("SetHostname", "sb", @@ -960,12 +1102,14 @@ static int connect_bus(Context *c, sd_event *event, sd_bus **ret) { } static int run(int argc, char *argv[]) { - _cleanup_(context_destroy) Context context = {}; + _cleanup_(context_destroy) Context context = { + .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */ + }; _cleanup_(sd_event_unrefp) sd_event *event = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-hostnamed.service", "Manage the system hostname and related metadata.", diff --git a/src/hwdb/hwdb.c b/src/hwdb/hwdb.c index 1246d6896..26cc83f31 100644 --- a/src/hwdb/hwdb.c +++ b/src/hwdb/hwdb.c @@ -44,12 +44,11 @@ static int help(void) { " -s --strict When updating, return non-zero exit value on any parsing error\n" " --usr Generate in " UDEVLIBEXECDIR " instead of /etc/udev\n" " -r --root=PATH Alternative root path in the filesystem\n\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } diff --git a/src/id128/id128.c b/src/id128/id128.c index 086f39810..435a56d4f 100644 --- a/src/id128/id128.c +++ b/src/id128/id128.c @@ -167,11 +167,11 @@ static int help(void) { " -p --pretty Generate samples of program code\n" " -a --app-specific=ID Generate app-specific IDs\n" " -u --uuid Output in UUID format\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -249,7 +249,7 @@ static int id128_main(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/import/curl-util.c b/src/import/curl-util.c index 5e0904379..e6db81063 100644 --- a/src/import/curl-util.c +++ b/src/import/curl-util.c @@ -231,7 +231,8 @@ int curl_glue_make(CURL **ret, const char *url, void *userdata) { if (!c) return -ENOMEM; - /* curl_easy_setopt(c, CURLOPT_VERBOSE, 1L); */ + if (DEBUG_LOGGING) + (void) curl_easy_setopt(c, CURLOPT_VERBOSE, 1L); if (curl_easy_setopt(c, CURLOPT_URL, url) != CURLE_OK) return -EIO; diff --git a/src/import/curl-util.h b/src/import/curl-util.h index 4ab52d73a..6b4f992fe 100644 --- a/src/import/curl-util.h +++ b/src/import/curl-util.h @@ -34,6 +34,6 @@ struct curl_slist *curl_slist_new(const char *first, ...) _sentinel_; int curl_header_strdup(const void *contents, size_t sz, const char *field, char **value); int curl_parse_http_time(const char *t, usec_t *ret); -DEFINE_TRIVIAL_CLEANUP_FUNC(CURL*, curl_easy_cleanup); -DEFINE_TRIVIAL_CLEANUP_FUNC(CURLM*, curl_multi_cleanup); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct curl_slist*, curl_slist_free_all); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CURL*, curl_easy_cleanup, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CURLM*, curl_multi_cleanup, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct curl_slist*, curl_slist_free_all, NULL); diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 3e0348f4c..d42c56172 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -95,7 +95,7 @@ int raw_export_new( .input_fd = -1, .on_finished = on_finished, .userdata = userdata, - .last_percent = (unsigned) -1, + .last_percent = UINT_MAX, .progress_ratelimit = { 100 * USEC_PER_MSEC, 1 }, }; diff --git a/src/import/export-tar.c b/src/import/export-tar.c index b8b650f01..b734c3004 100644 --- a/src/import/export-tar.c +++ b/src/import/export-tar.c @@ -97,8 +97,8 @@ int tar_export_new( .tar_fd = -1, .on_finished = on_finished, .userdata = userdata, - .quota_referenced = (uint64_t) -1, - .last_percent = (unsigned) -1, + .quota_referenced = UINT64_MAX, + .last_percent = UINT_MAX, .progress_ratelimit = { 100 * USEC_PER_MSEC, 1 }, }; @@ -120,7 +120,7 @@ static void tar_export_report_progress(TarExport *e) { assert(e); /* Do we have any quota info? If not, we don't know anything about the progress */ - if (e->quota_referenced == (uint64_t) -1) + if (e->quota_referenced == UINT64_MAX) return; if (e->written_uncompressed >= e->quota_referenced) @@ -281,9 +281,9 @@ int tar_export_start(TarExport *e, const char *path, int fd, ImportCompressType if (r < 0) return r; - e->quota_referenced = (uint64_t) -1; + e->quota_referenced = UINT64_MAX; - if (e->st.st_ino == 256) { /* might be a btrfs subvolume? */ + if (btrfs_might_be_subvol(&e->st)) { BtrfsQuotaInfo q; r = btrfs_subvol_get_subtree_quota_fd(sfd, 0, &q); diff --git a/src/import/export.c b/src/import/export.c index 83990df64..a4f3f6c38 100644 --- a/src/import/export.c +++ b/src/import/export.c @@ -7,13 +7,13 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "discover-image.h" #include "export-raw.h" #include "export-tar.h" #include "fd-util.h" #include "fs-util.h" #include "hostname-util.h" #include "import-util.h" -#include "machine-image.h" #include "main-func.h" #include "signal-util.h" #include "string-util.h" @@ -65,8 +65,8 @@ static int export_tar(int argc, char *argv[], void *userdata) { _cleanup_close_ int open_fd = -1; int r, fd; - if (machine_name_is_valid(argv[1])) { - r = image_find(IMAGE_MACHINE, argv[1], &image); + if (hostname_is_valid(argv[1], 0)) { + r = image_find(IMAGE_MACHINE, argv[1], NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Machine image %s not found.", argv[1]); if (r < 0) @@ -141,8 +141,8 @@ static int export_raw(int argc, char *argv[], void *userdata) { _cleanup_close_ int open_fd = -1; int r, fd; - if (machine_name_is_valid(argv[1])) { - r = image_find(IMAGE_MACHINE, argv[1], &image); + if (hostname_is_valid(argv[1], 0)) { + r = image_find(IMAGE_MACHINE, argv[1], NULL, &image); if (r == -ENOENT) return log_error_errno(r, "Machine image %s not found.", argv[1]); if (r < 0) @@ -289,7 +289,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - (void) ignore_signals(SIGPIPE, -1); + (void) ignore_signals(SIGPIPE); return export_main(argc, argv); } diff --git a/src/import/import-common.c b/src/import/import-common.c index 250270511..f77564c41 100644 --- a/src/import/import-common.c +++ b/src/import/import-common.c @@ -8,6 +8,7 @@ #include "alloc-util.h" #include "btrfs-util.h" #include "capability-util.h" +#include "chattr-util.h" #include "dirent-util.h" #include "fd-util.h" #include "fileio.h" @@ -17,10 +18,12 @@ #include "process-util.h" #include "selinux-util.h" #include "signal-util.h" +#include "stat-util.h" #include "tmpfile-util.h" #include "util.h" int import_make_read_only_fd(int fd) { + struct stat st; int r; assert(fd >= 0); @@ -28,26 +31,35 @@ int import_make_read_only_fd(int fd) { /* First, let's make this a read-only subvolume if it refers * to a subvolume */ r = btrfs_subvol_set_read_only_fd(fd, true); - if (IN_SET(r, -ENOTTY, -ENOTDIR, -EINVAL)) { - struct stat st; - - /* This doesn't refer to a subvolume, or the file - * system isn't even btrfs. In that, case fall back to - * chmod()ing */ - - r = fstat(fd, &st); - if (r < 0) - return log_error_errno(errno, "Failed to stat temporary image: %m"); - - /* Drop "w" flag */ - if (fchmod(fd, st.st_mode & 07555) < 0) - return log_error_errno(errno, "Failed to chmod() final image: %m"); - + if (r >= 0) return 0; - } else if (r < 0) + if (!ERRNO_IS_NOT_SUPPORTED(r) && !IN_SET(r, -ENOTDIR, -EINVAL)) return log_error_errno(r, "Failed to make subvolume read-only: %m"); + /* This doesn't refer to a subvolume, or the file system isn't even btrfs. In that, case fall back to + * chmod()ing */ + + r = fstat(fd, &st); + if (r < 0) + return log_error_errno(errno, "Failed to stat image: %m"); + + if (S_ISDIR(st.st_mode)) { + /* For directories set the immutable flag on the dir itself */ + + r = chattr_fd(fd, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to set +i attribute on directory image: %m"); + + } else if (S_ISREG(st.st_mode)) { + /* For regular files drop "w" flags */ + + if ((st.st_mode & 0222) != 0) + if (fchmod(fd, st.st_mode & 07555) < 0) + return log_error_errno(errno, "Failed to chmod() image: %m"); + } else + return log_error_errno(SYNTHETIC_ERRNO(EBADFD), "Image of unexpected type"); + return 0; } @@ -110,11 +122,11 @@ int import_fork_tar_x(const char *path, pid_t *ret) { } if (unshare(CLONE_NEWNET) < 0) - log_error_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); + log_warning_errno(errno, "Failed to lock tar into network namespace, ignoring: %m"); r = capability_bounding_set_drop(retain, true); if (r < 0) - log_error_errno(r, "Failed to drop capabilities, ignoring: %m"); + log_warning_errno(r, "Failed to drop capabilities, ignoring: %m"); /* Try "gtar" before "tar". We only test things upstream with GNU tar. Some distros appear to * install a different implementation as "tar" (in particular some that do not support the @@ -195,10 +207,10 @@ int import_fork_tar_c(const char *path, pid_t *ret) { } int import_mangle_os_tree(const char *path) { + _cleanup_free_ char *child = NULL, *t = NULL, *joined = NULL; _cleanup_closedir_ DIR *d = NULL, *cd = NULL; - _cleanup_free_ char *child = NULL, *t = NULL; - const char *joined; struct dirent *de; + struct stat st; int r; assert(path); @@ -240,14 +252,24 @@ int import_mangle_os_tree(const char *path) { if (errno != 0) return log_error_errno(errno, "Failed to iterate through directory '%s': %m", path); - log_debug("Directory '%s' does not look like a directory tree, and has multiple children, leaving as it is.", path); + log_debug("Directory '%s' does not look like an OS tree, and has multiple children, leaving as it is.", path); return 0; } - joined = prefix_roota(path, child); + if (fstatat(dirfd(d), child, &st, AT_SYMLINK_NOFOLLOW) < 0) + return log_debug_errno(errno, "Failed to stat file '%s/%s': %m", path, child); + r = stat_verify_directory(&st); + if (r < 0) { + log_debug_errno(r, "Child '%s' of directory '%s' is not a directory, leaving things as they are.", child, path); + return 0; + } + + joined = path_join(path, child); + if (!joined) + return log_oom(); r = path_is_os_tree(joined); if (r == -ENOTDIR) { - log_debug("Directory '%s' does not look like a directory tree, and contains a single regular file only, leaving as it is.", path); + log_debug("Directory '%s' does not look like an OS tree, and contains a single regular file only, leaving as it is.", path); return 0; } if (r < 0) @@ -293,6 +315,14 @@ int import_mangle_os_tree(const char *path) { if (unlinkat(dirfd(d), t, AT_REMOVEDIR) < 0) return log_error_errno(errno, "Failed to remove temporary directory '%s/%s': %m", path, t); + r = futimens(dirfd(d), (struct timespec[2]) { st.st_atim, st.st_mtim }); + if (r < 0) + log_debug_errno(r, "Failed to adjust top-level timestamps '%s', ignoring: %m", path); + + r = fchmod_and_chown(dirfd(d), st.st_mode, st.st_uid, st.st_gid); + if (r < 0) + return log_error_errno(r, "Failed to adjust top-level directory mode/ownership '%s': %m", path); + log_info("Successfully rearranged OS tree."); return 0; diff --git a/src/import/import-common.h b/src/import/import-common.h index b27a98083..d7e8fc485 100644 --- a/src/import/import-common.h +++ b/src/import/import-common.h @@ -3,6 +3,13 @@ #include +typedef enum ImportFlags { + IMPORT_FORCE = 1 << 0, /* replace existing image */ + IMPORT_READ_ONLY = 1 << 1, /* make generated image read-only */ + + IMPORT_FLAGS_MASK = IMPORT_FORCE|IMPORT_READ_ONLY, +} ImportFlags; + int import_make_read_only_fd(int fd); int import_make_read_only(const char *path); diff --git a/src/import/import-compress.c b/src/import/import-compress.c index b89ffb1b2..aa837af56 100644 --- a/src/import/import-compress.c +++ b/src/import/import-compress.c @@ -83,6 +83,13 @@ int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) { return 1; } +void import_uncompress_force_off(ImportCompress *c) { + assert(c); + + c->type = IMPORT_COMPRESS_UNCOMPRESSED; + c->encoding = false; +} + int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCompressCallback callback, void *userdata) { int r; @@ -125,9 +132,11 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END)) return -EIO; - r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata); - if (r < 0) - return r; + if (c->xz.avail_out < sizeof(buffer)) { + r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata); + if (r < 0) + return r; + } } break; @@ -146,9 +155,11 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo if (!IN_SET(r, Z_OK, Z_STREAM_END)) return -EIO; - r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata); - if (r < 0) - return r; + if (c->gzip.avail_out < sizeof(buffer)) { + r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata); + if (r < 0) + return r; + } } break; @@ -168,9 +179,11 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo if (!IN_SET(r, BZ_OK, BZ_STREAM_END)) return -EIO; - r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata); - if (r < 0) - return r; + if (c->bzip2.avail_out < sizeof(buffer)) { + r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata); + if (r < 0) + return r; + } } break; diff --git a/src/import/import-compress.h b/src/import/import-compress.h index e40f4dba0..0a4210378 100644 --- a/src/import/import-compress.h +++ b/src/import/import-compress.h @@ -17,7 +17,7 @@ typedef enum ImportCompressType { IMPORT_COMPRESS_GZIP, IMPORT_COMPRESS_BZIP2, _IMPORT_COMPRESS_TYPE_MAX, - _IMPORT_COMPRESS_TYPE_INVALID = -1, + _IMPORT_COMPRESS_TYPE_INVALID = -EINVAL, } ImportCompressType; typedef struct ImportCompress { @@ -37,6 +37,7 @@ typedef int (*ImportCompressCallback)(const void *data, size_t size, void *userd void import_compress_free(ImportCompress *c); int import_uncompress_detect(ImportCompress *c, const void *data, size_t size); +void import_uncompress_force_off(ImportCompress *c); int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCompressCallback callback, void *userdata); int import_compress_init(ImportCompress *c, ImportCompressType t); diff --git a/src/import/import-fs.c b/src/import/import-fs.c index 3b43ea112..a12ee77ef 100644 --- a/src/import/import-fs.c +++ b/src/import/import-fs.c @@ -5,13 +5,13 @@ #include "alloc-util.h" #include "btrfs-util.h" +#include "discover-image.h" #include "fd-util.h" #include "format-util.h" #include "fs-util.h" #include "hostname-util.h" #include "import-common.h" #include "import-util.h" -#include "machine-image.h" #include "mkdir.h" #include "ratelimit.h" #include "rm-rf.h" @@ -126,13 +126,13 @@ static int import_fs(int argc, char *argv[], void *userdata) { local = empty_or_dash_to_null(local); if (local) { - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local image name '%s' is not valid.", local); if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -196,6 +196,7 @@ static int import_fs(int argc, char *argv[], void *userdata) { if (r < 0) goto finish; + (void) import_assign_pool_quota_and_warn(arg_image_root); (void) import_assign_pool_quota_and_warn(temp_path); if (arg_read_only) { diff --git a/src/import/import-raw.c b/src/import/import-raw.c index 9f5c13ba1..0e7757b6f 100644 --- a/src/import/import-raw.c +++ b/src/import/import-raw.c @@ -34,8 +34,7 @@ struct RawImport { void *userdata; char *local; - bool force_local; - bool read_only; + ImportFlags flags; char *temp_path; char *final_path; @@ -65,10 +64,7 @@ RawImport* raw_import_unref(RawImport *i) { sd_event_unref(i->event); - if (i->temp_path) { - (void) unlink(i->temp_path); - free(i->temp_path); - } + unlink_and_free(i->temp_path); import_compress_free(&i->compress); @@ -108,7 +104,7 @@ int raw_import_new( .output_fd = -1, .on_finished = on_finished, .userdata = userdata, - .last_percent = (unsigned) -1, + .last_percent = UINT_MAX, .image_root = TAKE_PTR(root), .progress_ratelimit = { 100 * USEC_PER_MSEC, 1 }, }; @@ -213,13 +209,13 @@ static int raw_import_finish(RawImport *i) { (void) copy_xattr(i->input_fd, i->output_fd); } - if (i->read_only) { + if (i->flags & IMPORT_READ_ONLY) { r = import_make_read_only_fd(i->output_fd); if (r < 0) return r; } - if (i->force_local) + if (i->flags & IMPORT_FORCE) (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path); @@ -317,27 +313,23 @@ static int raw_import_process(RawImport *i) { r = log_error_errno(errno, "Failed to read input file: %m"); goto finish; } - if (l == 0) { - if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) { - log_error("Premature end of file."); - r = -EIO; - goto finish; - } - - r = raw_import_finish(i); - goto finish; - } i->buffer_size += l; if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) { - r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size); - if (r < 0) { - log_error_errno(r, "Failed to detect file compression: %m"); - goto finish; + + if (l == 0) { /* EOF */ + log_debug("File too short to be compressed, as no compression signature fits in, thus assuming uncompressed."); + import_uncompress_force_off(&i->compress); + } else { + r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size); + if (r < 0) { + log_error_errno(r, "Failed to detect file compression: %m"); + goto finish; + } + if (r == 0) /* Need more data */ + return 0; } - if (r == 0) /* Need more data */ - return 0; r = raw_import_open_disk(i); if (r < 0) @@ -346,10 +338,8 @@ static int raw_import_process(RawImport *i) { r = raw_import_try_reflink(i); if (r < 0) goto finish; - if (r > 0) { - r = raw_import_finish(i); - goto finish; - } + if (r > 0) + goto complete; } r = import_uncompress(&i->compress, i->buffer, i->buffer_size, raw_import_write, i); @@ -361,10 +351,16 @@ static int raw_import_process(RawImport *i) { i->written_compressed += i->buffer_size; i->buffer_size = 0; + if (l == 0) /* EOF */ + goto complete; + raw_import_report_progress(i); return 0; +complete: + r = raw_import_finish(i); + finish: if (i->on_finished) i->on_finished(i, r, i->userdata); @@ -386,14 +382,15 @@ static int raw_import_on_defer(sd_event_source *s, void *userdata) { return raw_import_process(i); } -int raw_import_start(RawImport *i, int fd, const char *local, bool force_local, bool read_only) { +int raw_import_start(RawImport *i, int fd, const char *local, ImportFlags flags) { int r; assert(i); assert(fd >= 0); assert(local); + assert(!(flags & ~IMPORT_FLAGS_MASK)); - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return -EINVAL; if (i->input_fd >= 0) @@ -406,8 +403,8 @@ int raw_import_start(RawImport *i, int fd, const char *local, bool force_local, r = free_and_strdup(&i->local, local); if (r < 0) return r; - i->force_local = force_local; - i->read_only = read_only; + + i->flags = flags; if (fstat(fd, &i->st) < 0) return -errno; diff --git a/src/import/import-raw.h b/src/import/import-raw.h index 4612a9ffe..e99703c15 100644 --- a/src/import/import-raw.h +++ b/src/import/import-raw.h @@ -3,6 +3,7 @@ #include "sd-event.h" +#include "import-common.h" #include "import-util.h" #include "macro.h" @@ -15,4 +16,4 @@ RawImport* raw_import_unref(RawImport *import); DEFINE_TRIVIAL_CLEANUP_FUNC(RawImport*, raw_import_unref); -int raw_import_start(RawImport *i, int fd, const char *local, bool force_local, bool read_only); +int raw_import_start(RawImport *i, int fd, const char *local, ImportFlags flags); diff --git a/src/import/import-tar.c b/src/import/import-tar.c index 9f68d45ea..7c4e5127a 100644 --- a/src/import/import-tar.c +++ b/src/import/import-tar.c @@ -36,8 +36,7 @@ struct TarImport { void *userdata; char *local; - bool force_local; - bool read_only; + ImportFlags flags; char *temp_path; char *final_path; @@ -74,10 +73,7 @@ TarImport* tar_import_unref(TarImport *i) { (void) wait_for_terminate(i->tar_pid, NULL); } - if (i->temp_path) { - (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - free(i->temp_path); - } + rm_rf_subvolume_and_free(i->temp_path); import_compress_free(&i->compress); @@ -117,7 +113,7 @@ int tar_import_new( .tar_fd = -1, .on_finished = on_finished, .userdata = userdata, - .last_percent = (unsigned) -1, + .last_percent = UINT_MAX, .image_root = TAKE_PTR(root), .progress_ratelimit = { 100 * USEC_PER_MSEC, 1 }, }; @@ -183,13 +179,13 @@ static int tar_import_finish(TarImport *i) { if (r < 0) return r; - if (i->read_only) { + if (i->flags & IMPORT_READ_ONLY) { r = import_make_read_only(i->temp_path); if (r < 0) return r; } - if (i->force_local) + if (i->flags & IMPORT_FORCE) (void) rm_rf(i->final_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); r = rename_noreplace(AT_FDCWD, i->temp_path, AT_FDCWD, i->final_path); @@ -223,8 +219,10 @@ static int tar_import_fork_tar(TarImport *i) { r = btrfs_subvol_make_fallback(i->temp_path, 0755); if (r < 0) return log_error_errno(r, "Failed to create directory/subvolume %s: %m", i->temp_path); - if (r > 0) /* actually btrfs subvol */ + if (r > 0) { /* actually btrfs subvol */ + (void) import_assign_pool_quota_and_warn(i->image_root); (void) import_assign_pool_quota_and_warn(i->temp_path); + } i->tar_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (i->tar_fd < 0) @@ -261,27 +259,23 @@ static int tar_import_process(TarImport *i) { r = log_error_errno(errno, "Failed to read input file: %m"); goto finish; } - if (l == 0) { - if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) { - log_error("Premature end of file."); - r = -EIO; - goto finish; - } - - r = tar_import_finish(i); - goto finish; - } i->buffer_size += l; if (i->compress.type == IMPORT_COMPRESS_UNKNOWN) { - r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size); - if (r < 0) { - log_error_errno(r, "Failed to detect file compression: %m"); - goto finish; + + if (l == 0) { /* EOF */ + log_debug("File too short to be compressed, as no compression signature fits in, thus assuming uncompressed."); + import_uncompress_force_off(&i->compress); + } else { + r = import_uncompress_detect(&i->compress, i->buffer, i->buffer_size); + if (r < 0) { + log_error_errno(r, "Failed to detect file compression: %m"); + goto finish; + } + if (r == 0) /* Need more data */ + return 0; } - if (r == 0) /* Need more data */ - return 0; r = tar_import_fork_tar(i); if (r < 0) @@ -297,6 +291,11 @@ static int tar_import_process(TarImport *i) { i->written_compressed += i->buffer_size; i->buffer_size = 0; + if (l == 0) { /* EOF */ + r = tar_import_finish(i); + goto finish; + } + tar_import_report_progress(i); return 0; @@ -322,14 +321,15 @@ static int tar_import_on_defer(sd_event_source *s, void *userdata) { return tar_import_process(i); } -int tar_import_start(TarImport *i, int fd, const char *local, bool force_local, bool read_only) { +int tar_import_start(TarImport *i, int fd, const char *local, ImportFlags flags) { int r; assert(i); assert(fd >= 0); assert(local); + assert(!(flags & ~IMPORT_FLAGS_MASK)); - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return -EINVAL; if (i->input_fd >= 0) @@ -342,8 +342,8 @@ int tar_import_start(TarImport *i, int fd, const char *local, bool force_local, r = free_and_strdup(&i->local, local); if (r < 0) return r; - i->force_local = force_local; - i->read_only = read_only; + + i->flags = flags; if (fstat(fd, &i->st) < 0) return -errno; diff --git a/src/import/import-tar.h b/src/import/import-tar.h index afbe98ad0..63b0bd4da 100644 --- a/src/import/import-tar.h +++ b/src/import/import-tar.h @@ -3,6 +3,7 @@ #include "sd-event.h" +#include "import-common.h" #include "import-util.h" #include "macro.h" @@ -15,4 +16,4 @@ TarImport* tar_import_unref(TarImport *import); DEFINE_TRIVIAL_CLEANUP_FUNC(TarImport*, tar_import_unref); -int tar_import_start(TarImport *import, int fd, const char *local, bool force_local, bool read_only); +int tar_import_start(TarImport *import, int fd, const char *local, ImportFlags flags); diff --git a/src/import/import.c b/src/import/import.c index eade0f0ec..fe4c03a4d 100644 --- a/src/import/import.c +++ b/src/import/import.c @@ -7,21 +7,20 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "discover-image.h" #include "fd-util.h" #include "fs-util.h" #include "hostname-util.h" #include "import-raw.h" #include "import-tar.h" #include "import-util.h" -#include "machine-image.h" #include "main-func.h" #include "signal-util.h" #include "string-util.h" #include "verbs.h" -static bool arg_force = false; -static bool arg_read_only = false; static const char *arg_image_root = "/var/lib/machines"; +static ImportFlags arg_import_flags = 0; static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { log_notice("Transfer aborted."); @@ -48,14 +47,12 @@ static int import_tar(int argc, char *argv[], void *userdata) { int r, fd; if (argc >= 2) - path = argv[1]; - path = empty_or_dash_to_null(path); + path = empty_or_dash_to_null(argv[1]); if (argc >= 3) - local = argv[2]; + local = empty_or_dash_to_null(argv[2]); else if (path) local = basename(path); - local = empty_or_dash_to_null(local); if (local) { r = tar_strip_suffixes(local, &ll); @@ -64,21 +61,20 @@ static int import_tar(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local image name '%s' is not valid.", local); - if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) { + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); - } else { + } else return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Image '%s' already exists.", local); - } } } else local = "imported"; @@ -112,7 +108,7 @@ static int import_tar(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to allocate importer: %m"); - r = tar_import_start(import, fd, local, arg_force, arg_read_only); + r = tar_import_start(import, fd, local, arg_import_flags); if (r < 0) return log_error_errno(r, "Failed to import image: %m"); @@ -143,14 +139,12 @@ static int import_raw(int argc, char *argv[], void *userdata) { int r, fd; if (argc >= 2) - path = argv[1]; - path = empty_or_dash_to_null(path); + path = empty_or_dash_to_null(argv[1]); if (argc >= 3) - local = argv[2]; + local = empty_or_dash_to_null(argv[2]); else if (path) local = basename(path); - local = empty_or_dash_to_null(local); if (local) { r = raw_strip_suffixes(local, &ll); @@ -159,21 +153,20 @@ static int import_raw(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local image name '%s' is not valid.", local); - if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + if (!FLAGS_SET(arg_import_flags, IMPORT_FORCE)) { + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); - } else { + } else return log_error_errno(SYNTHETIC_ERRNO(EEXIST), "Image '%s' already exists.", local); - } } } else local = "imported"; @@ -207,7 +200,7 @@ static int import_raw(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to allocate importer: %m"); - r = raw_import_start(import, fd, local, arg_force, arg_read_only); + r = raw_import_start(import, fd, local, arg_import_flags); if (r < 0) return log_error_errno(r, "Failed to import image: %m"); @@ -270,7 +263,7 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_FORCE: - arg_force = true; + arg_import_flags |= IMPORT_FORCE; break; case ARG_IMAGE_ROOT: @@ -278,7 +271,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_READ_ONLY: - arg_read_only = true; + arg_import_flags |= IMPORT_READ_ONLY; break; case '?': @@ -313,7 +306,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return 0; - (void) ignore_signals(SIGPIPE, -1); + (void) ignore_signals(SIGPIPE); return import_main(argc, argv); } diff --git a/src/import/importd.c b/src/import/importd.c index 63f80e0e3..fa8ff68a4 100644 --- a/src/import/importd.c +++ b/src/import/importd.c @@ -11,6 +11,7 @@ #include "bus-log-control-api.h" #include "bus-polkit.h" #include "def.h" +#include "env-util.h" #include "fd-util.h" #include "float.h" #include "hostname-util.h" @@ -21,6 +22,7 @@ #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "process-util.h" #include "service-util.h" #include "signal-util.h" @@ -45,7 +47,7 @@ typedef enum TransferType { TRANSFER_PULL_TAR, TRANSFER_PULL_RAW, _TRANSFER_TYPE_MAX, - _TRANSFER_TYPE_INVALID = -1, + _TRANSFER_TYPE_INVALID = -EINVAL, } TransferType; struct Transfer { @@ -149,10 +151,6 @@ static int transfer_new(Manager *m, Transfer **ret) { if (hashmap_size(m->transfers) >= TRANSFERS_MAX) return -E2BIG; - r = hashmap_ensure_allocated(&m->transfers, &trivial_hash_ops); - if (r < 0) - return r; - t = new(Transfer, 1); if (!t) return -ENOMEM; @@ -163,7 +161,7 @@ static int transfer_new(Manager *m, Transfer **ret) { .stdin_fd = -1, .stdout_fd = -1, .verify = _IMPORT_VERIFY_INVALID, - .progress_percent= (unsigned) -1, + .progress_percent= UINT_MAX, }; id = m->current_transfer_id + 1; @@ -171,7 +169,7 @@ static int transfer_new(Manager *m, Transfer **ret) { if (asprintf(&t->object_path, "/org/freedesktop/import1/transfer/_%" PRIu32, id) < 0) return -ENOMEM; - r = hashmap_put(m->transfers, UINT32_TO_PTR(id), t); + r = hashmap_ensure_put(&m->transfers, &trivial_hash_ops, UINT32_TO_PTR(id), t); if (r < 0) return r; @@ -188,7 +186,7 @@ static int transfer_new(Manager *m, Transfer **ret) { static double transfer_percent_as_double(Transfer *t) { assert(t); - if (t->progress_percent == (unsigned) -1) + if (t->progress_percent == UINT_MAX) return -DBL_MAX; return (double) t->progress_percent / 100.0; @@ -407,6 +405,10 @@ static int transfer_start(Transfer *t) { _exit(EXIT_FAILURE); } + r = setenv_systemd_exec_pid(true); + if (r < 0) + log_warning_errno(r, "Failed to update $SYSTEMD_EXEC_PID, ignoring: %m"); + switch (t->type) { case TRANSFER_IMPORT_TAR: @@ -717,7 +719,7 @@ static int method_import_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (!S_ISREG(st.st_mode) && !S_ISFIFO(st.st_mode)) return -EINVAL; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); @@ -787,7 +789,7 @@ static int method_import_fs(sd_bus_message *msg, void *userdata, sd_bus_error *e if (r < 0) return r; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); @@ -852,7 +854,7 @@ static int method_export_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_ if (r < 0) return r; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); @@ -932,7 +934,7 @@ static int method_pull_tar_or_raw(sd_bus_message *msg, void *userdata, sd_bus_er if (isempty(local)) local = NULL; - else if (!machine_name_is_valid(local)) + else if (!hostname_is_valid(local, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Local name %s is invalid", local); @@ -1365,7 +1367,7 @@ static int run(int argc, char *argv[]) { _cleanup_(manager_unrefp) Manager *m = NULL; int r; - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-importd.service", "VM and container image import and export service.", diff --git a/src/import/meson.build b/src/import/meson.build index 2207b8620..b3bc682b0 100644 --- a/src/import/meson.build +++ b/src/import/meson.build @@ -73,7 +73,7 @@ tests += [ [['src/import/test-qcow2.c', 'src/import/qcow2-util.c', 'src/import/qcow2-util.h'], - [libshared], + [], [libz], - 'HAVE_ZLIB', 'manual'], + [], 'HAVE_ZLIB', 'manual'], ] diff --git a/src/import/pull-common.c b/src/import/pull-common.c index 33be609ae..75c5c7493 100644 --- a/src/import/pull-common.c +++ b/src/import/pull-common.c @@ -110,7 +110,7 @@ int pull_find_old_etags( return 0; } -int pull_make_local_copy(const char *final, const char *image_root, const char *local, bool force_local) { +int pull_make_local_copy(const char *final, const char *image_root, const char *local, PullFlags flags) { const char *p; int r; @@ -122,7 +122,7 @@ int pull_make_local_copy(const char *final, const char *image_root, const char * p = prefix_roota(image_root, local); - if (force_local) + if (FLAGS_SET(flags, PULL_FORCE)) (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); r = btrfs_subvol_snapshot(final, p, @@ -255,7 +255,6 @@ int pull_make_verification_jobs( _cleanup_(pull_job_unrefp) PullJob *checksum_job = NULL, *signature_job = NULL; int r; - const char *chksums = NULL; assert(ret_checksum_job); assert(ret_signature_job); @@ -266,6 +265,7 @@ int pull_make_verification_jobs( if (verify != IMPORT_VERIFY_NO) { _cleanup_free_ char *checksum_url = NULL, *fn = NULL; + const char *chksums = NULL; /* Queue jobs for the checksum file for the image. */ r = import_url_last_component(url, &fn); @@ -302,10 +302,8 @@ int pull_make_verification_jobs( signature_job->uncompressed_max = signature_job->compressed_max = 1ULL * 1024ULL * 1024ULL; } - *ret_checksum_job = checksum_job; - *ret_signature_job = signature_job; - - checksum_job = signature_job = NULL; + *ret_checksum_job = TAKE_PTR(checksum_job); + *ret_signature_job = TAKE_PTR(signature_job); return 0; } @@ -365,70 +363,35 @@ static int verify_one(PullJob *checksum_job, PullJob *job) { return 1; } -int pull_verify(PullJob *main_job, - PullJob *roothash_job, - PullJob *settings_job, - PullJob *checksum_job, - PullJob *signature_job) { +static int verify_gpg( + const void *payload, size_t payload_size, + const void *signature, size_t signature_size) { _cleanup_close_pair_ int gpg_pipe[2] = { -1, -1 }; - _cleanup_close_ int sig_file = -1; char sig_file_path[] = "/tmp/sigXXXXXX", gpg_home[] = "/tmp/gpghomeXXXXXX"; _cleanup_(sigkill_waitp) pid_t pid = 0; bool gpg_home_created = false; int r; - assert(main_job); - assert(main_job->state == PULL_JOB_DONE); - - if (!checksum_job) - return 0; - - assert(main_job->calc_checksum); - assert(main_job->checksum); - - assert(checksum_job->state == PULL_JOB_DONE); - - if (!checksum_job->payload || checksum_job->payload_size <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), - "Checksum is empty, cannot verify."); - - r = verify_one(checksum_job, main_job); - if (r < 0) - return r; - - r = verify_one(checksum_job, roothash_job); - if (r < 0) - return r; - - r = verify_one(checksum_job, settings_job); - if (r < 0) - return r; - - if (!signature_job) - return 0; - - if (checksum_job->style == VERIFICATION_PER_FILE) - signature_job = checksum_job; - - assert(signature_job->state == PULL_JOB_DONE); - - if (!signature_job->payload || signature_job->payload_size <= 0) - return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), - "Signature is empty, cannot verify."); + assert(payload || payload_size == 0); + assert(signature || signature_size == 0); r = pipe2(gpg_pipe, O_CLOEXEC); if (r < 0) return log_error_errno(errno, "Failed to create pipe for gpg: %m"); - sig_file = mkostemp(sig_file_path, O_RDWR); - if (sig_file < 0) - return log_error_errno(errno, "Failed to create temporary file: %m"); + if (signature_size > 0) { + _cleanup_close_ int sig_file = -1; - r = loop_write(sig_file, signature_job->payload, signature_job->payload_size, false); - if (r < 0) { - log_error_errno(r, "Failed to write to temporary file: %m"); - goto finish; + sig_file = mkostemp(sig_file_path, O_RDWR); + if (sig_file < 0) + return log_error_errno(errno, "Failed to create temporary file: %m"); + + r = loop_write(sig_file, signature, signature_size, false); + if (r < 0) { + log_error_errno(r, "Failed to write to temporary file: %m"); + goto finish; + } } if (!mkdtemp(gpg_home)) { @@ -457,7 +420,7 @@ int pull_verify(PullJob *main_job, NULL, /* dash */ NULL /* trailing NULL */ }; - unsigned k = ELEMENTSOF(cmd) - 6; + size_t k = ELEMENTSOF(cmd) - 6; /* Child */ @@ -473,8 +436,7 @@ int pull_verify(PullJob *main_job, cmd[k++] = strjoina("--homedir=", gpg_home); - /* We add the user keyring only to the command line - * arguments, if it's around since gpg fails + /* We add the user keyring only to the command line arguments, if it's around since gpg fails * otherwise. */ if (access(USER_KEYRING_PATH, F_OK) >= 0) cmd[k++] = "--keyring=" USER_KEYRING_PATH; @@ -482,7 +444,7 @@ int pull_verify(PullJob *main_job, cmd[k++] = "--keyring=" VENDOR_KEYRING_PATH; cmd[k++] = "--verify"; - if (checksum_job->style == VERIFICATION_PER_DIRECTORY) { + if (signature) { cmd[k++] = sig_file_path; cmd[k++] = "-"; cmd[k++] = NULL; @@ -496,7 +458,7 @@ int pull_verify(PullJob *main_job, gpg_pipe[0] = safe_close(gpg_pipe[0]); - r = loop_write(gpg_pipe[1], checksum_job->payload, checksum_job->payload_size, false); + r = loop_write(gpg_pipe[1], payload, payload_size, false); if (r < 0) { log_error_errno(r, "Failed to write to pipe: %m"); goto finish; @@ -517,10 +479,117 @@ int pull_verify(PullJob *main_job, } finish: - (void) unlink(sig_file_path); + if (signature_size > 0) + (void) unlink(sig_file_path); if (gpg_home_created) (void) rm_rf(gpg_home, REMOVE_ROOT|REMOVE_PHYSICAL); return r; } + +int pull_verify(ImportVerify verify, + PullJob *main_job, + PullJob *checksum_job, + PullJob *signature_job, + PullJob *settings_job, + PullJob *roothash_job, + PullJob *roothash_signature_job, + PullJob *verity_job) { + + VerificationStyle style; + PullJob *j; + int r; + + assert(main_job); + assert(main_job->state == PULL_JOB_DONE); + + if (verify == IMPORT_VERIFY_NO) + return 0; + + assert(main_job->calc_checksum); + assert(main_job->checksum); + assert(checksum_job); + assert(checksum_job->state == PULL_JOB_DONE); + + if (!checksum_job->payload || checksum_job->payload_size <= 0) + return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), + "Checksum is empty, cannot verify."); + + FOREACH_POINTER(j, main_job, settings_job, roothash_job, roothash_signature_job, verity_job) { + r = verify_one(checksum_job, j); + if (r < 0) + return r; + } + + if (verify == IMPORT_VERIFY_CHECKSUM) + return 0; + + r = verification_style_from_url(checksum_job->url, &style); + if (r < 0) + return log_error_errno(r, "Failed to determine verification style from URL '%s': %m", checksum_job->url); + + if (style == VERIFICATION_PER_DIRECTORY) { + assert(signature_job); + assert(signature_job->state == PULL_JOB_DONE); + + if (!signature_job->payload || signature_job->payload_size <= 0) + return log_error_errno(SYNTHETIC_ERRNO(EBADMSG), + "Signature is empty, cannot verify."); + + return verify_gpg(checksum_job->payload, checksum_job->payload_size, signature_job->payload, signature_job->payload_size); + } else + return verify_gpg(checksum_job->payload, checksum_job->payload_size, NULL, 0); +} + +int verification_style_from_url(const char *url, VerificationStyle *ret) { + _cleanup_free_ char *last = NULL; + int r; + + assert(url); + assert(ret); + + /* Determines which kind of verification style is appropriate for this url */ + + r = import_url_last_component(url, &last); + if (r < 0) + return r; + + if (streq(last, "SHA256SUMS")) { + *ret = VERIFICATION_PER_DIRECTORY; + return 0; + } + + if (endswith(last, ".sha256")) { + *ret = VERIFICATION_PER_FILE; + return 0; + } + + return -EINVAL; +} + +int pull_job_restart_with_sha256sum(PullJob *j, char **ret) { + VerificationStyle style; + int r; + + assert(j); + + /* Generic implementation of a PullJobNotFound handler, that restarts the job requesting SHA256SUMS */ + + r = verification_style_from_url(j->url, &style); + if (r < 0) + return log_error_errno(r, "Failed to determine verification style of URL '%s': %m", j->url); + + if (style == VERIFICATION_PER_DIRECTORY) /* Nothing to do anymore */ + return 0; + + assert(style == VERIFICATION_PER_FILE); /* This must have been .sha256 style URL before */ + + log_debug("Got 404 for %s, now trying to get SHA256SUMS instead.", j->url); + + r = import_url_change_last_component(j->url, "SHA256SUMS", ret); + if (r < 0) + return log_error_errno(r, "Failed to replace SHA256SUMS suffix: %m"); + + return 1; +} diff --git a/src/import/pull-common.h b/src/import/pull-common.h index 025bcee2b..3902e29f2 100644 --- a/src/import/pull-common.h +++ b/src/import/pull-common.h @@ -6,7 +6,19 @@ #include "import-util.h" #include "pull-job.h" -int pull_make_local_copy(const char *final, const char *root, const char *local, bool force_local); +typedef enum PullFlags { + PULL_FORCE = 1 << 0, /* replace existing image */ + PULL_SETTINGS = 1 << 1, /* .nspawn settings file */ + PULL_ROOTHASH = 1 << 2, /* only for raw: .roothash file for verity */ + PULL_ROOTHASH_SIGNATURE = 1 << 3, /* only for raw: .roothash.p7s file for verity */ + PULL_VERITY = 1 << 4, /* only for raw: .verity file for verity */ + + /* The supported flags for the tar and the raw pulling */ + PULL_FLAGS_MASK_TAR = PULL_FORCE|PULL_SETTINGS, + PULL_FLAGS_MASK_RAW = PULL_FORCE|PULL_SETTINGS|PULL_ROOTHASH|PULL_ROOTHASH_SIGNATURE|PULL_VERITY, +} PullFlags; + +int pull_make_local_copy(const char *final, const char *root, const char *local, PullFlags flags); int pull_find_old_etags(const char *url, const char *root, int dt, const char *prefix, const char *suffix, char ***etags); @@ -15,4 +27,15 @@ int pull_make_path(const char *url, const char *etag, const char *image_root, co int pull_make_auxiliary_job(PullJob **ret, const char *url, int (*strip_suffixes)(const char *name, char **ret), const char *suffix, CurlGlue *glue, PullJobFinished on_finished, void *userdata); int pull_make_verification_jobs(PullJob **ret_checksum_job, PullJob **ret_signature_job, ImportVerify verify, const char *url, CurlGlue *glue, PullJobFinished on_finished, void *userdata); -int pull_verify(PullJob *main_job, PullJob *roothash_job, PullJob *settings_job, PullJob *checksum_job, PullJob *signature_job); +int pull_verify(ImportVerify verify, PullJob *main_job, PullJob *checksum_job, PullJob *signature_job, PullJob *settings_job, PullJob *roothash_job, PullJob *roothash_signature_job, PullJob *verity_job); + +typedef enum VerificationStyle { + VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline gpg signature */ + VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detached SHA256SUM.gpg signatures */ + _VERIFICATION_STYLE_MAX, + _VERIFICATION_STYLE_INVALID = -EINVAL, +} VerificationStyle; + +int verification_style_from_url(const char *url, VerificationStyle *style); + +int pull_job_restart_with_sha256sum(PullJob *job, char **ret); diff --git a/src/import/pull-job.c b/src/import/pull-job.c index eea00380a..33512cd77 100644 --- a/src/import/pull-job.c +++ b/src/import/pull-job.c @@ -61,22 +61,41 @@ static void pull_job_finish(PullJob *j, int ret) { j->on_finished(j); } -static int pull_job_restart(PullJob *j) { +static int pull_job_restart(PullJob *j, const char *new_url) { int r; - char *chksum_url = NULL; - r = import_url_change_last_component(j->url, "SHA256SUMS", &chksum_url); + assert(j); + assert(new_url); + + r = free_and_strdup(&j->url, new_url); if (r < 0) return r; - free(j->url); - j->url = chksum_url; j->state = PULL_JOB_INIT; + j->error = 0; j->payload = mfree(j->payload); j->payload_size = 0; j->payload_allocated = 0; j->written_compressed = 0; j->written_uncompressed = 0; + j->content_length = UINT64_MAX; + j->etag = mfree(j->etag); + j->etag_exists = false; + j->mtime = 0; + j->checksum = mfree(j->checksum); + + curl_glue_remove_and_free(j->glue, j->curl); + j->curl = NULL; + + curl_slist_free_all(j->request_header); + j->request_header = NULL; + + import_compress_free(&j->compress); + + if (j->checksum_context) { + gcry_md_close(j->checksum_context); + j->checksum_context = NULL; + } r = pull_job_begin(j); if (r < 0) @@ -114,23 +133,31 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { r = 0; goto finish; } else if (status >= 300) { - if (status == 404 && j->style == VERIFICATION_PER_FILE) { - /* retry pull job with SHA256SUMS file */ - r = pull_job_restart(j); + if (status == 404 && j->on_not_found) { + _cleanup_free_ char *new_url = NULL; + + /* This resource wasn't found, but the implementor wants to maybe let us know a new URL, query for it. */ + r = j->on_not_found(j, &new_url); if (r < 0) goto finish; - code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status); - if (code != CURLE_OK) { - log_error("Failed to retrieve response code: %s", curl_easy_strerror(code)); - r = -EIO; - goto finish; - } + if (r > 0) { /* A new url to use */ + assert(new_url); - if (status == 0) { - j->style = VERIFICATION_PER_DIRECTORY; - return; + r = pull_job_restart(j, new_url); + if (r < 0) + goto finish; + + code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status); + if (code != CURLE_OK) { + log_error("Failed to retrieve response code: %s", curl_easy_strerror(code)); + r = -EIO; + goto finish; + } + + if (status == 0) + return; } } @@ -149,7 +176,7 @@ void pull_job_curl_on_finished(CurlGlue *g, CURL *curl, CURLcode result) { goto finish; } - if (j->content_length != (uint64_t) -1 && + if (j->content_length != UINT64_MAX && j->content_length != j->written_compressed) { log_error("Download truncated."); r = -EIO; @@ -266,7 +293,7 @@ static int pull_job_write_compressed(PullJob *j, void *p, size_t sz) { if (j->written_compressed + sz > j->compressed_max) return log_error_errno(SYNTHETIC_ERRNO(EFBIG), "File overly large, refusing."); - if (j->content_length != (uint64_t) -1 && + if (j->content_length != UINT64_MAX && j->written_compressed + sz > j->content_length) return log_error_errno(SYNTHETIC_ERRNO(EFBIG), "Content length incorrect."); @@ -406,11 +433,22 @@ fail: return 0; } +static int http_status_ok(CURLcode status) { + /* Consider all HTTP status code in the 2xx range as OK */ + return status >= 200 && status <= 299; +} + +static int http_status_etag_exists(CURLcode status) { + /* This one is special, it's triggered by our etag mgmt logic */ + return status == 304; +} + static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb, void *userdata) { - PullJob *j = userdata; + _cleanup_free_ char *length = NULL, *last_modified = NULL, *etag = NULL; size_t sz = size * nmemb; - _cleanup_free_ char *length = NULL, *last_modified = NULL; - char *etag; + PullJob *j = userdata; + CURLcode code; + long status; int r; assert(contents); @@ -423,25 +461,39 @@ static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb assert(j->state == PULL_JOB_ANALYZING); - r = curl_header_strdup(contents, sz, "ETag:", &etag); - if (r < 0) { - log_oom(); + code = curl_easy_getinfo(j->curl, CURLINFO_RESPONSE_CODE, &status); + if (code != CURLE_OK) { + log_error("Failed to retrieve response code: %s", curl_easy_strerror(code)); + r = -EIO; goto fail; } - if (r > 0) { - free(j->etag); - j->etag = etag; - if (strv_contains(j->old_etags, j->etag)) { - log_info("Image already downloaded. Skipping download."); - j->etag_exists = true; - pull_job_finish(j, 0); + if (http_status_ok(status) || http_status_etag_exists(status)) { + /* Check Etag on OK and etag exists responses. */ + + r = curl_header_strdup(contents, sz, "ETag:", &etag); + if (r < 0) { + log_oom(); + goto fail; + } + if (r > 0) { + free_and_replace(j->etag, etag); + + if (strv_contains(j->old_etags, j->etag)) { + log_info("Image already downloaded. Skipping download. (%s)", j->etag); + j->etag_exists = true; + pull_job_finish(j, 0); + return sz; + } + return sz; } - - return sz; } + if (!http_status_ok(status)) /* Let's ignore the rest here, these requests are probably redirects and + * stuff where the headers aren't interesting to us */ + return sz; + r = curl_header_strdup(contents, sz, "Content-Length:", &length); if (r < 0) { log_oom(); @@ -450,7 +502,7 @@ static size_t pull_job_header_callback(void *contents, size_t size, size_t nmemb if (r > 0) { (void) safe_atou64(length, &j->content_length); - if (j->content_length != (uint64_t) -1) { + if (j->content_length != UINT64_MAX) { char bytes[FORMAT_BYTES_MAX]; if (j->content_length > j->compressed_max) { @@ -552,11 +604,10 @@ int pull_job_new(PullJob **ret, const char *url, CurlGlue *glue, void *userdata) .disk_fd = -1, .userdata = userdata, .glue = glue, - .content_length = (uint64_t) -1, + .content_length = UINT64_MAX, .start_usec = now(CLOCK_MONOTONIC), .compressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU, /* 64GB safety limit */ .uncompressed_max = 64LLU * 1024LLU * 1024LLU * 1024LLU, /* 64GB safety limit */ - .style = VERIFICATION_STYLE_UNSET, .url = TAKE_PTR(u), }; diff --git a/src/import/pull-job.h b/src/import/pull-job.h index 719196cae..8e416d51b 100644 --- a/src/import/pull-job.h +++ b/src/import/pull-job.h @@ -13,23 +13,18 @@ typedef void (*PullJobFinished)(PullJob *job); typedef int (*PullJobOpenDisk)(PullJob *job); typedef int (*PullJobHeader)(PullJob *job, const char *header, size_t sz); typedef void (*PullJobProgress)(PullJob *job); +typedef int (*PullJobNotFound)(PullJob *job, char **ret_new_url); typedef enum PullJobState { PULL_JOB_INIT, PULL_JOB_ANALYZING, /* Still reading into ->payload, to figure out what we have */ - PULL_JOB_RUNNING, /* Writing to destination */ + PULL_JOB_RUNNING, /* Writing to destination */ PULL_JOB_DONE, PULL_JOB_FAILED, _PULL_JOB_STATE_MAX, - _PULL_JOB_STATE_INVALID = -1, + _PULL_JOB_STATE_INVALID = -EINVAL, } PullJobState; -typedef enum VerificationStyle { - VERIFICATION_STYLE_UNSET, - VERIFICATION_PER_FILE, /* SuSE-style ".sha256" files with inline signature */ - VERIFICATION_PER_DIRECTORY, /* Ubuntu-style SHA256SUM files with detach SHA256SUM.gpg signatures */ -} VerificationStyle; - #define PULL_JOB_IS_COMPLETE(j) (IN_SET((j)->state, PULL_JOB_DONE, PULL_JOB_FAILED)) struct PullJob { @@ -43,6 +38,7 @@ struct PullJob { PullJobOpenDisk on_open_disk; PullJobHeader on_header; PullJobProgress on_progress; + PullJobNotFound on_not_found; CurlGlue *glue; CURL *curl; @@ -79,8 +75,6 @@ struct PullJob { gcry_md_hd_t checksum_context; char *checksum; - - VerificationStyle style; }; int pull_job_new(PullJob **job, const char *url, CurlGlue *glue, void *userdata); diff --git a/src/import/pull-raw.c b/src/import/pull-raw.c index 7956ef039..9b5d8ef9e 100644 --- a/src/import/pull-raw.c +++ b/src/import/pull-raw.c @@ -42,21 +42,22 @@ struct RawPull { sd_event *event; CurlGlue *glue; + PullFlags flags; + ImportVerify verify; char *image_root; PullJob *raw_job; - PullJob *roothash_job; - PullJob *settings_job; PullJob *checksum_job; PullJob *signature_job; + PullJob *settings_job; + PullJob *roothash_job; + PullJob *roothash_signature_job; + PullJob *verity_job; RawPullFinished on_finished; void *userdata; char *local; - bool force_local; - bool settings; - bool roothash; char *final_path; char *temp_path; @@ -67,7 +68,11 @@ struct RawPull { char *roothash_path; char *roothash_temp_path; - ImportVerify verify; + char *roothash_signature_path; + char *roothash_signature_temp_path; + + char *verity_path; + char *verity_temp_path; }; RawPull* raw_pull_unref(RawPull *i) { @@ -75,34 +80,30 @@ RawPull* raw_pull_unref(RawPull *i) { return NULL; pull_job_unref(i->raw_job); - pull_job_unref(i->settings_job); - pull_job_unref(i->roothash_job); pull_job_unref(i->checksum_job); pull_job_unref(i->signature_job); + pull_job_unref(i->settings_job); + pull_job_unref(i->roothash_job); + pull_job_unref(i->roothash_signature_job); + pull_job_unref(i->verity_job); curl_glue_unref(i->glue); sd_event_unref(i->event); - if (i->temp_path) { - (void) unlink(i->temp_path); - free(i->temp_path); - } - - if (i->roothash_temp_path) { - (void) unlink(i->roothash_temp_path); - free(i->roothash_temp_path); - } - - if (i->settings_temp_path) { - (void) unlink(i->settings_temp_path); - free(i->settings_temp_path); - } + unlink_and_free(i->temp_path); + unlink_and_free(i->settings_temp_path); + unlink_and_free(i->roothash_temp_path); + unlink_and_free(i->roothash_signature_temp_path); + unlink_and_free(i->verity_temp_path); free(i->final_path); - free(i->roothash_path); free(i->settings_path); + free(i->roothash_path); + free(i->roothash_signature_path); + free(i->verity_path); free(i->image_root); free(i->local); + return mfree(i); } @@ -169,6 +170,16 @@ static void raw_pull_report_progress(RawPull *i, RawProgress p) { percent = 0; + if (i->checksum_job) { + percent += i->checksum_job->progress_percent * 5 / 100; + remain -= 5; + } + + if (i->signature_job) { + percent += i->signature_job->progress_percent * 5 / 100; + remain -= 5; + } + if (i->settings_job) { percent += i->settings_job->progress_percent * 5 / 100; remain -= 5; @@ -179,14 +190,14 @@ static void raw_pull_report_progress(RawPull *i, RawProgress p) { remain -= 5; } - if (i->checksum_job) { - percent += i->checksum_job->progress_percent * 5 / 100; + if (i->roothash_signature_job) { + percent += i->roothash_signature_job->progress_percent * 5 / 100; remain -= 5; } - if (i->signature_job) { - percent += i->signature_job->progress_percent * 5 / 100; - remain -= 5; + if (i->verity_job) { + percent += i->verity_job->progress_percent * 10 / 100; + remain -= 10; } if (i->raw_job) @@ -294,7 +305,7 @@ static int raw_pull_copy_auxiliary_file( local = strjoina(i->image_root, "/", i->local, suffix); - r = copy_file_atomic(*path, local, 0644, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0)); + r = copy_file_atomic(*path, local, 0644, 0, 0, COPY_REFLINK | (FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0)); if (r == -EEXIST) log_warning_errno(r, "File %s already exists, not replacing.", local); else if (r == -ENOENT) @@ -338,7 +349,7 @@ static int raw_pull_make_local_copy(RawPull *i) { p = strjoina(i->image_root, "/", i->local, ".raw"); - if (i->force_local) + if (FLAGS_SET(i->flags, PULL_FORCE)) (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); r = tempfn_random(p, NULL, &tp); @@ -353,7 +364,7 @@ static int raw_pull_make_local_copy(RawPull *i) { * since it reduces fragmentation caused by not allowing in-place writes. */ (void) import_set_nocow_and_log(dfd, tp); - r = copy_bytes(i->raw_job->disk_fd, dfd, (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(i->raw_job->disk_fd, dfd, UINT64_MAX, COPY_REFLINK); if (r < 0) { (void) unlink(tp); return log_error_errno(r, "Failed to make writable copy of image: %m"); @@ -373,14 +384,26 @@ static int raw_pull_make_local_copy(RawPull *i) { log_info("Created new local image '%s'.", i->local); - if (i->roothash) { + if (FLAGS_SET(i->flags, PULL_SETTINGS)) { + r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path); + if (r < 0) + return r; + } + + if (FLAGS_SET(i->flags, PULL_ROOTHASH)) { r = raw_pull_copy_auxiliary_file(i, ".roothash", &i->roothash_path); if (r < 0) return r; } - if (i->settings) { - r = raw_pull_copy_auxiliary_file(i, ".nspawn", &i->settings_path); + if (FLAGS_SET(i->flags, PULL_ROOTHASH_SIGNATURE)) { + r = raw_pull_copy_auxiliary_file(i, ".roothash.p7s", &i->roothash_signature_path); + if (r < 0) + return r; + } + + if (FLAGS_SET(i->flags, PULL_VERITY)) { + r = raw_pull_copy_auxiliary_file(i, ".verity", &i->verity_path); if (r < 0) return r; } @@ -394,14 +417,18 @@ static bool raw_pull_is_done(RawPull *i) { if (!PULL_JOB_IS_COMPLETE(i->raw_job)) return false; - if (i->roothash_job && !PULL_JOB_IS_COMPLETE(i->roothash_job)) - return false; - if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job)) - return false; if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job)) return false; if (i->signature_job && !PULL_JOB_IS_COMPLETE(i->signature_job)) return false; + if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job)) + return false; + if (i->roothash_job && !PULL_JOB_IS_COMPLETE(i->roothash_job)) + return false; + if (i->roothash_signature_job && !PULL_JOB_IS_COMPLETE(i->roothash_signature_job)) + return false; + if (i->verity_job && !PULL_JOB_IS_COMPLETE(i->verity_job)) + return false; return true; } @@ -447,12 +474,18 @@ static void raw_pull_job_on_finished(PullJob *j) { assert(j->userdata); i = j->userdata; - if (j == i->roothash_job) { - if (j->error != 0) - log_info_errno(j->error, "Root hash file could not be retrieved, proceeding without."); - } else if (j == i->settings_job) { + if (j == i->settings_job) { if (j->error != 0) log_info_errno(j->error, "Settings file could not be retrieved, proceeding without."); + } else if (j == i->roothash_job) { + if (j->error != 0) + log_info_errno(j->error, "Root hash file could not be retrieved, proceeding without."); + } else if (j == i->roothash_signature_job) { + if (j->error != 0) + log_info_errno(j->error, "Root hash signature file could not be retrieved, proceeding without."); + } else if (j == i->verity_job) { + if (j->error != 0) + log_info_errno(j->error, "Verity integrity file could not be retrieved, proceeding without. %s", j->url); } else if (j->error != 0 && j != i->signature_job) { if (j == i->checksum_job) log_error_errno(j->error, "Failed to retrieve SHA256 checksum, cannot verify. (Try --verify=no?)"); @@ -463,27 +496,41 @@ static void raw_pull_job_on_finished(PullJob *j) { goto finish; } - /* This is invoked if either the download completed - * successfully, or the download was skipped because we - * already have the etag. In this case ->etag_exists is - * true. + /* This is invoked if either the download completed successfully, or the download was skipped because + * we already have the etag. In this case ->etag_exists is true. * * We only do something when we got all three files */ if (!raw_pull_is_done(i)) return; - if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) { - log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + if (i->signature_job && i->signature_job->error != 0) { + VerificationStyle style; - r = i->signature_job->error; - goto finish; + r = verification_style_from_url(i->checksum_job->url, &style); + if (r < 0) { + log_error_errno(r, "Failed to determine verification style from checksum URL: %m"); + goto finish; + } + + if (style == VERIFICATION_PER_DIRECTORY) { /* A failed signature file download only matters + * in per-directory verification mode, since only + * then the signature is detached, and thus a file + * of its own. */ + log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + r = i->signature_job->error; + goto finish; + } } - if (i->roothash_job) - i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd); if (i->settings_job) i->settings_job->disk_fd = safe_close(i->settings_job->disk_fd); + if (i->roothash_job) + i->roothash_job->disk_fd = safe_close(i->roothash_job->disk_fd); + if (i->roothash_signature_job) + i->roothash_signature_job->disk_fd = safe_close(i->roothash_signature_job->disk_fd); + if (i->verity_job) + i->verity_job->disk_fd = safe_close(i->verity_job->disk_fd); r = raw_pull_determine_path(i, ".raw", &i->final_path); if (r < 0) @@ -495,7 +542,14 @@ static void raw_pull_job_on_finished(PullJob *j) { raw_pull_report_progress(i, RAW_VERIFYING); - r = pull_verify(i->raw_job, i->roothash_job, i->settings_job, i->checksum_job, i->signature_job); + r = pull_verify(i->verify, + i->raw_job, + i->checksum_job, + i->signature_job, + i->settings_job, + i->roothash_job, + i->roothash_signature_job, + i->verity_job); if (r < 0) goto finish; @@ -598,6 +652,18 @@ static int raw_pull_job_on_open_disk_raw(PullJob *j) { return 0; } +static int raw_pull_job_on_open_disk_settings(PullJob *j) { + RawPull *i; + + assert(j); + assert(j->userdata); + + i = j->userdata; + assert(i->settings_job == j); + + return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path); +} + static int raw_pull_job_on_open_disk_roothash(PullJob *j) { RawPull *i; @@ -610,16 +676,28 @@ static int raw_pull_job_on_open_disk_roothash(PullJob *j) { return raw_pull_job_on_open_disk_generic(i, j, "roothash", &i->roothash_temp_path); } -static int raw_pull_job_on_open_disk_settings(PullJob *j) { +static int raw_pull_job_on_open_disk_roothash_signature(PullJob *j) { RawPull *i; assert(j); assert(j->userdata); i = j->userdata; - assert(i->settings_job == j); + assert(i->roothash_signature_job == j); - return raw_pull_job_on_open_disk_generic(i, j, "settings", &i->settings_temp_path); + return raw_pull_job_on_open_disk_generic(i, j, "roothash.p7s", &i->roothash_signature_temp_path); +} + +static int raw_pull_job_on_open_disk_verity(PullJob *j) { + RawPull *i; + + assert(j); + assert(j->userdata); + + i = j->userdata; + assert(i->verity_job == j); + + return raw_pull_job_on_open_disk_generic(i, j, "verity", &i->verity_temp_path); } static void raw_pull_job_on_progress(PullJob *j) { @@ -637,21 +715,20 @@ int raw_pull_start( RawPull *i, const char *url, const char *local, - bool force_local, - ImportVerify verify, - bool settings, - bool roothash) { + PullFlags flags, + ImportVerify verify) { int r; assert(i); assert(verify < _IMPORT_VERIFY_MAX); assert(verify >= 0); + assert(!(flags & ~PULL_FLAGS_MASK_RAW)); if (!http_url_is_valid(url)) return -EINVAL; - if (local && !machine_name_is_valid(local)) + if (local && !hostname_is_valid(local, 0)) return -EINVAL; if (i->raw_job) @@ -661,10 +738,8 @@ int raw_pull_start( if (r < 0) return r; - i->force_local = force_local; + i->flags = flags; i->verify = verify; - i->settings = settings; - i->roothash = roothash; /* Queue job for the image itself */ r = pull_job_new(&i->raw_job, url, i->glue, i); @@ -680,17 +755,11 @@ int raw_pull_start( if (r < 0) return r; - if (roothash) { - r = pull_make_auxiliary_job(&i->roothash_job, url, raw_strip_suffixes, ".roothash", i->glue, raw_pull_job_on_finished, i); - if (r < 0) - return r; + r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i); + if (r < 0) + return r; - i->roothash_job->on_open_disk = raw_pull_job_on_open_disk_roothash; - i->roothash_job->on_progress = raw_pull_job_on_progress; - i->roothash_job->calc_checksum = verify != IMPORT_VERIFY_NO; - } - - if (settings) { + if (FLAGS_SET(flags, PULL_SETTINGS)) { r = pull_make_auxiliary_job(&i->settings_job, url, raw_strip_suffixes, ".nspawn", i->glue, raw_pull_job_on_finished, i); if (r < 0) return r; @@ -700,29 +769,43 @@ int raw_pull_start( i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO; } - r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, raw_pull_job_on_finished, i); - if (r < 0) - return r; + if (FLAGS_SET(flags, PULL_ROOTHASH)) { + r = pull_make_auxiliary_job(&i->roothash_job, url, raw_strip_suffixes, ".roothash", i->glue, raw_pull_job_on_finished, i); + if (r < 0) + return r; + + i->roothash_job->on_open_disk = raw_pull_job_on_open_disk_roothash; + i->roothash_job->on_progress = raw_pull_job_on_progress; + i->roothash_job->calc_checksum = verify != IMPORT_VERIFY_NO; + } + + if (FLAGS_SET(flags, PULL_ROOTHASH_SIGNATURE)) { + r = pull_make_auxiliary_job(&i->roothash_signature_job, url, raw_strip_suffixes, ".roothash.p7s", i->glue, raw_pull_job_on_finished, i); + if (r < 0) + return r; + + i->roothash_signature_job->on_open_disk = raw_pull_job_on_open_disk_roothash_signature; + i->roothash_signature_job->on_progress = raw_pull_job_on_progress; + i->roothash_signature_job->calc_checksum = verify != IMPORT_VERIFY_NO; + } + + if (FLAGS_SET(flags, PULL_VERITY)) { + r = pull_make_auxiliary_job(&i->verity_job, url, raw_strip_suffixes, ".verity", i->glue, raw_pull_job_on_finished, i); + if (r < 0) + return r; + + i->verity_job->on_open_disk = raw_pull_job_on_open_disk_verity; + i->verity_job->on_progress = raw_pull_job_on_progress; + i->verity_job->calc_checksum = verify != IMPORT_VERIFY_NO; + } r = pull_job_begin(i->raw_job); if (r < 0) return r; - if (i->roothash_job) { - r = pull_job_begin(i->roothash_job); - if (r < 0) - return r; - } - - if (i->settings_job) { - r = pull_job_begin(i->settings_job); - if (r < 0) - return r; - } - if (i->checksum_job) { i->checksum_job->on_progress = raw_pull_job_on_progress; - i->checksum_job->style = VERIFICATION_PER_FILE; + i->checksum_job->on_not_found = pull_job_restart_with_sha256sum; r = pull_job_begin(i->checksum_job); if (r < 0) @@ -737,5 +820,29 @@ int raw_pull_start( return r; } + if (i->settings_job) { + r = pull_job_begin(i->settings_job); + if (r < 0) + return r; + } + + if (i->roothash_job) { + r = pull_job_begin(i->roothash_job); + if (r < 0) + return r; + } + + if (i->roothash_signature_job) { + r = pull_job_begin(i->roothash_signature_job); + if (r < 0) + return r; + } + + if (i->verity_job) { + r = pull_job_begin(i->verity_job); + if (r < 0) + return r; + } + return 0; } diff --git a/src/import/pull-raw.h b/src/import/pull-raw.h index e1d450d9d..985bda476 100644 --- a/src/import/pull-raw.h +++ b/src/import/pull-raw.h @@ -5,6 +5,7 @@ #include "import-util.h" #include "macro.h" +#include "pull-common.h" typedef struct RawPull RawPull; @@ -15,4 +16,4 @@ RawPull* raw_pull_unref(RawPull *pull); DEFINE_TRIVIAL_CLEANUP_FUNC(RawPull*, raw_pull_unref); -int raw_pull_start(RawPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings, bool roothash); +int raw_pull_start(RawPull *pull, const char *url, const char *local, PullFlags flags, ImportVerify verify); diff --git a/src/import/pull-tar.c b/src/import/pull-tar.c index 31e9a8e7d..a2ba56df2 100644 --- a/src/import/pull-tar.c +++ b/src/import/pull-tar.c @@ -40,19 +40,19 @@ struct TarPull { sd_event *event; CurlGlue *glue; + PullFlags flags; + ImportVerify verify; char *image_root; PullJob *tar_job; - PullJob *settings_job; PullJob *checksum_job; PullJob *signature_job; + PullJob *settings_job; TarPullFinished on_finished; void *userdata; char *local; - bool force_local; - bool settings; pid_t tar_pid; @@ -61,8 +61,6 @@ struct TarPull { char *settings_path; char *settings_temp_path; - - ImportVerify verify; }; TarPull* tar_pull_unref(TarPull *i) { @@ -75,22 +73,15 @@ TarPull* tar_pull_unref(TarPull *i) { } pull_job_unref(i->tar_job); - pull_job_unref(i->settings_job); pull_job_unref(i->checksum_job); pull_job_unref(i->signature_job); + pull_job_unref(i->settings_job); curl_glue_unref(i->glue); sd_event_unref(i->event); - if (i->temp_path) { - (void) rm_rf(i->temp_path, REMOVE_ROOT|REMOVE_PHYSICAL|REMOVE_SUBVOLUME); - free(i->temp_path); - } - - if (i->settings_temp_path) { - (void) unlink(i->settings_temp_path); - free(i->settings_temp_path); - } + rm_rf_subvolume_and_free(i->temp_path); + unlink_and_free(i->settings_temp_path); free(i->final_path); free(i->settings_path); @@ -163,11 +154,6 @@ static void tar_pull_report_progress(TarPull *i, TarProgress p) { percent = 0; - if (i->settings_job) { - percent += i->settings_job->progress_percent * 5 / 100; - remain -= 5; - } - if (i->checksum_job) { percent += i->checksum_job->progress_percent * 5 / 100; remain -= 5; @@ -178,6 +164,11 @@ static void tar_pull_report_progress(TarPull *i, TarProgress p) { remain -= 5; } + if (i->settings_job) { + percent += i->settings_job->progress_percent * 5 / 100; + remain -= 5; + } + if (i->tar_job) percent += i->tar_job->progress_percent * remain / 100; break; @@ -230,11 +221,11 @@ static int tar_pull_make_local_copy(TarPull *i) { if (!i->local) return 0; - r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->force_local); + r = pull_make_local_copy(i->final_path, i->image_root, i->local, i->flags); if (r < 0) return r; - if (i->settings) { + if (FLAGS_SET(i->flags, PULL_SETTINGS)) { const char *local_settings; assert(i->settings_job); @@ -244,7 +235,7 @@ static int tar_pull_make_local_copy(TarPull *i) { local_settings = strjoina(i->image_root, "/", i->local, ".nspawn"); - r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, 0, COPY_REFLINK | (i->force_local ? COPY_REPLACE : 0)); + r = copy_file_atomic(i->settings_path, local_settings, 0664, 0, 0, COPY_REFLINK | (FLAGS_SET(i->flags, PULL_FORCE) ? COPY_REPLACE : 0)); if (r == -EEXIST) log_warning_errno(r, "Settings file %s already exists, not replacing.", local_settings); else if (r == -ENOENT) @@ -264,12 +255,12 @@ static bool tar_pull_is_done(TarPull *i) { if (!PULL_JOB_IS_COMPLETE(i->tar_job)) return false; - if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job)) - return false; if (i->checksum_job && !PULL_JOB_IS_COMPLETE(i->checksum_job)) return false; if (i->signature_job && !PULL_JOB_IS_COMPLETE(i->signature_job)) return false; + if (i->settings_job && !PULL_JOB_IS_COMPLETE(i->settings_job)) + return false; return true; } @@ -302,11 +293,23 @@ static void tar_pull_job_on_finished(PullJob *j) { if (!tar_pull_is_done(i)) return; - if (i->signature_job && i->checksum_job->style == VERIFICATION_PER_DIRECTORY && i->signature_job->error != 0) { - log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + if (i->signature_job && i->signature_job->error != 0) { + VerificationStyle style; - r = i->signature_job->error; - goto finish; + r = verification_style_from_url(i->checksum_job->url, &style); + if (r < 0) { + log_error_errno(r, "Failed to determine verification style from checksum URL: %m"); + goto finish; + } + + if (style == VERIFICATION_PER_DIRECTORY) { /* A failed signature file download only matters + * in per-directory verification mode, since only + * then the signature is detached, and thus a file + * of its own. */ + log_error_errno(j->error, "Failed to retrieve signature file, cannot verify. (Try --verify=no?)"); + r = i->signature_job->error; + goto finish; + } } i->tar_job->disk_fd = safe_close(i->tar_job->disk_fd); @@ -333,7 +336,14 @@ static void tar_pull_job_on_finished(PullJob *j) { tar_pull_report_progress(i, TAR_VERIFYING); - r = pull_verify(i->tar_job, NULL, i->settings_job, i->checksum_job, i->signature_job); + r = pull_verify(i->verify, + i->tar_job, + i->checksum_job, + i->signature_job, + i->settings_job, + /* roothash_job = */ NULL, + /* roothash_signature_job = */ NULL, + /* verity_job = */ NULL); if (r < 0) goto finish; @@ -421,8 +431,10 @@ static int tar_pull_job_on_open_disk_tar(PullJob *j) { r = btrfs_subvol_make_fallback(i->temp_path, 0755); if (r < 0) return log_error_errno(r, "Failed to create directory/subvolume %s: %m", i->temp_path); - if (r > 0) /* actually btrfs subvol */ + if (r > 0) { /* actually btrfs subvol */ + (void) import_assign_pool_quota_and_warn(i->image_root); (void) import_assign_pool_quota_and_warn(i->temp_path); + } j->disk_fd = import_fork_tar_x(i->temp_path, &i->tar_pid); if (j->disk_fd < 0) @@ -471,20 +483,20 @@ int tar_pull_start( TarPull *i, const char *url, const char *local, - bool force_local, - ImportVerify verify, - bool settings) { + PullFlags flags, + ImportVerify verify) { int r; assert(i); assert(verify < _IMPORT_VERIFY_MAX); assert(verify >= 0); + assert(!(flags & ~PULL_FLAGS_MASK_TAR)); if (!http_url_is_valid(url)) return -EINVAL; - if (local && !machine_name_is_valid(local)) + if (local && !hostname_is_valid(local, 0)) return -EINVAL; if (i->tar_job) @@ -494,9 +506,8 @@ int tar_pull_start( if (r < 0) return r; - i->force_local = force_local; + i->flags = flags; i->verify = verify; - i->settings = settings; /* Set up download job for TAR file */ r = pull_job_new(&i->tar_job, url, i->glue, i); @@ -512,8 +523,13 @@ int tar_pull_start( if (r < 0) return r; + /* Set up download of checksum/signature files */ + r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_pull_job_on_finished, i); + if (r < 0) + return r; + /* Set up download job for the settings file (.nspawn) */ - if (settings) { + if (FLAGS_SET(flags, PULL_SETTINGS)) { r = pull_make_auxiliary_job(&i->settings_job, url, tar_strip_suffixes, ".nspawn", i->glue, tar_pull_job_on_finished, i); if (r < 0) return r; @@ -523,24 +539,13 @@ int tar_pull_start( i->settings_job->calc_checksum = verify != IMPORT_VERIFY_NO; } - /* Set up download of checksum/signature files */ - r = pull_make_verification_jobs(&i->checksum_job, &i->signature_job, verify, url, i->glue, tar_pull_job_on_finished, i); - if (r < 0) - return r; - r = pull_job_begin(i->tar_job); if (r < 0) return r; - if (i->settings_job) { - r = pull_job_begin(i->settings_job); - if (r < 0) - return r; - } - if (i->checksum_job) { i->checksum_job->on_progress = tar_pull_job_on_progress; - i->checksum_job->style = VERIFICATION_PER_FILE; + i->checksum_job->on_not_found = pull_job_restart_with_sha256sum; r = pull_job_begin(i->checksum_job); if (r < 0) @@ -555,5 +560,11 @@ int tar_pull_start( return r; } + if (i->settings_job) { + r = pull_job_begin(i->settings_job); + if (r < 0) + return r; + } + return 0; } diff --git a/src/import/pull-tar.h b/src/import/pull-tar.h index 78d982cf5..414077549 100644 --- a/src/import/pull-tar.h +++ b/src/import/pull-tar.h @@ -5,6 +5,7 @@ #include "import-util.h" #include "macro.h" +#include "pull-common.h" typedef struct TarPull TarPull; @@ -15,4 +16,4 @@ TarPull* tar_pull_unref(TarPull *pull); DEFINE_TRIVIAL_CLEANUP_FUNC(TarPull*, tar_pull_unref); -int tar_pull_start(TarPull *pull, const char *url, const char *local, bool force_local, ImportVerify verify, bool settings); +int tar_pull_start(TarPull *pull, const char *url, const char *local, PullFlags flags, ImportVerify verify); diff --git a/src/import/pull.c b/src/import/pull.c index 9aff377b9..d24c71b00 100644 --- a/src/import/pull.c +++ b/src/import/pull.c @@ -7,9 +7,9 @@ #include "sd-id128.h" #include "alloc-util.h" +#include "discover-image.h" #include "hostname-util.h" #include "import-util.h" -#include "machine-image.h" #include "main-func.h" #include "parse-util.h" #include "pull-raw.h" @@ -19,11 +19,9 @@ #include "verbs.h" #include "web-util.h" -static bool arg_force = false; static const char *arg_image_root = "/var/lib/machines"; static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE; -static bool arg_settings = true; -static bool arg_roothash = true; +static PullFlags arg_pull_flags = PULL_SETTINGS | PULL_ROOTHASH | PULL_ROOTHASH_SIGNATURE | PULL_VERITY; static int interrupt_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) { log_notice("Transfer aborted."); @@ -72,13 +70,13 @@ static int pull_tar(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local image name '%s' is not valid.", local); - if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + if (!FLAGS_SET(arg_pull_flags, PULL_FORCE)) { + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -105,7 +103,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to allocate puller: %m"); - r = tar_pull_start(pull, url, local, arg_force, arg_verify, arg_settings); + r = tar_pull_start(pull, url, local, arg_pull_flags & PULL_FLAGS_MASK_TAR, arg_verify); if (r < 0) return log_error_errno(r, "Failed to pull image: %m"); @@ -158,13 +156,13 @@ static int pull_raw(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local image name '%s' is not valid.", local); - if (!arg_force) { - r = image_find(IMAGE_MACHINE, local, NULL); + if (!FLAGS_SET(arg_pull_flags, PULL_FORCE)) { + r = image_find(IMAGE_MACHINE, local, NULL, NULL); if (r < 0) { if (r != -ENOENT) return log_error_errno(r, "Failed to check whether image '%s' exists: %m", local); @@ -191,7 +189,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { if (r < 0) return log_error_errno(r, "Failed to allocate puller: %m"); - r = raw_pull_start(pull, url, local, arg_force, arg_verify, arg_settings, arg_roothash); + r = raw_pull_start(pull, url, local, arg_pull_flags & PULL_FLAGS_MASK_RAW, arg_verify); if (r < 0) return log_error_errno(r, "Failed to pull image: %m"); @@ -214,6 +212,9 @@ static int help(int argc, char *argv[], void *userdata) { " 'checksum', 'signature'\n" " --settings=BOOL Download settings file with image\n" " --roothash=BOOL Download root hash file with image\n" + " --roothash-signature=BOOL\n" + " Download root hash signature file with image\n" + " --verity=BOOL Download verity file with image\n" " --image-root=PATH Image root directory\n\n" "Commands:\n" " tar URL [NAME] Download a TAR image\n" @@ -232,16 +233,20 @@ static int parse_argv(int argc, char *argv[]) { ARG_VERIFY, ARG_SETTINGS, ARG_ROOTHASH, + ARG_ROOTHASH_SIGNATURE, + ARG_VERITY, }; static const struct option options[] = { - { "help", no_argument, NULL, 'h' }, - { "version", no_argument, NULL, ARG_VERSION }, - { "force", no_argument, NULL, ARG_FORCE }, - { "image-root", required_argument, NULL, ARG_IMAGE_ROOT }, - { "verify", required_argument, NULL, ARG_VERIFY }, - { "settings", required_argument, NULL, ARG_SETTINGS }, - { "roothash", required_argument, NULL, ARG_ROOTHASH }, + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "force", no_argument, NULL, ARG_FORCE }, + { "image-root", required_argument, NULL, ARG_IMAGE_ROOT }, + { "verify", required_argument, NULL, ARG_VERIFY }, + { "settings", required_argument, NULL, ARG_SETTINGS }, + { "roothash", required_argument, NULL, ARG_ROOTHASH }, + { "roothash-signature", required_argument, NULL, ARG_ROOTHASH_SIGNATURE }, + { "verity", required_argument, NULL, ARG_VERITY }, {} }; @@ -261,7 +266,7 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_FORCE: - arg_force = true; + arg_pull_flags |= PULL_FORCE; break; case ARG_IMAGE_ROOT: @@ -281,7 +286,7 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to parse --settings= parameter '%s': %m", optarg); - arg_settings = r; + SET_FLAG(arg_pull_flags, PULL_SETTINGS, r); break; case ARG_ROOTHASH: @@ -289,7 +294,27 @@ static int parse_argv(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to parse --roothash= parameter '%s': %m", optarg); - arg_roothash = r; + SET_FLAG(arg_pull_flags, PULL_ROOTHASH, r); + + /* If we were asked to turn off the root hash, implicitly also turn off the root hash signature */ + if (!r) + SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, false); + break; + + case ARG_ROOTHASH_SIGNATURE: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --roothash-signature= parameter '%s': %m", optarg); + + SET_FLAG(arg_pull_flags, PULL_ROOTHASH_SIGNATURE, r); + break; + + case ARG_VERITY: + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --verity= parameter '%s': %m", optarg); + + SET_FLAG(arg_pull_flags, PULL_VERITY, r); break; case '?': @@ -324,7 +349,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - (void) ignore_signals(SIGPIPE, -1); + (void) ignore_signals(SIGPIPE); return pull_main(argc, argv); } diff --git a/src/initctl/initctl.c b/src/initctl/initctl.c index e0b78334f..c48fef16e 100644 --- a/src/initctl/initctl.c +++ b/src/initctl/initctl.c @@ -210,8 +210,9 @@ static int fifo_process(Fifo *f) { return 0; } -static void fifo_free(Fifo *f) { - assert(f); +static Fifo* fifo_free(Fifo *f) { + if (!f) + return NULL; if (f->server) { assert(f->server->n_fifos > 0); @@ -226,7 +227,7 @@ static void fifo_free(Fifo *f) { safe_close(f->fd); } - free(f); + return mfree(f); } DEFINE_TRIVIAL_CLEANUP_FUNC(Fifo*, fifo_free); @@ -317,7 +318,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program does not take arguments."); - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/journal-remote/browse.html b/src/journal-remote/browse.html index 9a5ae803f..4fe2cd84e 100644 --- a/src/journal-remote/browse.html +++ b/src/journal-remote/browse.html @@ -1,4 +1,5 @@ + Journal diff --git a/src/fuzz/fuzz-journal-remote.c b/src/journal-remote/fuzz-journal-remote.c similarity index 50% rename from src/fuzz/fuzz-journal-remote.c rename to src/journal-remote/fuzz-journal-remote.c index 9adbd4374..37eff2f74 100644 --- a/src/fuzz/fuzz-journal-remote.c +++ b/src/journal-remote/fuzz-journal-remote.c @@ -16,14 +16,12 @@ #include "strv.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { - _cleanup_fclose_ FILE *dev_null = NULL; - RemoteServer s = {}; - char name[] = "/tmp/fuzz-journal-remote.XXXXXX.journal"; + int fdin; void *mem; - int fdin; /* will be closed by journal_remote handler after EOF */ + _cleanup_(unlink_tempfilep) char name[] = "/tmp/fuzz-journal-remote.XXXXXX.journal"; _cleanup_close_ int fdout = -1; - sd_journal *j; - OutputMode mode; + _cleanup_(sd_journal_closep) sd_journal *j = NULL; + RemoteServer s = {}; int r; if (size <= 2) @@ -32,36 +30,54 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { if (!getenv("SYSTEMD_LOG_LEVEL")) log_set_max_level(LOG_CRIT); - assert_se((fdin = memfd_new_and_map("fuzz-journal-remote", size, &mem)) >= 0); + fdin = memfd_new_and_map("fuzz-journal-remote", size, &mem); + if (fdin < 0) + return log_error_errno(fdin, "memfd_new_and_map() failed: %m"); + memcpy(mem, data, size); assert_se(munmap(mem, size) == 0); fdout = mkostemps(name, STRLEN(".journal"), O_CLOEXEC); - assert_se(fdout >= 0); + if (fdout < 0) + return log_error_errno(errno, "mkostemps() failed: %m"); /* In */ - assert_se(journal_remote_server_init(&s, name, JOURNAL_WRITE_SPLIT_NONE, false, false) >= 0); - - assert_se(journal_remote_add_source(&s, fdin, (char*) "fuzz-data", false) > 0); - - while (s.active) { - r = journal_remote_handle_raw_source(NULL, fdin, 0, &s); - assert_se(r >= 0); + r = journal_remote_server_init(&s, name, JOURNAL_WRITE_SPLIT_NONE, false, false); + if (r < 0) { + assert_se(IN_SET(r, -ENOMEM, -EMFILE, -ENFILE)); + return r; } + r = journal_remote_add_source(&s, fdin, (char*) "fuzz-data", false); + if (r < 0) { + safe_close(fdin); + return r; + } + assert(r > 0); + + while (s.active) + assert_se(journal_remote_handle_raw_source(NULL, fdin, 0, &s) >= 0); + journal_remote_server_destroy(&s); assert_se(close(fdin) < 0 && errno == EBADF); /* Check that the fd is closed already */ /* Out */ r = sd_journal_open_files(&j, (const char**) STRV_MAKE(name), 0); - assert_se(r >= 0); + if (r < 0) { + assert_se(IN_SET(r, -ENOMEM, -EMFILE, -ENFILE)); + return r; + } - if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) - assert_se(dev_null = fopen("/dev/null", "we")); + _cleanup_fclose_ FILE *dev_null = NULL; + if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) { + dev_null = fopen("/dev/null", "we"); + if (!dev_null) + return log_error_errno(errno, "fopen(\"/dev/null\") failed: %m"); + } - for (mode = 0; mode < _OUTPUT_MODE_MAX; mode++) { + for (OutputMode mode = 0; mode < _OUTPUT_MODE_MAX; mode++) { if (!dev_null) log_info("/* %s */", output_mode_to_string(mode)); r = show_journal(dev_null ?: stdout, j, mode, 0, 0, -1, 0, NULL); @@ -71,8 +87,5 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { assert_se(r >= 0); } - sd_journal_close(j); - unlink(name); - return 0; } diff --git a/src/fuzz/fuzz-journal-remote.options b/src/journal-remote/fuzz-journal-remote.options similarity index 100% rename from src/fuzz/fuzz-journal-remote.options rename to src/journal-remote/fuzz-journal-remote.options diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c index 0723f7d8b..4cefe3918 100644 --- a/src/journal-remote/journal-gatewayd.c +++ b/src/journal-remote/journal-gatewayd.c @@ -22,6 +22,7 @@ #include "log.h" #include "logs-show.h" #include "main-func.h" +#include "memory-util.h" #include "microhttpd-util.h" #include "os-util.h" #include "parse-util.h" @@ -37,7 +38,7 @@ static char *arg_cert_pem = NULL; static char *arg_trust_pem = NULL; static const char *arg_directory = NULL; -STATIC_DESTRUCTOR_REGISTER(arg_key_pem, freep); +STATIC_DESTRUCTOR_REGISTER(arg_key_pem, erase_and_freep); STATIC_DESTRUCTOR_REGISTER(arg_cert_pem, freep); STATIC_DESTRUCTOR_REGISTER(arg_trust_pem, freep); @@ -500,7 +501,9 @@ static int request_handler_entries( if (!response) return respond_oom(connection); - MHD_add_response_header(response, "Content-Type", mime_types[m->mode]); + if (MHD_add_response_header(response, "Content-Type", mime_types[m->mode]) == MHD_NO) + return respond_oom(connection); + return MHD_queue_response(connection, MHD_HTTP_OK, response); } @@ -628,7 +631,9 @@ static int request_handler_fields( if (!response) return respond_oom(connection); - MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]); + if (MHD_add_response_header(response, "Content-Type", mime_types[m->mode == OUTPUT_JSON ? OUTPUT_JSON : OUTPUT_SHORT]) == MHD_NO) + return respond_oom(connection); + return MHD_queue_response(connection, MHD_HTTP_OK, response); } @@ -636,7 +641,7 @@ static int request_handler_redirect( struct MHD_Connection *connection, const char *target) { - char *page; + _cleanup_free_ char *page = NULL; _cleanup_(MHD_destroy_responsep) struct MHD_Response *response = NULL; assert(connection); @@ -646,13 +651,14 @@ static int request_handler_redirect( return respond_oom(connection); response = MHD_create_response_from_buffer(strlen(page), page, MHD_RESPMEM_MUST_FREE); - if (!response) { - free(page); + if (!response) + return respond_oom(connection); + TAKE_PTR(page); + + if (MHD_add_response_header(response, "Content-Type", "text/html") == MHD_NO || + MHD_add_response_header(response, "Location", target) == MHD_NO) return respond_oom(connection); - } - MHD_add_response_header(response, "Content-Type", "text/html"); - MHD_add_response_header(response, "Location", target); return MHD_queue_response(connection, MHD_HTTP_MOVED_PERMANENTLY, response); } @@ -681,7 +687,9 @@ static int request_handler_file( return respond_oom(connection); TAKE_FD(fd); - MHD_add_response_header(response, "Content-Type", mime_type); + if (MHD_add_response_header(response, "Content-Type", mime_type) == MHD_NO) + return respond_oom(connection); + return MHD_queue_response(connection, MHD_HTTP_OK, response); } @@ -754,7 +762,7 @@ static int request_handler_machine( if (r < 0) return mhd_respondf(connection, r, MHD_HTTP_INTERNAL_SERVER_ERROR, "Failed to determine disk usage: %m"); - (void) parse_os_release(NULL, "PRETTY_NAME", &os_name, NULL); + (void) parse_os_release(NULL, "PRETTY_NAME", &os_name); (void) get_virtualization(&v); r = asprintf(&json, @@ -782,7 +790,9 @@ static int request_handler_machine( return respond_oom(connection); TAKE_PTR(json); - MHD_add_response_header(response, "Content-Type", "application/json"); + if (MHD_add_response_header(response, "Content-Type", "application/json") == MHD_NO) + return respond_oom(connection); + return MHD_queue_response(connection, MHD_HTTP_OK, response); } @@ -851,10 +861,9 @@ static int help(void) { " --key=KEY.PEM Server key in PEM format\n" " --trust=CERT.PEM Certificate authority certificate in PEM format\n" " -D --directory=PATH Serve journal files in directory\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -896,7 +905,11 @@ static int parse_argv(int argc, char *argv[]) { if (arg_key_pem) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Key file specified twice"); - r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_key_pem, NULL); + r = read_full_file_full( + AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + NULL, + &arg_key_pem, NULL); if (r < 0) return log_error_errno(r, "Failed to read key file: %m"); assert(arg_key_pem); @@ -906,7 +919,11 @@ static int parse_argv(int argc, char *argv[]) { if (arg_cert_pem) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Certificate file specified twice"); - r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_cert_pem, NULL); + r = read_full_file_full( + AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_CONNECT_SOCKET, + NULL, + &arg_cert_pem, NULL); if (r < 0) return log_error_errno(r, "Failed to read certificate file: %m"); assert(arg_cert_pem); @@ -917,14 +934,18 @@ static int parse_argv(int argc, char *argv[]) { if (arg_trust_pem) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "CA certificate file specified twice"); - r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_CONNECT_SOCKET, NULL, &arg_trust_pem, NULL); + r = read_full_file_full( + AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_CONNECT_SOCKET, + NULL, + &arg_trust_pem, NULL); if (r < 0) return log_error_errno(r, "Failed to read CA certificate file: %m"); assert(arg_trust_pem); break; #else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Option --trust is not available."); + "Option --trust= is not available."); #endif case 'D': arg_directory = optarg; @@ -983,7 +1004,7 @@ static int run(int argc, char *argv[]) { MHD_USE_THREAD_PER_CONNECTION; int r, n; - log_setup_service(); + log_setup(); 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 d2aa1815c..ae1d43756 100644 --- a/src/journal-remote/journal-remote-main.c +++ b/src/journal-remote/journal-remote-main.c @@ -13,6 +13,8 @@ #include "journal-remote-write.h" #include "journal-remote.h" #include "main-func.h" +#include "memory-util.h" +#include "parse-argument.h" #include "pretty-print.h" #include "process-util.h" #include "rlimit-util.h" @@ -33,8 +35,8 @@ static const char* arg_listen_raw = NULL; static const char* arg_listen_http = NULL; static const char* arg_listen_https = NULL; static char** arg_files = NULL; /* Do not free this. */ -static int arg_compress = true; -static int arg_seal = false; +static bool arg_compress = true; +static bool arg_seal = false; static int http_socket = -1, https_socket = -1; static char** arg_gnutls_log = NULL; @@ -469,7 +471,7 @@ static int setup_microhttpd_server(RemoteServer *s, } r = sd_event_add_time(s->events, &d->timer_event, - CLOCK_MONOTONIC, (uint64_t) -1, 0, + CLOCK_MONOTONIC, UINT64_MAX, 0, null_timer_event_handler, d); if (r < 0) { log_error_errno(r, "Failed to add timer_event: %m"); @@ -482,13 +484,11 @@ static int setup_microhttpd_server(RemoteServer *s, goto error; } - r = hashmap_ensure_allocated(&s->daemons, &uint64_hash_ops); - if (r < 0) { + r = hashmap_ensure_put(&s->daemons, &uint64_hash_ops, &d->fd, d); + if (r == -ENOMEM) { log_oom(); goto error; } - - r = hashmap_put(s->daemons, &d->fd, d); if (r < 0) { log_error_errno(r, "Failed to add daemon to hashmap: %m"); goto error; @@ -802,10 +802,9 @@ static int help(void) { " Specify a list of gnutls logging categories\n" " --split-mode=none|host How many output files to create\n" "\nNote: file descriptors from sd_listen_fds() will be consumed, too.\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -963,40 +962,24 @@ static int parse_argv(int argc, char *argv[]) { case ARG_SPLIT_MODE: arg_split_mode = journal_write_split_mode_from_string(optarg); if (arg_split_mode == _JOURNAL_WRITE_SPLIT_INVALID) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid split mode: %s", optarg); + return log_error_errno(arg_split_mode, "Invalid split mode: %s", optarg); break; case ARG_COMPRESS: - if (optarg) { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse --compress= parameter."); - - arg_compress = !!r; - } else - arg_compress = true; - + r = parse_boolean_argument("--compress", optarg, &arg_compress); + if (r < 0) + return r; break; case ARG_SEAL: - if (optarg) { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse --seal= parameter."); - - arg_seal = !!r; - } else - arg_seal = true; - + r = parse_boolean_argument("--seal", optarg, &arg_seal); + if (r < 0) + return r; break; - case ARG_GNUTLS_LOG: { + case ARG_GNUTLS_LOG: #if HAVE_GNUTLS - const char* p = optarg; - for (;;) { + for (const char* p = optarg;;) { _cleanup_free_ char *word = NULL; r = extract_first_word(&p, &word, ",", 0); @@ -1015,7 +998,6 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Option --gnutls-log is not available."); #endif - } case '?': return -EINVAL; @@ -1077,12 +1059,20 @@ static int parse_argv(int argc, char *argv[]) { static int load_certificates(char **key, char **cert, char **trust) { int r; - r = read_full_file_full(AT_FDCWD, arg_key ?: PRIV_KEY_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, key, NULL); + r = read_full_file_full( + AT_FDCWD, arg_key ?: PRIV_KEY_FILE, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + NULL, + key, NULL); if (r < 0) return log_error_errno(r, "Failed to read key from file '%s': %m", arg_key ?: PRIV_KEY_FILE); - r = read_full_file_full(AT_FDCWD, arg_cert ?: CERT_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, cert, NULL); + r = read_full_file_full( + AT_FDCWD, arg_cert ?: CERT_FILE, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_CONNECT_SOCKET, + NULL, + cert, NULL); if (r < 0) return log_error_errno(r, "Failed to read certificate from file '%s': %m", arg_cert ?: CERT_FILE); @@ -1090,7 +1080,11 @@ static int load_certificates(char **key, char **cert, char **trust) { if (arg_trust_all) log_info("Certificate checking disabled."); else { - r = read_full_file_full(AT_FDCWD, arg_trust ?: TRUST_FILE, READ_FULL_FILE_CONNECT_SOCKET, NULL, trust, NULL); + r = read_full_file_full( + AT_FDCWD, arg_trust ?: TRUST_FILE, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_CONNECT_SOCKET, + NULL, + trust, NULL); if (r < 0) return log_error_errno(r, "Failed to read CA certificate file '%s': %m", arg_trust ?: TRUST_FILE); @@ -1106,11 +1100,12 @@ static int load_certificates(char **key, char **cert, char **trust) { static int run(int argc, char **argv) { _cleanup_(journal_remote_server_destroy) RemoteServer s = {}; _cleanup_(notify_on_cleanup) const char *notify_message = NULL; - _cleanup_free_ char *key = NULL, *cert = NULL, *trust = NULL; + _cleanup_(erase_and_freep) char *key = NULL; + _cleanup_free_ char *cert = NULL, *trust = NULL; int r; log_show_color(true); - log_parse_environment_cli(); + log_parse_environment(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/journal-remote/journal-remote-write.c b/src/journal-remote/journal-remote-write.c index 764a3ec70..ea7162318 100644 --- a/src/journal-remote/journal-remote-write.c +++ b/src/journal-remote/journal-remote-write.c @@ -4,7 +4,7 @@ #include "journal-remote.h" static int do_rotate(JournalFile **f, bool compress, bool seal) { - int r = journal_file_rotate(f, compress, (uint64_t) -1, seal, NULL); + int r = journal_file_rotate(f, compress, UINT64_MAX, seal, NULL); if (r < 0) { if (*f) log_error_errno(r, "Failed to rotate %s: %m", (*f)->path); diff --git a/src/journal-remote/journal-remote-write.h b/src/journal-remote/journal-remote-write.h index 46b55219d..123015b84 100644 --- a/src/journal-remote/journal-remote-write.h +++ b/src/journal-remote/journal-remote-write.h @@ -36,5 +36,5 @@ typedef enum JournalWriteSplitMode { JOURNAL_WRITE_SPLIT_NONE, JOURNAL_WRITE_SPLIT_HOST, _JOURNAL_WRITE_SPLIT_MAX, - _JOURNAL_WRITE_SPLIT_INVALID = -1 + _JOURNAL_WRITE_SPLIT_INVALID = -EINVAL, } JournalWriteSplitMode; diff --git a/src/journal-remote/journal-remote.c b/src/journal-remote/journal-remote.c index 0cee84445..6f71248aa 100644 --- a/src/journal-remote/journal-remote.c +++ b/src/journal-remote/journal-remote.c @@ -62,7 +62,7 @@ static int open_output(RemoteServer *s, Writer *w, const char* host) { r = journal_file_open_reliably(filename, O_RDWR|O_CREAT, 0640, - s->compress, (uint64_t) -1, s->seal, + s->compress, UINT64_MAX, s->seal, &w->metrics, w->mmap, NULL, NULL, &w->journal); diff --git a/src/journal-remote/journal-remote.conf.in b/src/journal-remote/journal-remote.conf.in index edc3abab4..1e4c3b971 100644 --- a/src/journal-remote/journal-remote.conf.in +++ b/src/journal-remote/journal-remote.conf.in @@ -1,15 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See journal-remote.conf(5) for details +# See journal-remote.conf(5) for details. [Remote] # Seal=false diff --git a/src/journal-remote/journal-upload-journal.c b/src/journal-remote/journal-upload-journal.c index 3296c2268..f23d5cf8b 100644 --- a/src/journal-remote/journal-upload-journal.c +++ b/src/journal-remote/journal-upload-journal.c @@ -399,7 +399,7 @@ int open_journal_for_upload(Uploader *u, return log_error_errno(r, "Failed to register input event: %m"); log_debug("Listening for journal events on fd:%d, timeout %d", - fd, u->timeout == (uint64_t) -1 ? -1 : (int) u->timeout); + fd, u->timeout == UINT64_MAX ? -1 : (int) u->timeout); } else log_debug("Not listening for journal events."); diff --git a/src/journal-remote/journal-upload.c b/src/journal-remote/journal-upload.c index bf362d091..a8f1f7e51 100644 --- a/src/journal-remote/journal-upload.c +++ b/src/journal-remote/journal-upload.c @@ -22,6 +22,7 @@ #include "log.h" #include "main-func.h" #include "mkdir.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -70,6 +71,9 @@ static void close_fd_input(Uploader *u); } \ } while (0) +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CURL*, curl_easy_cleanup, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct curl_slist*, curl_slist_free_all, NULL); + static size_t output_callback(char *buf, size_t size, size_t nmemb, @@ -179,29 +183,28 @@ int start_upload(Uploader *u, assert(input_callback); if (!u->header) { - struct curl_slist *h; + _cleanup_(curl_slist_free_allp) struct curl_slist *h = NULL; + struct curl_slist *l; h = curl_slist_append(NULL, "Content-Type: application/vnd.fdo.journal"); if (!h) return log_oom(); - h = curl_slist_append(h, "Transfer-Encoding: chunked"); - if (!h) { - curl_slist_free_all(h); + l = curl_slist_append(h, "Transfer-Encoding: chunked"); + if (!l) return log_oom(); - } + h = l; - h = curl_slist_append(h, "Accept: text/plain"); - if (!h) { - curl_slist_free_all(h); + l = curl_slist_append(h, "Accept: text/plain"); + if (!l) return log_oom(); - } + h = l; - u->header = h; + u->header = TAKE_PTR(h); } if (!u->easy) { - CURL *curl; + _cleanup_(curl_easy_cleanupp) CURL *curl = NULL; curl = curl_easy_init(); if (!curl) @@ -259,7 +262,7 @@ int start_upload(Uploader *u, easy_setopt(curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1, LOG_WARNING, ); - u->easy = curl; + u->easy = TAKE_PTR(curl); } else { /* truncate the potential old error message */ u->error[0] = '\0'; @@ -356,7 +359,7 @@ static int open_file_for_upload(Uploader *u, const char *filename) { u->input = fd; - if (arg_follow) { + if (arg_follow != 0) { r = sd_event_add_io(u->events, &u->input_event, fd, EPOLLIN, dispatch_fd_input, u); if (r < 0) { @@ -413,7 +416,7 @@ static int setup_uploader(Uploader *u, const char *url, const char *state_file) assert(url); *u = (Uploader) { - .input = -1 + .input = -1, }; host = STARTSWITH_SET(url, "http://", "https://"); @@ -606,10 +609,9 @@ static int help(void) { " --follow[=BOOL] Do [not] wait for input\n" " --save-state[=FILE] Save uploaded cursors (default \n" " " STATE_FILE ")\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -748,16 +750,10 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_FOLLOW: - if (optarg) { - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse --follow= parameter."); - - arg_follow = !!r; - } else - arg_follow = true; - + r = parse_boolean_argument("--follow", optarg, NULL); + if (r < 0) + return r; + arg_follow = r; break; case ARG_SAVE_STATE: @@ -821,7 +817,7 @@ static int run(int argc, char **argv) { int r; log_show_color(true); - log_parse_environment_cli(); + log_parse_environment(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); @@ -858,7 +854,7 @@ static int run(int argc, char **argv) { r = open_journal_for_upload(&u, j, arg_cursor ?: u.last_cursor, arg_cursor ? arg_after_cursor : true, - !!arg_follow); + arg_follow != 0); if (r < 0) return r; } diff --git a/src/journal-remote/journal-upload.conf.in b/src/journal-remote/journal-upload.conf.in index 5f59a6fe8..7d2bdc750 100644 --- a/src/journal-remote/journal-upload.conf.in +++ b/src/journal-remote/journal-upload.conf.in @@ -1,15 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See journal-upload.conf(5) for details +# See journal-upload.conf(5) for details. [Upload] # URL= diff --git a/src/journal-remote/log-generator.py b/src/journal-remote/log-generator.py index e1725b1a7..6e42d8a8b 100755 --- a/src/journal-remote/log-generator.py +++ b/src/journal-remote/log-generator.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + import sys import argparse diff --git a/src/journal-remote/meson.build b/src/journal-remote/meson.build index 4572f4bd1..c42d85bc4 100644 --- a/src/journal-remote/meson.build +++ b/src/journal-remote/meson.build @@ -16,16 +16,15 @@ libsystemd_journal_remote_sources = files(''' '''.split()) if conf.get('HAVE_MICROHTTPD') == 1 - libsystemd_journal_remote_sources += files(''' - microhttpd-util.h - microhttpd-util.c -'''.split()) + libsystemd_journal_remote_sources += files( + 'microhttpd-util.h', + 'microhttpd-util.c') endif libsystemd_journal_remote = static_library( 'systemd-journal-remote', libsystemd_journal_remote_sources, - include_directories : includes, + include_directories : journal_includes, dependencies : [threads, libmicrohttpd, libgnutls, @@ -59,7 +58,7 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1 input : 'journal-remote.conf.in', output : 'journal-remote.conf', configuration : substs) - if install_sysconfdir + if install_sysconfdir_samples install_data(journal_remote_conf, install_dir : pkgsysconfdir) endif @@ -75,3 +74,11 @@ if conf.get('ENABLE_REMOTE') == 1 and conf.get('HAVE_MICROHTTPD') == 1 chmod 755 $DESTDIR/var/log/journal/remote || :''') endif endif + +############################################################ + +fuzzers += [ + [['src/journal-remote/fuzz-journal-remote.c'], + [libsystemd_journal_remote, + libshared]], +] diff --git a/src/journal-remote/microhttpd-util.c b/src/journal-remote/microhttpd-util.c index d3fb0b8b1..e6a825449 100644 --- a/src/journal-remote/microhttpd-util.c +++ b/src/journal-remote/microhttpd-util.c @@ -39,7 +39,8 @@ static int mhd_respond_internal(struct MHD_Connection *connection, return MHD_NO; log_debug("Queueing response %u: %s", code, buffer); - MHD_add_response_header(response, "Content-Type", "text/plain"); + if (MHD_add_response_header(response, "Content-Type", "text/plain") == MHD_NO) + return MHD_NO; return MHD_queue_response(connection, code, response); } diff --git a/src/journal-remote/microhttpd-util.h b/src/journal-remote/microhttpd-util.h index 7f90a09c7..a92ba57d0 100644 --- a/src/journal-remote/microhttpd-util.h +++ b/src/journal-remote/microhttpd-util.h @@ -80,5 +80,5 @@ int check_permissions(struct MHD_Connection *connection, int *code, char **hostn */ int setup_gnutls_logger(char **categories); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Daemon*, MHD_stop_daemon); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct MHD_Response*, MHD_destroy_response); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct MHD_Daemon*, MHD_stop_daemon, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct MHD_Response*, MHD_destroy_response, NULL); diff --git a/src/journal/cat.c b/src/journal/cat.c index bccf61518..4ccc5e0a3 100644 --- a/src/journal/cat.c +++ b/src/journal/cat.c @@ -12,6 +12,7 @@ #include "alloc-util.h" #include "fd-util.h" #include "main-func.h" +#include "parse-argument.h" #include "parse-util.h" #include "pretty-print.h" #include "string-util.h" @@ -40,11 +41,11 @@ static int help(void) { " -p --priority=PRIORITY Set priority value (0..7)\n" " --stderr-priority=PRIORITY Set priority value (0..7) used for stderr\n" " --level-prefix=BOOL Control whether level prefix shall be parsed\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -67,7 +68,7 @@ static int parse_argv(int argc, char *argv[]) { {} }; - int c; + int c, r; assert(argc >= 0); assert(argv); @@ -104,16 +105,11 @@ static int parse_argv(int argc, char *argv[]) { "Failed to parse stderr priority value."); break; - case ARG_LEVEL_PREFIX: { - int k; - - k = parse_boolean(optarg); - if (k < 0) - return log_error_errno(k, "Failed to parse level prefix value."); - - arg_level_prefix = k; + case ARG_LEVEL_PREFIX: + r = parse_boolean_argument("--level-prefix=", optarg, &arg_level_prefix); + if (r < 0) + return r; break; - } case '?': return -EINVAL; @@ -129,7 +125,7 @@ static int run(int argc, char *argv[]) { _cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1; int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/fuzz/fuzz-journald-audit.c b/src/journal/fuzz-journald-audit.c similarity index 100% rename from src/fuzz/fuzz-journald-audit.c rename to src/journal/fuzz-journald-audit.c diff --git a/src/fuzz/fuzz-journald-kmsg.c b/src/journal/fuzz-journald-kmsg.c similarity index 100% rename from src/fuzz/fuzz-journald-kmsg.c rename to src/journal/fuzz-journald-kmsg.c diff --git a/src/fuzz/fuzz-journald-native-fd.c b/src/journal/fuzz-journald-native-fd.c similarity index 100% rename from src/fuzz/fuzz-journald-native-fd.c rename to src/journal/fuzz-journald-native-fd.c diff --git a/src/fuzz/fuzz-journald-native.c b/src/journal/fuzz-journald-native.c similarity index 100% rename from src/fuzz/fuzz-journald-native.c rename to src/journal/fuzz-journald-native.c diff --git a/src/fuzz/fuzz-journald-stream.c b/src/journal/fuzz-journald-stream.c similarity index 95% rename from src/fuzz/fuzz-journald-stream.c rename to src/journal/fuzz-journald-stream.c index 038b335cb..8a979df3c 100644 --- a/src/fuzz/fuzz-journald-stream.c +++ b/src/journal/fuzz-journald-stream.c @@ -27,7 +27,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { assert_se(stdout_stream_install(&s, stream_fds[0], &stream) >= 0); assert_se(write(stream_fds[1], data, size) == (ssize_t) size); while (ioctl(stream_fds[0], SIOCINQ, &v) == 0 && v) - sd_event_run(s.event, (uint64_t) -1); + sd_event_run(s.event, UINT64_MAX); if (s.n_stdout_streams) stdout_stream_destroy(stream); server_done(&s); diff --git a/src/fuzz/fuzz-journald-stream.options b/src/journal/fuzz-journald-stream.options similarity index 100% rename from src/fuzz/fuzz-journald-stream.options rename to src/journal/fuzz-journald-stream.options diff --git a/src/fuzz/fuzz-journald-syslog.c b/src/journal/fuzz-journald-syslog.c similarity index 100% rename from src/fuzz/fuzz-journald-syslog.c rename to src/journal/fuzz-journald-syslog.c diff --git a/src/fuzz/fuzz-journald.c b/src/journal/fuzz-journald.c similarity index 100% rename from src/fuzz/fuzz-journald.c rename to src/journal/fuzz-journald.c diff --git a/src/fuzz/fuzz-journald.h b/src/journal/fuzz-journald.h similarity index 100% rename from src/fuzz/fuzz-journald.h rename to src/journal/fuzz-journald.h diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c index bcf2e01d5..6b06320d7 100644 --- a/src/journal/journalctl.c +++ b/src/journal/journalctl.c @@ -5,7 +5,6 @@ #include #include #include -#include #include #include #include @@ -30,7 +29,6 @@ #include "catalog.h" #include "chattr-util.h" #include "def.h" -#include "device-private.h" #include "dissect-image.h" #include "fd-util.h" #include "fileio.h" @@ -55,6 +53,7 @@ #include "mountpoint-util.h" #include "nulstr-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pcre2-dlopen.h" @@ -165,8 +164,8 @@ typedef struct BootId { } BootId; #if HAVE_PCRE2 -DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_match_data*, sym_pcre2_match_data_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(pcre2_code*, sym_pcre2_code_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(pcre2_match_data*, sym_pcre2_match_data_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(pcre2_code*, sym_pcre2_code_free, NULL); static int pattern_compile(const char *pattern, unsigned flags, pcre2_code **out) { int errorcode, r; @@ -206,7 +205,7 @@ static int add_matches_for_device(sd_journal *j, const char *devpath) { if (stat(devpath, &st) < 0) return log_error_errno(errno, "Couldn't stat file: %m"); - r = device_new_from_stat_rdev(&device, &st); + r = sd_device_new_from_stat_rdev(&device, &st); if (r < 0) return log_error_errno(r, "Failed to get device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev)); @@ -402,12 +401,13 @@ static int help(void) { " --dump-catalog Show entries in the message catalog\n" " --update-catalog Update the message catalog database\n" " --setup-keys Generate a new FSS key pair\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - , ansi_underline(), ansi_normal() - , ansi_highlight(), ansi_normal() - ); + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); return 0; } @@ -564,7 +564,7 @@ static int parse_argv(int argc, char *argv[]) { arg_output = output_mode_from_string(optarg); if (arg_output < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown output format '%s'.", optarg); + return log_error_errno(arg_output, "Unknown output format '%s'.", optarg); if (IN_SET(arg_output, OUTPUT_EXPORT, OUTPUT_JSON, OUTPUT_JSON_PRETTY, OUTPUT_JSON_SSE, OUTPUT_JSON_SEQ, OUTPUT_CAT)) arg_quiet = true; @@ -718,13 +718,13 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, /* suppress_root= */ true, &arg_root); + r = parse_path_argument(optarg, /* suppress_root= */ true, &arg_root); if (r < 0) return r; break; case ARG_IMAGE: - r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image); + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image); if (r < 0) return r; break; @@ -834,7 +834,7 @@ static int parse_argv(int argc, char *argv[]) { to = log_level_from_string(dots + 2); if (from < 0 || to < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + return log_error_errno(from < 0 ? from : to, "Failed to parse log level range %s", optarg); arg_priorities = 0; @@ -852,8 +852,7 @@ static int parse_argv(int argc, char *argv[]) { p = log_level_from_string(optarg); if (p < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown log level %s", optarg); + return log_error_errno(p, "Unknown log level %s", optarg); arg_priorities = 0; @@ -884,8 +883,7 @@ static int parse_argv(int argc, char *argv[]) { num = log_facility_unshifted_from_string(fac); if (num < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Bad --facility= argument \"%s\".", fac); + return log_error_errno(num, "Bad --facility= argument \"%s\".", fac); if (set_ensure_put(&arg_facilities, NULL, INT_TO_PTR(num)) < 0) return log_oom(); @@ -2096,8 +2094,6 @@ static int wait_for_change(sd_journal *j, int poll_fd) { { .fd = poll_fd, .events = POLLIN }, { .fd = STDOUT_FILENO }, }; - - struct timespec ts; usec_t timeout; int r; @@ -2111,21 +2107,16 @@ static int wait_for_change(sd_journal *j, int poll_fd) { if (r < 0) return log_error_errno(r, "Failed to determine journal waiting time: %m"); - if (ppoll(pollfds, ELEMENTSOF(pollfds), - timeout == USEC_INFINITY ? NULL : timespec_store(&ts, timeout), NULL) < 0) { - if (errno == EINTR) - return 0; + r = ppoll_usec(pollfds, ELEMENTSOF(pollfds), timeout); + if (r == -EINTR) + return 0; + if (r < 0) + return log_error_errno(r, "Couldn't wait for journal event: %m"); - return log_error_errno(errno, "Couldn't wait for journal event: %m"); - } - - if (pollfds[1].revents & (POLLHUP|POLLERR|POLLNVAL)) /* STDOUT has been closed? */ + if (pollfds[1].revents & (POLLHUP|POLLERR)) /* STDOUT has been closed? */ return log_debug_errno(SYNTHETIC_ERRNO(ECANCELED), "Standard output has been closed."); - if (pollfds[0].revents & POLLNVAL) - return log_debug_errno(SYNTHETIC_ERRNO(EBADF), "Change fd closed?"); - r = sd_journal_process(j); if (r < 0) return log_error_errno(r, "Failed to process journal events: %m"); @@ -2144,7 +2135,7 @@ int main(int argc, char *argv[]) { int n_shown = 0, r, poll_fd = -1; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); /* 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/journal/journald-context.c b/src/journal/journald-context.c index 8736495a4..add0a5480 100644 --- a/src/journal/journald-context.c +++ b/src/journal/journald-context.c @@ -69,7 +69,7 @@ static size_t cache_max(void) { static size_t cached = -1; - if (cached == (size_t) -1) { + if (cached == SIZE_MAX) { uint64_t mem_total; int r; @@ -102,17 +102,13 @@ static int client_context_compare(const void *a, const void *b) { } static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { - ClientContext *c; + _cleanup_free_ ClientContext *c = NULL; int r; assert(s); assert(pid_is_valid(pid)); assert(ret); - r = hashmap_ensure_allocated(&s->client_contexts, NULL); - if (r < 0) - return r; - r = prioq_ensure_allocated(&s->client_contexts_lru, client_context_compare); if (r < 0) return r; @@ -136,13 +132,11 @@ static int client_context_new(Server *s, pid_t pid, ClientContext **ret) { .log_ratelimit_burst = s->ratelimit_burst, }; - r = hashmap_put(s->client_contexts, PID_TO_PTR(pid), c); - if (r < 0) { - free(c); + r = hashmap_ensure_put(&s->client_contexts, NULL, PID_TO_PTR(pid), c); + if (r < 0) return r; - } - *ret = c; + *ret = TAKE_PTR(c); return 0; } @@ -374,7 +368,7 @@ static int client_context_read_log_level_max( ll = log_level_from_string(value); if (ll < 0) - return -EINVAL; + return ll; c->log_level_max = ll; return 0; diff --git a/src/journal/journald-gperf.gperf b/src/journal/journald-gperf.gperf index c70ac9a5b..907659762 100644 --- a/src/journal/journald-gperf.gperf +++ b/src/journal/journald-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 1c5849ed5..102814a40 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -105,7 +105,7 @@ static int server_process_entry( * * Note that *remaining is altered on both success and failure. */ - size_t n = 0, j, tn = (size_t) -1, m = 0, entry_size = 0; + size_t n = 0, j, tn = SIZE_MAX, m = 0, entry_size = 0; char *identifier = NULL, *message = NULL; struct iovec *iovec = NULL; int priority = LOG_INFO; diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 10ebc3e22..6d87fa0f8 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -144,7 +144,7 @@ static int cache_space_refresh(Server *s, JournalStorage *storage) { ts = now(CLOCK_MONOTONIC); - if (space->timestamp != 0 && space->timestamp + RECHECK_SPACE_USEC > ts) + if (space->timestamp != 0 && usec_add(space->timestamp, RECHECK_SPACE_USEC) > ts) return 0; r = determine_path_usage(s, storage->path, &vfs_used, &vfs_avail); @@ -1206,7 +1206,7 @@ finish: server_driver_message(s, 0, NULL, LOG_MESSAGE("Time spent on flushing to %s is %s for %u entries.", s->system_storage.path, - format_timespan(ts, sizeof(ts), now(CLOCK_MONOTONIC) - start, 0), + format_timespan(ts, sizeof(ts), usec_sub_unsigned(now(CLOCK_MONOTONIC), start), 0), n), NULL); @@ -1625,17 +1625,19 @@ static int server_parse_config_file(Server *s) { assert(s); if (s->namespace) { - const char *namespaced; + const char *namespaced, *dropin_dirname; /* If we are running in namespace mode, load the namespace specific configuration file, and nothing else */ namespaced = strjoina(PKGSYSCONFDIR "/journald@", s->namespace, ".conf"); + dropin_dirname = strjoina("journald@", s->namespace, ".conf.d"); - r = config_parse(NULL, - namespaced, NULL, - "Journal\0", - config_item_perf_lookup, journald_gperf_lookup, - CONFIG_PARSE_WARN, s, - NULL); + r = config_parse_many( + STRV_MAKE_CONST(namespaced), + (const char* const*) CONF_PATHS_STRV("systemd"), + dropin_dirname, + "Journal\0", + config_item_perf_lookup, journald_gperf_lookup, + CONFIG_PARSE_WARN, s, NULL); if (r < 0) return r; @@ -2033,7 +2035,7 @@ static int server_open_varlink(Server *s, const char *socket, int fd) { assert(s); - r = varlink_server_new(&s->varlink_server, VARLINK_SERVER_ROOT_ONLY); + r = varlink_server_new(&s->varlink_server, VARLINK_SERVER_ROOT_ONLY|VARLINK_SERVER_INHERIT_USERDATA); if (r < 0) return r; @@ -2185,7 +2187,7 @@ int server_init(Server *s, const char *namespace) { .notify_fd = -1, .compress.enabled = true, - .compress.threshold_bytes = (uint64_t) -1, + .compress.threshold_bytes = UINT64_MAX, .seal = true, .set_audit = true, @@ -2593,7 +2595,7 @@ int config_parse_compress( if (isempty(rvalue)) { compress->enabled = true; - compress->threshold_bytes = (uint64_t) -1; + compress->threshold_bytes = UINT64_MAX; } else if (streq(rvalue, "1")) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Compress= ambiguously specified as 1, enabling compression with default threshold"); diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index 5fb145e25..09f80475a 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -25,7 +25,7 @@ typedef enum Storage { STORAGE_PERSISTENT, STORAGE_NONE, _STORAGE_MAX, - _STORAGE_INVALID = -1 + _STORAGE_INVALID = -EINVAL, } Storage; typedef enum SplitMode { @@ -33,7 +33,7 @@ typedef enum SplitMode { SPLIT_LOGIN, /* deprecated */ SPLIT_NONE, _SPLIT_MAX, - _SPLIT_INVALID = -1 + _SPLIT_INVALID = -EINVAL, } SplitMode; typedef struct JournalCompressOptions { diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 3241ef2bf..7bc26097f 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -60,7 +60,7 @@ typedef enum LineBreak { LINE_BREAK_EOF, LINE_BREAK_PID_CHANGE, _LINE_BREAK_MAX, - _LINE_BREAK_INVALID = -1, + _LINE_BREAK_INVALID = -EINVAL, } LineBreak; struct StdoutStream { @@ -98,9 +98,9 @@ struct StdoutStream { char id_field[STRLEN("_STREAM_ID=") + SD_ID128_STRING_MAX]; }; -void stdout_stream_free(StdoutStream *s) { +StdoutStream* stdout_stream_free(StdoutStream *s) { if (!s) - return; + return NULL; if (s->server) { @@ -129,7 +129,7 @@ void stdout_stream_free(StdoutStream *s) { free(s->state_file); free(s->buffer); - free(s); + return mfree(s); } DEFINE_TRIVIAL_CLEANUP_FUNC(StdoutStream*, stdout_stream_free); @@ -334,6 +334,22 @@ static int stdout_stream_log( return 0; } +static int syslog_parse_priority_and_facility(const char *s) { + int prio, r; + + /* Parses both facility and priority in one value, i.e. is different from log_level_from_string() + * which only parses the priority and refuses any facility value */ + + r = safe_atoi(s, &prio); + if (r < 0) + return r; + + if (prio < 0 || prio > 999) + return -ERANGE; + + return prio; +} + static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { char *orig; int r; @@ -373,22 +389,22 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { s->state = STDOUT_STREAM_PRIORITY; return 0; - case STDOUT_STREAM_PRIORITY: - r = safe_atoi(p, &s->priority); - if (r < 0 || s->priority < 0 || s->priority > 999) { - log_warning("Failed to parse log priority line."); - return -EINVAL; - } + case STDOUT_STREAM_PRIORITY: { + int priority; + priority = syslog_parse_priority_and_facility(p); + if (priority < 0) + return log_warning_errno(priority, "Failed to parse log priority line: %m"); + + s->priority = priority; s->state = STDOUT_STREAM_LEVEL_PREFIX; return 0; + } case STDOUT_STREAM_LEVEL_PREFIX: r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse level prefix line."); - return -EINVAL; - } + if (r < 0) + return log_warning_errno(r, "Failed to parse level prefix line: %m"); s->level_prefix = r; s->state = STDOUT_STREAM_FORWARD_TO_SYSLOG; @@ -396,10 +412,8 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { case STDOUT_STREAM_FORWARD_TO_SYSLOG: r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse forward to syslog line."); - return -EINVAL; - } + if (r < 0) + return log_warning_errno(r, "Failed to parse forward to syslog line: %m"); s->forward_to_syslog = r; s->state = STDOUT_STREAM_FORWARD_TO_KMSG; @@ -407,10 +421,8 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { case STDOUT_STREAM_FORWARD_TO_KMSG: r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse copy to kmsg line."); - return -EINVAL; - } + if (r < 0) + return log_warning_errno(r, "Failed to parse copy to kmsg line: %m"); s->forward_to_kmsg = r; s->state = STDOUT_STREAM_FORWARD_TO_CONSOLE; @@ -418,10 +430,8 @@ static int stdout_stream_line(StdoutStream *s, char *p, LineBreak line_break) { case STDOUT_STREAM_FORWARD_TO_CONSOLE: r = parse_boolean(p); - if (r < 0) { - log_warning("Failed to parse copy to console line."); - return -EINVAL; - } + if (r < 0) + return log_warning_errno(r, "Failed to parse copy to console line."); s->forward_to_console = r; s->state = STDOUT_STREAM_RUNNING; @@ -750,7 +760,7 @@ static int stdout_stream_load(StdoutStream *stream, const char *fname) { if (priority) { int p; - p = log_level_from_string(priority); + p = syslog_parse_priority_and_facility(priority); if (p >= 0) stream->priority = p; } diff --git a/src/journal/journald-stream.h b/src/journal/journald-stream.h index 0a033b4dc..7b756c05e 100644 --- a/src/journal/journald-stream.h +++ b/src/journal/journald-stream.h @@ -9,7 +9,7 @@ typedef struct StdoutStream StdoutStream; int server_open_stdout_socket(Server *s, const char *stdout_socket); int server_restore_streams(Server *s, FDSet *fds); -void stdout_stream_free(StdoutStream *s); +StdoutStream* stdout_stream_free(StdoutStream *s); int stdout_stream_install(Server *s, int fd, StdoutStream **ret); void stdout_stream_destroy(StdoutStream *s); void stdout_stream_send_notify(StdoutStream *s); diff --git a/src/journal/journald.conf b/src/journal/journald.conf index 2e1aacd8c..18d6b3077 100644 --- a/src/journal/journald.conf +++ b/src/journal/journald.conf @@ -1,13 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. +# +# Use 'systemd-analyze cat-config systemd/journald.conf' to display the full config. # # See journald.conf(5) for details. diff --git a/src/journal/meson.build b/src/journal/meson.build index 7aea28d12..171e27673 100644 --- a/src/journal/meson.build +++ b/src/journal/meson.build @@ -1,70 +1,6 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -journal_client_sources = files(''' - audit-type.c - audit-type.h - catalog.c - catalog.h - compress.c - compress.h - journal-def.h - journal-file.c - journal-file.h - journal-send.c - journal-vacuum.c - journal-vacuum.h - journal-verify.c - journal-verify.h - lookup3.c - lookup3.h - mmap-cache.c - mmap-cache.h - sd-journal.c -'''.split()) - -if conf.get('HAVE_GCRYPT') == 1 - journal_client_sources += files(''' - journal-authenticate.c - journal-authenticate.h - fsprg.c - fsprg.h - '''.split()) -endif - -############################################################ - -audit_type_includes = [config_h, - missing_audit_h, - 'linux/audit.h'] -if conf.get('HAVE_AUDIT') == 1 - audit_type_includes += 'libaudit.h' -endif - -generate_audit_type_list = find_program('generate-audit_type-list.sh') -audit_type_list_txt = custom_target( - 'audit_type-list.txt', - output : 'audit_type-list.txt', - command : [generate_audit_type_list, cpp] + audit_type_includes, - capture : true) - -audit_type_to_name = custom_target( - 'audit_type-to-name.h', - input : ['audit_type-to-name.awk', audit_type_list_txt], - output : 'audit_type-to-name.h', - command : [awk, '-f', '@INPUT0@', '@INPUT1@'], - capture : true) - -journal_client_sources += [audit_type_to_name] - -libjournal_client = static_library( - 'journal-client', - journal_client_sources, - include_directories : includes, - c_args : ['-fvisibility=default']) - -############################################################ - -libjournal_core_sources = files(''' +sources = files(''' journald-audit.c journald-audit.h journald-console.c @@ -85,20 +21,27 @@ libjournal_core_sources = files(''' journald-syslog.h journald-wall.c journald-wall.h - journal-internal.h '''.split()) +sources += custom_target( + 'journald-gperf.c', + input : 'journald-gperf.gperf', + output : 'journald-gperf.c', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + +libjournal_core = static_library( + 'journal-core', + sources, + include_directories : includes, + install : false) + +journal_includes = [includes, include_directories('.')] + systemd_journald_sources = files(''' journald.c journald-server.h '''.split()) -journald_gperf_c = custom_target( - 'journald-gperf.c', - input : 'journald-gperf.gperf', - output : 'journald-gperf.c', - command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) - systemd_cat_sources = files('cat.c') journalctl_sources = files(''' @@ -107,7 +50,7 @@ journalctl_sources = files(''' pcre2-dlopen.h '''.split()) -if install_sysconfdir +if install_sysconfdir_samples install_data('journald.conf', install_dir : pkgsysconfdir) endif @@ -131,3 +74,60 @@ if get_option('create-log-dirs') 'setfacl -nm g:wheel:rx,d:g:wheel:rx $DESTDIR/var/log/journal || :') endif endif + +############################################################ + +tests += [ + [['src/journal/test-journal-syslog.c'], + [libjournal_core, + libshared], + [threads, + libxz, + liblz4, + libselinux]], + + [['src/journal/test-journal-config.c'], + [libjournal_core, + libshared], + [libxz, + liblz4, + libselinux]], +] + +fuzzers += [ + [['src/journal/fuzz-journald-audit.c', + 'src/journal/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + + [['src/journal/fuzz-journald-kmsg.c', + 'src/journal/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + + [['src/journal/fuzz-journald-native.c', + 'src/journal/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + + [['src/journal/fuzz-journald-native-fd.c', + 'src/journal/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + + [['src/journal/fuzz-journald-stream.c', + 'src/journal/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], + + [['src/journal/fuzz-journald-syslog.c', + 'src/journal/fuzz-journald.c'], + [libjournal_core, + libshared], + [libselinux]], +] diff --git a/src/journal/pcre2-dlopen.c b/src/journal/pcre2-dlopen.c index fbe81f99e..5f78f7667 100644 --- a/src/journal/pcre2-dlopen.c +++ b/src/journal/pcre2-dlopen.c @@ -27,16 +27,24 @@ int dlopen_pcre2(void) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "PCRE2 support is not installed: %s", dlerror()); + /* So here's something weird: PCRE2 actually renames the symbols exported by the library via C + * macros, so that the exported symbols carry a suffix "_8" but when used from C the suffix is + * gone. In the argument list below we ignore this mangling. Surprisingly (at least to me), we + * actually get away with that. That's because DLSYM_ARG() useses STRINGIFY() to generate a string + * version of the symbol name, and that resolves the macro mapping implicitly already, so that the + * string actually contains the "_8" suffix already due to that and we don't have to append it + * manually anymore. C is weird. 🤯 */ + r = dlsym_many_and_warn( dl, LOG_ERR, - &sym_pcre2_match_data_create, "pcre2_match_data_create_8", - &sym_pcre2_match_data_free, "pcre2_match_data_free_8", - &sym_pcre2_code_free, "pcre2_code_free_8", - &sym_pcre2_compile, "pcre2_compile_8", - &sym_pcre2_get_error_message, "pcre2_get_error_message_8", - &sym_pcre2_match, "pcre2_match_8", - &sym_pcre2_get_ovector_pointer, "pcre2_get_ovector_pointer_8", + DLSYM_ARG(pcre2_match_data_create), + DLSYM_ARG(pcre2_match_data_free), + DLSYM_ARG(pcre2_code_free), + DLSYM_ARG(pcre2_compile), + DLSYM_ARG(pcre2_get_error_message), + DLSYM_ARG(pcre2_match), + DLSYM_ARG(pcre2_get_ovector_pointer), NULL); if (r < 0) return r; diff --git a/src/journal/test-journal-config.c b/src/journal/test-journal-config.c index 4f29e1b31..bd0de9600 100644 --- a/src/journal/test-journal-config.c +++ b/src/journal/test-journal-config.c @@ -43,7 +43,7 @@ static void test_config_compress(void) { /* Invalid Case */ COMPRESS_PARSE_CHECK("-1", true, 111); COMPRESS_PARSE_CHECK("blah blah", true, 111); - COMPRESS_PARSE_CHECK("", true, (uint64_t)-1); + COMPRESS_PARSE_CHECK("", true, UINT64_MAX); } int main(int argc, char *argv[]) { diff --git a/src/kernel-install/00-entry-directory.install b/src/kernel-install/00-entry-directory.install index 21c09fa69..ab616b282 100644 --- a/src/kernel-install/00-entry-directory.install +++ b/src/kernel-install/00-entry-directory.install @@ -1,6 +1,22 @@ #!/usr/bin/env bash # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # ex: ts=8 sw=4 sts=4 et filetype=sh +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . COMMAND="$1" KERNEL_VERSION="$2" @@ -13,7 +29,7 @@ if ! [[ $KERNEL_INSTALL_MACHINE_ID ]]; then fi if [[ $COMMAND != add ]]; then - exit 0 + exit 0 fi # If the boot dir exists (e.g. $ESP/), diff --git a/src/kernel-install/50-depmod.install b/src/kernel-install/50-depmod.install index 3850eacef..2fd959865 100644 --- a/src/kernel-install/50-depmod.install +++ b/src/kernel-install/50-depmod.install @@ -1,6 +1,22 @@ #!/usr/bin/env bash # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # ex: ts=8 sw=4 sts=4 et filetype=sh +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . COMMAND="$1" KERNEL_VERSION="$2" diff --git a/src/kernel-install/90-loaderentry.install b/src/kernel-install/90-loaderentry.install index d09674538..e6c7e99e6 100644 --- a/src/kernel-install/90-loaderentry.install +++ b/src/kernel-install/90-loaderentry.install @@ -1,6 +1,22 @@ #!/usr/bin/env bash # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- # ex: ts=8 sw=4 sts=4 et filetype=sh +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. +# +# systemd is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with systemd; If not, see . COMMAND="$1" KERNEL_VERSION="$2" @@ -73,11 +89,11 @@ else fi cp "$KERNEL_IMAGE" "$ENTRY_DIR_ABS/linux" && - chown root:root "$ENTRY_DIR_ABS/linux" && - chmod 0644 "$ENTRY_DIR_ABS/linux" || { - echo "Could not copy '$KERNEL_IMAGE to '$ENTRY_DIR_ABS/linux'." >&2 - exit 1 -} + chown root:root "$ENTRY_DIR_ABS/linux" && + chmod 0644 "$ENTRY_DIR_ABS/linux" || { + echo "Could not copy '$KERNEL_IMAGE to '$ENTRY_DIR_ABS/linux'." >&2 + exit 1 + } INITRD_OPTIONS=( "${@:${INITRD_OPTIONS_START}}" ) @@ -89,9 +105,9 @@ for initrd in "${INITRD_OPTIONS[@]}"; do cp "${initrd}" "$ENTRY_DIR_ABS/${initrd_basename}" && chown root:root "$ENTRY_DIR_ABS/${initrd_basename}" && chmod 0644 "$ENTRY_DIR_ABS/${initrd_basename}" || { - echo "Could not copy '${initrd}' to '$ENTRY_DIR_ABS/${initrd_basename}'." >&2 - exit 1 - } + echo "Could not copy '${initrd}' to '$ENTRY_DIR_ABS/${initrd_basename}'." >&2 + exit 1 + } fi done diff --git a/src/libsystemd-network/dhcp-identifier.c b/src/libsystemd-network/dhcp-identifier.c index ea9c77aa9..953fef19f 100644 --- a/src/libsystemd-network/dhcp-identifier.c +++ b/src/libsystemd-network/dhcp-identifier.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include "sd-device.h" @@ -8,7 +9,7 @@ #include "dhcp-identifier.h" #include "dhcp6-protocol.h" -#include "network-internal.h" +#include "network-util.h" #include "siphash24.h" #include "sparse-endian.h" #include "stdio-util.h" diff --git a/src/libsystemd-network/dhcp-identifier.h b/src/libsystemd-network/dhcp-identifier.h index e9f2ea7e9..1d9a9c55b 100644 --- a/src/libsystemd-network/dhcp-identifier.h +++ b/src/libsystemd-network/dhcp-identifier.h @@ -16,7 +16,7 @@ typedef enum DUIDType { DUID_TYPE_LL = 3, DUID_TYPE_UUID = 4, _DUID_TYPE_MAX, - _DUID_TYPE_INVALID = -1, + _DUID_TYPE_INVALID = -EINVAL, } DUIDType; /* RFC 3315 section 9.1: diff --git a/src/libsystemd-network/dhcp-option.c b/src/libsystemd-network/dhcp-option.c index 7e3fe4348..faa075cbd 100644 --- a/src/libsystemd-network/dhcp-option.c +++ b/src/libsystemd-network/dhcp-option.c @@ -80,11 +80,11 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, break; case SD_DHCP_OPTION_VENDOR_SPECIFIC: { - OrderedHashmap *s = (OrderedHashmap *) optval; + OrderedSet *s = (OrderedSet *) optval; struct sd_dhcp_option *p; size_t l = 0; - ORDERED_HASHMAP_FOREACH(p, s) + ORDERED_SET_FOREACH(p, s) l += p->length + 2; if (*offset + l + 2 > size) @@ -95,7 +95,7 @@ static int option_append(uint8_t options[], size_t size, size_t *offset, *offset += 2; - ORDERED_HASHMAP_FOREACH(p, s) { + ORDERED_SET_FOREACH(p, s) { options[*offset] = p->option; options[*offset + 1] = p->length; memcpy(&options[*offset + 2], p->data, p->length); diff --git a/src/libsystemd-network/dhcp-server-internal.h b/src/libsystemd-network/dhcp-server-internal.h index b57737ee2..b5293c3ed 100644 --- a/src/libsystemd-network/dhcp-server-internal.h +++ b/src/libsystemd-network/dhcp-server-internal.h @@ -9,7 +9,7 @@ #include "sd-event.h" #include "dhcp-internal.h" -#include "hashmap.h" +#include "ordered-set.h" #include "log.h" #include "time-util.h" @@ -58,8 +58,8 @@ struct sd_dhcp_server { DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX]; - OrderedHashmap *extra_options; - OrderedHashmap *vendor_options; + OrderedSet *extra_options; + OrderedSet *vendor_options; bool emit_router; diff --git a/src/libsystemd-network/dhcp6-internal.h b/src/libsystemd-network/dhcp6-internal.h index 9a32b007f..681c46231 100644 --- a/src/libsystemd-network/dhcp6-internal.h +++ b/src/libsystemd-network/dhcp6-internal.h @@ -97,7 +97,7 @@ typedef struct DHCP6IA DHCP6IA; int dhcp6_option_append(uint8_t **buf, size_t *buflen, uint16_t code, size_t optlen, const void *optval); int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia); -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix); +int dhcp6_option_append_pd(uint8_t **buf, size_t *buflen, const DHCP6IA *pd, const DHCP6Address *hint_pd_prefix); int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn); int dhcp6_option_append_user_class(uint8_t **buf, size_t *buflen, char * const *user_class); int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const *user_class); diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 9f47c1bbe..91162d636 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -41,14 +41,15 @@ typedef struct DHCP6PDPrefixOption { #define DHCP6_OPTION_IA_PD_LEN (sizeof(struct ia_pd)) #define DHCP6_OPTION_IA_TA_LEN (sizeof(struct ia_ta)) -static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, - size_t optlen) { - DHCP6Option *option = (DHCP6Option*) *buf; +static int option_append_hdr(uint8_t **buf, size_t *buflen, uint16_t optcode, size_t optlen) { + DHCP6Option *option; assert_return(buf, -EINVAL); assert_return(*buf, -EINVAL); assert_return(buflen, -EINVAL); + option = (DHCP6Option*) *buf; + if (optlen > 0xffff || *buflen < optlen + offsetof(DHCP6Option, data)) return -ENOBUFS; @@ -112,10 +113,13 @@ int dhcp6_option_append_vendor_option(uint8_t **buf, size_t *buflen, OrderedHash } int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) { - uint16_t len; - uint8_t *ia_hdr; - size_t iaid_offset, ia_buflen, ia_addrlen = 0; + size_t ia_buflen, ia_addrlen = 0; + struct ia_na ia_na; + struct ia_ta ia_ta; DHCP6Address *addr; + uint8_t *ia_hdr; + uint16_t len; + void *p; int r; assert_return(buf, -EINVAL); @@ -123,15 +127,23 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) { assert_return(buflen, -EINVAL); assert_return(ia, -EINVAL); + /* client should not send set T1 and T2. See, RFC 8415, and issue #18090. */ + switch (ia->type) { case SD_DHCP6_OPTION_IA_NA: len = DHCP6_OPTION_IA_NA_LEN; - iaid_offset = offsetof(DHCP6IA, ia_na); + ia_na = (struct ia_na) { + .id = ia->ia_na.id, + }; + p = &ia_na; break; case SD_DHCP6_OPTION_IA_TA: len = DHCP6_OPTION_IA_TA_LEN; - iaid_offset = offsetof(DHCP6IA, ia_ta); + ia_ta = (struct ia_ta) { + .id = ia->ia_ta.id, + }; + p = &ia_ta; break; default: @@ -147,30 +159,113 @@ int dhcp6_option_append_ia(uint8_t **buf, size_t *buflen, const DHCP6IA *ia) { *buf += offsetof(DHCP6Option, data); *buflen -= offsetof(DHCP6Option, data); - memcpy(*buf, (char*) ia + iaid_offset, len); + memcpy(*buf, p, len); *buf += len; *buflen -= len; LIST_FOREACH(addresses, addr, ia->addresses) { - r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR, - sizeof(addr->iaaddr)); + struct iaaddr a = { + .address = addr->iaaddr.address, + }; + + r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IAADDR, sizeof(struct iaaddr)); if (r < 0) return r; - memcpy(*buf, &addr->iaaddr, sizeof(addr->iaaddr)); + memcpy(*buf, &a, sizeof(struct iaaddr)); - *buf += sizeof(addr->iaaddr); - *buflen -= sizeof(addr->iaaddr); + *buf += sizeof(struct iaaddr); + *buflen -= sizeof(struct iaaddr); - ia_addrlen += offsetof(DHCP6Option, data) + sizeof(addr->iaaddr); + ia_addrlen += offsetof(DHCP6Option, data) + sizeof(struct iaaddr); } - r = option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); + return option_append_hdr(&ia_hdr, &ia_buflen, ia->type, len + ia_addrlen); +} + +static int option_append_pd_prefix(uint8_t **buf, size_t *buflen, const DHCP6Address *prefix) { + struct iapdprefix p; + int r; + + assert(buf); + assert(*buf); + assert(buflen); + assert(prefix); + + if (prefix->iapdprefix.prefixlen == 0) + return -EINVAL; + + /* Do not append T1 and T2. */ + + p = (struct iapdprefix) { + .prefixlen = prefix->iapdprefix.prefixlen, + .address = prefix->iapdprefix.address, + }; + + r = option_append_hdr(buf, buflen, SD_DHCP6_OPTION_IA_PD_PREFIX, sizeof(struct iapdprefix)); if (r < 0) return r; - return 0; + memcpy(*buf, &p, sizeof(struct iapdprefix)); + + *buf += sizeof(struct iapdprefix); + *buflen -= sizeof(struct iapdprefix); + + return offsetof(DHCP6Option, data) + sizeof(struct iapdprefix); +} + +int dhcp6_option_append_pd(uint8_t **buf, size_t *buflen, const DHCP6IA *pd, const DHCP6Address *hint_pd_prefix) { + struct ia_pd ia_pd; + size_t len, pd_buflen; + uint8_t *pd_hdr; + int r; + + assert_return(buf, -EINVAL); + assert_return(*buf, -EINVAL); + assert_return(buflen, -EINVAL); + assert_return(pd, -EINVAL); + assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL); + + /* Do not set T1 and T2. */ + ia_pd = (struct ia_pd) { + .id = pd->ia_pd.id, + }; + len = sizeof(struct ia_pd); + + if (*buflen < offsetof(DHCP6Option, data) + len) + return -ENOBUFS; + + pd_hdr = *buf; + pd_buflen = *buflen; + + /* The header will be written at the end of this function. */ + *buf += offsetof(DHCP6Option, data); + *buflen -= offsetof(DHCP6Option, data); + + memcpy(*buf, &ia_pd, len); + + *buf += sizeof(struct ia_pd); + *buflen -= sizeof(struct ia_pd); + + DHCP6Address *prefix; + LIST_FOREACH(addresses, prefix, pd->addresses) { + r = option_append_pd_prefix(buf, buflen, prefix); + if (r < 0) + return r; + + len += r; + } + + if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) { + r = option_append_pd_prefix(buf, buflen, hint_pd_prefix); + if (r < 0) + return r; + + len += r; + } + + return option_append_hdr(&pd_hdr, &pd_buflen, pd->type, len); } int dhcp6_option_append_fqdn(uint8_t **buf, size_t *buflen, const char *fqdn) { @@ -275,51 +370,6 @@ int dhcp6_option_append_vendor_class(uint8_t **buf, size_t *buflen, char * const return dhcp6_option_append(buf, buflen, SD_DHCP6_OPTION_VENDOR_CLASS, total, p); } -int dhcp6_option_append_pd(uint8_t *buf, size_t len, const DHCP6IA *pd, DHCP6Address *hint_pd_prefix) { - DHCP6Option *option = (DHCP6Option *)buf; - size_t i = sizeof(*option) + sizeof(pd->ia_pd); - DHCP6PDPrefixOption *prefix_opt; - DHCP6Address *prefix; - - assert_return(buf, -EINVAL); - assert_return(pd, -EINVAL); - assert_return(pd->type == SD_DHCP6_OPTION_IA_PD, -EINVAL); - - if (len < i) - return -ENOBUFS; - - option->code = htobe16(SD_DHCP6_OPTION_IA_PD); - - memcpy(&option->data, &pd->ia_pd, sizeof(pd->ia_pd)); - LIST_FOREACH(addresses, prefix, pd->addresses) { - if (len < i + sizeof(*prefix_opt)) - return -ENOBUFS; - - prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; - prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); - prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - - memcpy(&prefix_opt->iapdprefix, &prefix->iapdprefix, sizeof(struct iapdprefix)); - i += sizeof(*prefix_opt); - } - - if (hint_pd_prefix && hint_pd_prefix->iapdprefix.prefixlen > 0) { - if (len < i + sizeof(*prefix_opt)) - return -ENOBUFS; - - prefix_opt = (DHCP6PDPrefixOption *)&buf[i]; - prefix_opt->option.code = htobe16(SD_DHCP6_OPTION_IA_PD_PREFIX); - prefix_opt->option.len = htobe16(sizeof(prefix_opt->iapdprefix)); - - memcpy(&prefix_opt->iapdprefix, &hint_pd_prefix->iapdprefix, sizeof(struct iapdprefix)); - i += sizeof(*prefix_opt); - } - - option->len = htobe16(i - sizeof(*option)); - - return i; -} - static int option_parse_hdr(uint8_t **buf, size_t *buflen, uint16_t *optcode, size_t *optlen) { DHCP6Option *option = (DHCP6Option*) *buf; uint16_t len; @@ -375,8 +425,7 @@ int dhcp6_option_parse_status(DHCP6Option *option, size_t len) { return be16toh(statusopt->status); } -static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, - uint32_t *lifetime_valid) { +static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) { DHCP6AddressOption *addr_option = (DHCP6AddressOption *)option; DHCP6Address *addr; uint32_t lt_valid, lt_pref; @@ -389,16 +438,22 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, lt_pref = be32toh(addr_option->iaaddr.lifetime_preferred); if (lt_valid == 0 || lt_pref > lt_valid) { - log_dhcp6_client(client, "Valid lifetime of an IA address is zero or preferred lifetime %d > valid lifetime %d", + log_dhcp6_client(client, + "Valid lifetime of an IA address is zero or " + "preferred lifetime %"PRIu32" > valid lifetime %"PRIu32, lt_pref, lt_valid); - - return 0; + return -EINVAL; } if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*addr_option)) { r = dhcp6_option_parse_status((DHCP6Option *)addr_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*addr_option)); - if (r != 0) - return r < 0 ? r: 0; + if (r < 0) + return r; + if (r > 0) { + log_dhcp6_client(client, "Non-zero status code '%s' for address is received", + dhcp6_message_status_to_string(r)); + return -EINVAL; + } } addr = new0(DHCP6Address, 1); @@ -410,13 +465,12 @@ static int dhcp6_option_parse_address(DHCP6Option *option, DHCP6IA *ia, LIST_PREPEND(addresses, ia->addresses, addr); - *lifetime_valid = be32toh(addr->iaaddr.lifetime_valid); + *ret_lifetime_valid = be32toh(addr->iaaddr.lifetime_valid); return 0; } -static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, - uint32_t *lifetime_valid) { +static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, uint32_t *ret_lifetime_valid) { DHCP6PDPrefixOption *pdprefix_option = (DHCP6PDPrefixOption *)option; DHCP6Address *prefix; uint32_t lt_valid, lt_pref; @@ -429,16 +483,22 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, lt_pref = be32toh(pdprefix_option->iapdprefix.lifetime_preferred); if (lt_valid == 0 || lt_pref > lt_valid) { - log_dhcp6_client(client, "Valid lifetieme of a PD prefix is zero or preferred lifetime %d > valid lifetime %d", + log_dhcp6_client(client, + "Valid lifetieme of a PD prefix is zero or " + "preferred lifetime %"PRIu32" > valid lifetime %"PRIu32, lt_pref, lt_valid); - - return 0; + return -EINVAL; } if (be16toh(option->len) + offsetof(DHCP6Option, data) > sizeof(*pdprefix_option)) { r = dhcp6_option_parse_status((DHCP6Option *)pdprefix_option->options, be16toh(option->len) + offsetof(DHCP6Option, data) - sizeof(*pdprefix_option)); - if (r != 0) - return r < 0 ? r: 0; + if (r < 0) + return r; + if (r > 0) { + log_dhcp6_client(client, "Non-zero status code '%s' for PD prefix is received", + dhcp6_message_status_to_string(r)); + return -EINVAL; + } } prefix = new0(DHCP6Address, 1); @@ -450,7 +510,7 @@ static int dhcp6_option_parse_pdprefix(DHCP6Option *option, DHCP6IA *ia, LIST_PREPEND(addresses, ia->addresses, prefix); - *lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid); + *ret_lifetime_valid = be32toh(prefix->iapdprefix.lifetime_valid); return 0; } @@ -482,8 +542,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat lt_t2 = be32toh(ia->ia_na.lifetime_t2); if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA NA T1 %ds > T2 %ds", - lt_t1, lt_t2); + log_dhcp6_client(client, "IA NA T1 %"PRIu32"sec > T2 %"PRIu32"sec", lt_t1, lt_t2); return -EINVAL; } @@ -501,8 +560,7 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat lt_t2 = be32toh(ia->ia_pd.lifetime_t2); if (lt_t1 && lt_t2 && lt_t1 > lt_t2) { - log_dhcp6_client(client, "IA PD T1 %ds > T2 %ds", - lt_t1, lt_t2); + log_dhcp6_client(client, "IA PD T1 %"PRIu32"sec > T2 %"PRIu32"sec", lt_t1, lt_t2); return -EINVAL; } @@ -542,10 +600,9 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat } r = dhcp6_option_parse_address(option, ia, <_valid); - if (r < 0) + if (r < 0 && r != -EINVAL) return r; - - if (lt_valid < lt_min) + if (r >= 0 && lt_valid < lt_min) lt_min = lt_valid; break; @@ -558,10 +615,9 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat } r = dhcp6_option_parse_pdprefix(option, ia, <_valid); - if (r < 0) + if (r < 0 && r != -EINVAL) return r; - - if (lt_valid < lt_min) + if (r >= 0 && lt_valid < lt_min) lt_min = lt_valid; break; @@ -594,26 +650,26 @@ int dhcp6_option_parse_ia(DHCP6Option *iaoption, DHCP6IA *ia, uint16_t *ret_stat switch(iatype) { case SD_DHCP6_OPTION_IA_NA: - if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2) { + if (!ia->ia_na.lifetime_t1 && !ia->ia_na.lifetime_t2 && lt_min != UINT32_MAX) { lt_t1 = lt_min / 2; lt_t2 = lt_min / 10 * 8; ia->ia_na.lifetime_t1 = htobe32(lt_t1); ia->ia_na.lifetime_t2 = htobe32(lt_t2); - log_dhcp6_client(client, "Computed IA NA T1 %ds and T2 %ds as both were zero", + log_dhcp6_client(client, "Computed IA NA T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero", lt_t1, lt_t2); } break; case SD_DHCP6_OPTION_IA_PD: - if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2) { + if (!ia->ia_pd.lifetime_t1 && !ia->ia_pd.lifetime_t2 && lt_min != UINT32_MAX) { lt_t1 = lt_min / 2; lt_t2 = lt_min / 10 * 8; ia->ia_pd.lifetime_t1 = htobe32(lt_t1); ia->ia_pd.lifetime_t2 = htobe32(lt_t2); - log_dhcp6_client(client, "Computed IA PD T1 %ds and T2 %ds as both were zero", + log_dhcp6_client(client, "Computed IA PD T1 %"PRIu32"sec and T2 %"PRIu32"sec as both were zero", lt_t1, lt_t2); } diff --git a/src/fuzz/fuzz-dhcp-server.c b/src/libsystemd-network/fuzz-dhcp-server.c similarity index 100% rename from src/fuzz/fuzz-dhcp-server.c rename to src/libsystemd-network/fuzz-dhcp-server.c diff --git a/src/fuzz/fuzz-dhcp-server.options b/src/libsystemd-network/fuzz-dhcp-server.options similarity index 100% rename from src/fuzz/fuzz-dhcp-server.options rename to src/libsystemd-network/fuzz-dhcp-server.options diff --git a/src/fuzz/fuzz-dhcp6-client.c b/src/libsystemd-network/fuzz-dhcp6-client.c similarity index 98% rename from src/fuzz/fuzz-dhcp6-client.c rename to src/libsystemd-network/fuzz-dhcp6-client.c index e5e70dd60..acb8d9b98 100644 --- a/src/fuzz/fuzz-dhcp6-client.c +++ b/src/libsystemd-network/fuzz-dhcp6-client.c @@ -41,7 +41,7 @@ static void fuzz_client(const uint8_t *data, size_t size, bool is_information_re assert_se(write(test_dhcp_fd[1], data, size) == (ssize_t) size); - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); assert_se(sd_dhcp6_client_stop(client) >= 0); diff --git a/src/fuzz/fuzz-dhcp6-client.options b/src/libsystemd-network/fuzz-dhcp6-client.options similarity index 100% rename from src/fuzz/fuzz-dhcp6-client.options rename to src/libsystemd-network/fuzz-dhcp6-client.options diff --git a/src/fuzz/fuzz-lldp.c b/src/libsystemd-network/fuzz-lldp.c similarity index 100% rename from src/fuzz/fuzz-lldp.c rename to src/libsystemd-network/fuzz-lldp.c diff --git a/src/fuzz/fuzz-lldp.options b/src/libsystemd-network/fuzz-lldp.options similarity index 100% rename from src/fuzz/fuzz-lldp.options rename to src/libsystemd-network/fuzz-lldp.options diff --git a/src/fuzz/fuzz-ndisc-rs.c b/src/libsystemd-network/fuzz-ndisc-rs.c similarity index 97% rename from src/fuzz/fuzz-ndisc-rs.c rename to src/libsystemd-network/fuzz-ndisc-rs.c index d74cd2fff..20350d449 100644 --- a/src/fuzz/fuzz-ndisc-rs.c +++ b/src/libsystemd-network/fuzz-ndisc-rs.c @@ -53,7 +53,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { assert_se(sd_ndisc_set_mac(nd, &mac_addr) >= 0); assert_se(sd_ndisc_start(nd) >= 0); assert_se(write(test_fd[1], data, size) == (ssize_t) size); - (void) sd_event_run(e, (uint64_t) -1); + (void) sd_event_run(e, UINT64_MAX); assert_se(sd_ndisc_stop(nd) >= 0); close(test_fd[1]); diff --git a/src/fuzz/fuzz-ndisc-rs.options b/src/libsystemd-network/fuzz-ndisc-rs.options similarity index 100% rename from src/fuzz/fuzz-ndisc-rs.options rename to src/libsystemd-network/fuzz-ndisc-rs.options diff --git a/src/libsystemd-network/icmp6-util.c b/src/libsystemd-network/icmp6-util.c index 4af012534..67c6b55d8 100644 --- a/src/libsystemd-network/icmp6-util.c +++ b/src/libsystemd-network/icmp6-util.c @@ -145,8 +145,8 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { return 0; } -int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst, - triple_timestamp *timestamp) { +int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *ret_dst, + triple_timestamp *ret_timestamp) { CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(int)) + /* ttl */ CMSG_SPACE(sizeof(struct timeval))) control; @@ -161,6 +161,8 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst, .msg_controllen = sizeof(control), }; struct cmsghdr *cmsg; + struct in6_addr addr = {}; + triple_timestamp t = {}; ssize_t len; iov = IOVEC_MAKE(buffer, size); @@ -175,8 +177,8 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst, if (msg.msg_namelen == sizeof(struct sockaddr_in6) && sa.in6.sin6_family == AF_INET6) { - *dst = sa.in6.sin6_addr; - if (in_addr_is_link_local(AF_INET6, (union in_addr_union*) dst) <= 0) + addr = sa.in6.sin6_addr; + if (!in6_addr_is_link_local(&addr)) return -EADDRNOTAVAIL; } else if (msg.msg_namelen > 0) @@ -200,11 +202,13 @@ int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst, if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP && cmsg->cmsg_len == CMSG_LEN(sizeof(struct timeval))) - triple_timestamp_from_realtime(timestamp, timeval_load((struct timeval*) CMSG_DATA(cmsg))); + triple_timestamp_from_realtime(&t, timeval_load((struct timeval*) CMSG_DATA(cmsg))); } - if (!triple_timestamp_is_set(timestamp)) - triple_timestamp_get(timestamp); + if (!triple_timestamp_is_set(&t)) + triple_timestamp_get(&t); + *ret_dst = addr; + *ret_timestamp = t; return 0; } diff --git a/src/libsystemd-network/icmp6-util.h b/src/libsystemd-network/icmp6-util.h index 50d21b5b5..f7ad26b5e 100644 --- a/src/libsystemd-network/icmp6-util.h +++ b/src/libsystemd-network/icmp6-util.h @@ -20,5 +20,5 @@ int icmp6_bind_router_solicitation(int ifindex); int icmp6_bind_router_advertisement(int ifindex); int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr); -int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *dst, - triple_timestamp *timestamp); +int icmp6_receive(int fd, void *buffer, size_t size, struct in6_addr *ret_dst, + triple_timestamp *ret_timestamp); diff --git a/src/libsystemd-network/lldp-internal.h b/src/libsystemd-network/lldp-internal.h index f23695f97..daedbb088 100644 --- a/src/libsystemd-network/lldp-internal.h +++ b/src/libsystemd-network/lldp-internal.h @@ -35,5 +35,5 @@ struct sd_lldp { #define log_lldp_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "LLDP: " fmt, ##__VA_ARGS__) #define log_lldp(fmt, ...) log_lldp_errno(0, fmt, ##__VA_ARGS__) -const char* lldp_event_to_string(sd_lldp_event e) _const_; -sd_lldp_event lldp_event_from_string(const char *s) _pure_; +const char* lldp_event_to_string(sd_lldp_event_t e) _const_; +sd_lldp_event_t lldp_event_from_string(const char *s) _pure_; diff --git a/src/libsystemd-network/lldp-network.c b/src/libsystemd-network/lldp-network.c index 9616cb625..43141b2d7 100644 --- a/src/libsystemd-network/lldp-network.c +++ b/src/libsystemd-network/lldp-network.c @@ -22,7 +22,7 @@ int lldp_network_bind_raw_socket(int ifindex) { BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ethhdr, h_proto)), /* A <- protocol */ BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_LLDP, 1, 0), /* A != ETHERTYPE_LLDP */ BPF_STMT(BPF_RET + BPF_K, 0), /* drop packet */ - BPF_STMT(BPF_RET + BPF_K, (uint32_t) -1), /* accept packet */ + BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept packet */ }; static const struct sock_fprog fprog = { diff --git a/src/libsystemd-network/meson.build b/src/libsystemd-network/meson.build index 604cfd999..6bc4a3f54 100644 --- a/src/libsystemd-network/meson.build +++ b/src/libsystemd-network/meson.build @@ -17,6 +17,7 @@ sources = files(''' arp-util.h arp-util.c network-internal.c + network-internal.h sd-ndisc.c ndisc-internal.h ndisc-router.h @@ -42,10 +43,77 @@ sources = files(''' sd-lldp.c '''.split()) -network_internal_h = files('network-internal.h') - libsystemd_network = static_library( 'systemd-network', sources, - network_internal_h, include_directories : includes) + +libsystemd_network_includes = [includes, include_directories('.')] + +############################################################ + +tests += [ + [['src/libsystemd-network/test-dhcp-option.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-sd-dhcp-lease.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-dhcp-client.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-dhcp-server.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-ipv4ll.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-ipv4ll-manual.c'], + [libshared, + libsystemd_network], + [], [], '', 'manual'], + + [['src/libsystemd-network/test-acd.c'], + [libshared, + libsystemd_network], + [], [], '', 'manual'], + + [['src/libsystemd-network/test-ndisc-rs.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-ndisc-ra.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-dhcp6-client.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/test-lldp.c'], + [libshared, + libsystemd_network]], +] + +fuzzers += [ + [['src/libsystemd-network/fuzz-dhcp6-client.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/fuzz-dhcp-server.c'], + [libsystemd_network, + libshared]], + + [['src/libsystemd-network/fuzz-lldp.c'], + [libshared, + libsystemd_network]], + + [['src/libsystemd-network/fuzz-ndisc-rs.c'], + [libshared, + libsystemd_network]], +] diff --git a/src/libsystemd-network/ndisc-internal.h b/src/libsystemd-network/ndisc-internal.h index 65f9371b2..70b254867 100644 --- a/src/libsystemd-network/ndisc-internal.h +++ b/src/libsystemd-network/ndisc-internal.h @@ -40,5 +40,5 @@ struct sd_ndisc { #define log_ndisc_errno(error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "NDISC: " fmt, ##__VA_ARGS__) #define log_ndisc(fmt, ...) log_ndisc_errno(0, fmt, ##__VA_ARGS__) -const char* ndisc_event_to_string(sd_ndisc_event e) _const_; -sd_ndisc_event ndisc_event_from_string(const char *s) _pure_; +const char* ndisc_event_to_string(sd_ndisc_event_t e) _const_; +sd_ndisc_event_t ndisc_event_from_string(const char *s) _pure_; diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c index 3cb71dbda..c88293a92 100644 --- a/src/libsystemd-network/ndisc-router.c +++ b/src/libsystemd-network/ndisc-router.c @@ -56,7 +56,7 @@ _public_ int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *r assert_return(rt, -EINVAL); assert_return(ret_addr, -EINVAL); - if (IN6_IS_ADDR_UNSPECIFIED(&rt->address)) + if (in6_addr_is_null(&rt->address)) return -ENODATA; *ret_addr = rt->address; diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c index e4a07419e..12b73cd50 100644 --- a/src/libsystemd-network/network-internal.c +++ b/src/libsystemd-network/network-internal.c @@ -4,658 +4,15 @@ #include #include -#include "sd-id128.h" #include "sd-ndisc.h" #include "alloc-util.h" -#include "arphrd-list.h" -#include "condition.h" -#include "conf-parser.h" -#include "device-util.h" #include "dhcp-lease-internal.h" -#include "env-util.h" -#include "ether-addr-util.h" +#include "extract-word.h" #include "hexdecoct.h" #include "log.h" #include "network-internal.h" #include "parse-util.h" -#include "siphash24.h" -#include "socket-util.h" -#include "string-table.h" -#include "string-util.h" -#include "strv.h" -#include "utf8.h" -#include "util.h" - -const char *net_get_name_persistent(sd_device *device) { - const char *name, *field; - - assert(device); - - /* fetch some persistent data unique (on this machine) to this device */ - FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") - if (sd_device_get_property_value(device, field, &name) >= 0) - return name; - - return NULL; -} - -#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) - -int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) { - size_t l, sz = 0; - const char *name; - int r; - uint8_t *v; - - assert(device); - - /* net_get_name_persistent() will return one of the device names based on stable information about - * the device. If this is not available, we fall back to using the actual device name. */ - name = net_get_name_persistent(device); - if (!name && use_sysname) - (void) sd_device_get_sysname(device, &name); - if (!name) - return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), - "No stable identifying information found"); - - log_device_debug(device, "Using \"%s\" as stable identifying information", name); - l = strlen(name); - sz = sizeof(sd_id128_t) + l; - v = newa(uint8_t, sz); - - /* Fetch some persistent data unique to this machine */ - r = sd_id128_get_machine((sd_id128_t*) v); - if (r < 0) - return r; - memcpy(v + sizeof(sd_id128_t), name, l); - - /* Let's hash the machine ID plus the device name. We use - * a fixed, but originally randomly created hash key here. */ - *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); - return 0; -} - -static bool net_condition_test_strv(char * const *patterns, const char *string) { - char * const *p; - bool match = false, has_positive_rule = false; - - if (strv_isempty(patterns)) - return true; - - STRV_FOREACH(p, patterns) { - const char *q = *p; - bool invert; - - invert = *q == '!'; - q += invert; - - if (!invert) - has_positive_rule = true; - - if (string && fnmatch(q, string, 0) == 0) { - if (invert) - return false; - else - match = true; - } - } - - return has_positive_rule ? match : true; -} - -static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { - if (net_condition_test_strv(patterns, ifname)) - return true; - - char * const *p; - STRV_FOREACH(p, alternative_names) - if (net_condition_test_strv(patterns, *p)) - return true; - - return false; -} - -static int net_condition_test_property(char * const *match_property, sd_device *device) { - char * const *p; - - if (strv_isempty(match_property)) - return true; - - STRV_FOREACH(p, match_property) { - _cleanup_free_ char *key = NULL; - const char *val, *dev_val; - bool invert, v; - - invert = **p == '!'; - - val = strchr(*p + invert, '='); - if (!val) - return -EINVAL; - - key = strndup(*p + invert, val - *p - invert); - if (!key) - return -ENOMEM; - - val++; - - v = device && - sd_device_get_property_value(device, key, &dev_val) >= 0 && - fnmatch(val, dev_val, 0) == 0; - - if (invert ? v : !v) - return false; - } - - return true; -} - -static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { - [NL80211_IFTYPE_ADHOC] = "ad-hoc", - [NL80211_IFTYPE_STATION] = "station", - [NL80211_IFTYPE_AP] = "ap", - [NL80211_IFTYPE_AP_VLAN] = "ap-vlan", - [NL80211_IFTYPE_WDS] = "wds", - [NL80211_IFTYPE_MONITOR] = "monitor", - [NL80211_IFTYPE_MESH_POINT] = "mesh-point", - [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client", - [NL80211_IFTYPE_P2P_GO] = "p2p-go", - [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device", - [NL80211_IFTYPE_OCB] = "ocb", - [NL80211_IFTYPE_NAN] = "nan", -}; - -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); - -char *link_get_type_string(unsigned short iftype, sd_device *device) { - const char *t, *devtype; - char *p; - - if (device && - sd_device_get_devtype(device, &devtype) >= 0 && - !isempty(devtype)) - return strdup(devtype); - - t = arphrd_to_name(iftype); - if (!t) - return NULL; - - p = strdup(t); - if (!p) - return NULL; - - ascii_strlower(p); - return p; -} - -bool net_match_config(Set *match_mac, - Set *match_permanent_mac, - char * const *match_paths, - char * const *match_drivers, - char * const *match_iftypes, - char * const *match_names, - char * const *match_property, - char * const *match_wifi_iftype, - char * const *match_ssid, - Set *match_bssid, - sd_device *device, - const struct ether_addr *dev_mac, - const struct ether_addr *dev_permanent_mac, - const char *dev_driver, - unsigned short dev_iftype, - const char *dev_name, - char * const *alternative_names, - enum nl80211_iftype dev_wifi_iftype, - const char *dev_ssid, - const struct ether_addr *dev_bssid) { - - _cleanup_free_ char *dev_iftype_str; - const char *dev_path = NULL; - - dev_iftype_str = link_get_type_string(dev_iftype, device); - - if (device) { - const char *mac_str; - - (void) sd_device_get_property_value(device, "ID_PATH", &dev_path); - if (!dev_driver) - (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &dev_driver); - if (!dev_name) - (void) sd_device_get_sysname(device, &dev_name); - if (!dev_mac && - sd_device_get_sysattr_value(device, "address", &mac_str) >= 0) - dev_mac = ether_aton(mac_str); - } - - if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac))) - return false; - - if (match_permanent_mac && - (!dev_permanent_mac || - ether_addr_is_null(dev_permanent_mac) || - !set_contains(match_permanent_mac, dev_permanent_mac))) - return false; - - if (!net_condition_test_strv(match_paths, dev_path)) - return false; - - if (!net_condition_test_strv(match_drivers, dev_driver)) - return false; - - if (!net_condition_test_strv(match_iftypes, dev_iftype_str)) - return false; - - if (!net_condition_test_ifname(match_names, dev_name, alternative_names)) - return false; - - if (!net_condition_test_property(match_property, device)) - return false; - - if (!net_condition_test_strv(match_wifi_iftype, wifi_iftype_to_string(dev_wifi_iftype))) - return false; - - if (!net_condition_test_strv(match_ssid, dev_ssid)) - return false; - - if (match_bssid && (!dev_bssid || !set_contains(match_bssid, dev_bssid))) - return false; - - return true; -} - -int config_parse_net_condition(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) { - - ConditionType cond = ltype; - Condition **list = data, *c; - bool negate; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - *list = condition_free_list_type(*list, cond); - return 0; - } - - negate = rvalue[0] == '!'; - if (negate) - rvalue++; - - c = condition_new(cond, rvalue, false, negate); - if (!c) - return log_oom(); - - /* Drop previous assignment. */ - *list = condition_free_list_type(*list, cond); - - LIST_PREPEND(conditions, *list, c); - return 0; -} - -int config_parse_match_strv( - 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) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - *sv = strv_free(*sv); - return 0; - } - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_match_ifnames( - 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) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, 0); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Failed to parse interface name list: %s", rvalue); - return 0; - } - - if (!ifname_valid_full(word, ltype)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Interface name is not valid or too long, ignoring assignment: %s", word); - continue; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_match_property( - 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) { - - const char *p = rvalue; - char ***sv = data; - bool invert; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - invert = *p == '!'; - p += invert; - - for (;;) { - _cleanup_free_ char *word = NULL, *k = NULL; - - r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); - if (r == 0) - return 0; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - if (!env_assignment_is_valid(word)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid property or value, ignoring assignment: %s", word); - continue; - } - - if (invert) { - k = strjoin("!", word); - if (!k) - return log_oom(); - } else - k = TAKE_PTR(word); - - r = strv_consume(sv, TAKE_PTR(k)); - if (r < 0) - return log_oom(); - } -} - -int config_parse_ifalias(const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - char **s = data; - _cleanup_free_ char *n = NULL; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = strdup(rvalue); - if (!n) - return log_oom(); - - if (!ascii_is_valid(n) || strlen(n) >= IFALIASZ) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Interface alias is not ASCII clean or is too long, ignoring assignment: %s", rvalue); - return 0; - } - - if (isempty(n)) - *s = mfree(*s); - else - free_and_replace(*s, n); - - return 0; -} - -int config_parse_hwaddr(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_ struct ether_addr *n = NULL; - struct ether_addr **hwaddr = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - n = new0(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = ether_addr_from_string(rvalue, n); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address, ignoring assignment: %s", rvalue); - return 0; - } - - free_and_replace(*hwaddr, n); - - return 0; -} - -int config_parse_hwaddrs(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_set_free_free_ Set *s = NULL; - const char *p = rvalue; - Set **hwaddrs = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - if (isempty(rvalue)) { - /* Empty assignment resets the list */ - *hwaddrs = set_free_free(*hwaddrs); - return 0; - } - - s = set_new(ðer_addr_hash_ops); - if (!s) - return log_oom(); - - for (;;) { - _cleanup_free_ char *word = NULL; - _cleanup_free_ struct ether_addr *n = NULL; - - r = extract_first_word(&p, &word, NULL, 0); - if (r == 0) - break; - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - n = new(struct ether_addr, 1); - if (!n) - return log_oom(); - - r = ether_addr_from_string(word, n); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address, ignoring: %s", word); - continue; - } - - r = set_put(s, n); - if (r < 0) - return log_oom(); - if (r > 0) - n = NULL; /* avoid cleanup */ - } - - r = set_ensure_allocated(hwaddrs, ðer_addr_hash_ops); - if (r < 0) - return log_oom(); - - r = set_move(*hwaddrs, s); - if (r < 0) - return log_oom(); - - return 0; -} - -int config_parse_bridge_port_priority( - 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) { - - uint16_t i; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = safe_atou16(rvalue, &i); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Failed to parse bridge port priority, ignoring: %s", rvalue); - return 0; - } - - if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Bridge port priority is larger than maximum %u, ignoring: %s", LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue); - return 0; - } - - *((uint16_t *)data) = i; - - return 0; -} size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, diff --git a/src/libsystemd-network/network-internal.h b/src/libsystemd-network/network-internal.h index 5dae5ab30..e5b853c0c 100644 --- a/src/libsystemd-network/network-internal.h +++ b/src/libsystemd-network/network-internal.h @@ -1,53 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include #include +#include -#include "sd-device.h" #include "sd-dhcp-lease.h" -#include "conf-parser.h" -#include "set.h" -#include "strv.h" - -#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 -#define LINK_BRIDGE_PORT_PRIORITY_MAX 63 - -char *link_get_type_string(unsigned short iftype, sd_device *device); -bool net_match_config(Set *match_mac, - Set *match_permanent_mac, - char * const *match_paths, - char * const *match_drivers, - char * const *match_iftypes, - char * const *match_names, - char * const *match_property, - char * const *match_wifi_iftype, - char * const *match_ssid, - Set *match_bssid, - sd_device *device, - const struct ether_addr *dev_mac, - const struct ether_addr *dev_permanent_mac, - const char *dev_driver, - unsigned short dev_iftype, - const char *dev_name, - char * const *alternative_names, - enum nl80211_iftype dev_wifi_iftype, - const char *dev_ssid, - const struct ether_addr *dev_bssid); - -CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); -CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); -CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); -CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); -CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); -CONFIG_PARSER_PROTOTYPE(config_parse_match_property); -CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); -CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); - -int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result); -const char *net_get_name_persistent(sd_device *device); - size_t serialize_in_addrs(FILE *f, const struct in_addr *addresses, size_t size, diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index d472fcd94..fb94fdc88 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -29,6 +29,7 @@ #include "sort-util.h" #include "string-util.h" #include "strv.h" +#include "time-util.h" #include "utf8.h" #include "web-util.h" @@ -38,6 +39,9 @@ #define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) #define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) +#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report + * transient failure. */ + typedef struct sd_dhcp_client_id { uint8_t type; union { @@ -95,6 +99,9 @@ struct sd_dhcp_client { uint32_t fallback_lease_lifetime; uint32_t xid; usec_t start_time; + usec_t t1_time; + usec_t t2_time; + usec_t expire_time; uint64_t attempt; uint64_t max_attempts; OrderedHashmap *extra_options; @@ -267,7 +274,6 @@ int sd_dhcp_client_set_request_address( } int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { - assert_return(client, -EINVAL); assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); assert_return(ifindex > 0, -EINVAL); @@ -341,13 +347,14 @@ int sd_dhcp_client_get_client_id( assert_return(data, -EINVAL); assert_return(data_len, -EINVAL); - *type = 0; - *data = NULL; - *data_len = 0; if (client->client_id_len) { *type = client->client_id.type; *data = client->client_id.raw.data; *data_len = client->client_id_len - sizeof(client->client_id.type); + } else { + *type = 0; + *data = NULL; + *data_len = 0; } return 0; @@ -537,7 +544,7 @@ int sd_dhcp_client_set_hostname( /* Make sure hostnames qualify as DNS and as Linux hostnames */ if (hostname && - !(hostname_is_valid(hostname, false) && dns_name_is_valid(hostname) > 0)) + !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0)) return -EINVAL; return free_and_strdup(&client->hostname, hostname); @@ -622,11 +629,7 @@ int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) { assert_return(client, -EINVAL); assert_return(v, -EINVAL); - r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v); + r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v); if (r < 0) return r; @@ -728,6 +731,37 @@ static void client_stop(sd_dhcp_client *client, int error) { client_initialize(client); } +/* RFC2131 section 4.1: + * retransmission delays should include -1 to +1 sec of random 'fuzz'. */ +#define RFC2131_RANDOM_FUZZ \ + ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC) + +/* RFC2131 section 4.1: + * for retransmission delays, timeout should start at 4s then double + * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added. + * This assumes the first call will be using attempt 1. */ +static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) { + usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC; + + return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ); +} + +/* RFC2131 section 4.4.5: + * T1 defaults to (0.5 * duration_of_lease). + * T2 defaults to (0.875 * duration_of_lease). */ +#define T1_DEFAULT(lifetime) ((lifetime) / 2) +#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8) + +/* RFC2131 section 4.4.5: + * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) + * and one-half of the remaining lease time (in REBINDING state), down to a minimum + * of 60 seconds. + * Note that while the default T1/T2 initial times do have random 'fuzz' applied, + * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */ +static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) { + return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC); +} + static int cmp_uint8(const uint8_t *a, const uint8_t *b) { return CMP(*a, *b); } @@ -1191,9 +1225,8 @@ static int client_timeout_resend( sd_dhcp_client *client = userdata; DHCP_CLIENT_DONT_DESTROY(client); - usec_t next_timeout = 0; + usec_t next_timeout; uint64_t time_now; - uint32_t time_left; int r; assert(s); @@ -1207,22 +1240,11 @@ static int client_timeout_resend( switch (client->state) { case DHCP_STATE_RENEWING: - - time_left = (client->lease->t2 - client->lease->t1) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; - + next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time); break; case DHCP_STATE_REBINDING: - - time_left = (client->lease->lifetime - client->lease->t2) / 2; - if (time_left < 60) - time_left = 60; - - next_timeout = time_now + time_left * USEC_PER_SEC; + next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time); break; case DHCP_STATE_REBOOTING: @@ -1234,32 +1256,29 @@ static int client_timeout_resend( r = client_start(client); if (r < 0) goto error; - else { - log_dhcp_client(client, "REBOOTED"); - return 0; - } + + log_dhcp_client(client, "REBOOTED"); + return 0; case DHCP_STATE_INIT: case DHCP_STATE_INIT_REBOOT: case DHCP_STATE_SELECTING: case DHCP_STATE_REQUESTING: case DHCP_STATE_BOUND: - - if (client->attempt < client->max_attempts) - client->attempt++; - else + if (client->attempt >= client->max_attempts) goto error; - next_timeout = time_now + ((UINT64_C(1) << MIN(client->attempt, (uint64_t) 6)) - 1) * USEC_PER_SEC; - + client->attempt++; + next_timeout = client_compute_request_timeout(time_now, client->attempt); break; case DHCP_STATE_STOPPED: r = -EINVAL; goto error; - } - next_timeout += (random_u32() & 0x1fffff); + default: + assert_not_reached("Unhandled choice"); + } r = event_reset_time(client->event, &client->timeout_resend, clock_boottime_or_monotonic(), @@ -1299,12 +1318,10 @@ static int client_timeout_resend( client->state = DHCP_STATE_REBOOTING; client->request_sent = time_now; - break; case DHCP_STATE_REBOOTING: case DHCP_STATE_BOUND: - break; case DHCP_STATE_STOPPED: @@ -1312,6 +1329,9 @@ static int client_timeout_resend( goto error; } + if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS) + client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE); + return 0; error: @@ -1625,25 +1645,8 @@ static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t le return r; } -static uint64_t client_compute_timeout(sd_dhcp_client *client, uint32_t lifetime, double factor) { - assert(client); - assert(client->request_sent); - assert(lifetime > 0); - - if (lifetime > 3) - lifetime -= 3; - else - lifetime = 0; - - return client->request_sent + (lifetime * USEC_PER_SEC * factor) + - + (random_u32() & 0x1fffff); -} - static int client_set_lease_timeouts(sd_dhcp_client *client) { usec_t time_now; - uint64_t lifetime_timeout; - uint64_t t2_timeout; - uint64_t t1_timeout; char time_string[FORMAT_TIMESPAN_MAX]; int r; @@ -1666,93 +1669,76 @@ static int client_set_lease_timeouts(sd_dhcp_client *client) { return r; assert(client->request_sent <= time_now); - /* convert the various timeouts from relative (secs) to absolute (usecs) */ - lifetime_timeout = client_compute_timeout(client, client->lease->lifetime, 1); - if (client->lease->t1 > 0 && client->lease->t2 > 0) { - /* both T1 and T2 are given */ - if (client->lease->t1 < client->lease->t2 && - client->lease->t2 < client->lease->lifetime) { - /* they are both valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - } else { - /* discard both */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - } - } else if (client->lease->t2 > 0 && client->lease->t2 < client->lease->lifetime) { - /* only T2 is given, and it is valid */ - t2_timeout = client_compute_timeout(client, client->lease->t2, 1); - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - if (t2_timeout <= t1_timeout) { - /* the computed T1 would be invalid, so discard T2 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } - } else if (client->lease->t1 > 0 && client->lease->t1 < client->lease->lifetime) { - /* only T1 is given, and it is valid */ - t1_timeout = client_compute_timeout(client, client->lease->t1, 1); - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - if (t2_timeout <= t1_timeout) { - /* the computed T2 would be invalid, so discard T1 */ - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t2 = client->lease->lifetime / 2; - } - } else { - /* fall back to the default timeouts */ - t1_timeout = client_compute_timeout(client, client->lease->lifetime, 0.5); - client->lease->t1 = client->lease->lifetime / 2; - t2_timeout = client_compute_timeout(client, client->lease->lifetime, 7.0 / 8.0); - client->lease->t2 = (client->lease->lifetime * 7) / 8; - } + /* verify that 0 < t2 < lifetime */ + if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime) + client->lease->t2 = T2_DEFAULT(client->lease->lifetime); + /* verify that 0 < t1 < lifetime */ + if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2) + client->lease->t1 = T1_DEFAULT(client->lease->lifetime); + /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check + * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT + * guarantees t1 < t2. */ + if (client->lease->t1 >= client->lease->t2) + client->lease->t2 = T2_DEFAULT(client->lease->lifetime); + + client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC; + client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC; + client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC; + + /* RFC2131 section 4.4.5: + * Times T1 and T2 SHOULD be chosen with some random "fuzz". + * Since the RFC doesn't specify here the exact 'fuzz' to use, + * we use the range from section 4.1: -1 to +1 sec. */ + client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ); + client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ); + + /* after fuzzing, ensure t2 is still >= t1 */ + client->t2_time = MAX(client->t1_time, client->t2_time); /* arm lifetime timeout */ r = event_reset_time(client->event, &client->timeout_expire, clock_boottime_or_monotonic(), - lifetime_timeout, 10 * USEC_PER_MSEC, + client->expire_time, 10 * USEC_PER_MSEC, client_timeout_expire, client, client->event_priority, "dhcp4-lifetime", true); if (r < 0) return r; - log_dhcp_client(client, "lease expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, lifetime_timeout - time_now, USEC_PER_SEC)); - /* don't arm earlier timeouts if this has already expired */ - if (lifetime_timeout <= time_now) + if (client->expire_time <= time_now) return 0; + log_dhcp_client(client, "lease expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->expire_time - time_now, USEC_PER_SEC)); + /* arm T2 timeout */ r = event_reset_time(client->event, &client->timeout_t2, clock_boottime_or_monotonic(), - t2_timeout, 10 * USEC_PER_MSEC, + client->t2_time, 10 * USEC_PER_MSEC, client_timeout_t2, client, client->event_priority, "dhcp4-t2-timeout", true); if (r < 0) return r; - log_dhcp_client(client, "T2 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t2_timeout - time_now, USEC_PER_SEC)); - /* don't arm earlier timeout if this has already expired */ - if (t2_timeout <= time_now) + if (client->t2_time <= time_now) return 0; + log_dhcp_client(client, "T2 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t2_time - time_now, USEC_PER_SEC)); + /* arm T1 timeout */ r = event_reset_time(client->event, &client->timeout_t1, clock_boottime_or_monotonic(), - t1_timeout, 10 * USEC_PER_MSEC, + client->t1_time, 10 * USEC_PER_MSEC, client_timeout_t1, client, client->event_priority, "dhcp4-t1-timer", true); if (r < 0) return r; - log_dhcp_client(client, "T1 expires in %s", - format_timespan(time_string, FORMAT_TIMESPAN_MAX, t1_timeout - time_now, USEC_PER_SEC)); + if (client->t1_time > time_now) + log_dhcp_client(client, "T1 expires in %s", + format_timespan(time_string, FORMAT_TIMESPAN_MAX, client->t1_time - time_now, USEC_PER_SEC)); return 0; } @@ -2243,7 +2229,7 @@ int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { .mtu = DHCP_DEFAULT_MIN_SIZE, .port = DHCP_PORT_CLIENT, .anonymize = !!anonymize, - .max_attempts = (uint64_t) -1, + .max_attempts = UINT64_MAX, .ip_service_type = -1, }; /* NOTE: this could be moved to a function. */ diff --git a/src/libsystemd-network/sd-dhcp-lease.c b/src/libsystemd-network/sd-dhcp-lease.c index 8a138ff4b..6d88c88e6 100644 --- a/src/libsystemd-network/sd-dhcp-lease.c +++ b/src/libsystemd-network/sd-dhcp-lease.c @@ -19,6 +19,7 @@ #include "env-file.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" @@ -98,7 +99,7 @@ int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { int sd_dhcp_lease_get_servers( sd_dhcp_lease *lease, - sd_dhcp_lease_server_type what, + sd_dhcp_lease_server_type_t what, const struct in_addr **addr) { assert_return(lease, -EINVAL); @@ -280,7 +281,7 @@ static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { free(lease->hostname); free(lease->domainname); - for (sd_dhcp_lease_server_type i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) + for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) free(lease->servers[i].addr); free(lease->static_route); @@ -868,7 +869,7 @@ int dhcp_lease_new(sd_dhcp_lease **ret) { } int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { - _cleanup_free_ char *temp_path = NULL; + _cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; struct sd_dhcp_raw_option *option; struct in_addr address; @@ -888,7 +889,7 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { r = fopen_temporary(lease_file, &f, &temp_path); if (r < 0) - goto fail; + return r; (void) fchmod(fileno(f), 0644); @@ -991,10 +992,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { _cleanup_free_ char *client_id_hex = NULL; client_id_hex = hexmem(client_id, client_id_len); - if (!client_id_hex) { - r = -ENOMEM; - goto fail; - } + if (!client_id_hex) + return -ENOMEM; fprintf(f, "CLIENTID=%s\n", client_id_hex); } @@ -1003,10 +1002,8 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { _cleanup_free_ char *option_hex = NULL; option_hex = hexmem(data, data_len); - if (!option_hex) { - r = -ENOMEM; - goto fail; - } + if (!option_hex) + return -ENOMEM; fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); } @@ -1016,29 +1013,23 @@ int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { xsprintf(key, "OPTION_%" PRIu8, option->tag); r = serialize_dhcp_option(f, key, option->data, option->length); if (r < 0) - goto fail; + return r; } r = fflush_and_check(f); if (r < 0) - goto fail; + return r; - if (rename(temp_path, lease_file) < 0) { - r = -errno; - goto fail; - } + r = conservative_rename(temp_path, lease_file); + if (r < 0) + return r; + + temp_path = mfree(temp_path); return 0; - -fail: - if (temp_path) - (void) unlink(temp_path); - - return log_error_errno(r, "Failed to save lease data %s: %m", lease_file); } int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { - _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; _cleanup_free_ char *address = NULL, @@ -1266,13 +1257,13 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { } if (client_id_hex) { - r = unhexmem(client_id_hex, (size_t) -1, &lease->client_id, &lease->client_id_len); + r = unhexmem(client_id_hex, SIZE_MAX, &lease->client_id, &lease->client_id_len); if (r < 0) log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); } if (vendor_specific_hex) { - r = unhexmem(vendor_specific_hex, (size_t) -1, &lease->vendor_specific, &lease->vendor_specific_len); + r = unhexmem(vendor_specific_hex, SIZE_MAX, &lease->vendor_specific, &lease->vendor_specific_len); if (r < 0) log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); } @@ -1284,7 +1275,7 @@ int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { if (!options[i]) continue; - r = unhexmem(options[i], (size_t) -1, &data, &len); + r = unhexmem(options[i], SIZE_MAX, &data, &len); if (r < 0) { log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); continue; diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index dfced720c..2b1384cff 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -15,6 +15,7 @@ #include "fd-util.h" #include "in-addr-util.h" #include "io-util.h" +#include "ordered-set.h" #include "siphash24.h" #include "string-util.h" #include "unaligned.h" @@ -148,13 +149,13 @@ static sd_dhcp_server *dhcp_server_free(sd_dhcp_server *server) { free(server->timezone); - for (sd_dhcp_lease_server_type i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) + for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) free(server->servers[i].addr); hashmap_free(server->leases_by_client_id); - ordered_hashmap_free(server->extra_options); - ordered_hashmap_free(server->vendor_options); + ordered_set_free(server->extra_options); + ordered_set_free(server->vendor_options); free(server->bound_leases); return mfree(server); @@ -424,66 +425,23 @@ static int server_message_init(sd_dhcp_server *server, DHCPPacket **ret, return 0; } -static int server_send_offer(sd_dhcp_server *server, DHCPRequest *req, - be32_t address) { - _cleanup_free_ DHCPPacket *packet = NULL; - size_t offset; - be32_t lease_time; - int r; - - r = server_message_init(server, &packet, DHCP_OFFER, &offset, req); - if (r < 0) - return r; - - packet->dhcp.yiaddr = address; - - lease_time = htobe32(req->lifetime); - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME, 4, - &lease_time); - if (r < 0) - return r; - - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_SUBNET_MASK, 4, &server->netmask); - if (r < 0) - return r; - - if (server->emit_router) { - r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_ROUTER, 4, &server->address); - if (r < 0) - return r; - } - - r = dhcp_server_send_packet(server, req, packet, DHCP_OFFER, offset); - if (r < 0) - return r; - - return 0; -} - -static int server_send_ack( +static int server_send_offer_or_ack( sd_dhcp_server *server, DHCPRequest *req, - be32_t address) { - - static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = { - [SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER, - [SD_DHCP_LEASE_NTP] = SD_DHCP_OPTION_NTP_SERVER, - [SD_DHCP_LEASE_SIP] = SD_DHCP_OPTION_SIP_SERVER, - [SD_DHCP_LEASE_POP3] = SD_DHCP_OPTION_POP3_SERVER, - [SD_DHCP_LEASE_SMTP] = SD_DHCP_OPTION_SMTP_SERVER, - [SD_DHCP_LEASE_LPR] = SD_DHCP_OPTION_LPR_SERVER, - }; + be32_t address, + uint8_t type) { _cleanup_free_ DHCPPacket *packet = NULL; - be32_t lease_time; sd_dhcp_option *j; + be32_t lease_time; size_t offset; int r; - r = server_message_init(server, &packet, DHCP_ACK, &offset, req); + assert(server); + assert(req); + assert(IN_SET(type, DHCP_OFFER, DHCP_ACK)); + + r = server_message_init(server, &packet, type, &offset, req); if (r < 0) return r; @@ -508,46 +466,57 @@ static int server_send_ack( return r; } - for (sd_dhcp_lease_server_type k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++) { + if (type == DHCP_ACK) { + static const uint8_t option_map[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = { + [SD_DHCP_LEASE_DNS] = SD_DHCP_OPTION_DOMAIN_NAME_SERVER, + [SD_DHCP_LEASE_NTP] = SD_DHCP_OPTION_NTP_SERVER, + [SD_DHCP_LEASE_SIP] = SD_DHCP_OPTION_SIP_SERVER, + [SD_DHCP_LEASE_POP3] = SD_DHCP_OPTION_POP3_SERVER, + [SD_DHCP_LEASE_SMTP] = SD_DHCP_OPTION_SMTP_SERVER, + [SD_DHCP_LEASE_LPR] = SD_DHCP_OPTION_LPR_SERVER, + }; - if (server->servers[k].size <= 0) - continue; + for (sd_dhcp_lease_server_type_t k = 0; k < _SD_DHCP_LEASE_SERVER_TYPE_MAX; k++) { + if (server->servers[k].size <= 0) + continue; - r = dhcp_option_append( - &packet->dhcp, req->max_optlen, &offset, 0, - option_map[k], - sizeof(struct in_addr) * server->servers[k].size, server->servers[k].addr); - if (r < 0) - return r; + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + option_map[k], + sizeof(struct in_addr) * server->servers[k].size, + server->servers[k].addr); + if (r < 0) + return r; + } + + + if (server->timezone) { + r = dhcp_option_append( + &packet->dhcp, req->max_optlen, &offset, 0, + SD_DHCP_OPTION_NEW_TZDB_TIMEZONE, + strlen(server->timezone), server->timezone); + if (r < 0) + return r; + } } - - if (server->timezone) { - r = dhcp_option_append( - &packet->dhcp, req->max_optlen, &offset, 0, - SD_DHCP_OPTION_NEW_TZDB_TIMEZONE, - strlen(server->timezone), server->timezone); - if (r < 0) - return r; - } - - ORDERED_HASHMAP_FOREACH(j, server->extra_options) { + ORDERED_SET_FOREACH(j, server->extra_options) { r = dhcp_option_append(&packet->dhcp, req->max_optlen, &offset, 0, j->option, j->length, j->data); if (r < 0) return r; } - if (!ordered_hashmap_isempty(server->vendor_options)) { + if (!ordered_set_isempty(server->vendor_options)) { r = dhcp_option_append( &packet->dhcp, req->max_optlen, &offset, 0, SD_DHCP_OPTION_VENDOR_SPECIFIC, - ordered_hashmap_size(server->vendor_options), server->vendor_options); + ordered_set_size(server->vendor_options), server->vendor_options); if (r < 0) return r; } - r = dhcp_server_send_packet(server, req, packet, DHCP_ACK, offset); + r = dhcp_server_send_packet(server, req, packet, type, offset); if (r < 0) return r; @@ -648,12 +617,12 @@ static int parse_request(uint8_t code, uint8_t len, const void *option, void *us return 0; } -static void dhcp_request_free(DHCPRequest *req) { +static DHCPRequest* dhcp_request_free(DHCPRequest *req) { if (!req) - return; + return NULL; free(req->client_id.data); - free(req); + return mfree(req); } DEFINE_TRIVIAL_CLEANUP_FUNC(DHCPRequest*, dhcp_request_free); @@ -782,7 +751,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, /* no free addresses left */ return 0; - r = server_send_offer(server, req, address); + r = server_send_offer_or_ack(server, req, address, DHCP_OFFER); if (r < 0) /* this only fails on critical errors */ return log_dhcp_server_errno(server, r, "Could not send offer: %m"); @@ -885,7 +854,7 @@ int dhcp_server_handle_message(sd_dhcp_server *server, DHCPMessage *message, lease->expiration = req->lifetime * USEC_PER_SEC + time_now; - r = server_send_ack(server, req, address); + r = server_send_offer_or_ack(server, req, address, DHCP_ACK); if (r < 0) { /* this only fails on critical errors */ log_dhcp_server_errno(server, r, "Could not send ack: %m"); @@ -1056,13 +1025,12 @@ int sd_dhcp_server_start(sd_dhcp_server *server) { } int sd_dhcp_server_forcerenew(sd_dhcp_server *server) { - unsigned i; int r = 0; assert_return(server, -EINVAL); assert(server->bound_leases); - for (i = 0; i < server->pool_size; i++) { + for (uint32_t i = 0; i < server->pool_size; i++) { DHCPLease *lease = server->bound_leases[i]; if (!lease || lease == &server->invalid_lease) @@ -1118,7 +1086,7 @@ int sd_dhcp_server_set_default_lease_time(sd_dhcp_server *server, uint32_t t) { int sd_dhcp_server_set_servers( sd_dhcp_server *server, - sd_dhcp_lease_server_type what, + sd_dhcp_lease_server_type_t what, const struct in_addr addresses[], size_t n_addresses) { @@ -1181,11 +1149,7 @@ int sd_dhcp_server_add_option(sd_dhcp_server *server, sd_dhcp_option *v) { assert_return(server, -EINVAL); assert_return(v, -EINVAL); - r = ordered_hashmap_ensure_allocated(&server->extra_options, &dhcp_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(server->extra_options, UINT_TO_PTR(v->option), v); + r = ordered_set_ensure_put(&server->extra_options, &dhcp_option_hash_ops, v); if (r < 0) return r; @@ -1199,11 +1163,7 @@ int sd_dhcp_server_add_vendor_option(sd_dhcp_server *server, sd_dhcp_option *v) assert_return(server, -EINVAL); assert_return(v, -EINVAL); - r = ordered_hashmap_ensure_allocated(&server->vendor_options, &dhcp_option_hash_ops); - if (r < 0) - return -ENOMEM; - - r = ordered_hashmap_put(server->vendor_options, v, v); + r = ordered_set_ensure_put(&server->vendor_options, &dhcp_option_hash_ops, v); if (r < 0) return r; diff --git a/src/libsystemd-network/sd-dhcp6-client.c b/src/libsystemd-network/sd-dhcp6-client.c index d5020519c..410bfda10 100644 --- a/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libsystemd-network/sd-dhcp6-client.c @@ -21,10 +21,10 @@ #include "hexdecoct.h" #include "hostname-util.h" #include "in-addr-util.h" -#include "network-internal.h" #include "random-util.h" #include "socket-util.h" #include "string-table.h" +#include "strv.h" #include "util.h" #include "web-util.h" @@ -157,7 +157,6 @@ int sd_dhcp6_client_set_callback( } int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) { - assert_return(client, -EINVAL); assert_return(ifindex > 0, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -172,7 +171,7 @@ int sd_dhcp6_client_set_local_address( assert_return(client, -EINVAL); assert_return(local_address, -EINVAL); - assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) local_address) > 0, -EINVAL); + assert_return(in6_addr_is_link_local(local_address) > 0, -EINVAL); assert_return(IN_SET(client->state, DHCP6_STATE_STOPPED), -EBUSY); @@ -235,11 +234,7 @@ int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option * assert_return(client, -EINVAL); assert_return(v, -EINVAL); - r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp6_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(client->vendor_options, v, v); + r = ordered_hashmap_ensure_put(&client->vendor_options, &dhcp6_option_hash_ops, v, v); if (r < 0) return r; @@ -351,6 +346,7 @@ int sd_dhcp6_client_duid_as_string( assert_return(client, -EINVAL); assert_return(client->duid_len > 0, -ENODATA); + assert_return(duid, -EINVAL); v = dhcp6_duid_type_to_string(be16toh(client->duid.type)); if (v) { @@ -407,7 +403,7 @@ int sd_dhcp6_client_set_fqdn( /* Make sure FQDN qualifies as DNS and as Linux hostname */ if (fqdn && - !(hostname_is_valid(fqdn, false) && dns_name_is_valid(fqdn) > 0)) + !(hostname_is_valid(fqdn, 0) && dns_name_is_valid(fqdn) > 0)) return -EINVAL; return free_and_strdup(&client->fqdn, fqdn); @@ -454,7 +450,6 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) } int sd_dhcp6_client_set_request_mud_url(sd_dhcp6_client *client, const char *mudurl) { - assert_return(client, -EINVAL); assert_return(client->state == DHCP6_STATE_STOPPED, -EBUSY); assert_return(mudurl, -EINVAL); @@ -568,11 +563,7 @@ int sd_dhcp6_client_add_option(sd_dhcp6_client *client, sd_dhcp6_option *v) { assert_return(client, -EINVAL); assert_return(v, -EINVAL); - r = ordered_hashmap_ensure_allocated(&client->extra_options, &dhcp6_option_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(client->extra_options, UINT_TO_PTR(v->option), v); + r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp6_option_hash_ops, UINT_TO_PTR(v->option), v); if (r < 0) return r; @@ -707,12 +698,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->ia_pd, &client->hint_pd_prefix); + r = dhcp6_option_append_pd(&opt, &optlen, &client->ia_pd, &client->hint_pd_prefix); if (r < 0) return r; - - opt += r; - optlen -= r; } break; @@ -771,12 +759,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD) && client->lease->pd.addresses) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); + r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL); if (r < 0) return r; - - opt += r; - optlen -= r; } break; @@ -823,12 +808,9 @@ static int client_send_message(sd_dhcp6_client *client, usec_t time_now) { } if (FLAGS_SET(client->request, DHCP6_REQUEST_IA_PD)) { - r = dhcp6_option_append_pd(opt, optlen, &client->lease->pd, NULL); + r = dhcp6_option_append_pd(&opt, &optlen, &client->lease->pd, NULL); if (r < 0) return r; - - opt += r; - optlen -= r; } break; @@ -1702,7 +1684,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { assert_return(client, -EINVAL); assert_return(client->event, -EINVAL); assert_return(client->ifindex > 0, -EINVAL); - assert_return(in_addr_is_link_local(AF_INET6, (const union in_addr_union *) &client->local_address) > 0, -EINVAL); + assert_return(in6_addr_is_link_local(&client->local_address) > 0, -EINVAL); if (!IN_SET(client->state, DHCP6_STATE_STOPPED)) return -EBUSY; diff --git a/src/libsystemd-network/sd-ipv4acd.c b/src/libsystemd-network/sd-ipv4acd.c index 2e1e46c1c..defd23d85 100644 --- a/src/libsystemd-network/sd-ipv4acd.c +++ b/src/libsystemd-network/sd-ipv4acd.c @@ -16,10 +16,12 @@ #include "ether-addr-util.h" #include "event-util.h" #include "fd-util.h" +#include "format-util.h" #include "in-addr-util.h" -#include "list.h" +#include "log-link.h" #include "random-util.h" #include "siphash24.h" +#include "string-table.h" #include "string-util.h" #include "time-util.h" @@ -44,7 +46,7 @@ typedef enum IPv4ACDState { IPV4ACD_STATE_ANNOUNCING, IPV4ACD_STATE_RUNNING, _IPV4ACD_STATE_MAX, - _IPV4ACD_STATE_INVALID = -1 + _IPV4ACD_STATE_INVALID = -EINVAL, } IPv4ACDState; struct sd_ipv4acd { @@ -54,6 +56,7 @@ struct sd_ipv4acd { int ifindex; int fd; + char ifname[IF_NAMESIZE + 1]; unsigned n_iteration; unsigned n_conflict; @@ -72,13 +75,30 @@ struct sd_ipv4acd { void* userdata; }; -#define log_ipv4acd_errno(acd, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4ACD: " fmt, ##__VA_ARGS__) -#define log_ipv4acd(acd, fmt, ...) log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) +#define log_ipv4acd_errno(acd, error, fmt, ...) \ + log_interface_full_errno(sd_ipv4acd_get_ifname(acd), LOG_DEBUG, error, "IPV4ACD: " fmt, ##__VA_ARGS__) +#define log_ipv4acd(acd, fmt, ...) \ + log_ipv4acd_errno(acd, 0, fmt, ##__VA_ARGS__) + +static const char * const ipv4acd_state_table[_IPV4ACD_STATE_MAX] = { + [IPV4ACD_STATE_INIT] = "init", + [IPV4ACD_STATE_STARTED] = "started", + [IPV4ACD_STATE_WAITING_PROBE] = "waiting-probe", + [IPV4ACD_STATE_PROBING] = "probing", + [IPV4ACD_STATE_WAITING_ANNOUNCE] = "waiting-announce", + [IPV4ACD_STATE_ANNOUNCING] = "announcing", + [IPV4ACD_STATE_RUNNING] = "running", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(ipv4acd_state, IPv4ACDState); static void ipv4acd_set_state(sd_ipv4acd *acd, IPv4ACDState st, bool reset_counter) { assert(acd); assert(st < _IPV4ACD_STATE_MAX); + if (st != acd->state) + log_ipv4acd(acd, "%s -> %s", ipv4acd_state_to_string(acd->state), ipv4acd_state_to_string(st)); + if (st == acd->state && !reset_counter) acd->n_iteration++; else { @@ -378,15 +398,35 @@ fail: } int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int ifindex) { + char ifname[IF_NAMESIZE + 1]; + assert_return(acd, -EINVAL); assert_return(ifindex > 0, -EINVAL); assert_return(acd->state == IPV4ACD_STATE_INIT, -EBUSY); + if (!format_ifname(ifindex, ifname)) + return -ENODEV; + + strcpy(acd->ifname, ifname); acd->ifindex = ifindex; return 0; } +int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd) { + if (!acd) + return -EINVAL; + + return acd->ifindex; +} + +const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd) { + if (!acd) + return NULL; + + return empty_to_null(acd->ifname); +} + int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr) { assert_return(acd, -EINVAL); assert_return(addr, -EINVAL); diff --git a/src/libsystemd-network/sd-ipv4ll.c b/src/libsystemd-network/sd-ipv4ll.c index 09f2bda7f..a83c9b06d 100644 --- a/src/libsystemd-network/sd-ipv4ll.c +++ b/src/libsystemd-network/sd-ipv4ll.c @@ -15,7 +15,7 @@ #include "alloc-util.h" #include "ether-addr-util.h" #include "in-addr-util.h" -#include "list.h" +#include "log-link.h" #include "random-util.h" #include "siphash24.h" #include "sparse-endian.h" @@ -49,8 +49,10 @@ struct sd_ipv4ll { void* userdata; }; -#define log_ipv4ll_errno(ll, error, fmt, ...) log_internal(LOG_DEBUG, error, PROJECT_FILE, __LINE__, __func__, "IPV4LL: " fmt, ##__VA_ARGS__) -#define log_ipv4ll(ll, fmt, ...) log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) +#define log_ipv4ll_errno(ll, error, fmt, ...) \ + log_interface_full_errno(sd_ipv4ll_get_ifname(ll), LOG_DEBUG, error, "IPV4LL: " fmt, ##__VA_ARGS__) +#define log_ipv4ll(ll, fmt, ...) \ + log_ipv4ll_errno(ll, 0, fmt, ##__VA_ARGS__) static void ipv4ll_on_acd(sd_ipv4acd *ll, int event, void *userdata); @@ -103,6 +105,20 @@ int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { return sd_ipv4acd_set_ifindex(ll->acd, ifindex); } +int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) { + if (!ll) + return -EINVAL; + + return sd_ipv4acd_get_ifindex(ll->acd); +} + +const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll) { + if (!ll) + return NULL; + + return sd_ipv4acd_get_ifname(ll->acd); +} + int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { int r; @@ -170,7 +186,7 @@ int sd_ipv4ll_is_running(sd_ipv4ll *ll) { static bool ipv4ll_address_is_valid(const struct in_addr *address) { assert(address); - if (!in_addr_is_link_local(AF_INET, (const union in_addr_union *) address)) + if (!in4_addr_is_link_local(address)) return false; return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); diff --git a/src/libsystemd-network/sd-lldp.c b/src/libsystemd-network/sd-lldp.c index 8b666522c..3c0285df4 100644 --- a/src/libsystemd-network/sd-lldp.c +++ b/src/libsystemd-network/sd-lldp.c @@ -21,13 +21,13 @@ #define LLDP_DEFAULT_NEIGHBORS_MAX 128U static const char * const lldp_event_table[_SD_LLDP_EVENT_MAX] = { - [SD_LLDP_EVENT_ADDED] = "added", - [SD_LLDP_EVENT_REMOVED] = "removed", + [SD_LLDP_EVENT_ADDED] = "added", + [SD_LLDP_EVENT_REMOVED] = "removed", [SD_LLDP_EVENT_UPDATED] = "updated", [SD_LLDP_EVENT_REFRESHED] = "refreshed", }; -DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event); +DEFINE_STRING_TABLE_LOOKUP(lldp_event, sd_lldp_event_t); static void lldp_flush_neighbors(sd_lldp *lldp) { assert(lldp); @@ -35,7 +35,7 @@ static void lldp_flush_neighbors(sd_lldp *lldp) { hashmap_clear(lldp->neighbor_by_id); } -static void lldp_callback(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n) { +static void lldp_callback(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n) { assert(lldp); assert(event >= 0 && event < _SD_LLDP_EVENT_MAX); @@ -373,7 +373,7 @@ _public_ int sd_lldp_new(sd_lldp **ret) { .n_ref = 1, .fd = -1, .neighbors_max = LLDP_DEFAULT_NEIGHBORS_MAX, - .capability_mask = (uint16_t) -1, + .capability_mask = UINT16_MAX, }; lldp->neighbor_by_id = hashmap_new(&lldp_neighbor_hash_ops); diff --git a/src/libsystemd-network/sd-ndisc.c b/src/libsystemd-network/sd-ndisc.c index db7ada60a..8f0400175 100644 --- a/src/libsystemd-network/sd-ndisc.c +++ b/src/libsystemd-network/sd-ndisc.c @@ -28,9 +28,9 @@ static const char * const ndisc_event_table[_SD_NDISC_EVENT_MAX] = { [SD_NDISC_EVENT_ROUTER] = "router", }; -DEFINE_STRING_TABLE_LOOKUP(ndisc_event, sd_ndisc_event); +DEFINE_STRING_TABLE_LOOKUP(ndisc_event, sd_ndisc_event_t); -static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event event, sd_ndisc_router *rt) { +static void ndisc_callback(sd_ndisc *ndisc, sd_ndisc_event_t event, sd_ndisc_router *rt) { assert(ndisc); assert(event >= 0 && event < _SD_NDISC_EVENT_MAX); @@ -221,12 +221,11 @@ static int ndisc_recv(sd_event_source *s, int fd, uint32_t revents, void *userda if (!rt) return -ENOMEM; - r = icmp6_receive(fd, NDISC_ROUTER_RAW(rt), rt->raw_size, &rt->address, - &rt->timestamp); + r = icmp6_receive(fd, NDISC_ROUTER_RAW(rt), rt->raw_size, &rt->address, &rt->timestamp); if (r < 0) { switch (r) { case -EADDRNOTAVAIL: - (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &rt->address, &addr); + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &rt->address, &addr); log_ndisc("Received RA from non-link-local address %s. Ignoring", addr); break; diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index 8beb845d7..164b24c68 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -167,7 +167,7 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, uint32_t router_li if (r < 0) return r; - if (dst && !IN6_IS_ADDR_UNSPECIFIED(dst)) + if (dst && in6_addr_is_set(dst)) dst_addr.sin6_addr = *dst; adv.nd_ra_type = ND_ROUTER_ADVERT; @@ -244,7 +244,7 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat if (r < 0) { switch (r) { case -EADDRNOTAVAIL: - (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr); + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr); log_radv("Received RS from non-link-local address %s. Ignoring", addr); break; @@ -272,7 +272,7 @@ static int radv_recv(sd_event_source *s, int fd, uint32_t revents, void *userdat return 0; } - (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &src, &addr); + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) &src, &addr); r = radv_send(ra, &src, ra->lifetime); if (r < 0) @@ -536,35 +536,36 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) { return -EINVAL; /* Refuse prefixes that don't have a prefix set */ - if (IN6_IS_ADDR_UNSPECIFIED(&p->opt.in6_addr)) + if (in6_addr_is_null(&p->opt.in6_addr)) return -ENOEXEC; + (void) in_addr_prefix_to_string(AF_INET6, + (const union in_addr_union*) &p->opt.in6_addr, + p->opt.prefixlen, &addr_p); + LIST_FOREACH(prefix, cur, ra->prefixes) { r = in_addr_prefix_intersect(AF_INET6, - (union in_addr_union*) &cur->opt.in6_addr, + (const union in_addr_union*) &cur->opt.in6_addr, cur->opt.prefixlen, - (union in_addr_union*) &p->opt.in6_addr, + (const union in_addr_union*) &p->opt.in6_addr, p->opt.prefixlen); - if (r > 0) { - _cleanup_free_ char *addr_cur = NULL; + if (r < 0) + return r; + if (r == 0) + continue; - (void) in_addr_to_string(AF_INET6, - (union in_addr_union*) &p->opt.in6_addr, - &addr_p); + if (dynamic && cur->opt.prefixlen == p->opt.prefixlen) + goto update; - if (dynamic && cur->opt.prefixlen == p->opt.prefixlen) - goto update; + _cleanup_free_ char *addr_cur = NULL; + (void) in_addr_prefix_to_string(AF_INET6, + (const union in_addr_union*) &cur->opt.in6_addr, + cur->opt.prefixlen, &addr_cur); + log_radv("IPv6 prefix %s already configured, ignoring %s", + strna(addr_cur), strna(addr_p)); - (void) in_addr_to_string(AF_INET6, - (union in_addr_union*) &cur->opt.in6_addr, - &addr_cur); - log_radv("IPv6 prefix %s/%u already configured, ignoring %s/%u", - addr_cur, cur->opt.prefixlen, - addr_p, p->opt.prefixlen); - - return -EEXIST; - } + return -EEXIST; } p = sd_radv_prefix_ref(p); @@ -573,10 +574,8 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) { ra->n_prefixes++; - (void) in_addr_to_string(AF_INET6, (union in_addr_union*) &p->opt.in6_addr, &addr_p); - if (!dynamic) { - log_radv("Added prefix %s/%d", addr_p, p->opt.prefixlen); + log_radv("Added prefix %s", strna(addr_p)); return 0; } @@ -609,8 +608,8 @@ _public_ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p, int dynamic) { cur->valid_until = valid_until; cur->preferred_until = preferred_until; - log_radv("Updated prefix %s/%u preferred %s valid %s", - addr_p, p->opt.prefixlen, + log_radv("Updated prefix %s preferred %s valid %s", + strna(addr_p), format_timespan(time_string_preferred, FORMAT_TIMESPAN_MAX, preferred, USEC_PER_SEC), format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX, @@ -631,9 +630,7 @@ _public_ sd_radv_prefix *sd_radv_remove_prefix(sd_radv *ra, if (prefixlen != cur->opt.prefixlen) continue; - if (!in_addr_equal(AF_INET6, - (union in_addr_union *)prefix, - (union in_addr_union *)&cur->opt.in6_addr)) + if (!in6_addr_equal(prefix, &cur->opt.in6_addr)) continue; LIST_REMOVE(prefix, ra->prefixes, cur); @@ -658,17 +655,16 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int if (!p) return -EINVAL; - (void) in_addr_to_string(AF_INET6, - (union in_addr_union*) &p->opt.in6_addr, - &pretty); + (void) in_addr_prefix_to_string(AF_INET6, + (const union in_addr_union*) &p->opt.in6_addr, + p->opt.prefixlen, &pretty); LIST_FOREACH(prefix, cur, ra->route_prefixes) { - _cleanup_free_ char *addr = NULL; r = in_addr_prefix_intersect(AF_INET6, - (union in_addr_union*) &cur->opt.in6_addr, + (const union in_addr_union*) &cur->opt.in6_addr, cur->opt.prefixlen, - (union in_addr_union*) &p->opt.in6_addr, + (const union in_addr_union*) &p->opt.in6_addr, p->opt.prefixlen); if (r < 0) return r; @@ -678,12 +674,12 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int if (dynamic && cur->opt.prefixlen == p->opt.prefixlen) goto update; - (void) in_addr_to_string(AF_INET6, - (union in_addr_union*) &cur->opt.in6_addr, - &addr); - log_radv("IPv6 route prefix %s/%u already configured, ignoring %s/%u", - strempty(addr), cur->opt.prefixlen, - strempty(pretty), p->opt.prefixlen); + _cleanup_free_ char *addr = NULL; + (void) in_addr_prefix_to_string(AF_INET6, + (const union in_addr_union*) &cur->opt.in6_addr, + cur->opt.prefixlen, &addr); + log_radv("IPv6 route prefix %s already configured, ignoring %s", + strna(addr), strna(pretty)); return -EEXIST; } @@ -694,7 +690,7 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int ra->n_route_prefixes++; if (!dynamic) { - log_radv("Added prefix %s/%u", strempty(pretty), p->opt.prefixlen); + log_radv("Added prefix %s", strna(pretty)); return 0; } @@ -717,8 +713,8 @@ _public_ int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p, int if (valid_until == USEC_INFINITY) return -EOVERFLOW; - log_radv("Updated route prefix %s/%u valid %s", - strempty(pretty), p->opt.prefixlen, + log_radv("Updated route prefix %s valid %s", + strna(pretty), format_timespan(time_string_valid, FORMAT_TIMESPAN_MAX, valid, USEC_PER_SEC)); return 0; diff --git a/src/libsystemd-network/test-dhcp-client.c b/src/libsystemd-network/test-dhcp-client.c index d39d1f57a..b464d3d70 100644 --- a/src/libsystemd-network/test-dhcp-client.c +++ b/src/libsystemd-network/test-dhcp-client.c @@ -308,7 +308,7 @@ static void test_discover_message(sd_event *e) { assert_se(IN_SET(res, 0, -EINPROGRESS)); - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); sd_dhcp_client_stop(client); sd_dhcp_client_unref(client); diff --git a/src/libsystemd-network/test-dhcp6-client.c b/src/libsystemd-network/test-dhcp6-client.c index e6a43dcd5..96dc02a7e 100644 --- a/src/libsystemd-network/test-dhcp6-client.c +++ b/src/libsystemd-network/test-dhcp6-client.c @@ -449,6 +449,7 @@ static int test_advertise_option(sd_event *e) { case SD_DHCP6_OPTION_IA_NA: assert_se(optlen == 94); + assert_se(optval == &msg_advertise[26]); assert_se(!memcmp(optval, &msg_advertise[26], optlen)); val = htobe32(0x0ecfa37d); @@ -466,6 +467,7 @@ static int test_advertise_option(sd_event *e) { case SD_DHCP6_OPTION_SERVERID: assert_se(optlen == 14); + assert_se(optval == &msg_advertise[179]); assert_se(!memcmp(optval, &msg_advertise[179], optlen)); assert_se(dhcp6_lease_set_serverid(lease, optval, @@ -650,12 +652,12 @@ static int test_client_verify_request(DHCP6Message *request, size_t len) { assert_se(optlen == 40); assert_se(!memcmp(optval, &test_iaid, sizeof(test_iaid))); - val = htobe32(80); + /* T1 and T2 should not be set. */ + val = 0; assert_se(!memcmp(optval + 4, &val, sizeof(val))); - - val = htobe32(120); assert_se(!memcmp(optval + 8, &val, sizeof(val))); + /* Then, this should refuse all addresses. */ assert_se(dhcp6_option_parse_ia(option, &lease->ia, NULL) >= 0); break; @@ -694,14 +696,7 @@ static int test_client_verify_request(DHCP6Message *request, size_t len) { found_elapsed_time); sd_dhcp6_lease_reset_address_iter(lease); - assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, - <_valid) >= 0); - assert_se(!memcmp(&addr, &msg_advertise[42], sizeof(addr))); - assert_se(lt_pref == 150); - assert_se(lt_valid == 180); - - assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, - <_valid) == -ENOMSG); + assert_se(sd_dhcp6_lease_get_address(lease, &addr, <_pref, <_valid) == -ENOMSG); return 0; } diff --git a/src/libsystemd-network/test-ipv4ll.c b/src/libsystemd-network/test-ipv4ll.c index b213f4188..768595969 100644 --- a/src/libsystemd-network/test-ipv4ll.c +++ b/src/libsystemd-network/test-ipv4ll.c @@ -126,7 +126,6 @@ static void test_public_api_setters(sd_event *e) { assert_se(sd_ipv4ll_set_ifindex(ll, -1) == -EINVAL); assert_se(sd_ipv4ll_set_ifindex(ll, -99) == -EINVAL); assert_se(sd_ipv4ll_set_ifindex(ll, 1) == 0); - assert_se(sd_ipv4ll_set_ifindex(ll, 99) == 0); assert_se(sd_ipv4ll_ref(ll) == ll); assert_se(sd_ipv4ll_unref(ll) == NULL); @@ -161,25 +160,25 @@ static void test_basic_request(sd_event *e) { assert_se(sd_ipv4ll_set_ifindex(ll, 1) == 0); assert_se(sd_ipv4ll_start(ll) == 1); - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); assert_se(sd_ipv4ll_start(ll) == 0); assert_se(sd_ipv4ll_is_running(ll)); /* PROBE */ - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp)); if (extended) { /* PROBE */ - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp)); /* PROBE */ - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); assert_se(recv(test_fd[1], &arp, sizeof(struct ether_arp), 0) == sizeof(struct ether_arp)); - sd_event_run(e, (uint64_t) -1); + sd_event_run(e, UINT64_MAX); assert_se(basic_request_handler_bind == 1); } diff --git a/src/libsystemd-network/test-lldp.c b/src/libsystemd-network/test-lldp.c index c52d422fc..0331e387f 100644 --- a/src/libsystemd-network/test-lldp.c +++ b/src/libsystemd-network/test-lldp.c @@ -30,7 +30,7 @@ int lldp_network_bind_raw_socket(int ifindex) { return test_fd[0]; } -static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { +static void lldp_handler(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, void *userdata) { lldp_handler_calls++; } diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index 1b2bba889..ce596bb96 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -232,7 +232,7 @@ int icmp6_send_router_solicitation(int s, const struct ether_addr *ether_addr) { return send_ra_function(0); } -static void test_callback(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) { +static void test_callback(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) { sd_event *e = userdata; static unsigned idx = 0; uint64_t flags_array[] = { diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index f83b364c9..74eff7fcf 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -736,3 +736,18 @@ global: sd_device_has_current_tag; sd_device_set_sysattr_valuef; } LIBSYSTEMD_246; + +LIBSYSTEMD_248 { +global: + sd_bus_open_user_machine; + sd_bus_message_send; + + sd_event_source_set_ratelimit; + sd_event_source_get_ratelimit; + sd_event_source_is_ratelimited; + + sd_device_get_action; + sd_device_get_seqnum; + sd_device_new_from_stat_rdev; + sd_device_trigger; +} LIBSYSTEMD_247; diff --git a/src/libsystemd/meson.build b/src/libsystemd/meson.build index 50716f7b9..ad50815a7 100644 --- a/src/libsystemd/meson.build +++ b/src/libsystemd/meson.build @@ -1,13 +1,72 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +sd_journal_sources = files( + 'sd-journal/audit-type.c', + 'sd-journal/audit-type.h', + 'sd-journal/catalog.c', + 'sd-journal/catalog.h', + 'sd-journal/compress.c', + 'sd-journal/compress.h', + 'sd-journal/journal-def.h', + 'sd-journal/journal-file.c', + 'sd-journal/journal-file.h', + 'sd-journal/journal-internal.h', + 'sd-journal/journal-send.c', + 'sd-journal/journal-vacuum.c', + 'sd-journal/journal-vacuum.h', + 'sd-journal/journal-verify.c', + 'sd-journal/journal-verify.h', + 'sd-journal/lookup3.c', + 'sd-journal/lookup3.h', + 'sd-journal/mmap-cache.c', + 'sd-journal/mmap-cache.h', + 'sd-journal/sd-journal.c') + +if conf.get('HAVE_GCRYPT') == 1 + sd_journal_sources += files( + 'sd-journal/fsprg.c', + 'sd-journal/fsprg.h', + 'sd-journal/journal-authenticate.c', + 'sd-journal/journal-authenticate.h') +endif + +audit_type_includes = [config_h, + missing_audit_h, + 'linux/audit.h'] +if conf.get('HAVE_AUDIT') == 1 + audit_type_includes += 'libaudit.h' +endif + +generate_audit_type_list = find_program('sd-journal/generate-audit_type-list.sh') +audit_type_list_txt = custom_target( + 'audit_type-list.txt', + output : 'audit_type-list.txt', + command : [generate_audit_type_list, cpp] + audit_type_includes, + capture : true) + +audit_type_to_name = custom_target( + 'audit_type-to-name.h', + input : ['sd-journal/audit_type-to-name.awk', audit_type_list_txt], + output : 'audit_type-to-name.h', + command : [awk, '-f', '@INPUT0@', '@INPUT1@'], + capture : true) + +sd_journal_sources += [audit_type_to_name] + +############################################################ + id128_sources = files(''' sd-id128/id128-util.c sd-id128/id128-util.h sd-id128/sd-id128.c '''.split()) +############################################################ + sd_daemon_sources = files('sd-daemon/sd-daemon.c') +############################################################ + sd_event_sources = files(''' sd-event/event-source.h sd-event/event-util.c @@ -15,8 +74,12 @@ sd_event_sources = files(''' sd-event/sd-event.c '''.split()) +############################################################ + sd_login_sources = files('sd-login/sd-login.c') +############################################################ + libsystemd_sources = files(''' sd-bus/bus-common-errors.c sd-bus/bus-common-errors.h @@ -81,6 +144,7 @@ libsystemd_sources = files(''' sd-netlink/netlink-types.h sd-netlink/netlink-util.c sd-netlink/netlink-util.h + sd-netlink/nfnl-message.c sd-netlink/rtnl-message.c sd-netlink/sd-netlink.c sd-network/network-util.c @@ -90,7 +154,7 @@ libsystemd_sources = files(''' sd-resolve/resolve-private.h sd-resolve/sd-resolve.c sd-utf8/sd-utf8.c -'''.split()) + id128_sources + sd_daemon_sources + sd_event_sources + sd_login_sources +'''.split()) + sd_journal_sources + id128_sources + sd_daemon_sources + sd_event_sources + sd_login_sources disable_mempool_c = files('disable-mempool.c') @@ -100,16 +164,162 @@ libsystemd_static = static_library( 'systemd_static', libsystemd_sources, install : false, - include_directories : includes, + include_directories : libsystemd_includes, link_with : libbasic, dependencies : [threads, librt], c_args : libsystemd_c_args) -libsystemd_sym = 'src/libsystemd/libsystemd.sym' +libsystemd_sym = files('libsystemd.sym') +libsystemd_sym_path = join_paths(meson.current_source_dir(), 'libsystemd.sym') + +static_libsystemd = get_option('static-libsystemd') +static_libsystemd_pic = static_libsystemd == 'true' or static_libsystemd == 'pic' configure_file( input : 'libsystemd.pc.in', output : 'libsystemd.pc', configuration : substs, install_dir : pkgconfiglibdir == 'no' ? '' : pkgconfiglibdir) + +############################################################ + +tests += [ + [['src/libsystemd/sd-journal/test-journal.c']], + + [['src/libsystemd/sd-journal/test-journal-send.c']], + + [['src/libsystemd/sd-journal/test-journal-match.c']], + + [['src/libsystemd/sd-journal/test-journal-enum.c'], + [], [], [], '', 'timeout=360'], + + [['src/libsystemd/sd-journal/test-journal-stream.c']], + + [['src/libsystemd/sd-journal/test-journal-flush.c']], + + [['src/libsystemd/sd-journal/test-journal-init.c']], + + [['src/libsystemd/sd-journal/test-journal-verify.c']], + + [['src/libsystemd/sd-journal/test-journal-interleaving.c']], + + [['src/libsystemd/sd-journal/test-mmap-cache.c']], + + [['src/libsystemd/sd-journal/test-catalog.c']], + + [['src/libsystemd/sd-journal/test-compress.c'], + [], + [liblz4, + libzstd, + libxz]], + + [['src/libsystemd/sd-journal/test-compress-benchmark.c'], + [], + [liblz4, + libzstd, + libxz], + [], '', 'timeout=90'], + + [['src/libsystemd/sd-journal/test-audit-type.c']], +] + +############################################################ + +tests += [ + [['src/libsystemd/sd-bus/test-bus-address.c'], + [], + [threads]], + + [['src/libsystemd/sd-bus/test-bus-marshal.c'], + [], + [threads, + libglib, + libgobject, + libgio, + libdbus]], + + [['src/libsystemd/sd-bus/test-bus-signature.c'], + [], + [threads]], + + [['src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c'], + [], + [threads]], + + [['src/libsystemd/sd-bus/test-bus-watch-bind.c'], + [], + [threads], + [], '', 'timeout=120'], + + [['src/libsystemd/sd-bus/test-bus-chat.c'], + [], + [threads]], + + [['src/libsystemd/sd-bus/test-bus-cleanup.c'], + [], + [threads, + libseccomp]], + + [['src/libsystemd/sd-bus/test-bus-track.c'], + [], + [libseccomp]], + + [['src/libsystemd/sd-bus/test-bus-server.c'], + [], + [threads]], + + [['src/libsystemd/sd-bus/test-bus-objects.c'], + [], + [threads]], + + [['src/libsystemd/sd-bus/test-bus-vtable.c', + 'src/libsystemd/sd-bus/test-vtable-data.h']], + + [['src/libsystemd/sd-bus/test-bus-gvariant.c'], + [], + [libglib, + libgobject, + libgio]], + + [['src/libsystemd/sd-bus/test-bus-creds.c']], + + [['src/libsystemd/sd-bus/test-bus-match.c']], + + [['src/libsystemd/sd-bus/test-bus-benchmark.c'], + [], + [threads], + [], '', 'manual'], + + [['src/libsystemd/sd-bus/test-bus-introspect.c', + 'src/libsystemd/sd-bus/test-vtable-data.h']], + + [['src/libsystemd/sd-event/test-event.c']], + + [['src/libsystemd/sd-netlink/test-netlink.c']], + + [['src/libsystemd/sd-resolve/test-resolve.c'], + [], + [threads], + [], '', 'timeout=120'], + + [['src/libsystemd/sd-login/test-login.c']], + + [['src/libsystemd/sd-device/test-sd-device.c']], + + [['src/libsystemd/sd-device/test-sd-device-monitor.c']], +] + +if cxx_cmd != '' + tests += [ + [['src/libsystemd/sd-bus/test-bus-vtable-cc.cc']], + ] +endif + +############################################################ + +fuzzers += [ + [['src/libsystemd/sd-bus/fuzz-bus-message.c']], + + [['src/libsystemd/sd-bus/fuzz-bus-match.c']], +] diff --git a/src/libsystemd/sd-bus/bus-common-errors.c b/src/libsystemd/sd-bus/bus-common-errors.c index ef1fa3711..dc6211bc9 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.c +++ b/src/libsystemd/sd-bus/bus-common-errors.c @@ -75,6 +75,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_LINK, ENXIO), SD_BUS_ERROR_MAP(BUS_ERROR_LINK_BUSY, EBUSY), SD_BUS_ERROR_MAP(BUS_ERROR_NETWORK_DOWN, ENETDOWN), + SD_BUS_ERROR_MAP(BUS_ERROR_NO_SOURCE, ESRCH), + SD_BUS_ERROR_MAP(BUS_ERROR_STUB_LOOP, ELOOP), SD_BUS_ERROR_MAP(BUS_ERROR_NO_SUCH_DNSSD_SERVICE, ENOENT), SD_BUS_ERROR_MAP(BUS_ERROR_DNSSD_SERVICE_EXISTS, EEXIST), @@ -101,6 +103,8 @@ BUS_ERROR_MAP_ELF_REGISTER const sd_bus_error_map bus_common_errors[] = { SD_BUS_ERROR_MAP(BUS_ERROR_TRANSFER_IN_PROGRESS, EBUSY), SD_BUS_ERROR_MAP(BUS_ERROR_NO_PRODUCT_UUID, EOPNOTSUPP), + SD_BUS_ERROR_MAP(BUS_ERROR_FILE_IS_PROTECTED, EACCES), + SD_BUS_ERROR_MAP(BUS_ERROR_READ_ONLY_FILESYSTEM, EROFS), SD_BUS_ERROR_MAP(BUS_ERROR_SPEED_METER_INACTIVE, EOPNOTSUPP), SD_BUS_ERROR_MAP(BUS_ERROR_UNMANAGED_INTERFACE, EOPNOTSUPP), diff --git a/src/libsystemd/sd-bus/bus-common-errors.h b/src/libsystemd/sd-bus/bus-common-errors.h index 7e5be17d5..e56b5d139 100644 --- a/src/libsystemd/sd-bus/bus-common-errors.h +++ b/src/libsystemd/sd-bus/bus-common-errors.h @@ -3,121 +3,126 @@ #include "bus-error.h" -#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" -#define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" -#define BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID "org.freedesktop.systemd1.NoUnitForInvocationID" -#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" -#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" -#define BUS_ERROR_BAD_UNIT_SETTING "org.freedesktop.systemd1.BadUnitSetting" -#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" -#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob" -#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed" -#define BUS_ERROR_ALREADY_SUBSCRIBED "org.freedesktop.systemd1.AlreadySubscribed" -#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency" +#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit" +#define BUS_ERROR_NO_UNIT_FOR_PID "org.freedesktop.systemd1.NoUnitForPID" +#define BUS_ERROR_NO_UNIT_FOR_INVOCATION_ID "org.freedesktop.systemd1.NoUnitForInvocationID" +#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists" +#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed" +#define BUS_ERROR_BAD_UNIT_SETTING "org.freedesktop.systemd1.BadUnitSetting" +#define BUS_ERROR_JOB_FAILED "org.freedesktop.systemd1.JobFailed" +#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob" +#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed" +#define BUS_ERROR_ALREADY_SUBSCRIBED "org.freedesktop.systemd1.AlreadySubscribed" +#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency" #define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting" -#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" -#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" -#define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" -#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated" -#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked" -#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" -#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" -#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" -#define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning" -#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser" -#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced" -#define BUS_ERROR_DISK_FULL "org.freedesktop.systemd1.DiskFull" -#define BUS_ERROR_NOTHING_TO_CLEAN "org.freedesktop.systemd1.NothingToClean" -#define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy" -#define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive" +#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic" +#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive" +#define BUS_ERROR_UNIT_MASKED "org.freedesktop.systemd1.UnitMasked" +#define BUS_ERROR_UNIT_GENERATED "org.freedesktop.systemd1.UnitGenerated" +#define BUS_ERROR_UNIT_LINKED "org.freedesktop.systemd1.UnitLinked" +#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable" +#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation" +#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown" +#define BUS_ERROR_SCOPE_NOT_RUNNING "org.freedesktop.systemd1.ScopeNotRunning" +#define BUS_ERROR_NO_SUCH_DYNAMIC_USER "org.freedesktop.systemd1.NoSuchDynamicUser" +#define BUS_ERROR_NOT_REFERENCED "org.freedesktop.systemd1.NotReferenced" +#define BUS_ERROR_DISK_FULL "org.freedesktop.systemd1.DiskFull" +#define BUS_ERROR_NOTHING_TO_CLEAN "org.freedesktop.systemd1.NothingToClean" +#define BUS_ERROR_UNIT_BUSY "org.freedesktop.systemd1.UnitBusy" +#define BUS_ERROR_UNIT_INACTIVE "org.freedesktop.systemd1.UnitInactive" -#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" -#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage" -#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" -#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" -#define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking" -#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping" -#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping" +#define BUS_ERROR_NO_SUCH_MACHINE "org.freedesktop.machine1.NoSuchMachine" +#define BUS_ERROR_NO_SUCH_IMAGE "org.freedesktop.machine1.NoSuchImage" +#define BUS_ERROR_NO_MACHINE_FOR_PID "org.freedesktop.machine1.NoMachineForPID" +#define BUS_ERROR_MACHINE_EXISTS "org.freedesktop.machine1.MachineExists" +#define BUS_ERROR_NO_PRIVATE_NETWORKING "org.freedesktop.machine1.NoPrivateNetworking" +#define BUS_ERROR_NO_SUCH_USER_MAPPING "org.freedesktop.machine1.NoSuchUserMapping" +#define BUS_ERROR_NO_SUCH_GROUP_MAPPING "org.freedesktop.machine1.NoSuchGroupMapping" -#define BUS_ERROR_NO_SUCH_PORTABLE_IMAGE "org.freedesktop.portable1.NoSuchImage" -#define BUS_ERROR_BAD_PORTABLE_IMAGE_TYPE "org.freedesktop.portable1.BadImageType" +#define BUS_ERROR_NO_SUCH_PORTABLE_IMAGE "org.freedesktop.portable1.NoSuchImage" +#define BUS_ERROR_BAD_PORTABLE_IMAGE_TYPE "org.freedesktop.portable1.BadImageType" -#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" -#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" -#define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser" -#define BUS_ERROR_NO_USER_FOR_PID "org.freedesktop.login1.NoUserForPID" -#define BUS_ERROR_NO_SUCH_SEAT "org.freedesktop.login1.NoSuchSeat" -#define BUS_ERROR_SESSION_NOT_ON_SEAT "org.freedesktop.login1.SessionNotOnSeat" -#define BUS_ERROR_NOT_IN_CONTROL "org.freedesktop.login1.NotInControl" -#define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken" -#define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken" -#define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" -#define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" -#define BUS_ERROR_SESSION_BUSY "org.freedesktop.login1.SessionBusy" -#define BUS_ERROR_NOT_YOUR_DEVICE "org.freedesktop.login1.NotYourDevice" +#define BUS_ERROR_NO_SUCH_SESSION "org.freedesktop.login1.NoSuchSession" +#define BUS_ERROR_NO_SESSION_FOR_PID "org.freedesktop.login1.NoSessionForPID" +#define BUS_ERROR_NO_SUCH_USER "org.freedesktop.login1.NoSuchUser" +#define BUS_ERROR_NO_USER_FOR_PID "org.freedesktop.login1.NoUserForPID" +#define BUS_ERROR_NO_SUCH_SEAT "org.freedesktop.login1.NoSuchSeat" +#define BUS_ERROR_SESSION_NOT_ON_SEAT "org.freedesktop.login1.SessionNotOnSeat" +#define BUS_ERROR_NOT_IN_CONTROL "org.freedesktop.login1.NotInControl" +#define BUS_ERROR_DEVICE_IS_TAKEN "org.freedesktop.login1.DeviceIsTaken" +#define BUS_ERROR_DEVICE_NOT_TAKEN "org.freedesktop.login1.DeviceNotTaken" +#define BUS_ERROR_OPERATION_IN_PROGRESS "org.freedesktop.login1.OperationInProgress" +#define BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED "org.freedesktop.login1.SleepVerbNotSupported" +#define BUS_ERROR_SESSION_BUSY "org.freedesktop.login1.SessionBusy" +#define BUS_ERROR_NOT_YOUR_DEVICE "org.freedesktop.login1.NotYourDevice" -#define BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED "org.freedesktop.timedate1.AutomaticTimeSyncEnabled" -#define BUS_ERROR_NO_NTP_SUPPORT "org.freedesktop.timedate1.NoNTPSupport" +#define BUS_ERROR_AUTOMATIC_TIME_SYNC_ENABLED "org.freedesktop.timedate1.AutomaticTimeSyncEnabled" +#define BUS_ERROR_NO_NTP_SUPPORT "org.freedesktop.timedate1.NoNTPSupport" -#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess" +#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess" -#define BUS_ERROR_NO_NAME_SERVERS "org.freedesktop.resolve1.NoNameServers" -#define BUS_ERROR_INVALID_REPLY "org.freedesktop.resolve1.InvalidReply" -#define BUS_ERROR_NO_SUCH_RR "org.freedesktop.resolve1.NoSuchRR" -#define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop" -#define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted" -#define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService" -#define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed" -#define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor" -#define BUS_ERROR_RR_TYPE_UNSUPPORTED "org.freedesktop.resolve1.ResourceRecordTypeUnsupported" -#define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink" -#define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy" -#define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown" -#define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService" -#define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists" -#define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." +#define BUS_ERROR_NO_NAME_SERVERS "org.freedesktop.resolve1.NoNameServers" +#define BUS_ERROR_INVALID_REPLY "org.freedesktop.resolve1.InvalidReply" +#define BUS_ERROR_NO_SUCH_RR "org.freedesktop.resolve1.NoSuchRR" +#define BUS_ERROR_CNAME_LOOP "org.freedesktop.resolve1.CNameLoop" +#define BUS_ERROR_ABORTED "org.freedesktop.resolve1.Aborted" +#define BUS_ERROR_NO_SUCH_SERVICE "org.freedesktop.resolve1.NoSuchService" +#define BUS_ERROR_DNSSEC_FAILED "org.freedesktop.resolve1.DnssecFailed" +#define BUS_ERROR_NO_TRUST_ANCHOR "org.freedesktop.resolve1.NoTrustAnchor" +#define BUS_ERROR_RR_TYPE_UNSUPPORTED "org.freedesktop.resolve1.ResourceRecordTypeUnsupported" +#define BUS_ERROR_NO_SUCH_LINK "org.freedesktop.resolve1.NoSuchLink" +#define BUS_ERROR_LINK_BUSY "org.freedesktop.resolve1.LinkBusy" +#define BUS_ERROR_NETWORK_DOWN "org.freedesktop.resolve1.NetworkDown" +#define BUS_ERROR_NO_SOURCE "org.freedesktop.resolve1.NoSource" +#define BUS_ERROR_STUB_LOOP "org.freedesktop.resolve1.StubLoop" +#define BUS_ERROR_NO_SUCH_DNSSD_SERVICE "org.freedesktop.resolve1.NoSuchDnssdService" +#define BUS_ERROR_DNSSD_SERVICE_EXISTS "org.freedesktop.resolve1.DnssdServiceExists" +#define _BUS_ERROR_DNS "org.freedesktop.resolve1.DnsError." -#define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" -#define BUS_ERROR_TRANSFER_IN_PROGRESS "org.freedesktop.import1.TransferInProgress" +#define BUS_ERROR_NO_SUCH_TRANSFER "org.freedesktop.import1.NoSuchTransfer" +#define BUS_ERROR_TRANSFER_IN_PROGRESS "org.freedesktop.import1.TransferInProgress" -#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID" +#define BUS_ERROR_NO_PRODUCT_UUID "org.freedesktop.hostname1.NoProductUUID" +#define BUS_ERROR_FILE_IS_PROTECTED "org.freedesktop.hostname1.FileIsProtected" +#define BUS_ERROR_READ_ONLY_FILESYSTEM "org.freedesktop.hostname1.ReadOnlyFilesystem" -#define BUS_ERROR_SPEED_METER_INACTIVE "org.freedesktop.network1.SpeedMeterInactive" -#define BUS_ERROR_UNMANAGED_INTERFACE "org.freedesktop.network1.UnmanagedInterface" +#define BUS_ERROR_SPEED_METER_INACTIVE "org.freedesktop.network1.SpeedMeterInactive" +#define BUS_ERROR_UNMANAGED_INTERFACE "org.freedesktop.network1.UnmanagedInterface" -#define BUS_ERROR_NO_SUCH_HOME "org.freedesktop.home1.NoSuchHome" -#define BUS_ERROR_UID_IN_USE "org.freedesktop.home1.UIDInUse" -#define BUS_ERROR_USER_NAME_EXISTS "org.freedesktop.home1.UserNameExists" -#define BUS_ERROR_HOME_EXISTS "org.freedesktop.home1.HomeExists" -#define BUS_ERROR_HOME_ALREADY_ACTIVE "org.freedesktop.home1.HomeAlreadyActive" -#define BUS_ERROR_HOME_ALREADY_FIXATED "org.freedesktop.home1.HomeAlreadyFixated" -#define BUS_ERROR_HOME_UNFIXATED "org.freedesktop.home1.HomeUnfixated" -#define BUS_ERROR_HOME_NOT_ACTIVE "org.freedesktop.home1.HomeNotActive" -#define BUS_ERROR_HOME_ABSENT "org.freedesktop.home1.HomeAbsent" -#define BUS_ERROR_HOME_BUSY "org.freedesktop.home1.HomeBusy" -#define BUS_ERROR_BAD_PASSWORD "org.freedesktop.home1.BadPassword" -#define BUS_ERROR_BAD_RECOVERY_KEY "org.freedesktop.home1.BadRecoveryKey" -#define BUS_ERROR_LOW_PASSWORD_QUALITY "org.freedesktop.home1.LowPasswordQuality" -#define BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN "org.freedesktop.home1.BadPasswordAndNoToken" -#define BUS_ERROR_TOKEN_PIN_NEEDED "org.freedesktop.home1.TokenPinNeeded" -#define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED "org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded" -#define BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED "org.freedesktop.home1.TokenUserPresenceNeeded" -#define BUS_ERROR_TOKEN_ACTION_TIMEOUT "org.freedesktop.home1.TokenActionTimeout" -#define BUS_ERROR_TOKEN_PIN_LOCKED "org.freedesktop.home1.TokenPinLocked" -#define BUS_ERROR_TOKEN_BAD_PIN "org.freedesktop.home1.BadPin" +#define BUS_ERROR_NO_SUCH_HOME "org.freedesktop.home1.NoSuchHome" +#define BUS_ERROR_UID_IN_USE "org.freedesktop.home1.UIDInUse" +#define BUS_ERROR_USER_NAME_EXISTS "org.freedesktop.home1.UserNameExists" +#define BUS_ERROR_HOME_EXISTS "org.freedesktop.home1.HomeExists" +#define BUS_ERROR_HOME_ALREADY_ACTIVE "org.freedesktop.home1.HomeAlreadyActive" +#define BUS_ERROR_HOME_ALREADY_FIXATED "org.freedesktop.home1.HomeAlreadyFixated" +#define BUS_ERROR_HOME_UNFIXATED "org.freedesktop.home1.HomeUnfixated" +#define BUS_ERROR_HOME_NOT_ACTIVE "org.freedesktop.home1.HomeNotActive" +#define BUS_ERROR_HOME_ABSENT "org.freedesktop.home1.HomeAbsent" +#define BUS_ERROR_HOME_BUSY "org.freedesktop.home1.HomeBusy" +#define BUS_ERROR_BAD_PASSWORD "org.freedesktop.home1.BadPassword" +#define BUS_ERROR_BAD_RECOVERY_KEY "org.freedesktop.home1.BadRecoveryKey" +#define BUS_ERROR_LOW_PASSWORD_QUALITY "org.freedesktop.home1.LowPasswordQuality" +#define BUS_ERROR_BAD_PASSWORD_AND_NO_TOKEN "org.freedesktop.home1.BadPasswordAndNoToken" +#define BUS_ERROR_TOKEN_PIN_NEEDED "org.freedesktop.home1.TokenPinNeeded" +#define BUS_ERROR_TOKEN_PROTECTED_AUTHENTICATION_PATH_NEEDED \ + "org.freedesktop.home1.TokenProtectedAuthenticationPathNeeded" +#define BUS_ERROR_TOKEN_USER_PRESENCE_NEEDED "org.freedesktop.home1.TokenUserPresenceNeeded" +#define BUS_ERROR_TOKEN_ACTION_TIMEOUT "org.freedesktop.home1.TokenActionTimeout" +#define BUS_ERROR_TOKEN_PIN_LOCKED "org.freedesktop.home1.TokenPinLocked" +#define BUS_ERROR_TOKEN_BAD_PIN "org.freedesktop.home1.BadPin" #define BUS_ERROR_TOKEN_BAD_PIN_FEW_TRIES_LEFT "org.freedesktop.home1.BadPinFewTriesLeft" -#define BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT "org.freedesktop.home1.BadPinOneTryLeft" -#define BUS_ERROR_BAD_SIGNATURE "org.freedesktop.home1.BadSignature" -#define BUS_ERROR_HOME_RECORD_MISMATCH "org.freedesktop.home1.RecordMismatch" -#define BUS_ERROR_HOME_RECORD_DOWNGRADE "org.freedesktop.home1.RecordDowngrade" -#define BUS_ERROR_HOME_RECORD_SIGNED "org.freedesktop.home1.RecordSigned" -#define BUS_ERROR_BAD_HOME_SIZE "org.freedesktop.home1.BadHomeSize" -#define BUS_ERROR_NO_PRIVATE_KEY "org.freedesktop.home1.NoPrivateKey" -#define BUS_ERROR_HOME_LOCKED "org.freedesktop.home1.HomeLocked" -#define BUS_ERROR_HOME_NOT_LOCKED "org.freedesktop.home1.HomeNotLocked" -#define BUS_ERROR_NO_DISK_SPACE "org.freedesktop.home1.NoDiskSpace" -#define BUS_ERROR_TOO_MANY_OPERATIONS "org.freedesktop.home1.TooManyOperations" -#define BUS_ERROR_AUTHENTICATION_LIMIT_HIT "org.freedesktop.home1.AuthenticationLimitHit" -#define BUS_ERROR_HOME_CANT_AUTHENTICATE "org.freedesktop.home1.HomeCantAuthenticate" +#define BUS_ERROR_TOKEN_BAD_PIN_ONE_TRY_LEFT "org.freedesktop.home1.BadPinOneTryLeft" +#define BUS_ERROR_BAD_SIGNATURE "org.freedesktop.home1.BadSignature" +#define BUS_ERROR_HOME_RECORD_MISMATCH "org.freedesktop.home1.RecordMismatch" +#define BUS_ERROR_HOME_RECORD_DOWNGRADE "org.freedesktop.home1.RecordDowngrade" +#define BUS_ERROR_HOME_RECORD_SIGNED "org.freedesktop.home1.RecordSigned" +#define BUS_ERROR_BAD_HOME_SIZE "org.freedesktop.home1.BadHomeSize" +#define BUS_ERROR_NO_PRIVATE_KEY "org.freedesktop.home1.NoPrivateKey" +#define BUS_ERROR_HOME_LOCKED "org.freedesktop.home1.HomeLocked" +#define BUS_ERROR_HOME_NOT_LOCKED "org.freedesktop.home1.HomeNotLocked" +#define BUS_ERROR_NO_DISK_SPACE "org.freedesktop.home1.NoDiskSpace" +#define BUS_ERROR_TOO_MANY_OPERATIONS "org.freedesktop.home1.TooManyOperations" +#define BUS_ERROR_AUTHENTICATION_LIMIT_HIT "org.freedesktop.home1.AuthenticationLimitHit" +#define BUS_ERROR_HOME_CANT_AUTHENTICATE "org.freedesktop.home1.HomeCantAuthenticate" BUS_ERROR_MAP_ELF_USE(bus_common_errors); diff --git a/src/libsystemd/sd-bus/bus-control.c b/src/libsystemd/sd-bus/bus-control.c index 3ee22c963..d96b7256a 100644 --- a/src/libsystemd/sd-bus/bus-control.c +++ b/src/libsystemd/sd-bus/bus-control.c @@ -13,7 +13,6 @@ #include "bus-control.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-util.h" #include "capability-util.h" #include "process-util.h" #include "stdio-util.h" @@ -742,7 +741,7 @@ _public_ int sd_bus_get_owner_creds(sd_bus *bus, uint64_t mask, sd_bus_creds **r mask &= ~SD_BUS_CREDS_AUGMENT; do_label = bus->label && (mask & SD_BUS_CREDS_SELINUX_CONTEXT); - do_groups = bus->n_groups != (size_t) -1 && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS); + do_groups = bus->n_groups != SIZE_MAX && (mask & SD_BUS_CREDS_SUPPLEMENTARY_GIDS); /* Avoid allocating anything if we have no chance of returning useful data */ if (!bus->ucred_valid && !do_label && !do_groups) diff --git a/src/libsystemd/sd-bus/bus-convenience.c b/src/libsystemd/sd-bus/bus-convenience.c index 0314642f3..a36aeb238 100644 --- a/src/libsystemd/sd-bus/bus-convenience.c +++ b/src/libsystemd/sd-bus/bus-convenience.c @@ -7,9 +7,16 @@ #include "bus-message.h" #include "bus-signature.h" #include "bus-type.h" -#include "bus-util.h" #include "string-util.h" +_public_ int sd_bus_message_send(sd_bus_message *reply) { + assert_return(reply, -EINVAL); + assert_return(reply->bus, -EINVAL); + assert_return(!bus_pid_changed(reply->bus), -ECHILD); + + return sd_bus_send(reply->bus, reply, NULL); +} + _public_ int sd_bus_emit_signalv( sd_bus *bus, const char *path, @@ -199,7 +206,7 @@ _public_ int sd_bus_reply_method_returnv( return r; } - return sd_bus_send(call->bus, m, NULL); + return sd_bus_message_send(m); } _public_ int sd_bus_reply_method_return( @@ -240,7 +247,7 @@ _public_ int sd_bus_reply_method_error( if (r < 0) return r; - return sd_bus_send(call->bus, m, NULL); + return sd_bus_message_send(m); } _public_ int sd_bus_reply_method_errorfv( diff --git a/src/libsystemd/sd-bus/bus-creds.c b/src/libsystemd/sd-bus/bus-creds.c index 3896d9411..5e748fdb4 100644 --- a/src/libsystemd/sd-bus/bus-creds.c +++ b/src/libsystemd/sd-bus/bus-creds.c @@ -8,7 +8,6 @@ #include "bus-creds.h" #include "bus-label.h" #include "bus-message.h" -#include "bus-util.h" #include "capability-util.h" #include "cgroup-util.h" #include "errno-util.h" @@ -1003,7 +1002,7 @@ int bus_creds_add_more(sd_bus_creds *c, uint64_t mask, pid_t pid, pid_t tid) { const char *p; p = procfs_file_alloca(pid, "cmdline"); - r = read_full_file(p, &c->cmdline, &c->cmdline_size); + r = read_full_virtual_file(p, &c->cmdline, &c->cmdline_size); if (r == -ENOENT) return -ESRCH; if (r < 0) { diff --git a/src/libsystemd/sd-bus/bus-dump.c b/src/libsystemd/sd-bus/bus-dump.c index 3ff87be67..d5d22b0d8 100644 --- a/src/libsystemd/sd-bus/bus-dump.c +++ b/src/libsystemd/sd-bus/bus-dump.c @@ -55,6 +55,15 @@ _public_ int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags) { f = stdout; if (flags & SD_BUS_MESSAGE_DUMP_WITH_HEADER) { + char buf[FORMAT_TIMESTAMP_MAX]; + const char *p; + usec_t ts = m->realtime; + + if (ts == 0) + ts = now(CLOCK_REALTIME); + + p = format_timestamp_style(buf, sizeof(buf), ts, TIMESTAMP_US_UTC); + fprintf(f, "%s%s%s Type=%s%s%s Endian=%c Flags=%u Version=%u", m->header->type == SD_BUS_MESSAGE_METHOD_ERROR ? ansi_highlight_red() : @@ -72,7 +81,7 @@ _public_ int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags) { m->header->version); /* Display synthetic message serial number in a more readable - * format than (uint32_t) -1 */ + * format than UINT32_MAX */ if (BUS_MESSAGE_COOKIE(m) == 0xFFFFFFFFULL) fprintf(f, " Cookie=-1"); else @@ -81,6 +90,8 @@ _public_ int sd_bus_message_dump(sd_bus_message *m, FILE *f, uint64_t flags) { if (m->reply_cookie != 0) fprintf(f, " ReplyCookie=%" PRIu64, m->reply_cookie); + fprintf(f, " Timestamp=\"%s\"", strna(p)); + fputs("\n", f); if (m->sender) diff --git a/src/libsystemd/sd-bus/bus-error.h b/src/libsystemd/sd-bus/bus-error.h index 557284faf..d981f7244 100644 --- a/src/libsystemd/sd-bus/bus-error.h +++ b/src/libsystemd/sd-bus/bus-error.h @@ -28,11 +28,17 @@ int bus_error_set_errnofv(sd_bus_error *e, int error, const char *format, va_lis * the bus error table, and BUS_ERROR_MAP_ELF_USE has to be used at * least once per compilation unit (i.e. per library), to ensure that * the error map is really added to the final binary. + * + * In addition, set the retain attribute so that the section cannot be + * discarded by ld --gc-sections -z start-stop-gc. Older compilers would + * warn for the unknown attribute, so just disable -Wattributes. */ #define BUS_ERROR_MAP_ELF_REGISTER \ + _Pragma("GCC diagnostic ignored \"-Wattributes\"") \ _section_("SYSTEMD_BUS_ERROR_MAP") \ _used_ \ + __attribute__((retain)) \ _alignptr_ \ _variable_no_sanitize_address_ diff --git a/src/libsystemd/sd-bus/bus-internal.c b/src/libsystemd/sd-bus/bus-internal.c index 3f03ad7c4..0f1ea45c0 100644 --- a/src/libsystemd/sd-bus/bus-internal.c +++ b/src/libsystemd/sd-bus/bus-internal.c @@ -3,6 +3,7 @@ #include "alloc-util.h" #include "bus-internal.h" #include "bus-message.h" +#include "escape.h" #include "hexdecoct.h" #include "string-util.h" @@ -91,8 +92,13 @@ bool interface_name_is_valid(const char *p) { (!dot && *q >= '0' && *q <= '9') || *q == '_'; - if (!good) + if (!good) { + if (DEBUG_LOGGING) { + _cleanup_free_ char *iface = cescape(p); + log_debug("The interface %s is invalid as it contains special character", strnull(iface)); + } return false; + } dot = false; } diff --git a/src/libsystemd/sd-bus/bus-internal.h b/src/libsystemd/sd-bus/bus-internal.h index 233a22831..4a45507da 100644 --- a/src/libsystemd/sd-bus/bus-internal.h +++ b/src/libsystemd/sd-bus/bus-internal.h @@ -44,8 +44,8 @@ struct match_callback { unsigned last_iteration; /* Don't dispatch this slot with messages that arrived in any iteration before or at the this - * one. We use this to ensure that matches don't apply "retroactively" and thus can confuse the - * caller: matches will only match incoming messages from the moment on the match was installed. */ + * one. We use this to ensure that matches don't apply "retroactively" and confuse the caller: + * only messages received after the match was installed will be considered. */ uint64_t after; char *match_string; @@ -122,22 +122,22 @@ typedef enum BusSlotType { BUS_NODE_ENUMERATOR, BUS_NODE_VTABLE, BUS_NODE_OBJECT_MANAGER, - _BUS_SLOT_INVALID = -1, + _BUS_SLOT_INVALID = -EINVAL, } BusSlotType; struct sd_bus_slot { unsigned n_ref; - BusSlotType type:5; + BusSlotType type:8; - /* Slots can be "floating" or not. If they are not floating (the usual case) then they reference the bus object - * they are associated with. This means the bus object stays allocated at least as long as there is a slot - * around associated with it. If it is floating, then the slot's lifecycle is bound to the lifecycle of the - * bus: it will be disconnected from the bus when the bus is destroyed, and it keeping the slot reffed hence - * won't mean the bus stays reffed too. Internally this means the reference direction is reversed: floating - * slots objects are referenced by the bus object, and not vice versa. */ - bool floating:1; - - bool match_added:1; + /* Slots can be "floating" or not. If they are not floating (the usual case) then they reference the + * bus object they are associated with. This means the bus object stays allocated at least as long as + * there is a slot around associated with it. If it is floating, then the slot's lifecycle is bound + * to the lifecycle of the bus: it will be disconnected from the bus when the bus is destroyed, and + * it keeping the slot reffed hence won't mean the bus stays reffed too. Internally this means the + * reference direction is reversed: floating slots objects are referenced by the bus object, and not + * vice versa. */ + bool floating; + bool match_added; sd_bus *bus; void *userdata; @@ -401,7 +401,7 @@ void bus_close_io_fds(sd_bus *b); int bus_set_address_system(sd_bus *bus); int bus_set_address_user(sd_bus *bus); int bus_set_address_system_remote(sd_bus *b, const char *host); -int bus_set_address_system_machine(sd_bus *b, const char *machine); +int bus_set_address_machine(sd_bus *b, bool user, const char *machine); int bus_maybe_reply_error(sd_bus_message *m, int r, sd_bus_error *error); diff --git a/src/libsystemd/sd-bus/bus-kernel.c b/src/libsystemd/sd-bus/bus-kernel.c index 6bba44693..cba1ab295 100644 --- a/src/libsystemd/sd-bus/bus-kernel.c +++ b/src/libsystemd/sd-bus/bus-kernel.c @@ -20,7 +20,6 @@ #include "bus-kernel.h" #include "bus-label.h" #include "bus-message.h" -#include "bus-util.h" #include "capability-util.h" #include "fd-util.h" #include "fileio.h" @@ -41,10 +40,8 @@ void close_and_munmap(int fd, void *address, size_t size) { } void bus_flush_memfd(sd_bus *b) { - unsigned i; - assert(b); - for (i = 0; i < b->n_memfd_cache; i++) + for (unsigned i = 0; i < b->n_memfd_cache; i++) close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped); } diff --git a/src/libsystemd/sd-bus/bus-match.c b/src/libsystemd/sd-bus/bus-match.c index d7da4bf00..96b50aeae 100644 --- a/src/libsystemd/sd-bus/bus-match.c +++ b/src/libsystemd/sd-bus/bus-match.c @@ -4,7 +4,6 @@ #include "bus-internal.h" #include "bus-match.h" #include "bus-message.h" -#include "bus-util.h" #include "fd-util.h" #include "fileio.h" #include "hexdecoct.h" @@ -409,12 +408,9 @@ int bus_match_run( if (r != 0) return r; } - } else { - struct bus_match_node *c; - + } else /* No hash table, so let's iterate manually... */ - - for (c = node->child; c; c = c->next) { + for (struct bus_match_node *c = node->child; c; c = c->next) { if (!value_node_test(c, node->type, test_u8, test_str, test_strv, m)) continue; @@ -425,7 +421,6 @@ int bus_match_run( if (bus && bus->match_callbacks_modified) return 0; } - } if (bus && bus->match_callbacks_modified) return 0; @@ -441,7 +436,7 @@ static int bus_match_add_compare_value( const char *value_str, struct bus_match_node **ret) { - struct bus_match_node *c = NULL, *n = NULL; + struct bus_match_node *c, *n = NULL; int r; assert(where); @@ -453,25 +448,22 @@ static int bus_match_add_compare_value( ; if (c) { - /* Comparison node already exists? Then let's see if - * the value node exists too. */ + /* Comparison node already exists? Then let's see if the value node exists too. */ if (t == BUS_MATCH_MESSAGE_TYPE) n = hashmap_get(c->compare.children, UINT_TO_PTR(value_u8)); else if (BUS_MATCH_CAN_HASH(t)) n = hashmap_get(c->compare.children, value_str); - else { + else for (n = c->child; n && !value_node_same(n, t, value_u8, value_str); n = n->next) ; - } if (n) { *ret = n; return 0; } } else { - /* Comparison node, doesn't exist yet? Then let's - * create it. */ + /* Comparison node, doesn't exist yet? Then let's create it. */ c = new0(struct bus_match_node, 1); if (!c) { @@ -707,9 +699,7 @@ static int match_component_compare(const struct bus_match_component *a, const st } void bus_match_parse_free(struct bus_match_component *components, unsigned n_components) { - unsigned i; - - for (i = 0; i < n_components; i++) + for (unsigned i = 0; i < n_components; i++) free(components[i].value_str); free(components); @@ -717,51 +707,54 @@ void bus_match_parse_free(struct bus_match_component *components, unsigned n_com int bus_match_parse( const char *match, - struct bus_match_component **_components, - unsigned *_n_components) { + struct bus_match_component **ret_components, + unsigned *ret_n_components) { - const char *p = match; struct bus_match_component *components = NULL; size_t components_allocated = 0; - unsigned n_components = 0, i; - _cleanup_free_ char *value = NULL; + unsigned n_components = 0; int r; assert(match); - assert(_components); - assert(_n_components); + assert(ret_components); + assert(ret_n_components); - while (*p != 0) { + while (*match != '\0') { const char *eq, *q; enum bus_match_node_type t; unsigned j = 0; + _cleanup_free_ char *value = NULL; size_t value_allocated = 0; bool escaped = false, quoted; uint8_t u; /* Avahi's match rules appear to include whitespace, skip over it */ - p += strspn(p, " "); + match += strspn(match, " "); - eq = strchr(p, '='); - if (!eq) - return -EINVAL; + eq = strchr(match, '='); + if (!eq) { + r = -EINVAL; + goto fail; + } - t = bus_match_node_type_from_string(p, eq - p); - if (t < 0) - return -EINVAL; + t = bus_match_node_type_from_string(match, eq - match); + if (t < 0) { + r = -EINVAL; + goto fail; + } quoted = eq[1] == '\''; for (q = eq + 1 + quoted;; q++) { - if (*q == 0) { + if (*q == '\0') { if (quoted) { r = -EINVAL; goto fail; } else { if (value) - value[j] = 0; + value[j] = '\0'; break; } } @@ -775,14 +768,13 @@ int bus_match_parse( if (quoted) { if (*q == '\'') { if (value) - value[j] = 0; + value[j] = '\0'; break; } } else { if (*q == ',') { if (value) - value[j] = 0; - + value[j] = '\0'; break; } } @@ -819,10 +811,11 @@ int bus_match_parse( goto fail; } - components[n_components].type = t; - components[n_components].value_str = TAKE_PTR(value); - components[n_components].value_u8 = u; - n_components++; + components[n_components++] = (struct bus_match_component) { + .type = t, + .value_str = TAKE_PTR(value), + .value_u8 = u, + }; if (q[quoted] == 0) break; @@ -832,21 +825,21 @@ int bus_match_parse( goto fail; } - p = q + 1 + quoted; + match = q + 1 + quoted; } /* Order the whole thing, so that we always generate the same tree */ typesafe_qsort(components, n_components, match_component_compare); /* Check for duplicates */ - for (i = 0; i+1 < n_components; i++) + for (unsigned i = 0; i+1 < n_components; i++) if (components[i].type == components[i+1].type) { r = -EINVAL; goto fail; } - *_components = components; - *_n_components = n_components; + *ret_components = components; + *ret_n_components = n_components; return 0; @@ -856,10 +849,8 @@ fail: } char *bus_match_to_string(struct bus_match_component *components, unsigned n_components) { - _cleanup_fclose_ FILE *f = NULL; - char *buffer = NULL; + _cleanup_free_ char *buffer = NULL; size_t size = 0; - unsigned i; int r; if (n_components <= 0) @@ -867,11 +858,11 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com assert(components); - f = open_memstream_unlocked(&buffer, &size); + FILE *f = open_memstream_unlocked(&buffer, &size); if (!f) return NULL; - for (i = 0; i < n_components; i++) { + for (unsigned i = 0; i < n_components; i++) { char buf[32]; if (i != 0) @@ -890,10 +881,10 @@ char *bus_match_to_string(struct bus_match_component *components, unsigned n_com } r = fflush_and_check(f); + safe_fclose(f); if (r < 0) return NULL; - - return buffer; + return TAKE_PTR(buffer); } int bus_match_add( @@ -902,23 +893,22 @@ int bus_match_add( unsigned n_components, struct match_callback *callback) { - unsigned i; - struct bus_match_node *n; int r; assert(root); assert(callback); - n = root; - for (i = 0; i < n_components; i++) { - r = bus_match_add_compare_value( - n, components[i].type, - components[i].value_u8, components[i].value_str, &n); + for (unsigned i = 0; i < n_components; i++) { + r = bus_match_add_compare_value(root, + components[i].type, + components[i].value_u8, + components[i].value_str, + &root); if (r < 0) return r; } - return bus_match_add_leaf(n, callback); + return bus_match_add_leaf(root, callback); } int bus_match_remove( @@ -1029,42 +1019,39 @@ const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[] } } -void bus_match_dump(struct bus_match_node *node, unsigned level) { - struct bus_match_node *c; - _cleanup_free_ char *pfx = NULL; +void bus_match_dump(FILE *out, struct bus_match_node *node, unsigned level) { char buf[32]; if (!node) return; - pfx = strrep(" ", level); - printf("%s[%s]", strempty(pfx), bus_match_node_type_to_string(node->type, buf, sizeof(buf))); + fprintf(out, "%*s[%s]", 2 * level, "", bus_match_node_type_to_string(node->type, buf, sizeof(buf))); if (node->type == BUS_MATCH_VALUE) { if (node->parent->type == BUS_MATCH_MESSAGE_TYPE) - printf(" <%u>\n", node->value.u8); + fprintf(out, " <%u>\n", node->value.u8); else - printf(" <%s>\n", node->value.str); + fprintf(out, " <%s>\n", node->value.str); } else if (node->type == BUS_MATCH_ROOT) - puts(" root"); + fputs(" root\n", out); else if (node->type == BUS_MATCH_LEAF) - printf(" %p/%p\n", node->leaf.callback->callback, container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata); + fprintf(out, " %p/%p\n", node->leaf.callback->callback, + container_of(node->leaf.callback, sd_bus_slot, match_callback)->userdata); else - putchar('\n'); + putc('\n', out); if (BUS_MATCH_CAN_HASH(node->type)) { - + struct bus_match_node *c; HASHMAP_FOREACH(c, node->compare.children) - bus_match_dump(c, level + 1); + bus_match_dump(out, c, level + 1); } - for (c = node->child; c; c = c->next) - bus_match_dump(c, level + 1); + for (struct bus_match_node *c = node->child; c; c = c->next) + bus_match_dump(out, c, level + 1); } enum bus_match_scope bus_match_get_scope(const struct bus_match_component *components, unsigned n_components) { bool found_driver = false; - unsigned i; if (n_components <= 0) return BUS_MATCH_GENERIC; @@ -1077,7 +1064,7 @@ enum bus_match_scope bus_match_get_scope(const struct bus_match_component *compo * local messages, then we check if it only matches on the * driver. */ - for (i = 0; i < n_components; i++) { + for (unsigned i = 0; i < n_components; i++) { const struct bus_match_component *c = components + i; if (c->type == BUS_MATCH_SENDER) { @@ -1096,5 +1083,4 @@ enum bus_match_scope bus_match_get_scope(const struct bus_match_component *compo } return found_driver ? BUS_MATCH_DRIVER : BUS_MATCH_GENERIC; - } diff --git a/src/libsystemd/sd-bus/bus-match.h b/src/libsystemd/sd-bus/bus-match.h index e44e40644..6042f90fb 100644 --- a/src/libsystemd/sd-bus/bus-match.h +++ b/src/libsystemd/sd-bus/bus-match.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #include "sd-bus.h" #include "hashmap.h" @@ -27,7 +29,7 @@ enum bus_match_node_type { BUS_MATCH_ARG_HAS, BUS_MATCH_ARG_HAS_LAST = BUS_MATCH_ARG_HAS + 63, _BUS_MATCH_NODE_TYPE_MAX, - _BUS_MATCH_NODE_TYPE_INVALID = -1 + _BUS_MATCH_NODE_TYPE_INVALID = -EINVAL, }; struct bus_match_node { @@ -68,12 +70,12 @@ int bus_match_remove(struct bus_match_node *root, struct match_callback *callbac void bus_match_free(struct bus_match_node *node); -void bus_match_dump(struct bus_match_node *node, unsigned level); +void bus_match_dump(FILE *out, struct bus_match_node *node, unsigned level); const char* bus_match_node_type_to_string(enum bus_match_node_type t, char buf[], size_t l); enum bus_match_node_type bus_match_node_type_from_string(const char *k, size_t n); -int bus_match_parse(const char *match, struct bus_match_component **_components, unsigned *_n_components); +int bus_match_parse(const char *match, struct bus_match_component **ret_components, unsigned *ret_n_components); void bus_match_parse_free(struct bus_match_component *components, unsigned n_components); char *bus_match_to_string(struct bus_match_component *components, unsigned n_components); diff --git a/src/libsystemd/sd-bus/bus-message.c b/src/libsystemd/sd-bus/bus-message.c index 86ff5bdfa..b25064b67 100644 --- a/src/libsystemd/sd-bus/bus-message.c +++ b/src/libsystemd/sd-bus/bus-message.c @@ -12,7 +12,6 @@ #include "bus-message.h" #include "bus-signature.h" #include "bus-type.h" -#include "bus-util.h" #include "fd-util.h" #include "io-util.h" #include "memfd-util.h" @@ -162,8 +161,7 @@ static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, b start = ALIGN_TO(old_size, align); new_size = start + sz; - if (new_size < start || - new_size > (size_t) ((uint32_t) -1)) + if (new_size < start || new_size > UINT32_MAX) goto poison; if (old_size == new_size) @@ -1338,8 +1336,7 @@ static void *message_extend_body( added = padding + sz; /* Check for 32bit overflows */ - if (end_body > (size_t) ((uint32_t) -1) || - end_body < start_body) { + if (end_body < start_body || end_body > UINT32_MAX) { m->poisoned = true; return NULL; } @@ -1471,7 +1468,7 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void if (c->enclosing != 0) return -ENXIO; - e = strextend(&c->signature, CHAR_TO_STR(type), NULL); + e = strextend(&c->signature, CHAR_TO_STR(type)); if (!e) { m->poisoned = true; return -ENOMEM; @@ -1664,7 +1661,7 @@ _public_ int sd_bus_message_append_string_space( if (c->enclosing != 0) return -ENXIO; - e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL); + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING)); if (!e) { m->poisoned = true; return -ENOMEM; @@ -1768,7 +1765,7 @@ static int bus_message_open_array( /* Extend the existing signature */ - e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents, NULL); + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_ARRAY), contents); if (!e) { m->poisoned = true; return -ENOMEM; @@ -1853,7 +1850,7 @@ static int bus_message_open_variant( if (c->enclosing != 0) return -ENXIO; - e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT), NULL); + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_VARIANT)); if (!e) { m->poisoned = true; return -ENOMEM; @@ -1921,7 +1918,7 @@ static int bus_message_open_struct( if (c->enclosing != 0) return -ENXIO; - e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END), NULL); + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_BEGIN), contents, CHAR_TO_STR(SD_BUS_TYPE_STRUCT_END)); if (!e) { m->poisoned = true; return -ENOMEM; @@ -2341,13 +2338,13 @@ _public_ int sd_bus_message_appendv( assert_return(!m->sealed, -EPERM); assert_return(!m->poisoned, -ESTALE); - n_array = (unsigned) -1; + n_array = UINT_MAX; n_struct = strlen(types); for (;;) { const char *t; - if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { + if (n_array == 0 || (n_array == UINT_MAX && n_struct == 0)) { r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); if (r < 0) return r; @@ -2362,7 +2359,7 @@ _public_ int sd_bus_message_appendv( } t = types; - if (n_array != (unsigned) -1) + if (n_array != UINT_MAX) n_array--; else { types++; @@ -2446,7 +2443,7 @@ _public_ int sd_bus_message_appendv( return r; } - if (n_array == (unsigned) -1) { + if (n_array == UINT_MAX) { types += k; n_struct -= k; } @@ -2479,7 +2476,7 @@ _public_ int sd_bus_message_appendv( types = s; n_struct = strlen(s); - n_array = (unsigned) -1; + n_array = UINT_MAX; break; } @@ -2503,7 +2500,7 @@ _public_ int sd_bus_message_appendv( return r; } - if (n_array == (unsigned) -1) { + if (n_array == UINT_MAX) { types += k - 1; n_struct -= k - 1; } @@ -2514,7 +2511,7 @@ _public_ int sd_bus_message_appendv( types = t + 1; n_struct = k - 2; - n_array = (unsigned) -1; + n_array = UINT_MAX; break; } @@ -2676,7 +2673,7 @@ _public_ int sd_bus_message_append_array_memfd( if (r < 0) return r; - if (offset == 0 && size == (uint64_t) -1) + if (offset == 0 && size == UINT64_MAX) size = real_size; else if (offset + size > real_size) return -EMSGSIZE; @@ -2693,7 +2690,7 @@ _public_ int sd_bus_message_append_array_memfd( if (size % sz != 0) return -EINVAL; - if (size > (uint64_t) (uint32_t) -1) + if (size > (uint64_t) UINT32_MAX) return -EINVAL; r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY, CHAR_TO_STR(type)); @@ -2751,7 +2748,7 @@ _public_ int sd_bus_message_append_string_memfd( if (r < 0) return r; - if (offset == 0 && size == (uint64_t) -1) + if (offset == 0 && size == UINT64_MAX) size = real_size; else if (offset + size > real_size) return -EMSGSIZE; @@ -2760,7 +2757,7 @@ _public_ int sd_bus_message_append_string_memfd( if (size == 0) return -EINVAL; - if (size > (uint64_t) (uint32_t) -1) + if (size > (uint64_t) UINT32_MAX) return -EINVAL; c = message_get_last_container(m); @@ -2776,7 +2773,7 @@ _public_ int sd_bus_message_append_string_memfd( if (c->enclosing != 0) return -ENXIO; - e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING), NULL); + e = strextend(&c->signature, CHAR_TO_STR(SD_BUS_TYPE_STRING)); if (!e) { m->poisoned = true; return -ENOMEM; @@ -4431,7 +4428,7 @@ _public_ int sd_bus_message_readv( * in a single stackframe. We hence implement our own * home-grown stack in an array. */ - n_array = (unsigned) -1; /* length of current array entries */ + n_array = UINT_MAX; /* length of current array entries */ n_struct = strlen(types); /* length of current struct contents signature */ for (;;) { @@ -4439,7 +4436,7 @@ _public_ int sd_bus_message_readv( n_loop++; - if (n_array == 0 || (n_array == (unsigned) -1 && n_struct == 0)) { + if (n_array == 0 || (n_array == UINT_MAX && n_struct == 0)) { r = type_stack_pop(stack, ELEMENTSOF(stack), &stack_ptr, &types, &n_struct, &n_array); if (r < 0) return r; @@ -4454,7 +4451,7 @@ _public_ int sd_bus_message_readv( } t = types; - if (n_array != (unsigned) -1) + if (n_array != UINT_MAX) n_array--; else { types++; @@ -4515,7 +4512,7 @@ _public_ int sd_bus_message_readv( } } - if (n_array == (unsigned) -1) { + if (n_array == UINT_MAX) { types += k; n_struct -= k; } @@ -4554,7 +4551,7 @@ _public_ int sd_bus_message_readv( types = s; n_struct = strlen(s); - n_array = (unsigned) -1; + n_array = UINT_MAX; break; } @@ -4582,7 +4579,7 @@ _public_ int sd_bus_message_readv( } } - if (n_array == (unsigned) -1) { + if (n_array == UINT_MAX) { types += k - 1; n_struct -= k - 1; } @@ -4593,7 +4590,7 @@ _public_ int sd_bus_message_readv( types = t + 1; n_struct = k - 2; - n_array = (unsigned) -1; + n_array = UINT_MAX; break; } @@ -5035,7 +5032,7 @@ static int message_skip_fields( char t; size_t l; - if (array_size != (uint32_t) -1 && + if (array_size != UINT32_MAX && array_size <= *ri - original_index) return 0; @@ -5123,7 +5120,7 @@ static int message_skip_fields( if (r < 0) return r; - r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s); + r = message_skip_fields(m, ri, UINT32_MAX, (const char**) &s); if (r < 0) return r; @@ -5141,7 +5138,7 @@ static int message_skip_fields( strncpy(sig, *signature + 1, l); sig[l] = '\0'; - r = message_skip_fields(m, ri, (uint32_t) -1, (const char**) &s); + r = message_skip_fields(m, ri, UINT32_MAX, (const char**) &s); if (r < 0) return r; } @@ -5248,7 +5245,7 @@ int bus_message_parse_fields(sd_bus_message *m) { _cleanup_free_ char *sig = NULL; const char *signature; uint64_t field_type; - size_t item_size = (size_t) -1; + size_t item_size = SIZE_MAX; if (BUS_MESSAGE_IS_GVARIANT(m)) { uint64_t *u64; @@ -5462,7 +5459,7 @@ int bus_message_parse_fields(sd_bus_message *m) { default: if (!BUS_MESSAGE_IS_GVARIANT(m)) - r = message_skip_fields(m, &ri, (uint32_t) -1, (const char **) &signature); + r = message_skip_fields(m, &ri, UINT32_MAX, (const char **) &signature); } if (r < 0) @@ -5588,17 +5585,26 @@ int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz) { } int bus_message_read_strv_extend(sd_bus_message *m, char ***l) { - const char *s; + char type; + const char *contents, *s; int r; assert(m); assert(l); - r = sd_bus_message_enter_container(m, 'a', "s"); + r = sd_bus_message_peek_type(m, &type, &contents); + if (r < 0) + return r; + + if (type != SD_BUS_TYPE_ARRAY || !STR_IN_SET(contents, "s", "o", "g")) + return -ENXIO; + + r = sd_bus_message_enter_container(m, 'a', NULL); if (r <= 0) return r; - while ((r = sd_bus_message_read_basic(m, 's', &s)) > 0) { + /* sd_bus_message_read_basic() does content validation for us. */ + while ((r = sd_bus_message_read_basic(m, *contents, &s)) > 0) { r = strv_extend(l, s); if (r < 0) return r; diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c index 275c4318a..bfd42aea7 100644 --- a/src/libsystemd/sd-bus/bus-objects.c +++ b/src/libsystemd/sd-bus/bus-objects.c @@ -8,7 +8,6 @@ #include "bus-signature.h" #include "bus-slot.h" #include "bus-type.h" -#include "bus-util.h" #include "missing_capability.h" #include "set.h" #include "string-util.h" diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 4881fd0d3..832526cc1 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -620,7 +620,7 @@ static void bus_get_peercred(sd_bus *b) { assert(b); assert(!b->ucred_valid); assert(!b->label); - assert(b->n_groups == (size_t) -1); + assert(b->n_groups == SIZE_MAX); /* Get the peer for socketpair() sockets */ b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0; diff --git a/src/libsystemd/sd-bus/bus-track.c b/src/libsystemd/sd-bus/bus-track.c index 5f8716e2a..bc36673b8 100644 --- a/src/libsystemd/sd-bus/bus-track.c +++ b/src/libsystemd/sd-bus/bus-track.c @@ -5,7 +5,6 @@ #include "alloc-util.h" #include "bus-internal.h" #include "bus-track.h" -#include "bus-util.h" #include "string-util.h" struct track_item { diff --git a/src/libsystemd/sd-bus/fuzz-bus-match.c b/src/libsystemd/sd-bus/fuzz-bus-match.c new file mode 100644 index 000000000..0585338e2 --- /dev/null +++ b/src/libsystemd/sd-bus/fuzz-bus-match.c @@ -0,0 +1,86 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "bus-internal.h" +#include "bus-match.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fuzz.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_free_ char *out = NULL; /* out should be freed after g */ + size_t out_size; + _cleanup_fclose_ FILE *g = NULL; + _cleanup_(sd_bus_unrefp) sd_bus *bus = NULL; + int r; + + /* We don't want to fill the logs with messages about parse errors. + * Disable most logging if not running standalone */ + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); + + r = sd_bus_new(&bus); + assert_se(r >= 0); + + struct bus_match_node root = { + .type = BUS_MATCH_ROOT, + }; + + /* Note that we use the pointer to match_callback substructure, but the code + * uses container_of() to access outside of the passed-in type. */ + sd_bus_slot slot = { + .type = BUS_MATCH_CALLBACK, + .match_callback = {}, + }; + + if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) + assert_se(g = open_memstream_unlocked(&out, &out_size)); + + for (size_t offset = 0; offset < size; ) { + _cleanup_free_ char *line = NULL; + char *end; + + end = memchr((char*) data + offset, '\n', size - offset); + + line = memdup_suffix0((char*) data + offset, + end ? end - (char*) data - offset : size - offset); + if (!line) + return log_oom_debug(); + + offset = end ? (size_t) (end - (char*) data + 1) : size; + + struct bus_match_component *components; + unsigned n_components; + r = bus_match_parse(line, &components, &n_components); + if (IN_SET(r, -EINVAL, -ENOMEM)) { + log_debug_errno(r, "Failed to parse line: %m"); + continue; + } + assert_se(r >= 0); /* We only expect EINVAL and ENOMEM errors, or success. */ + + log_debug("Parsed %u components.", n_components); + + _cleanup_free_ char *again = bus_match_to_string(components, n_components); + if (!again) { + bus_match_parse_free(components, n_components); + log_oom(); + break; + } + + if (g) + fprintf(g, "%s\n", again); + + r = bus_match_add(&root, components, n_components, &slot.match_callback); + bus_match_parse_free(components, n_components); + if (r < 0) { + log_error_errno(r, "Failed to add match: %m"); + break; + } + } + + bus_match_dump(g ?: stdout, &root, 0); /* We do this even on failure, to check consistency after error. */ + bus_match_free(&root); + + return 0; +} diff --git a/src/fuzz/fuzz-bus-message.c b/src/libsystemd/sd-bus/fuzz-bus-message.c similarity index 100% rename from src/fuzz/fuzz-bus-message.c rename to src/libsystemd/sd-bus/fuzz-bus-message.c diff --git a/src/libsystemd/sd-bus/sd-bus.c b/src/libsystemd/sd-bus/sd-bus.c index b8d4dc8d9..e719c7437 100644 --- a/src/libsystemd/sd-bus/sd-bus.c +++ b/src/libsystemd/sd-bus/sd-bus.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -26,13 +25,13 @@ #include "bus-socket.h" #include "bus-track.h" #include "bus-type.h" -#include "bus-util.h" #include "cgroup-util.h" #include "def.h" #include "errno-util.h" #include "fd-util.h" #include "hexdecoct.h" #include "hostname-util.h" +#include "io-util.h" #include "macro.h" #include "memory-util.h" #include "missing_syscall.h" @@ -41,6 +40,7 @@ #include "process-util.h" #include "string-util.h" #include "strv.h" +#include "user-util.h" #define log_debug_bus_message(m) \ do { \ @@ -247,7 +247,7 @@ _public_ int sd_bus_new(sd_bus **ret) { .creds_mask = SD_BUS_CREDS_WELL_KNOWN_NAMES|SD_BUS_CREDS_UNIQUE_NAME, .accept_fd = true, .original_pid = getpid_cached(), - .n_groups = (size_t) -1, + .n_groups = SIZE_MAX, .close_on_exit = true, }; @@ -973,7 +973,7 @@ static int parse_container_unix_address(sd_bus *b, const char **p, char **guid) return -EINVAL; if (machine) { - if (!streq(machine, ".host") && !machine_name_is_valid(machine)) + if (!hostname_is_valid(machine, VALID_HOSTNAME_DOT_HOST)) return -EINVAL; free_and_replace(b->machine, machine); @@ -1448,7 +1448,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) { } if (!in_charset(p, "0123456789") || *p == '\0') { - if (!machine_name_is_valid(p) || got_forward_slash) + if (!hostname_is_valid(p, 0) || got_forward_slash) return -EINVAL; m = TAKE_PTR(p); @@ -1463,7 +1463,7 @@ int bus_set_address_system_remote(sd_bus *b, const char *host) { interpret_port_as_machine_old_syntax: /* Let's make sure this is not a port of some kind, * and is a valid machine name. */ - if (!in_charset(m, "0123456789") && machine_name_is_valid(m)) + if (!in_charset(m, "0123456789") && hostname_is_valid(m, 0)) c = strjoina(",argv", p ? "7" : "5", "=--machine=", m); } @@ -1514,44 +1514,228 @@ _public_ int sd_bus_open_system_remote(sd_bus **ret, const char *host) { return 0; } -int bus_set_address_system_machine(sd_bus *b, const char *machine) { - _cleanup_free_ char *e = NULL; - char *a; +int bus_set_address_machine(sd_bus *b, bool user, const char *machine) { + _cleanup_free_ char *a = NULL; + const char *rhs; assert(b); assert(machine); - e = bus_address_escape(machine); - if (!e) - return -ENOMEM; + rhs = strchr(machine, '@'); + if (rhs || user) { + _cleanup_free_ char *u = NULL, *eu = NULL, *erhs = NULL; - a = strjoin("x-machine-unix:machine=", e); - if (!a) - return -ENOMEM; + /* If there's an "@" in the container specification, we'll connect as a user specified at its + * left hand side, which is useful in combination with user=true. This isn't as trivial as it + * might sound: it's not sufficient to enter the container and connect to some socket there, + * since the --user socket path depends on $XDG_RUNTIME_DIR which is set via PAM. Thus, to be + * able to connect, we need to have a PAM session. Our way out? We use systemd-run to get + * into the container and acquire a PAM session there, and then invoke systemd-stdio-bridge + * in it, which propagates the bus transport to us.*/ + + if (rhs) { + if (rhs > machine) + u = strndup(machine, rhs - machine); + else + u = getusername_malloc(); /* Empty user name, let's use the local one */ + if (!u) + return -ENOMEM; + + eu = bus_address_escape(u); + if (!eu) + return -ENOMEM; + + rhs++; + } else { + /* No "@" specified but we shall connect to the user instance? Then assume root (and + * not a user named identically to the calling one). This means: + * + * --machine=foobar --user → connect to user bus of root user in container "foobar" + * --machine=@foobar --user → connect to user bus of user named like the calling user in container "foobar" + * + * Why? so that behaviour for "--machine=foobar --system" is roughly similar to + * "--machine=foobar --user": both times we unconditionally connect as root user + * regardless what the calling user is. */ + + rhs = machine; + } + + if (!isempty(rhs)) { + erhs = bus_address_escape(rhs); + if (!erhs) + return -ENOMEM; + } + + /* systemd-run -M… -PGq --wait -pUser=… -pPAMName=login systemd-stdio-bridge */ + + a = strjoin("unixexec:path=systemd-run," + "argv1=-M", erhs ?: ".host", "," + "argv2=-PGq," + "argv3=--wait," + "argv4=-pUser%3d", eu ?: "root", ",", + "argv5=-pPAMName%3dlogin," + "argv6=systemd-stdio-bridge"); + if (!a) + return -ENOMEM; + + if (user) { + char *k; + + /* Ideally we'd use the "--user" switch to systemd-stdio-bridge here, but it's only + * available in recent systemd versions. Using the "-p" switch with the explicit path + * is a working alternative, and is compatible with older versions, hence that's what + * we use here. */ + + k = strjoin(a, ",argv7=-punix:path%3d%24%7bXDG_RUNTIME_DIR%7d/bus"); + if (!k) + return -ENOMEM; + + free_and_replace(a, k); + } + } else { + _cleanup_free_ char *e = NULL; + + /* Just a container name, we can go the simple way, and just join the container, and connect + * to the well-known path of the system bus there. */ + + e = bus_address_escape(machine); + if (!e) + return -ENOMEM; + + a = strjoin("x-machine-unix:machine=", e); + if (!a) + return -ENOMEM; + } return free_and_replace(b->address, a); } -_public_ int sd_bus_open_system_machine(sd_bus **ret, const char *machine) { +static int user_and_machine_valid(const char *user_and_machine) { + const char *h; + + /* Checks if a container specification in the form "user@container" or just "container" is valid. + * + * If the "@" syntax is used we'll allow either the "user" or the "container" part to be omitted, but + * not both. */ + + h = strchr(user_and_machine, '@'); + if (!h) + h = user_and_machine; + else { + _cleanup_free_ char *user = NULL; + + user = strndup(user_and_machine, h - user_and_machine); + if (!user) + return -ENOMEM; + + if (!isempty(user) && !valid_user_group_name(user, VALID_USER_RELAX)) + return false; + + h++; + + if (isempty(h)) + return !isempty(user); + } + + return hostname_is_valid(h, VALID_HOSTNAME_DOT_HOST); +} + +static int user_and_machine_equivalent(const char *user_and_machine) { + _cleanup_free_ char *un = NULL; + const char *f; + + /* Returns true if the specified user+machine name are actually equivalent to our own identity and + * our own host. If so we can shortcut things. Why bother? Because that way we don't have to fork + * off short-lived worker processes that are then unavailable for authentication and logging in the + * peer. Moreover joining a namespace requires privileges. If we are in the right namespace anyway, + * we can avoid permission problems thus. */ + + assert(user_and_machine); + + /* Omitting the user name means that we shall use the same user name as we run as locally, which + * means we'll end up on the same host, let's shortcut */ + if (streq(user_and_machine, "@.host")) + return true; + + /* Otherwise, if we are root, then we can also allow the ".host" syntax, as that's the user this + * would connect to. */ + if (geteuid() == 0 && STR_IN_SET(user_and_machine, ".host", "root@.host")) + return true; + + /* Otherwise, we have to figure our user name, and compare things with that. */ + un = getusername_malloc(); + if (!un) + return -ENOMEM; + + f = startswith(user_and_machine, un); + if (!f) + return false; + + return STR_IN_SET(f, "@", "@.host"); +} + +_public_ int sd_bus_open_system_machine(sd_bus **ret, const char *user_and_machine) { _cleanup_(bus_freep) sd_bus *b = NULL; int r; - assert_return(machine, -EINVAL); + assert_return(user_and_machine, -EINVAL); assert_return(ret, -EINVAL); - assert_return(streq(machine, ".host") || machine_name_is_valid(machine), -EINVAL); + + if (user_and_machine_equivalent(user_and_machine)) + return sd_bus_open_system(ret); + + r = user_and_machine_valid(user_and_machine); + if (r < 0) + return r; + + assert_return(r > 0, -EINVAL); r = sd_bus_new(&b); if (r < 0) return r; - r = bus_set_address_system_machine(b, machine); + r = bus_set_address_machine(b, false, user_and_machine); if (r < 0) return r; b->bus_client = true; - b->trusted = false; b->is_system = true; - b->is_local = false; + + r = sd_bus_start(b); + if (r < 0) + return r; + + *ret = TAKE_PTR(b); + return 0; +} + +_public_ int sd_bus_open_user_machine(sd_bus **ret, const char *user_and_machine) { + _cleanup_(bus_freep) sd_bus *b = NULL; + int r; + + assert_return(user_and_machine, -EINVAL); + assert_return(ret, -EINVAL); + + /* Shortcut things if we'd end up on this host and as the same user. */ + if (user_and_machine_equivalent(user_and_machine)) + return sd_bus_open_user(ret); + + r = user_and_machine_valid(user_and_machine); + if (r < 0) + return r; + + assert_return(r > 0, -EINVAL); + + r = sd_bus_new(&b); + if (r < 0) + return r; + + r = bus_set_address_machine(b, true, user_and_machine); + if (r < 0) + return r; + + b->bus_client = true; + b->trusted = true; r = sd_bus_start(b); if (r < 0) @@ -1780,8 +1964,8 @@ int bus_seal_synthetic_message(sd_bus *b, sd_bus_message *m) { * hence let's fill something in for synthetic messages. Since * synthetic messages might have a fake sender and we don't * want to interfere with the real sender's serial numbers we - * pick a fixed, artificial one. We use (uint32_t) -1 rather - * than (uint64_t) -1 since dbus1 only had 32bit identifiers, + * pick a fixed, artificial one. We use UINT32_MAX rather + * than UINT64_MAX since dbus1 only had 32bit identifiers, * even though kdbus can do 64bit. */ return sd_bus_message_seal(m, 0xFFFFFFFFULL, 0); } @@ -2021,7 +2205,9 @@ _public_ int sd_bus_send_to(sd_bus *bus, sd_bus_message *m, const char *destinat static usec_t calc_elapse(sd_bus *bus, uint64_t usec) { assert(bus); - if (usec == (uint64_t) -1) + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); + + if (usec == USEC_INFINITY) return 0; /* We start all timeouts the instant we enter BUS_HELLO/BUS_RUNNING state, so that the don't run in parallel @@ -2031,7 +2217,7 @@ static usec_t calc_elapse(sd_bus *bus, uint64_t usec) { if (IN_SET(bus->state, BUS_WATCH_BIND, BUS_OPENING, BUS_AUTHENTICATING)) return usec; else - return now(CLOCK_MONOTONIC) + usec; + return usec_add(now(CLOCK_MONOTONIC), usec); } static int timeout_compare(const void *a, const void *b) { @@ -2146,7 +2332,7 @@ int bus_ensure_running(sd_bus *bus) { if (r > 0) continue; - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) return r; } @@ -2274,7 +2460,7 @@ _public_ int sd_bus_call( left = timeout - n; } else - left = (uint64_t) -1; + left = UINT64_MAX; r = bus_poll(bus, true, left); if (r < 0) @@ -2394,12 +2580,12 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { c = prioq_peek(bus->reply_callbacks_prioq); if (!c) { - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; } if (c->timeout_usec == 0) { - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; } @@ -2412,7 +2598,7 @@ _public_ int sd_bus_get_timeout(sd_bus *bus, uint64_t *timeout_usec) { case BUS_WATCH_BIND: case BUS_OPENING: - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; default: @@ -3071,9 +3257,8 @@ _public_ int sd_bus_process_priority(sd_bus *bus, int64_t priority, sd_bus_messa static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { struct pollfd p[2] = {}; - int r, n; - struct timespec ts; usec_t m = USEC_INFINITY; + int r, n; assert(bus); @@ -3125,19 +3310,12 @@ static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec) { } } - if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m)) + if (timeout_usec != UINT64_MAX && (m == USEC_INFINITY || timeout_usec < m)) m = timeout_usec; - r = ppoll(p, n, m == USEC_INFINITY ? NULL : timespec_store(&ts, m), NULL); - if (r < 0) - return -errno; - if (r == 0) - return 0; - - if (p[0].revents & POLLNVAL) - return -EBADF; - if (n >= 2 && (p[1].revents & POLLNVAL)) - return -EBADF; + r = ppoll_usec(p, n, m); + if (r <= 0) + return r; return 1; } @@ -3198,7 +3376,7 @@ _public_ int sd_bus_flush(sd_bus *bus) { if (bus->wqueue_size <= 0) return 0; - r = bus_poll(bus, false, (uint64_t) -1); + r = bus_poll(bus, false, UINT64_MAX); if (r < 0) return r; } diff --git a/src/libsystemd/sd-bus/test-bus-benchmark.c b/src/libsystemd/sd-bus/test-bus-benchmark.c index 8c6711797..13c08fe29 100644 --- a/src/libsystemd/sd-bus/test-bus-benchmark.c +++ b/src/libsystemd/sd-bus/test-bus-benchmark.c @@ -8,10 +8,10 @@ #include "alloc-util.h" #include "bus-internal.h" #include "bus-kernel.h" -#include "bus-util.h" #include "def.h" #include "fd-util.h" #include "missing_resource.h" +#include "string-util.h" #include "time-util.h" #include "util.h" diff --git a/src/libsystemd/sd-bus/test-bus-chat.c b/src/libsystemd/sd-bus/test-bus-chat.c index c3c31c65e..df6dd6215 100644 --- a/src/libsystemd/sd-bus/test-bus-chat.c +++ b/src/libsystemd/sd-bus/test-bus-chat.c @@ -11,12 +11,12 @@ #include "bus-error.h" #include "bus-internal.h" #include "bus-match.h" -#include "bus-util.h" #include "errno-util.h" #include "fd-util.h" #include "format-util.h" #include "log.h" #include "macro.h" +#include "string-util.h" #include "tests.h" #include "util.h" @@ -101,7 +101,7 @@ static int server_init(sd_bus **_bus) { goto fail; } - bus_match_dump(&bus->match_callbacks, 0); + bus_match_dump(stdout, &bus->match_callbacks, 0); *_bus = bus; return 0; @@ -127,7 +127,7 @@ static int server(sd_bus *bus) { } if (r == 0) { - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) { log_error_errno(r, "Failed to wait: %m"); goto fail; @@ -472,7 +472,7 @@ static void* client2(void *p) { goto finish; } if (r == 0) { - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) { log_error_errno(r, "Failed to wait: %m"); goto finish; diff --git a/src/libsystemd/sd-bus/test-bus-cleanup.c b/src/libsystemd/sd-bus/test-bus-cleanup.c index ece0a12ba..f563db74e 100644 --- a/src/libsystemd/sd-bus/test-bus-cleanup.c +++ b/src/libsystemd/sd-bus/test-bus-cleanup.c @@ -6,7 +6,6 @@ #include "bus-internal.h" #include "bus-message.h" -#include "bus-util.h" #include "tests.h" static bool use_system_bus = false; diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index 6551e692f..13801becc 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -3,7 +3,6 @@ #include "sd-bus.h" #include "bus-dump.h" -#include "bus-util.h" #include "cgroup-util.h" #include "tests.h" diff --git a/src/libsystemd/sd-bus/test-bus-error.c b/src/libsystemd/sd-bus/test-bus-error.c index 2e3803c9b..84728e4e8 100644 --- a/src/libsystemd/sd-bus/test-bus-error.c +++ b/src/libsystemd/sd-bus/test-bus-error.c @@ -2,11 +2,12 @@ #include "sd-bus.h" +#include "alloc-util.h" #include "bus-common-errors.h" #include "bus-error.h" -#include "bus-util.h" #include "errno-list.h" #include "errno-util.h" +#include "string-util.h" static void test_error(void) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL, second = SD_BUS_ERROR_NULL; @@ -14,7 +15,7 @@ static void test_error(void) { const sd_bus_error temporarily_const_error = { .name = SD_BUS_ERROR_ACCESS_DENIED, .message = "oh! no", - ._need_free = -1 + ._need_free = -1, }; assert_se(!sd_bus_error_is_set(&error)); diff --git a/src/libsystemd/sd-bus/test-bus-gvariant.c b/src/libsystemd/sd-bus/test-bus-gvariant.c index b0033f1d1..edd8301d4 100644 --- a/src/libsystemd/sd-bus/test-bus-gvariant.c +++ b/src/libsystemd/sd-bus/test-bus-gvariant.c @@ -11,7 +11,6 @@ #include "bus-gvariant.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-util.h" #include "macro.h" #include "tests.h" #include "util.h" diff --git a/src/libsystemd/sd-bus/test-bus-match.c b/src/libsystemd/sd-bus/test-bus-match.c index aa6ddd336..7a20a6c3c 100644 --- a/src/libsystemd/sd-bus/test-bus-match.c +++ b/src/libsystemd/sd-bus/test-bus-match.c @@ -3,7 +3,6 @@ #include "bus-match.h" #include "bus-message.h" #include "bus-slot.h" -#include "bus-util.h" #include "log.h" #include "macro.h" #include "memory-util.h" @@ -38,13 +37,12 @@ static bool mask_contains(unsigned a[], unsigned n) { } static int match_add(sd_bus_slot *slots, struct bus_match_node *root, const char *match, int value) { - struct bus_match_component *components = NULL; - unsigned n_components = 0; + struct bus_match_component *components; + unsigned n_components; sd_bus_slot *s; int r; s = slots + value; - zero(*s); r = bus_match_parse(match, &components, &n_components); if (r < 0) @@ -75,8 +73,7 @@ int main(int argc, char *argv[]) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; - enum bus_match_node_type i; - sd_bus_slot slots[19]; + sd_bus_slot slots[19] = {}; int r; test_setup_logging(LOG_INFO); @@ -106,7 +103,7 @@ int main(int argc, char *argv[]) { assert_se(match_add(slots, &root, "arg4has='po'", 17) >= 0); assert_se(match_add(slots, &root, "arg4='pi'", 18) >= 0); - bus_match_dump(&root, 0); + bus_match_dump(stdout, &root, 0); assert_se(sd_bus_message_new_signal(bus, &m, "/foo/bar", "bar.x", "waldo") >= 0); assert_se(sd_bus_message_append(m, "ssssas", "one", "two", "/prefix/three", "prefix.four", 3, "pi", "pa", "po") >= 0); @@ -119,13 +116,13 @@ int main(int argc, char *argv[]) { assert_se(bus_match_remove(&root, &slots[8].match_callback) >= 0); assert_se(bus_match_remove(&root, &slots[13].match_callback) >= 0); - bus_match_dump(&root, 0); + bus_match_dump(stdout, &root, 0); zero(mask); assert_se(bus_match_run(NULL, &root, m) == 0); assert_se(mask_contains((unsigned[]) { 9, 5, 10, 12, 14, 7, 15, 16, 17 }, 9)); - for (i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) { + for (enum bus_match_node_type i = 0; i < _BUS_MATCH_NODE_TYPE_MAX; i++) { char buf[32]; const char *x; diff --git a/src/libsystemd/sd-bus/test-bus-objects.c b/src/libsystemd/sd-bus/test-bus-objects.c index 911621188..a71add434 100644 --- a/src/libsystemd/sd-bus/test-bus-objects.c +++ b/src/libsystemd/sd-bus/test-bus-objects.c @@ -9,7 +9,6 @@ #include "bus-dump.h" #include "bus-internal.h" #include "bus-message.h" -#include "bus-util.h" #include "log.h" #include "macro.h" #include "strv.h" @@ -256,7 +255,7 @@ static void *server(void *p) { } if (r == 0) { - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) { log_error_errno(r, "Failed to wait: %m"); goto fail; @@ -298,8 +297,7 @@ static int client(struct context *c) { assert_se(r >= 0); assert_se(streq(s, "<<>>")); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, ""); assert_se(r < 0); @@ -307,6 +305,12 @@ static int client(struct context *c) { sd_bus_error_free(&error); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Doesntexist", &error, &reply, NULL); /* NULL and "" are equivalent */ + assert_se(r < 0); + assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)); + + sd_bus_error_free(&error); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AlterSomething", &error, &reply, "as", 1, "hallo"); assert_se(r < 0); assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)); @@ -320,8 +324,7 @@ static int client(struct context *c) { assert_se(r >= 0); assert_se(streq(s, "<<>>")); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Something", &error, "s", "test"); assert_se(r >= 0); @@ -333,8 +336,7 @@ static int client(struct context *c) { assert_se(r >= 0); assert_se(streq(s, "test")); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); r = sd_bus_set_property(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "AutomaticIntegerProperty", &error, "u", 815); assert_se(r >= 0); @@ -353,8 +355,16 @@ static int client(struct context *c) { assert_se(r >= 0); fputs(s, stdout); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); + + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL); /* NULL and "" are equivalent */ + assert_se(r >= 0); + + r = sd_bus_message_read(reply, "s", &s); + assert_se(r >= 0); + fputs(s, stdout); + + reply = sd_bus_message_unref(reply); r = sd_bus_get_property(bus, "org.freedesktop.systemd.test", "/value/xuzz", "org.freedesktop.systemd.ValueTest", "Value", &error, &reply, "s"); assert_se(r >= 0); @@ -363,66 +373,60 @@ static int client(struct context *c) { assert_se(r >= 0); log_info("read %s", s); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL); assert_se(r >= 0); r = sd_bus_message_read(reply, "s", &s); assert_se(r >= 0); fputs(s, stdout); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL); assert_se(r >= 0); r = sd_bus_message_read(reply, "s", &s); assert_se(r >= 0); fputs(s, stdout); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Introspectable", "Introspect", &error, &reply, NULL); assert_se(r >= 0); r = sd_bus_message_read(reply, "s", &s); assert_se(r >= 0); fputs(s, stdout); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", NULL); assert_se(r >= 0); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.DBus.Properties", "GetAll", &error, &reply, "s", "org.freedesktop.systemd.ValueTest2"); assert_se(r < 0); assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_INTERFACE)); sd_bus_error_free(&error); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, NULL); assert_se(r < 0); assert_se(sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)); sd_bus_error_free(&error); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects", &error, &reply, NULL); assert_se(r >= 0); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest", &error, NULL, NULL); assert_se(r >= 0); r = sd_bus_process(bus, &reply); @@ -431,10 +435,9 @@ static int client(struct context *c) { assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/value/a", "org.freedesktop.systemd.ValueTest", "NotifyTest2", &error, NULL, NULL); assert_se(r >= 0); r = sd_bus_process(bus, &reply); @@ -443,10 +446,9 @@ static int client(struct context *c) { assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.Properties", "PropertiesChanged")); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesAdded", &error, NULL, NULL); assert_se(r >= 0); r = sd_bus_process(bus, &reply); @@ -455,10 +457,9 @@ static int client(struct context *c) { assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitInterfacesRemoved", &error, NULL, NULL); assert_se(r >= 0); r = sd_bus_process(bus, &reply); @@ -467,10 +468,9 @@ static int client(struct context *c) { assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved")); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectAdded", &error, NULL, NULL); assert_se(r >= 0); r = sd_bus_process(bus, &reply); @@ -479,10 +479,9 @@ static int client(struct context *c) { assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded")); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "EmitObjectRemoved", &error, NULL, NULL); assert_se(r >= 0); r = sd_bus_process(bus, &reply); @@ -491,10 +490,9 @@ static int client(struct context *c) { assert_se(sd_bus_message_is_signal(reply, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved")); sd_bus_message_dump(reply, stdout, SD_BUS_MESSAGE_DUMP_WITH_HEADER); - sd_bus_message_unref(reply); - reply = NULL; + reply = sd_bus_message_unref(reply); - r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, ""); + r = sd_bus_call_method(bus, "org.freedesktop.systemd.test", "/foo", "org.freedesktop.systemd.test", "Exit", &error, NULL, NULL); assert_se(r >= 0); sd_bus_flush(bus); diff --git a/src/libsystemd/sd-bus/test-bus-server.c b/src/libsystemd/sd-bus/test-bus-server.c index 5cb100b2f..ab4045ee1 100644 --- a/src/libsystemd/sd-bus/test-bus-server.c +++ b/src/libsystemd/sd-bus/test-bus-server.c @@ -6,10 +6,10 @@ #include "sd-bus.h" #include "bus-internal.h" -#include "bus-util.h" #include "log.h" #include "macro.h" #include "memory-util.h" +#include "string-util.h" struct context { int fds[2]; @@ -47,7 +47,7 @@ static void *server(void *p) { } if (r == 0) { - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) { log_error_errno(r, "Failed to wait: %m"); goto fail; diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index 6f0b97562..b373c173c 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -40,7 +40,7 @@ static void unsetenv_all(bool unset_environment) { _public_ int sd_listen_fds(int unset_environment) { const char *e; - int n, r, fd; + int n, r; pid_t pid; e = getenv("LISTEN_PID"); @@ -75,7 +75,7 @@ _public_ int sd_listen_fds(int unset_environment) { goto finish; } - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { + for (int fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { r = fd_cloexec(fd, true); if (r < 0) goto finish; diff --git a/src/libsystemd/sd-device/device-enumerator.c b/src/libsystemd/sd-device/device-enumerator.c index 364134888..c98b029af 100644 --- a/src/libsystemd/sd-device/device-enumerator.c +++ b/src/libsystemd/sd-device/device-enumerator.c @@ -21,7 +21,7 @@ typedef enum DeviceEnumerationType { DEVICE_ENUMERATION_TYPE_DEVICES, DEVICE_ENUMERATION_TYPE_SUBSYSTEMS, _DEVICE_ENUMERATION_TYPE_MAX, - _DEVICE_ENUMERATION_TYPE_INVALID = -1, + _DEVICE_ENUMERATION_TYPE_INVALID = -EINVAL, } DeviceEnumerationType; struct sd_device_enumerator { @@ -63,11 +63,9 @@ _public_ int sd_device_enumerator_new(sd_device_enumerator **ret) { } static sd_device_enumerator *device_enumerator_free(sd_device_enumerator *enumerator) { - size_t i; - assert(enumerator); - for (i = 0; i < enumerator->n_devices; i++) + for (size_t i = 0; i < enumerator->n_devices; i++) sd_device_unref(enumerator->devices[i]); free(enumerator->devices); @@ -287,13 +285,11 @@ int device_enumerator_add_device(sd_device_enumerator *enumerator, sd_device *de static bool match_sysattr_value(sd_device *device, const char *sysattr, const char *match_value) { const char *value; - int r; assert(device); assert(sysattr); - r = sd_device_get_sysattr_value(device, sysattr, &value); - if (r < 0) + if (sd_device_get_sysattr_value(device, sysattr, &value) < 0) return false; if (!match_value) @@ -784,7 +780,6 @@ static void device_enumerator_dedup_devices(sd_device_enumerator *enumerator) { int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { int r = 0, k; - size_t i; assert(enumerator); @@ -792,7 +787,7 @@ int device_enumerator_scan_devices(sd_device_enumerator *enumerator) { enumerator->type == DEVICE_ENUMERATION_TYPE_DEVICES) return 0; - for (i = 0; i < enumerator->n_devices; i++) + for (size_t i = 0; i < enumerator->n_devices; i++) sd_device_unref(enumerator->devices[i]); enumerator->n_devices = 0; @@ -851,7 +846,6 @@ _public_ sd_device *sd_device_enumerator_get_device_next(sd_device_enumerator *e int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { const char *subsysdir; int r = 0, k; - size_t i; assert(enumerator); @@ -859,7 +853,7 @@ int device_enumerator_scan_subsystems(sd_device_enumerator *enumerator) { enumerator->type == DEVICE_ENUMERATION_TYPE_SUBSYSTEMS) return 0; - for (i = 0; i < enumerator->n_devices; i++) + for (size_t i = 0; i < enumerator->n_devices; i++) sd_device_unref(enumerator->devices[i]); enumerator->n_devices = 0; diff --git a/src/libsystemd/sd-device/device-internal.h b/src/libsystemd/sd-device/device-internal.h index 3321c8e2d..c1a81e3b4 100644 --- a/src/libsystemd/sd-device/device-internal.h +++ b/src/libsystemd/sd-device/device-internal.h @@ -76,7 +76,7 @@ struct sd_device { gid_t devgid; /* only set when device is passed through netlink */ - DeviceAction action; + sd_device_action_t action; uint64_t seqnum; bool parent_set:1; /* no need to try to reload parent */ diff --git a/src/libsystemd/sd-device/device-monitor-private.h b/src/libsystemd/sd-device/device-monitor-private.h index 2ca3a313b..33e271460 100644 --- a/src/libsystemd/sd-device/device-monitor-private.h +++ b/src/libsystemd/sd-device/device-monitor-private.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + #include "sd-device.h" typedef enum MonitorNetlinkGroup { @@ -8,7 +10,7 @@ typedef enum MonitorNetlinkGroup { MONITOR_GROUP_KERNEL, MONITOR_GROUP_UDEV, _MONITOR_NETLINK_GROUP_MAX, - _MONITOR_NETLINK_GROUP_INVALID = -1, + _MONITOR_NETLINK_GROUP_INVALID = -EINVAL, } MonitorNetlinkGroup; int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group, int fd); diff --git a/src/libsystemd/sd-device/device-monitor.c b/src/libsystemd/sd-device/device-monitor.c index fd5900704..203106ab4 100644 --- a/src/libsystemd/sd-device/device-monitor.c +++ b/src/libsystemd/sd-device/device-monitor.c @@ -627,8 +627,9 @@ _public_ int sd_device_monitor_filter_update(sd_device_monitor *m) { if (m->filter_uptodate) return 0; - if (hashmap_isempty(m->subsystem_filter) && - set_isempty(m->tag_filter)) { + if (m->snl.nl.nl_groups == MONITOR_GROUP_KERNEL || + (hashmap_isempty(m->subsystem_filter) && + set_isempty(m->tag_filter))) { m->filter_uptodate = true; return 0; } @@ -732,15 +733,13 @@ _public_ int sd_device_monitor_filter_add_match_subsystem_devtype(sd_device_moni return -ENOMEM; } - r = hashmap_ensure_allocated(&m->subsystem_filter, NULL); + r = hashmap_ensure_put(&m->subsystem_filter, NULL, s, d); if (r < 0) return r; - r = hashmap_put(m->subsystem_filter, s, d); - if (r < 0) - return r; + TAKE_PTR(s); + TAKE_PTR(d); - s = d = NULL; m->filter_uptodate = false; return 0; diff --git a/src/libsystemd/sd-device/device-private.c b/src/libsystemd/sd-device/device-private.c index 9070dfbdd..7a7204b14 100644 --- a/src/libsystemd/sd-device/device-private.c +++ b/src/libsystemd/sd-device/device-private.c @@ -98,7 +98,7 @@ int device_get_devnode_mode(sd_device *device, mode_t *mode) { if (r < 0) return r; - if (device->devmode == (mode_t) -1) + if (device->devmode == MODE_INVALID) return -ENOENT; if (mode) @@ -116,7 +116,7 @@ int device_get_devnode_uid(sd_device *device, uid_t *uid) { if (r < 0) return r; - if (device->devuid == (uid_t) -1) + if (device->devuid == UID_INVALID) return -ENOENT; if (uid) @@ -154,7 +154,7 @@ int device_get_devnode_gid(sd_device *device, gid_t *gid) { if (r < 0) return r; - if (device->devgid == (gid_t) -1) + if (device->devgid == GID_INVALID) return -ENOENT; if (gid) @@ -183,20 +183,8 @@ static int device_set_devgid(sd_device *device, const char *gid) { return 0; } -int device_get_action(sd_device *device, DeviceAction *action) { - assert(device); - - if (device->action < 0) - return -ENOENT; - - if (action) - *action = device->action; - - return 0; -} - static int device_set_action(sd_device *device, const char *action) { - DeviceAction a; + sd_device_action_t a; int r; assert(device); @@ -204,9 +192,9 @@ static int device_set_action(sd_device *device, const char *action) { a = device_action_from_string(action); if (a < 0) - return -EINVAL; + return a; - r = device_add_property_internal(device, "ACTION", action); + r = device_add_property_internal(device, "ACTION", device_action_to_string(a)); if (r < 0) return r; @@ -215,18 +203,6 @@ static int device_set_action(sd_device *device, const char *action) { return 0; } -int device_get_seqnum(sd_device *device, uint64_t *seqnum) { - assert(device); - - if (device->seqnum == 0) - return -ENOENT; - - if (seqnum) - *seqnum = device->seqnum; - - return 0; -} - static int device_set_seqnum(sd_device *device, const char *str) { uint64_t seqnum; int r; @@ -355,7 +331,12 @@ static int device_amend(sd_device *device, const char *key, const char *value) { return 0; } -static int device_append(sd_device *device, char *key, const char **_major, const char **_minor) { +static int device_append( + sd_device *device, + char *key, + const char **_major, + const char **_minor) { + const char *major = NULL, *minor = NULL; char *value; int r; @@ -384,10 +365,10 @@ static int device_append(sd_device *device, char *key, const char **_major, cons return r; } - if (major != 0) + if (major) *_major = major; - if (minor != 0) + if (minor) *_minor = minor; return 0; @@ -448,7 +429,6 @@ int device_new_from_strv(sd_device **ret, char **strv) { int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; const char *major = NULL, *minor = NULL; - unsigned i = 0; int r; assert(ret); @@ -459,11 +439,11 @@ int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len) { if (r < 0) return r; - while (i < len) { + for (size_t i = 0; i < len; ) { char *key; const char *end; - key = (char*)&nulstr[i]; + key = (char*) &nulstr[i]; end = memchr(key, '\0', len - i); if (!end) return log_device_debug_errno(device, SYNTHETIC_ERRNO(EINVAL), @@ -720,22 +700,6 @@ int device_new_from_synthetic_event(sd_device **new_device, const char *syspath, return 0; } -int device_new_from_stat_rdev(sd_device **ret, const struct stat *st) { - char type; - - assert(ret); - assert(st); - - if (S_ISBLK(st->st_mode)) - type = 'b'; - else if (S_ISCHR(st->st_mode)) - type = 'c'; - else - return -ENOTTY; - - return sd_device_new_from_devnum(ret, type, st->st_rdev); -} - int device_copy_properties(sd_device *device_dst, sd_device *device_src) { const char *property, *value; int r; @@ -999,19 +963,19 @@ int device_delete_db(sd_device *device) { return 0; } -static const char* const device_action_table[_DEVICE_ACTION_MAX] = { - [DEVICE_ACTION_ADD] = "add", - [DEVICE_ACTION_REMOVE] = "remove", - [DEVICE_ACTION_CHANGE] = "change", - [DEVICE_ACTION_MOVE] = "move", - [DEVICE_ACTION_ONLINE] = "online", - [DEVICE_ACTION_OFFLINE] = "offline", - [DEVICE_ACTION_BIND] = "bind", - [DEVICE_ACTION_UNBIND] = "unbind", +static const char* const device_action_table[_SD_DEVICE_ACTION_MAX] = { + [SD_DEVICE_ADD] = "add", + [SD_DEVICE_REMOVE] = "remove", + [SD_DEVICE_CHANGE] = "change", + [SD_DEVICE_MOVE] = "move", + [SD_DEVICE_ONLINE] = "online", + [SD_DEVICE_OFFLINE] = "offline", + [SD_DEVICE_BIND] = "bind", + [SD_DEVICE_UNBIND] = "unbind", }; -DEFINE_STRING_TABLE_LOOKUP(device_action, DeviceAction); +DEFINE_STRING_TABLE_LOOKUP(device_action, sd_device_action_t); void dump_device_action_table(void) { - DUMP_STRING_TABLE(device_action, DeviceAction, _DEVICE_ACTION_MAX); + DUMP_STRING_TABLE(device_action, sd_device_action_t, _SD_DEVICE_ACTION_MAX); } diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h index db81934f3..ec76f772e 100644 --- a/src/libsystemd/sd-device/device-private.h +++ b/src/libsystemd/sd-device/device-private.h @@ -10,22 +10,8 @@ #include "macro.h" -typedef enum DeviceAction { - DEVICE_ACTION_ADD, - DEVICE_ACTION_REMOVE, - DEVICE_ACTION_CHANGE, - DEVICE_ACTION_MOVE, - DEVICE_ACTION_ONLINE, - DEVICE_ACTION_OFFLINE, - DEVICE_ACTION_BIND, - DEVICE_ACTION_UNBIND, - _DEVICE_ACTION_MAX, - _DEVICE_ACTION_INVALID = -1, -} DeviceAction; - int device_new_from_nulstr(sd_device **ret, uint8_t *nulstr, size_t len); int device_new_from_strv(sd_device **ret, char **strv); -int device_new_from_stat_rdev(sd_device **ret, const struct stat *st); int device_get_id_filename(sd_device *device, const char **ret); @@ -34,8 +20,6 @@ int device_get_watch_handle(sd_device *device, int *handle); int device_get_devnode_mode(sd_device *device, mode_t *mode); int device_get_devnode_uid(sd_device *device, uid_t *uid); int device_get_devnode_gid(sd_device *device, gid_t *gid); -int device_get_action(sd_device *device, DeviceAction *action); -int device_get_seqnum(sd_device *device, uint64_t *seqnum); void device_seal(sd_device *device); void device_set_is_initialized(sd_device *device); @@ -73,6 +57,6 @@ static inline int device_read_db(sd_device *device) { return device_read_db_internal(device, false); } -DeviceAction device_action_from_string(const char *s) _pure_; -const char *device_action_to_string(DeviceAction a) _const_; +sd_device_action_t device_action_from_string(const char *s) _pure_; +const char *device_action_to_string(sd_device_action_t a) _const_; void dump_device_action_table(void); diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c index d1aa3282b..e556a6f83 100644 --- a/src/libsystemd/sd-device/sd-device.c +++ b/src/libsystemd/sd-device/sd-device.c @@ -26,6 +26,7 @@ #include "string-util.h" #include "strv.h" #include "strxcpyx.h" +#include "user-util.h" #include "util.h" int device_new_aux(sd_device **ret) { @@ -40,10 +41,10 @@ int device_new_aux(sd_device **ret) { *device = (sd_device) { .n_ref = 1, .watch_handle = -1, - .devmode = (mode_t) -1, - .devuid = (uid_t) -1, - .devgid = (gid_t) -1, - .action = _DEVICE_ACTION_INVALID, + .devmode = MODE_INVALID, + .devuid = UID_INVALID, + .devgid = GID_INVALID, + .action = _SD_DEVICE_ACTION_INVALID, }; *ret = device; @@ -65,9 +66,9 @@ static sd_device *device_free(sd_device *device) { free(device->properties_strv); free(device->properties_nulstr); - ordered_hashmap_free_free_free(device->properties); - ordered_hashmap_free_free_free(device->properties_db); - hashmap_free_free_free(device->sysattr_values); + ordered_hashmap_free(device->properties); + ordered_hashmap_free(device->properties_db); + hashmap_free(device->sysattr_values); set_free(device->sysattrs); set_free(device->all_tags); set_free(device->current_tags); @@ -78,46 +79,46 @@ static sd_device *device_free(sd_device *device) { DEFINE_PUBLIC_TRIVIAL_REF_UNREF_FUNC(sd_device, sd_device, device_free); -int device_add_property_aux(sd_device *device, const char *_key, const char *_value, bool db) { +int device_add_property_aux(sd_device *device, const char *key, const char *value, bool db) { OrderedHashmap **properties; assert(device); - assert(_key); + assert(key); if (db) properties = &device->properties_db; else properties = &device->properties; - if (_value) { - _cleanup_free_ char *key = NULL, *value = NULL, *old_key = NULL, *old_value = NULL; + if (value) { + _cleanup_free_ char *new_key = NULL, *new_value = NULL, *old_key = NULL, *old_value = NULL; int r; - r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops); + r = ordered_hashmap_ensure_allocated(properties, &string_hash_ops_free_free); if (r < 0) return r; - key = strdup(_key); - if (!key) + new_key = strdup(key); + if (!new_key) return -ENOMEM; - value = strdup(_value); - if (!value) + new_value = strdup(value); + if (!new_value) return -ENOMEM; old_value = ordered_hashmap_get2(*properties, key, (void**) &old_key); - r = ordered_hashmap_replace(*properties, key, value); + /* ordered_hashmap_replace() does not fail when the hashmap already has the entry. */ + r = ordered_hashmap_replace(*properties, new_key, new_value); if (r < 0) return r; - key = NULL; - value = NULL; + TAKE_PTR(new_key); + TAKE_PTR(new_value); } else { - _cleanup_free_ char *key = NULL; - _cleanup_free_ char *value = NULL; + _cleanup_free_ char *old_key = NULL, *old_value = NULL; - value = ordered_hashmap_remove2(*properties, _key, (void**) &key); + old_value = ordered_hashmap_remove2(*properties, key, (void**) &old_key); } if (!db) { @@ -198,7 +199,7 @@ int device_set_syspath(sd_device *device, const char *_syspath, bool verify) { devpath = syspath + STRLEN("/sys"); - if (devpath[0] == '\0') + if (devpath[0] != '/') /* '/sys' alone is not a valid device path */ return -ENODEV; @@ -231,8 +232,7 @@ _public_ int sd_device_new_from_syspath(sd_device **ret, const char *syspath) { } _public_ int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum) { - char *syspath; - char id[DECIMAL_STR_MAX(unsigned) * 2 + 1]; + char id[DECIMAL_STR_MAX(unsigned) * 2 + 1], *syspath; assert_return(ret, -EINVAL); assert_return(IN_SET(type, 'b', 'c'), -EINVAL); @@ -317,6 +317,22 @@ _public_ int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *s return -ENODEV; } +_public_ int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st) { + char type; + + assert_return(ret, -EINVAL); + assert_return(st, -EINVAL); + + if (S_ISBLK(st->st_mode)) + type = 'b'; + else if (S_ISCHR(st->st_mode)) + type = 'c'; + else + return -ENOTTY; + + return sd_device_new_from_devnum(ret, type, st->st_rdev); +} + int device_set_devtype(sd_device *device, const char *devtype) { _cleanup_free_ char *t = NULL; int r; @@ -399,7 +415,7 @@ int device_set_devmode(sd_device *device, const char *_devmode) { } int device_set_devnum(sd_device *device, const char *major, const char *minor) { - unsigned maj = 0, min = 0; + unsigned maj, min = 0; int r; assert(device); @@ -408,7 +424,7 @@ int device_set_devnum(sd_device *device, const char *major, const char *minor) { r = safe_atou(major, &maj); if (r < 0) return r; - if (!maj) + if (maj == 0) return 0; if (minor) { @@ -497,14 +513,14 @@ int device_read_uevent_file(sd_device *device) { path = strjoina(syspath, "/uevent"); - r = read_full_file(path, &uevent, &uevent_len); + r = read_full_virtual_file(path, &uevent, &uevent_len); if (r == -EACCES) { /* empty uevent files may be write-only */ device->uevent_loaded = true; return 0; } if (r == -ENOENT) - /* some devices may not have uevent files, see set_syspath() */ + /* some devices may not have uevent files, see device_set_syspath() */ return 0; if (r < 0) return log_device_debug_errno(device, r, "sd-device: Failed to read uevent file '%s': %m", path); @@ -659,11 +675,11 @@ _public_ int sd_device_new_from_device_id(sd_device **ret, const char *id) { _public_ int sd_device_get_syspath(sd_device *device, const char **ret) { assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); assert(path_startswith(device->syspath, "/sys/")); - *ret = device->syspath; + if (ret) + *ret = device->syspath; return 0; } @@ -705,8 +721,6 @@ static int device_new_from_child(sd_device **ret, sd_device *child) { } _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) { - - assert_return(ret, -EINVAL); assert_return(child, -EINVAL); if (!child->parent_set) { @@ -718,7 +732,8 @@ _public_ int sd_device_get_parent(sd_device *child, sd_device **ret) { if (!child->parent) return -ENOENT; - *ret = child->parent; + if (ret) + *ret = child->parent; return 0; } @@ -764,7 +779,6 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { const char *syspath, *drivers = NULL; int r; - assert_return(ret, -EINVAL); assert_return(device, -EINVAL); r = sd_device_get_syspath(device, &syspath); @@ -821,7 +835,8 @@ _public_ int sd_device_get_subsystem(sd_device *device, const char **ret) { if (!device->subsystem) return -ENOENT; - *ret = device->subsystem; + if (ret) + *ret = device->subsystem; return 0; } @@ -853,10 +868,11 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const r = sd_device_get_parent(child, &parent); while (r >= 0) { const char *parent_subsystem = NULL; - const char *parent_devtype = NULL; (void) sd_device_get_subsystem(parent, &parent_subsystem); if (streq_ptr(parent_subsystem, subsystem)) { + const char *parent_devtype = NULL; + if (!devtype) break; @@ -870,7 +886,8 @@ _public_ int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const if (r < 0) return r; - *ret = parent; + if (ret) + *ret = parent; return 0; } @@ -913,7 +930,6 @@ int device_set_driver(sd_device *device, const char *_driver) { _public_ int sd_device_get_driver(sd_device *device, const char **ret) { assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); if (!device->driver_set) { _cleanup_free_ char *driver = NULL; @@ -940,18 +956,19 @@ _public_ int sd_device_get_driver(sd_device *device, const char **ret) { if (!device->driver) return -ENOENT; - *ret = device->driver; + if (ret) + *ret = device->driver; return 0; } _public_ int sd_device_get_devpath(sd_device *device, const char **devpath) { assert_return(device, -EINVAL); - assert_return(devpath, -EINVAL); assert(device->devpath); assert(device->devpath[0] == '/'); - *devpath = device->devpath; + if (devpath) + *devpath = device->devpath; return 0; } @@ -959,7 +976,6 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) { int r; assert_return(device, -EINVAL); - assert_return(devname, -EINVAL); r = device_read_uevent_file(device); if (r < 0) @@ -970,7 +986,8 @@ _public_ int sd_device_get_devname(sd_device *device, const char **devname) { assert(path_startswith(device->devname, "/dev/")); - *devname = device->devname; + if (devname) + *devname = device->devname; return 0; } @@ -1020,7 +1037,6 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) { int r; assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); if (!device->sysname_set) { r = device_set_sysname(device); @@ -1030,7 +1046,8 @@ _public_ int sd_device_get_sysname(sd_device *device, const char **ret) { assert_return(device->sysname, -ENOENT); - *ret = device->sysname; + if (ret) + *ret = device->sysname; return 0; } @@ -1038,7 +1055,6 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) { int r; assert_return(device, -EINVAL); - assert_return(ret, -EINVAL); if (!device->sysname_set) { r = device_set_sysname(device); @@ -1049,7 +1065,32 @@ _public_ int sd_device_get_sysnum(sd_device *device, const char **ret) { if (!device->sysnum) return -ENOENT; - *ret = device->sysnum; + if (ret) + *ret = device->sysnum; + return 0; +} + +_public_ int sd_device_get_action(sd_device *device, sd_device_action_t *ret) { + assert_return(device, -EINVAL); + + if (device->action < 0) + return -ENOENT; + + if (ret) + *ret = device->action; + + return 0; +} + +_public_ int sd_device_get_seqnum(sd_device *device, uint64_t *ret) { + assert_return(device, -EINVAL); + + if (device->seqnum == 0) + return -ENOENT; + + if (ret) + *ret = device->seqnum; + return 0; } @@ -1395,7 +1436,6 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u int r; assert_return(device, -EINVAL); - assert_return(usec, -EINVAL); r = device_read_db(device); if (r < 0) @@ -1412,7 +1452,8 @@ _public_ int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *u if (now_ts < device->usec_initialized) return -EIO; - *usec = now_ts - device->usec_initialized; + if (usec) + *usec = now_ts - device->usec_initialized; return 0; } @@ -1760,8 +1801,8 @@ _public_ int sd_device_has_current_tag(sd_device *device, const char *tag) { return set_contains(device->current_tags, tag); } -_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **_value) { - char *value; +_public_ int sd_device_get_property_value(sd_device *device, const char *key, const char **ret_value) { + const char *value; int r; assert_return(device, -EINVAL); @@ -1775,40 +1816,39 @@ _public_ int sd_device_get_property_value(sd_device *device, const char *key, co if (!value) return -ENOENT; - if (_value) - *_value = value; + if (ret_value) + *ret_value = value; return 0; } -/* replaces the value if it already exists */ -static int device_add_sysattr_value(sd_device *device, const char *_key, char *value) { - _cleanup_free_ char *key = NULL; - _cleanup_free_ char *value_old = NULL; +static int device_cache_sysattr_value(sd_device *device, const char *key, char *value) { + _cleanup_free_ char *new_key = NULL, *old_value = NULL; int r; assert(device); - assert(_key); + assert(key); - r = hashmap_ensure_allocated(&device->sysattr_values, &string_hash_ops); - if (r < 0) - return r; + /* This takes the reference of the input value. The input value may be NULL. + * This replaces the value if it already exists. */ - value_old = hashmap_remove2(device->sysattr_values, _key, (void **)&key); - if (!key) { - key = strdup(_key); - if (!key) + /* First, remove the old cache entry. So, we do not need to clear cache on error. */ + old_value = hashmap_remove2(device->sysattr_values, key, (void **) &new_key); + if (!new_key) { + new_key = strdup(key); + if (!new_key) return -ENOMEM; } - r = hashmap_put(device->sysattr_values, key, value); + r = hashmap_ensure_put(&device->sysattr_values, &string_hash_ops_free_free, new_key, value); if (r < 0) return r; - TAKE_PTR(key); + + TAKE_PTR(new_key); return 0; } -static int device_get_sysattr_value(sd_device *device, const char *_key, const char **_value) { +static int device_get_cached_sysattr_value(sd_device *device, const char *_key, const char **_value) { const char *key = NULL, *value; assert(device); @@ -1825,7 +1865,7 @@ static int device_get_sysattr_value(sd_device *device, const char *_key, const c /* We cache all sysattr lookups. If an attribute does not exist, it is stored * with a NULL value in the cache, otherwise the returned string is stored */ -_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **_value) { +_public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const char **ret_value) { _cleanup_free_ char *value = NULL; const char *path, *syspath, *cached_value = NULL; struct stat statbuf; @@ -1835,7 +1875,7 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, assert_return(sysattr, -EINVAL); /* look for possibly already cached result */ - r = device_get_sysattr_value(device, sysattr, &cached_value); + r = device_get_cached_sysattr_value(device, sysattr, &cached_value); if (r != -ENOENT) { if (r < 0) return r; @@ -1844,8 +1884,8 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, /* we looked up the sysattr before and it did not exist */ return -ENOENT; - if (_value) - *_value = cached_value; + if (ret_value) + *ret_value = cached_value; return 0; } @@ -1857,12 +1897,16 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, path = prefix_roota(syspath, sysattr); r = lstat(path, &statbuf); if (r < 0) { - /* remember that we could not access the sysattr */ - r = device_add_sysattr_value(device, sysattr, NULL); - if (r < 0) - return r; + int k; - return -ENOENT; + /* remember that we could not access the sysattr */ + k = device_cache_sysattr_value(device, sysattr, NULL); + if (k < 0) + log_device_debug_errno(device, k, + "sd-device: failed to cache attribute '%s' with NULL, ignoring: %m", + sysattr); + + return r; } else if (S_ISLNK(statbuf.st_mode)) { /* Some core links return only the last element of the target path, * these are just values, the paths should not be exposed. */ @@ -1872,35 +1916,38 @@ _public_ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, return r; } else return -EINVAL; - } else if (S_ISDIR(statbuf.st_mode)) { + } else if (S_ISDIR(statbuf.st_mode)) /* skip directories */ - return -EINVAL; - } else if (!(statbuf.st_mode & S_IRUSR)) { + return -EISDIR; + else if (!(statbuf.st_mode & S_IRUSR)) /* skip non-readable files */ return -EPERM; - } else { - size_t size; - + else { /* read attribute value */ - r = read_full_virtual_file(path, &value, &size); + r = read_full_virtual_file(path, &value, NULL); if (r < 0) return r; /* drop trailing newlines */ - while (size > 0 && value[--size] == '\n') - value[size] = '\0'; + delete_trailing_chars(value, "\n"); } - r = device_add_sysattr_value(device, sysattr, value); - if (r < 0) - return r; - - *_value = TAKE_PTR(value); + /* Unfortunately, we need to return 'const char*' instead of 'char*'. Hence, failure in caching + * sysattr value is critical unlike the other places. */ + r = device_cache_sysattr_value(device, sysattr, value); + if (r < 0) { + log_device_debug_errno(device, r, + "sd-device: failed to cache attribute '%s' with '%s'%s: %m", + sysattr, value, ret_value ? "" : ", ignoring"); + if (ret_value) + return r; + } else if (ret_value) + *ret_value = TAKE_PTR(value); return 0; } -static void device_remove_sysattr_value(sd_device *device, const char *_key) { +static void device_remove_cached_sysattr_value(sd_device *device, const char *_key) { _cleanup_free_ char *key = NULL; assert(device); @@ -1909,8 +1956,6 @@ static void device_remove_sysattr_value(sd_device *device, const char *_key) { free(hashmap_remove2(device->sysattr_values, _key, (void **) &key)); } -/* set the attribute and save it in the cache. If a NULL value is passed the - * attribute is cleared from the cache */ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *_value) { _cleanup_free_ char *value = NULL; const char *syspath, *path; @@ -1920,8 +1965,11 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, assert_return(device, -EINVAL); assert_return(sysattr, -EINVAL); + /* Set the attribute and save it in the cache. */ + if (!_value) { - device_remove_sysattr_value(device, sysattr); + /* If input value is NULL, then clear cache and not write anything. */ + device_remove_cached_sysattr_value(device, sysattr); return 0; } @@ -1934,7 +1982,7 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, len = strlen(_value); /* drop trailing newlines */ - while (len > 0 && _value[len - 1] == '\n') + while (len > 0 && strchr(NEWLINE, _value[len - 1])) len --; /* value length is limited to 4k */ @@ -1947,27 +1995,22 @@ _public_ int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, r = write_string_file(path, value, WRITE_STRING_FILE_DISABLE_BUFFER | WRITE_STRING_FILE_NOFOLLOW); if (r < 0) { - if (r == -ELOOP) - return -EINVAL; - if (r == -EISDIR) - return r; - - r = free_and_strdup(&value, ""); - if (r < 0) - return r; - - r = device_add_sysattr_value(device, sysattr, value); - if (r < 0) - return r; - TAKE_PTR(value); - - return -ENXIO; + /* On failure, clear cache entry, as we do not know how it fails. */ + device_remove_cached_sysattr_value(device, sysattr); + return r; } - r = device_add_sysattr_value(device, sysattr, value); + /* Do not cache action string written into uevent file. */ + if (streq(sysattr, "uevent")) + return 0; + + r = device_cache_sysattr_value(device, sysattr, value); if (r < 0) - return r; - TAKE_PTR(value); + log_device_debug_errno(device, r, + "sd-device: failed to cache attribute '%s' with '%s', ignoring: %m", + sysattr, value); + else + TAKE_PTR(value); return 0; } @@ -1981,7 +2024,7 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr assert_return(sysattr, -EINVAL); if (!format) { - device_remove_sysattr_value(device, sysattr); + device_remove_cached_sysattr_value(device, sysattr); return 0; } @@ -1994,3 +2037,15 @@ _public_ int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr return sd_device_set_sysattr_value(device, sysattr, value); } + +_public_ int sd_device_trigger(sd_device *device, sd_device_action_t action) { + const char *s; + + assert_return(device, -EINVAL); + + s = device_action_to_string(action); + if (!s) + return -EINVAL; + + return sd_device_set_sysattr_value(device, "uevent", s); +} diff --git a/src/libsystemd/sd-device/test-sd-device-thread.c b/src/libsystemd/sd-device/test-sd-device-thread.c index 6f3015515..644f3c2ae 100644 --- a/src/libsystemd/sd-device/test-sd-device-thread.c +++ b/src/libsystemd/sd-device/test-sd-device-thread.c @@ -1,19 +1,25 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include -#include #include #include #include "sd-device.h" #include "device-util.h" -#include "macro.h" + +#define handle_error_errno(error, msg) \ + ({ \ + errno = abs(error); \ + perror(msg); \ + EXIT_FAILURE; \ + }) static void* thread(void *p) { sd_device **d = p; - assert_se(!(*d = sd_device_unref(*d))); + *d = sd_device_unref(*d); return NULL; } @@ -22,18 +28,25 @@ int main(int argc, char *argv[]) { sd_device *loopback; pthread_t t; const char *key, *value; + int r; - assert_se(unsetenv("SYSTEMD_MEMPOOL") == 0); - - assert_se(sd_device_new_from_syspath(&loopback, "/sys/class/net/lo") >= 0); + r = sd_device_new_from_syspath(&loopback, "/sys/class/net/lo"); + if (r < 0) + return handle_error_errno(r, "Failed to create loopback device object"); FOREACH_DEVICE_PROPERTY(loopback, key, value) printf("%s=%s\n", key, value); - assert_se(pthread_create(&t, NULL, thread, &loopback) == 0); - assert_se(pthread_join(t, NULL) == 0); + r = pthread_create(&t, NULL, thread, &loopback); + if (r != 0) + return handle_error_errno(r, "Failed to create thread"); - assert_se(!loopback); + r = pthread_join(t, NULL); + if (r != 0) + return handle_error_errno(r, "Failed to wait thread finished"); + + if (loopback) + return handle_error_errno(r, "loopback device is not unref()ed"); return 0; } diff --git a/src/libsystemd/sd-device/test-sd-device.c b/src/libsystemd/sd-device/test-sd-device.c index 9f48d2bf1..aaa16f740 100644 --- a/src/libsystemd/sd-device/test-sd-device.c +++ b/src/libsystemd/sd-device/test-sd-device.c @@ -1,9 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include "device-enumerator-private.h" +#include "device-internal.h" #include "device-private.h" #include "device-util.h" +#include "errno-util.h" #include "hashmap.h" +#include "nulstr-util.h" #include "string-util.h" #include "tests.h" #include "time-util.h" @@ -49,7 +52,7 @@ static void test_sd_device_one(sd_device *d) { } r = sd_device_get_sysattr_value(d, "name_assign_type", &val); - assert_se(r >= 0 || IN_SET(r, -ENOENT, -EINVAL)); + assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r) || IN_SET(r, -ENOENT, -EINVAL)); r = sd_device_get_property_value(d, "ID_NET_DRIVER", &val); assert_se(r >= 0 || r == -ENOENT); @@ -161,6 +164,47 @@ static void test_sd_device_enumerator_filter_subsystem(void) { assert_se(n_new_dev <= 10); } +static void test_sd_device_new_from_nulstr(void) { + const char *devlinks = + "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0" + "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0" + "/dev/disk/by-label/Arch\\x20Linux\0" + "/dev/disk/by-uuid/a07b87e5-4af5-4a59-bde9-yyyyyyyyyyyy\0" + "/dev/disk/by-partlabel/Arch\\x20Linux\0" + "\0"; + + _cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL; + _cleanup_free_ uint8_t *nulstr_copy = NULL; + const char *devlink; + const uint8_t *nulstr; + size_t len; + + log_info("/* %s */", __func__); + + assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0); + + /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a + * test for generating and parsing nulstr. For issue #17772. */ + NULSTR_FOREACH(devlink, devlinks) { + log_device_info(device, "setting devlink: %s", devlink); + assert_se(device_add_devlink(device, devlink) >= 0); + assert_se(set_contains(device->devlinks, devlink)); + } + + /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */ + assert_se(device_add_property_internal(device, "SEQNUM", "1") >= 0); + assert_se(device_add_property_internal(device, "ACTION", "change") >= 0); + + assert_se(device_get_properties_nulstr(device, &nulstr, &len) >= 0); + assert_se(nulstr_copy = newdup(uint8_t, nulstr, len)); + assert_se(device_new_from_nulstr(&from_nulstr, nulstr_copy, len) >= 0); + + NULSTR_FOREACH(devlink, devlinks) { + log_device_info(from_nulstr, "checking devlink: %s", devlink); + assert_se(set_contains(from_nulstr->devlinks, devlink)); + } +} + int main(int argc, char **argv) { test_setup_logging(LOG_INFO); @@ -168,5 +212,7 @@ int main(int argc, char **argv) { test_sd_device_enumerator_subsystems(); test_sd_device_enumerator_filter_subsystem(); + test_sd_device_new_from_nulstr(); + return 0; } diff --git a/src/libsystemd/sd-device/test-udev-device-thread.c b/src/libsystemd/sd-device/test-udev-device-thread.c deleted file mode 100644 index a493152d4..000000000 --- a/src/libsystemd/sd-device/test-udev-device-thread.c +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include -#include -#include -#include - -#include "libudev.h" - -#include "macro.h" - -static void* thread(void *p) { - struct udev_device **d = p; - - assert_se(!(*d = udev_device_unref(*d))); - - return NULL; -} - -int main(int argc, char *argv[]) { - struct udev_device *loopback; - pthread_t t; - - assert_se(unsetenv("SYSTEMD_MEMPOOL") == 0); - - assert_se(loopback = udev_device_new_from_syspath(NULL, "/sys/class/net/lo")); - - assert_se(udev_device_get_properties_list_entry(loopback)); - - assert_se(pthread_create(&t, NULL, thread, &loopback) == 0); - assert_se(pthread_join(t, NULL) == 0); - - assert_se(!loopback); - - return 0; -} diff --git a/src/libsystemd/sd-event/event-source.h b/src/libsystemd/sd-event/event-source.h index 62d07187a..d2dc21470 100644 --- a/src/libsystemd/sd-event/event-source.h +++ b/src/libsystemd/sd-event/event-source.h @@ -11,6 +11,7 @@ #include "hashmap.h" #include "list.h" #include "prioq.h" +#include "ratelimit.h" typedef enum EventSourceType { SOURCE_IO, @@ -27,7 +28,7 @@ typedef enum EventSourceType { SOURCE_WATCHDOG, SOURCE_INOTIFY, _SOURCE_EVENT_SOURCE_TYPE_MAX, - _SOURCE_EVENT_SOURCE_TYPE_INVALID = -1 + _SOURCE_EVENT_SOURCE_TYPE_INVALID = -EINVAL, } EventSourceType; /* All objects we use in epoll events start with this value, so that @@ -39,7 +40,7 @@ typedef enum WakeupType { WAKEUP_SIGNAL_DATA, WAKEUP_INOTIFY_DATA, _WAKEUP_TYPE_MAX, - _WAKEUP_TYPE_INVALID = -1, + _WAKEUP_TYPE_INVALID = -EINVAL, } WakeupType; struct inode_data; @@ -55,12 +56,13 @@ struct sd_event_source { char *description; - EventSourceType type:5; + EventSourceType type; signed int enabled:3; bool pending:1; bool dispatching:1; bool floating:1; bool exit_on_failure:1; + bool ratelimited:1; int64_t priority; unsigned pending_index; @@ -72,6 +74,13 @@ struct sd_event_source { LIST_FIELDS(sd_event_source, sources); + RateLimit rate_limit; + + /* These are primarily fields relevant for time event sources, but since any event source can + * effectively become one when rate-limited, this is part of the common fields. */ + unsigned earliest_index; + unsigned latest_index; + union { struct { sd_event_io_handler_t callback; @@ -84,8 +93,6 @@ struct sd_event_source { struct { sd_event_time_handler_t callback; usec_t next, accuracy; - unsigned earliest_index; - unsigned latest_index; } time; struct { sd_event_signal_handler_t callback; diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c index 789a8c7df..b76b0623f 100644 --- a/src/libsystemd/sd-event/sd-event.c +++ b/src/libsystemd/sd-event/sd-event.c @@ -37,6 +37,16 @@ static bool EVENT_SOURCE_WATCH_PIDFD(sd_event_source *s) { s->child.options == WEXITED; } +static bool event_source_is_online(sd_event_source *s) { + assert(s); + return s->enabled != SD_EVENT_OFF && !s->ratelimited; +} + +static bool event_source_is_offline(sd_event_source *s) { + assert(s); + return s->enabled == SD_EVENT_OFF || s->ratelimited; +} + static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] = { [SOURCE_IO] = "io", [SOURCE_TIME_REALTIME] = "realtime", @@ -55,7 +65,25 @@ static const char* const event_source_type_table[_SOURCE_EVENT_SOURCE_TYPE_MAX] DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(event_source_type, int); -#define EVENT_SOURCE_IS_TIME(t) IN_SET((t), SOURCE_TIME_REALTIME, SOURCE_TIME_BOOTTIME, SOURCE_TIME_MONOTONIC, SOURCE_TIME_REALTIME_ALARM, SOURCE_TIME_BOOTTIME_ALARM) +#define EVENT_SOURCE_IS_TIME(t) \ + IN_SET((t), \ + SOURCE_TIME_REALTIME, \ + SOURCE_TIME_BOOTTIME, \ + SOURCE_TIME_MONOTONIC, \ + SOURCE_TIME_REALTIME_ALARM, \ + SOURCE_TIME_BOOTTIME_ALARM) + +#define EVENT_SOURCE_CAN_RATE_LIMIT(t) \ + IN_SET((t), \ + SOURCE_IO, \ + SOURCE_TIME_REALTIME, \ + SOURCE_TIME_BOOTTIME, \ + SOURCE_TIME_MONOTONIC, \ + SOURCE_TIME_REALTIME_ALARM, \ + SOURCE_TIME_BOOTTIME_ALARM, \ + SOURCE_SIGNAL, \ + SOURCE_DEFER, \ + SOURCE_INOTIFY) struct sd_event { unsigned n_ref; @@ -81,7 +109,7 @@ struct sd_event { Hashmap *signal_data; /* indexed by priority */ Hashmap *child_sources; - unsigned n_enabled_child_sources; + unsigned n_online_child_sources; Set *post_sources; @@ -120,7 +148,7 @@ struct sd_event { LIST_HEAD(sd_event_source, sources); - usec_t last_run, last_log; + usec_t last_run_usec, last_log_usec; unsigned delays[sizeof(usec_t) * 8]; }; @@ -146,6 +174,11 @@ static int pending_prioq_compare(const void *a, const void *b) { if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; + /* Non rate-limited ones first. */ + r = CMP(!!x->ratelimited, !!y->ratelimited); + if (r != 0) + return r; + /* Lower priority values first */ r = CMP(x->priority, y->priority); if (r != 0) @@ -168,6 +201,11 @@ static int prepare_prioq_compare(const void *a, const void *b) { if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF) return 1; + /* Non rate-limited ones first. */ + r = CMP(!!x->ratelimited, !!y->ratelimited); + if (r != 0) + return r; + /* Move most recently prepared ones last, so that we can stop * preparing as soon as we hit one that has already been * prepared in the current iteration */ @@ -179,12 +217,30 @@ static int prepare_prioq_compare(const void *a, const void *b) { return CMP(x->priority, y->priority); } +static usec_t time_event_source_next(const sd_event_source *s) { + assert(s); + + /* We have two kinds of event sources that have elapsation times associated with them: the actual + * time based ones and the ones for which a ratelimit can be in effect (where we want to be notified + * once the ratelimit time window ends). Let's return the next elapsing time depending on what we are + * looking at here. */ + + if (s->ratelimited) { /* If rate-limited the next elapsation is when the ratelimit time window ends */ + assert(s->rate_limit.begin != 0); + assert(s->rate_limit.interval != 0); + return usec_add(s->rate_limit.begin, s->rate_limit.interval); + } + + /* Otherwise this must be a time event source, if not ratelimited */ + if (EVENT_SOURCE_IS_TIME(s->type)) + return s->time.next; + + return USEC_INFINITY; +} + static int earliest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; - assert(EVENT_SOURCE_IS_TIME(x->type)); - assert(x->type == y->type); - /* Enabled ones first */ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; @@ -198,19 +254,30 @@ static int earliest_time_prioq_compare(const void *a, const void *b) { return 1; /* Order by time */ - return CMP(x->time.next, y->time.next); + return CMP(time_event_source_next(x), time_event_source_next(y)); } static usec_t time_event_source_latest(const sd_event_source *s) { - return usec_add(s->time.next, s->time.accuracy); + assert(s); + + if (s->ratelimited) { /* For ratelimited stuff the earliest and the latest time shall actually be the + * same, as we should avoid adding additional inaccuracy on an inaccuracy time + * window */ + assert(s->rate_limit.begin != 0); + assert(s->rate_limit.interval != 0); + return usec_add(s->rate_limit.begin, s->rate_limit.interval); + } + + /* Must be a time event source, if not ratelimited */ + if (EVENT_SOURCE_IS_TIME(s->type)) + return usec_add(s->time.next, s->time.accuracy); + + return USEC_INFINITY; } static int latest_time_prioq_compare(const void *a, const void *b) { const sd_event_source *x = a, *y = b; - assert(EVENT_SOURCE_IS_TIME(x->type)); - assert(x->type == y->type); - /* Enabled ones first */ if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF) return -1; @@ -340,7 +407,7 @@ _public_ int sd_event_new(sd_event** ret) { e->epoll_fd = fd_move_above_stdio(e->epoll_fd); if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { - log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 ... 2^63 us will be logged every 5s."); + log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 … 2^63 us will be logged every 5s."); e->profile_delays = true; } @@ -380,7 +447,7 @@ static void source_io_unregister(sd_event_source *s) { return; if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->io.fd, NULL) < 0) - log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", strna(s->description), event_source_type_to_string(s->type)); s->io.registered = false; @@ -422,7 +489,7 @@ static void source_child_pidfd_unregister(sd_event_source *s) { if (EVENT_SOURCE_WATCH_PIDFD(s)) if (epoll_ctl(s->event->epoll_fd, EPOLL_CTL_DEL, s->child.pidfd, NULL) < 0) - log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll: %m", + log_debug_errno(errno, "Failed to remove source %s (type %s) from epoll, ignoring: %m", strna(s->description), event_source_type_to_string(s->type)); s->child.registered = false; @@ -562,10 +629,6 @@ static int event_make_signal_data( return 0; } } else { - r = hashmap_ensure_allocated(&e->signal_data, &uint64_hash_ops); - if (r < 0) - return r; - d = new(struct signal_data, 1); if (!d) return -ENOMEM; @@ -576,7 +639,7 @@ static int event_make_signal_data( .priority = priority, }; - r = hashmap_put(e->signal_data, &d->priority, d); + r = hashmap_ensure_put(&e->signal_data, &uint64_hash_ops, &d->priority, d); if (r < 0) { free(d); return r; @@ -661,12 +724,12 @@ static void event_gc_signal_data(sd_event *e, const int64_t *priority, int sig) * and possibly drop the signalfd for it. */ if (sig == SIGCHLD && - e->n_enabled_child_sources > 0) + e->n_online_child_sources > 0) return; if (e->signal_sources && e->signal_sources[sig] && - e->signal_sources[sig]->enabled != SD_EVENT_OFF) + event_source_is_online(e->signal_sources[sig])) return; /* @@ -713,13 +776,32 @@ static void event_source_time_prioq_reshuffle(sd_event_source *s) { struct clock_data *d; assert(s); - assert(EVENT_SOURCE_IS_TIME(s->type)); /* Called whenever the event source's timer ordering properties changed, i.e. time, accuracy, * pending, enable state. Makes sure the two prioq's are ordered properly again. */ - assert_se(d = event_get_clock_data(s->event, s->type)); - prioq_reshuffle(d->earliest, s, &s->time.earliest_index); - prioq_reshuffle(d->latest, s, &s->time.latest_index); + + if (s->ratelimited) + d = &s->event->monotonic; + else { + assert(EVENT_SOURCE_IS_TIME(s->type)); + assert_se(d = event_get_clock_data(s->event, s->type)); + } + + prioq_reshuffle(d->earliest, s, &s->earliest_index); + prioq_reshuffle(d->latest, s, &s->latest_index); + d->needs_rearm = true; +} + +static void event_source_time_prioq_remove( + sd_event_source *s, + struct clock_data *d) { + + assert(s); + assert(d); + + prioq_remove(d->earliest, s, &s->earliest_index); + prioq_remove(d->latest, s, &s->latest_index); + s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; d->needs_rearm = true; } @@ -745,17 +827,18 @@ static void source_disconnect(sd_event_source *s) { case SOURCE_TIME_BOOTTIME: case SOURCE_TIME_MONOTONIC: case SOURCE_TIME_REALTIME_ALARM: - case SOURCE_TIME_BOOTTIME_ALARM: { - struct clock_data *d; + case SOURCE_TIME_BOOTTIME_ALARM: + /* Only remove this event source from the time event source here if it is not ratelimited. If + * it is ratelimited, we'll remove it below, separately. Why? Because the clock used might + * differ: ratelimiting always uses CLOCK_MONOTONIC, but timer events might use any clock */ - d = event_get_clock_data(s->event, s->type); - assert(d); + if (!s->ratelimited) { + struct clock_data *d; + assert_se(d = event_get_clock_data(s->event, s->type)); + event_source_time_prioq_remove(s, d); + } - prioq_remove(d->earliest, s, &s->time.earliest_index); - prioq_remove(d->latest, s, &s->time.latest_index); - d->needs_rearm = true; break; - } case SOURCE_SIGNAL: if (s->signal.sig > 0) { @@ -770,9 +853,9 @@ static void source_disconnect(sd_event_source *s) { case SOURCE_CHILD: if (s->child.pid > 0) { - if (s->enabled != SD_EVENT_OFF) { - assert(s->event->n_enabled_child_sources > 0); - s->event->n_enabled_child_sources--; + if (event_source_is_online(s)) { + assert(s->event->n_online_child_sources > 0); + s->event->n_online_child_sources--; } (void) hashmap_remove(s->event->child_sources, PID_TO_PTR(s->child.pid)); @@ -842,6 +925,9 @@ static void source_disconnect(sd_event_source *s) { if (s->prepare) prioq_remove(s->event->prepare, s, &s->prepare_index); + if (s->ratelimited) + event_source_time_prioq_remove(s, &s->event->monotonic); + event = TAKE_PTR(s->event); LIST_REMOVE(sources, event->sources, s); event->n_sources--; @@ -853,7 +939,7 @@ static void source_disconnect(sd_event_source *s) { sd_event_unref(event); } -static void source_free(sd_event_source *s) { +static sd_event_source* source_free(sd_event_source *s) { assert(s); source_disconnect(s); @@ -903,7 +989,7 @@ static void source_free(sd_event_source *s) { s->destroy_callback(s->userdata); free(s->description); - free(s); + return mfree(s); } DEFINE_TRIVIAL_CLEANUP_FUNC(sd_event_source*, source_free); @@ -953,7 +1039,7 @@ static int source_set_pending(sd_event_source *s, bool b) { } } - return 0; + return 1; } static sd_event_source *source_new(sd_event *e, bool floating, EventSourceType type) { @@ -1088,6 +1174,52 @@ static int time_exit_callback(sd_event_source *s, uint64_t usec, void *userdata) return sd_event_exit(sd_event_source_get_event(s), PTR_TO_INT(userdata)); } +static int setup_clock_data(sd_event *e, struct clock_data *d, clockid_t clock) { + int r; + + assert(d); + + if (d->fd < 0) { + r = event_setup_timer_fd(e, d, clock); + if (r < 0) + return r; + } + + r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); + if (r < 0) + return r; + + r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); + if (r < 0) + return r; + + return 0; +} + +static int event_source_time_prioq_put( + sd_event_source *s, + struct clock_data *d) { + + int r; + + assert(s); + assert(d); + + r = prioq_put(d->earliest, s, &s->earliest_index); + if (r < 0) + return r; + + r = prioq_put(d->latest, s, &s->latest_index); + if (r < 0) { + assert_se(prioq_remove(d->earliest, s, &s->earliest_index) > 0); + s->earliest_index = PRIOQ_IDX_NULL; + return r; + } + + d->needs_rearm = true; + return 0; +} + _public_ int sd_event_add_time( sd_event *e, sd_event_source **ret, @@ -1104,7 +1236,7 @@ _public_ int sd_event_add_time( assert_return(e, -EINVAL); assert_return(e = event_resolve(e), -ENOPKG); - assert_return(accuracy != (uint64_t) -1, -EINVAL); + assert_return(accuracy != UINT64_MAX, -EINVAL); assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(e), -ECHILD); @@ -1118,23 +1250,12 @@ _public_ int sd_event_add_time( if (!callback) callback = time_exit_callback; - d = event_get_clock_data(e, type); - assert(d); + assert_se(d = event_get_clock_data(e, type)); - r = prioq_ensure_allocated(&d->earliest, earliest_time_prioq_compare); + r = setup_clock_data(e, d, clock); if (r < 0) return r; - r = prioq_ensure_allocated(&d->latest, latest_time_prioq_compare); - if (r < 0) - return r; - - if (d->fd < 0) { - r = event_setup_timer_fd(e, d, clock); - if (r < 0) - return r; - } - s = source_new(e, !ret, type); if (!s) return -ENOMEM; @@ -1142,17 +1263,11 @@ _public_ int sd_event_add_time( s->time.next = usec; s->time.accuracy = accuracy == 0 ? DEFAULT_ACCURACY_USEC : accuracy; s->time.callback = callback; - s->time.earliest_index = s->time.latest_index = PRIOQ_IDX_NULL; + s->earliest_index = s->latest_index = PRIOQ_IDX_NULL; s->userdata = userdata; s->enabled = SD_EVENT_ONESHOT; - d->needs_rearm = true; - - r = prioq_put(d->earliest, s, &s->time.earliest_index); - if (r < 0) - return r; - - r = prioq_put(d->latest, s, &s->time.latest_index); + r = event_source_time_prioq_put(s, d); if (r < 0) return r; @@ -1285,7 +1400,7 @@ _public_ int sd_event_add_child( if (!callback) callback = child_exit_callback; - if (e->n_enabled_child_sources == 0) { + if (e->n_online_child_sources == 0) { /* Caller must block SIGCHLD before using us to watch children, even if pidfd is available, * for compatibility with pre-pidfd and because we don't want the reap the child processes * ourselves, i.e. call waitid(), and don't want Linux' default internal logic for that to @@ -1350,7 +1465,7 @@ _public_ int sd_event_add_child( e->need_process_child = true; } - e->n_enabled_child_sources++; + e->n_online_child_sources++; if (ret) *ret = s; @@ -1382,7 +1497,7 @@ _public_ int sd_event_add_child_pidfd( if (!callback) callback = child_exit_callback; - if (e->n_enabled_child_sources == 0) { + if (e->n_online_child_sources == 0) { r = signal_is_blocked(SIGCHLD); if (r < 0) return r; @@ -1432,7 +1547,7 @@ _public_ int sd_event_add_child_pidfd( e->need_process_child = true; } - e->n_enabled_child_sources++; + e->n_online_child_sources++; if (ret) *ret = s; @@ -1608,10 +1723,6 @@ static int event_make_inotify_data( fd = fd_move_above_stdio(fd); - r = hashmap_ensure_allocated(&e->inotify_data, &uint64_hash_ops); - if (r < 0) - return r; - d = new(struct inotify_data, 1); if (!d) return -ENOMEM; @@ -1622,7 +1733,7 @@ static int event_make_inotify_data( .priority = priority, }; - r = hashmap_put(e->inotify_data, &d->priority, d); + r = hashmap_ensure_put(&e->inotify_data, &uint64_hash_ops, &d->priority, d); if (r < 0) { d->fd = safe_close(d->fd); free(d); @@ -2018,7 +2129,7 @@ _public_ int sd_event_source_set_io_fd(sd_event_source *s, int fd) { if (s->io.fd == fd) return 0; - if (s->enabled == SD_EVENT_OFF) { + if (event_source_is_offline(s)) { s->io.fd = fd; s->io.registered = false; } else { @@ -2085,7 +2196,7 @@ _public_ int sd_event_source_set_io_events(sd_event_source *s, uint32_t events) if (r < 0) return r; - if (s->enabled != SD_EVENT_OFF) { + if (event_source_is_online(s)) { r = source_io_register(s, s->enabled, events); if (r < 0) return r; @@ -2188,7 +2299,7 @@ _public_ int sd_event_source_set_priority(sd_event_source *s, int64_t priority) event_gc_inode_data(s->event, old_inode_data); - } else if (s->type == SOURCE_SIGNAL && s->enabled != SD_EVENT_OFF) { + } else if (s->type == SOURCE_SIGNAL && event_source_is_online(s)) { struct signal_data *old, *d; /* Move us from the signalfd belonging to the old @@ -2225,29 +2336,39 @@ fail: return r; } -_public_ int sd_event_source_get_enabled(sd_event_source *s, int *m) { +_public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); - if (m) - *m = s->enabled; + if (ret) + *ret = s->enabled; + return s->enabled != SD_EVENT_OFF; } -static int event_source_disable(sd_event_source *s) { +static int event_source_offline( + sd_event_source *s, + int enabled, + bool ratelimited) { + + bool was_offline; int r; assert(s); - assert(s->enabled != SD_EVENT_OFF); + assert(enabled == SD_EVENT_OFF || ratelimited); /* Unset the pending flag when this event source is disabled */ - if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + if (s->enabled != SD_EVENT_OFF && + enabled == SD_EVENT_OFF && + !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { r = source_set_pending(s, false); if (r < 0) return r; } - s->enabled = SD_EVENT_OFF; + was_offline = event_source_is_offline(s); + s->enabled = enabled; + s->ratelimited = ratelimited; switch (s->type) { @@ -2268,8 +2389,10 @@ static int event_source_disable(sd_event_source *s) { break; case SOURCE_CHILD: - assert(s->event->n_enabled_child_sources > 0); - s->event->n_enabled_child_sources--; + if (!was_offline) { + assert(s->event->n_online_child_sources > 0); + s->event->n_online_child_sources--; + } if (EVENT_SOURCE_WATCH_PIDFD(s)) source_child_pidfd_unregister(s); @@ -2290,26 +2413,42 @@ static int event_source_disable(sd_event_source *s) { assert_not_reached("Wut? I shouldn't exist."); } - return 0; + return 1; } -static int event_source_enable(sd_event_source *s, int enable) { +static int event_source_online( + sd_event_source *s, + int enabled, + bool ratelimited) { + + bool was_online; int r; assert(s); - assert(IN_SET(enable, SD_EVENT_ON, SD_EVENT_ONESHOT)); - assert(s->enabled == SD_EVENT_OFF); + assert(enabled != SD_EVENT_OFF || !ratelimited); /* Unset the pending flag when this event source is enabled */ - if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { + if (s->enabled == SD_EVENT_OFF && + enabled != SD_EVENT_OFF && + !IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { r = source_set_pending(s, false); if (r < 0) return r; } + /* Are we really ready for onlining? */ + if (enabled == SD_EVENT_OFF || ratelimited) { + /* Nope, we are not ready for onlining, then just update the precise state and exit */ + s->enabled = enabled; + s->ratelimited = ratelimited; + return 0; + } + + was_online = event_source_is_online(s); + switch (s->type) { case SOURCE_IO: - r = source_io_register(s, enable, s->io.events); + r = source_io_register(s, enabled, s->io.events); if (r < 0) return r; break; @@ -2327,7 +2466,7 @@ static int event_source_enable(sd_event_source *s, int enable) { if (EVENT_SOURCE_WATCH_PIDFD(s)) { /* yes, we have pidfd */ - r = source_child_pidfd_register(s, enable); + r = source_child_pidfd_register(s, enabled); if (r < 0) return r; } else { @@ -2340,8 +2479,8 @@ static int event_source_enable(sd_event_source *s, int enable) { } } - s->event->n_enabled_child_sources++; - + if (!was_online) + s->event->n_online_child_sources++; break; case SOURCE_TIME_REALTIME: @@ -2359,7 +2498,8 @@ static int event_source_enable(sd_event_source *s, int enable) { assert_not_reached("Wut? I shouldn't exist."); } - s->enabled = enable; + s->enabled = enabled; + s->ratelimited = ratelimited; /* Non-failing operations below */ switch (s->type) { @@ -2379,7 +2519,7 @@ static int event_source_enable(sd_event_source *s, int enable) { break; } - return 0; + return 1; } _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { @@ -2397,7 +2537,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { return 0; if (m == SD_EVENT_OFF) - r = event_source_disable(s); + r = event_source_offline(s, m, s->ratelimited); else { if (s->enabled != SD_EVENT_OFF) { /* Switching from "on" to "oneshot" or back? If that's the case, we can take a shortcut, the @@ -2406,7 +2546,7 @@ _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { return 0; } - r = event_source_enable(s, m); + r = event_source_online(s, m, s->ratelimited); } if (r < 0) return r; @@ -2454,10 +2594,11 @@ _public_ int sd_event_source_set_time_relative(sd_event_source *s, uint64_t usec if (r < 0) return r; - if (usec >= USEC_INFINITY - t) + usec = usec_add(t, usec); + if (usec == USEC_INFINITY) return -EOVERFLOW; - return sd_event_source_set_time(s, t + usec); + return sd_event_source_set_time(s, usec); } _public_ int sd_event_source_get_time_accuracy(sd_event_source *s, uint64_t *usec) { @@ -2474,7 +2615,7 @@ _public_ int sd_event_source_set_time_accuracy(sd_event_source *s, uint64_t usec int r; assert_return(s, -EINVAL); - assert_return(usec != (uint64_t) -1, -EINVAL); + assert_return(usec != UINT64_MAX, -EINVAL); assert_return(EVENT_SOURCE_IS_TIME(s->type), -EDOM); assert_return(s->event->state != SD_EVENT_FINISHED, -ESTALE); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -2663,6 +2804,96 @@ _public_ void *sd_event_source_set_userdata(sd_event_source *s, void *userdata) return ret; } +static int event_source_enter_ratelimited(sd_event_source *s) { + int r; + + assert(s); + + /* When an event source becomes ratelimited, we place it in the CLOCK_MONOTONIC priority queue, with + * the end of the rate limit time window, much as if it was a timer event source. */ + + if (s->ratelimited) + return 0; /* Already ratelimited, this is a NOP hence */ + + /* Make sure we can install a CLOCK_MONOTONIC event further down. */ + r = setup_clock_data(s->event, &s->event->monotonic, CLOCK_MONOTONIC); + if (r < 0) + return r; + + /* Timer event sources are already using the earliest/latest queues for the timer scheduling. Let's + * first remove them from the prioq appropriate for their own clock, so that we can use the prioq + * fields of the event source then for adding it to the CLOCK_MONOTONIC prioq instead. */ + if (EVENT_SOURCE_IS_TIME(s->type)) + event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); + + /* Now, let's add the event source to the monotonic clock instead */ + r = event_source_time_prioq_put(s, &s->event->monotonic); + if (r < 0) + goto fail; + + /* And let's take the event source officially offline */ + r = event_source_offline(s, s->enabled, /* ratelimited= */ true); + if (r < 0) { + event_source_time_prioq_remove(s, &s->event->monotonic); + goto fail; + } + + event_source_pp_prioq_reshuffle(s); + + log_debug("Event source %p (%s) entered rate limit state.", s, strna(s->description)); + return 0; + +fail: + /* Reinstall time event sources in the priority queue as before. This shouldn't fail, since the queue + * space for it should already be allocated. */ + if (EVENT_SOURCE_IS_TIME(s->type)) + assert_se(event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)) >= 0); + + return r; +} + +static int event_source_leave_ratelimit(sd_event_source *s) { + int r; + + assert(s); + + if (!s->ratelimited) + return 0; + + /* Let's take the event source out of the monotonic prioq first. */ + event_source_time_prioq_remove(s, &s->event->monotonic); + + /* Let's then add the event source to its native clock prioq again — if this is a timer event source */ + if (EVENT_SOURCE_IS_TIME(s->type)) { + r = event_source_time_prioq_put(s, event_get_clock_data(s->event, s->type)); + if (r < 0) + goto fail; + } + + /* Let's try to take it online again. */ + r = event_source_online(s, s->enabled, /* ratelimited= */ false); + if (r < 0) { + /* Do something roughly sensible when this failed: undo the two prioq ops above */ + if (EVENT_SOURCE_IS_TIME(s->type)) + event_source_time_prioq_remove(s, event_get_clock_data(s->event, s->type)); + + goto fail; + } + + event_source_pp_prioq_reshuffle(s); + ratelimit_reset(&s->rate_limit); + + log_debug("Event source %p (%s) left rate limit state.", s, strna(s->description)); + return 0; + +fail: + /* Do something somewhat reasonable when we cannot move an event sources out of ratelimited mode: + * simply put it back in it, maybe we can then process it more successfully next iteration. */ + assert_se(event_source_time_prioq_put(s, &s->event->monotonic) >= 0); + + return r; +} + static usec_t sleep_between(sd_event *e, usec_t a, usec_t b) { usec_t c; assert(e); @@ -2760,7 +2991,7 @@ static int event_arm_timer( d->needs_rearm = false; a = prioq_peek(d->earliest); - if (!a || a->enabled == SD_EVENT_OFF || a->time.next == USEC_INFINITY) { + if (!a || a->enabled == SD_EVENT_OFF || time_event_source_next(a) == USEC_INFINITY) { if (d->fd < 0) return 0; @@ -2779,7 +3010,7 @@ static int event_arm_timer( b = prioq_peek(d->latest); assert_se(b && b->enabled != SD_EVENT_OFF); - t = sleep_between(e, a->time.next, time_event_source_latest(b)); + t = sleep_between(e, time_event_source_next(a), time_event_source_latest(b)); if (d->next == t) return 0; @@ -2857,10 +3088,22 @@ static int process_timer( for (;;) { s = prioq_peek(d->earliest); - if (!s || - s->time.next > n || - s->enabled == SD_EVENT_OFF || - s->pending) + if (!s || time_event_source_next(s) > n) + break; + + if (s->ratelimited) { + /* This is an event sources whose ratelimit window has ended. Let's turn it on + * again. */ + assert(s->ratelimited); + + r = event_source_leave_ratelimit(s); + if (r < 0) + return r; + + continue; + } + + if (s->enabled == SD_EVENT_OFF || s->pending) break; r = source_set_pending(s, true); @@ -2873,11 +3116,19 @@ static int process_timer( return 0; } -static int process_child(sd_event *e) { +static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priority) { + int64_t min_priority = threshold; + bool something_new = false; sd_event_source *s; int r; assert(e); + assert(ret_min_priority); + + if (!e->need_process_child) { + *ret_min_priority = min_priority; + return 0; + } e->need_process_child = false; @@ -2902,10 +3153,13 @@ static int process_child(sd_event *e) { HASHMAP_FOREACH(s, e->child_sources) { assert(s->type == SOURCE_CHILD); + if (s->priority > threshold) + continue; + if (s->pending) continue; - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) continue; if (s->child.exited) @@ -2938,10 +3192,15 @@ static int process_child(sd_event *e) { r = source_set_pending(s, true); if (r < 0) return r; + if (r > 0) { + something_new = true; + min_priority = MIN(min_priority, s->priority); + } } } - return 0; + *ret_min_priority = min_priority; + return something_new; } static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { @@ -2952,7 +3211,7 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { if (s->pending) return 0; - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) return 0; if (!EVENT_SOURCE_WATCH_PIDFD(s)) @@ -2971,13 +3230,13 @@ static int process_pidfd(sd_event *e, sd_event_source *s, uint32_t revents) { return source_set_pending(s, true); } -static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { - bool read_one = false; +static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, int64_t *min_priority) { int r; assert(e); assert(d); assert_return(events == EPOLLIN, -EIO); + assert(min_priority); /* If there's a signal queued on this priority and SIGCHLD is on this priority too, then make sure to recheck the @@ -3003,7 +3262,7 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { n = read(d->fd, &si, sizeof(si)); if (n < 0) { if (IN_SET(errno, EAGAIN, EINTR)) - return read_one; + return 0; return -errno; } @@ -3013,8 +3272,6 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { assert(SIGNAL_VALID(si.ssi_signo)); - read_one = true; - if (e->signal_sources) s = e->signal_sources[si.ssi_signo]; if (!s) @@ -3028,12 +3285,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events) { r = source_set_pending(s, true); if (r < 0) return r; + if (r > 0 && *min_priority >= s->priority) { + *min_priority = s->priority; + return 1; /* an event source with smaller priority is queued. */ + } - return 1; + return 0; } } -static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t revents) { +static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t revents, int64_t threshold) { ssize_t n; assert(e); @@ -3049,6 +3310,9 @@ static int event_inotify_data_read(sd_event *e, struct inotify_data *d, uint32_t if (d->buffer_filled > 0) return 0; + if (d->priority > threshold) + return 0; + n = read(d->fd, &d->buffer, sizeof(d->buffer)); if (n < 0) { if (IN_SET(errno, EAGAIN, EINTR)) @@ -3112,7 +3376,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) continue; r = source_set_pending(s, true); @@ -3148,7 +3412,7 @@ static int event_inotify_data_process(sd_event *e, struct inotify_data *d) { * sources if IN_IGNORED or IN_UNMOUNT is set. */ LIST_FOREACH(inotify.by_inode_data, s, inode_data->event_sources) { - if (s->enabled == SD_EVENT_OFF) + if (event_source_is_offline(s)) continue; if ((d->buffer.ev.mask & (IN_IGNORED|IN_UNMOUNT)) == 0 && @@ -3202,6 +3466,16 @@ static int source_dispatch(sd_event_source *s) { * callback might have invalidated/disconnected the event source. */ saved_event = sd_event_ref(s->event); + /* Check if we hit the ratelimit for this event source, if so, let's disable it. */ + assert(!s->ratelimited); + if (!ratelimit_below(&s->rate_limit)) { + r = event_source_enter_ratelimited(s); + if (r < 0) + return r; + + return 1; + } + if (!IN_SET(s->type, SOURCE_DEFER, SOURCE_EXIT)) { r = source_set_pending(s, false); if (r < 0) @@ -3215,7 +3489,7 @@ static int source_dispatch(sd_event_source *s) { * post sources as pending */ SET_FOREACH(z, s->event->post_sources) { - if (z->enabled == SD_EVENT_OFF) + if (event_source_is_offline(z)) continue; r = source_set_pending(z, true); @@ -3335,7 +3609,7 @@ static int event_prepare(sd_event *e) { sd_event_source *s; s = prioq_peek(e->prepare); - if (!s || s->prepare_iteration == e->iteration || s->enabled == SD_EVENT_OFF) + if (!s || s->prepare_iteration == e->iteration || event_source_is_offline(s)) break; s->prepare_iteration = e->iteration; @@ -3370,18 +3644,17 @@ static int event_prepare(sd_event *e) { static int dispatch_exit(sd_event *e) { sd_event_source *p; - _cleanup_(sd_event_unrefp) sd_event *ref = NULL; int r; assert(e); p = prioq_peek(e->exit); - if (!p || p->enabled == SD_EVENT_OFF) { + if (!p || event_source_is_offline(p)) { e->state = SD_EVENT_FINISHED; return 0; } - ref = sd_event_ref(e); + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); e->iteration++; e->state = SD_EVENT_EXITING; r = source_dispatch(p); @@ -3398,7 +3671,7 @@ static sd_event_source* event_next_pending(sd_event *e) { if (!p) return NULL; - if (p->enabled == SD_EVENT_OFF) + if (event_source_is_offline(p)) return NULL; return p; @@ -3477,6 +3750,9 @@ _public_ int sd_event_prepare(sd_event *e) { * syscalls */ assert_return(!e->default_event_ptr || e->tid == gettid(), -EREMOTEIO); + /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + if (e->exit_requested) goto pending; @@ -3526,44 +3802,103 @@ pending: return r; } -_public_ int sd_event_wait(sd_event *e, uint64_t timeout) { - size_t event_queue_max; - int r, m, i; +static int epoll_wait_usec( + int fd, + struct epoll_event *events, + int maxevents, + usec_t timeout) { - assert_return(e, -EINVAL); - assert_return(e = event_resolve(e), -ENOPKG); - assert_return(!event_pid_changed(e), -ECHILD); - assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); - assert_return(e->state == SD_EVENT_ARMED, -EBUSY); + int r, msec; +#if 0 + static bool epoll_pwait2_absent = false; - if (e->exit_requested) { - e->state = SD_EVENT_PENDING; - return 1; + /* A wrapper that uses epoll_pwait2() if available, and falls back to epoll_wait() if not. + * + * FIXME: this is temporarily disabled until epoll_pwait2() becomes more widely available. + * See https://github.com/systemd/systemd/pull/18973 and + * https://github.com/systemd/systemd/issues/19052. */ + + if (!epoll_pwait2_absent && timeout != USEC_INFINITY) { + struct timespec ts; + + r = epoll_pwait2(fd, + events, + maxevents, + timespec_store(&ts, timeout), + NULL); + if (r >= 0) + return r; + if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) + return -errno; /* Only fallback to old epoll_wait() if the syscall is masked or not + * supported. */ + + epoll_pwait2_absent = true; + } +#endif + + if (timeout == USEC_INFINITY) + msec = -1; + else { + usec_t k; + + k = DIV_ROUND_UP(timeout, USEC_PER_MSEC); + if (k >= INT_MAX) + msec = INT_MAX; /* Saturate */ + else + msec = (int) k; } - event_queue_max = MAX(e->n_sources, 1u); - if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, event_queue_max)) + r = epoll_wait(fd, + events, + maxevents, + msec); + if (r < 0) + return -errno; + + return r; +} + +static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t *ret_min_priority) { + int64_t min_priority = threshold; + bool something_new = false; + size_t n_event_queue, m; + int r; + + assert(e); + assert(ret_min_priority); + + n_event_queue = MAX(e->n_sources, 1u); + if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, n_event_queue)) return -ENOMEM; /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ if (e->inotify_data_buffered) timeout = 0; - m = epoll_wait(e->epoll_fd, e->event_queue, event_queue_max, - timeout == (uint64_t) -1 ? -1 : (int) DIV_ROUND_UP(timeout, USEC_PER_MSEC)); - if (m < 0) { - if (errno == EINTR) { - e->state = SD_EVENT_PENDING; - return 1; - } + for (;;) { + r = epoll_wait_usec(e->epoll_fd, e->event_queue, e->event_queue_allocated, timeout); + if (r < 0) + return r; - r = -errno; - goto finish; + m = (size_t) r; + + if (m < e->event_queue_allocated) + break; + + if (e->event_queue_allocated >= n_event_queue * 10) + break; + + if (!GREEDY_REALLOC(e->event_queue, e->event_queue_allocated, e->event_queue_allocated + n_event_queue)) + return -ENOMEM; + + timeout = 0; } - triple_timestamp_get(&e->timestamp); + /* Set timestamp only when this is called first time. */ + if (threshold == INT64_MAX) + triple_timestamp_get(&e->timestamp); - for (i = 0; i < m; i++) { + for (size_t i = 0; i < m; i++) { if (e->event_queue[i].data.ptr == INT_TO_PTR(SOURCE_WATCHDOG)) r = flush_timer(e, e->watchdog_fd, e->event_queue[i].events, NULL); @@ -3577,6 +3912,11 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { assert(s); + if (s->priority > threshold) + continue; + + min_priority = MIN(min_priority, s->priority); + switch (s->type) { case SOURCE_IO: @@ -3604,19 +3944,75 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { } case WAKEUP_SIGNAL_DATA: - r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events); + r = process_signal(e, e->event_queue[i].data.ptr, e->event_queue[i].events, &min_priority); break; case WAKEUP_INOTIFY_DATA: - r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events); + r = event_inotify_data_read(e, e->event_queue[i].data.ptr, e->event_queue[i].events, threshold); break; default: assert_not_reached("Invalid wake-up pointer"); } } + if (r < 0) + return r; + if (r > 0) + something_new = true; + } + + *ret_min_priority = min_priority; + return something_new; +} + +_public_ int sd_event_wait(sd_event *e, uint64_t timeout) { + int r; + + assert_return(e, -EINVAL); + assert_return(e = event_resolve(e), -ENOPKG); + assert_return(!event_pid_changed(e), -ECHILD); + assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); + assert_return(e->state == SD_EVENT_ARMED, -EBUSY); + + if (e->exit_requested) { + e->state = SD_EVENT_PENDING; + return 1; + } + + for (int64_t threshold = INT64_MAX; ; threshold--) { + int64_t epoll_min_priority, child_min_priority; + + /* There may be a possibility that new epoll (especially IO) and child events are + * triggered just after process_epoll() call but before process_child(), and the new IO + * events may have higher priority than the child events. To salvage these events, + * let's call epoll_wait() again, but accepts only events with higher priority than the + * previous. See issue https://github.com/systemd/systemd/issues/18190 and comments + * https://github.com/systemd/systemd/pull/18750#issuecomment-785801085 + * https://github.com/systemd/systemd/pull/18922#issuecomment-792825226 */ + + r = process_epoll(e, timeout, threshold, &epoll_min_priority); + if (r == -EINTR) { + e->state = SD_EVENT_PENDING; + return 1; + } if (r < 0) goto finish; + if (r == 0 && threshold < INT64_MAX) + /* No new epoll event. */ + break; + + r = process_child(e, threshold, &child_min_priority); + if (r < 0) + goto finish; + if (r == 0) + /* No new child event. */ + break; + + threshold = MIN(epoll_min_priority, child_min_priority); + if (threshold == INT64_MIN) + break; + + timeout = 0; } r = process_watchdog(e); @@ -3643,19 +4039,12 @@ _public_ int sd_event_wait(sd_event *e, uint64_t timeout) { if (r < 0) goto finish; - if (e->need_process_child) { - r = process_child(e); - if (r < 0) - goto finish; - } - r = process_inotify(e); if (r < 0) goto finish; if (event_next_pending(e)) { e->state = SD_EVENT_PENDING; - return 1; } @@ -3682,9 +4071,8 @@ _public_ int sd_event_dispatch(sd_event *e) { p = event_next_pending(e); if (p) { - _cleanup_(sd_event_unrefp) sd_event *ref = NULL; + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); - ref = sd_event_ref(e); e->state = SD_EVENT_RUNNING; r = source_dispatch(p); e->state = SD_EVENT_INITIAL; @@ -3718,29 +4106,32 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { assert_return(e->state != SD_EVENT_FINISHED, -ESTALE); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - if (e->profile_delays && e->last_run) { + if (e->profile_delays && e->last_run_usec != 0) { usec_t this_run; unsigned l; this_run = now(CLOCK_MONOTONIC); - l = u64log2(this_run - e->last_run); + l = u64log2(this_run - e->last_run_usec); assert(l < ELEMENTSOF(e->delays)); e->delays[l]++; - if (this_run - e->last_log >= 5*USEC_PER_SEC) { + if (this_run - e->last_log_usec >= 5*USEC_PER_SEC) { event_log_delays(e); - e->last_log = this_run; + e->last_log_usec = this_run; } } + /* Make sure that none of the preparation callbacks ends up freeing the event source under our feet */ + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = sd_event_ref(e); + r = sd_event_prepare(e); if (r == 0) /* There was nothing? Then wait... */ r = sd_event_wait(e, timeout); if (e->profile_delays) - e->last_run = now(CLOCK_MONOTONIC); + e->last_run_usec = now(CLOCK_MONOTONIC); if (r > 0) { /* There's something now, then let's dispatch it */ @@ -3755,7 +4146,6 @@ _public_ int sd_event_run(sd_event *e, uint64_t timeout) { } _public_ int sd_event_loop(sd_event *e) { - _cleanup_(sd_event_unrefp) sd_event *ref = NULL; int r; assert_return(e, -EINVAL); @@ -3763,10 +4153,10 @@ _public_ int sd_event_loop(sd_event *e) { assert_return(!event_pid_changed(e), -ECHILD); assert_return(e->state == SD_EVENT_INITIAL, -EBUSY); - ref = sd_event_ref(e); + _unused_ _cleanup_(sd_event_unrefp) sd_event *ref = NULL; while (e->state != SD_EVENT_FINISHED) { - r = sd_event_run(e, (uint64_t) -1); + r = sd_event_run(e, UINT64_MAX); if (r < 0) return r; } @@ -4008,3 +4398,53 @@ _public_ int sd_event_source_set_exit_on_failure(sd_event_source *s, int b) { s->exit_on_failure = b; return 1; } + +_public_ int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval, unsigned burst) { + int r; + + assert_return(s, -EINVAL); + + /* Turning on ratelimiting on event source types that don't support it, is a loggable offense. Doing + * so is a programming error. */ + assert_return(EVENT_SOURCE_CAN_RATE_LIMIT(s->type), -EDOM); + + /* When ratelimiting is configured we'll always reset the rate limit state first and start fresh, + * non-ratelimited. */ + r = event_source_leave_ratelimit(s); + if (r < 0) + return r; + + s->rate_limit = (RateLimit) { interval, burst }; + return 0; +} + +_public_ int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval, unsigned *ret_burst) { + assert_return(s, -EINVAL); + + /* Querying whether an event source has ratelimiting configured is not a loggable offsense, hence + * don't use assert_return(). Unlike turning on ratelimiting it's not really a programming error */ + if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) + return -EDOM; + + if (!ratelimit_configured(&s->rate_limit)) + return -ENOEXEC; + + if (ret_interval) + *ret_interval = s->rate_limit.interval; + if (ret_burst) + *ret_burst = s->rate_limit.burst; + + return 0; +} + +_public_ int sd_event_source_is_ratelimited(sd_event_source *s) { + assert_return(s, -EINVAL); + + if (!EVENT_SOURCE_CAN_RATE_LIMIT(s->type)) + return false; + + if (!ratelimit_configured(&s->rate_limit)) + return false; + + return s->ratelimited; +} diff --git a/src/libsystemd/sd-event/test-event.c b/src/libsystemd/sd-event/test-event.c index 1c4d0e25a..0bc2f507a 100644 --- a/src/libsystemd/sd-event/test-event.c +++ b/src/libsystemd/sd-event/test-event.c @@ -13,6 +13,7 @@ #include "parse-util.h" #include "path-util.h" #include "process-util.h" +#include "random-util.h" #include "rm-rf.h" #include "signal-util.h" #include "stdio-util.h" @@ -201,6 +202,8 @@ static void test_basic(bool with_pidfd) { uint64_t event_now; int64_t priority; + log_info("/* %s(pidfd=%s) */", __func__, yes_no(with_pidfd)); + assert_se(setenv("SYSTEMD_PIDFD", yes_no(with_pidfd), 1) >= 0); assert_se(pipe(a) >= 0); @@ -217,7 +220,7 @@ static void test_basic(bool with_pidfd) { got_unref = false; assert_se(sd_event_add_io(e, &t, k[0], EPOLLIN, unref_handler, NULL) >= 0); assert_se(write(k[1], &ch, 1) == 1); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(got_unref); got_a = false, got_b = false, got_c = false, got_d = 0; @@ -227,10 +230,10 @@ static void test_basic(bool with_pidfd) { assert_se(sd_event_add_io(e, &w, d[0], EPOLLIN, io_handler, INT_TO_PTR('d')) >= 0); assert_se(sd_event_source_set_enabled(w, SD_EVENT_ONESHOT) >= 0); assert_se(write(d[1], &ch, 1) >= 0); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(got_d == 1); assert_se(write(d[1], &ch, 1) >= 0); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(got_d == 2); assert_se(sd_event_add_io(e, &x, a[0], EPOLLIN, io_handler, INT_TO_PTR('a')) >= 0); @@ -258,15 +261,15 @@ static void test_basic(bool with_pidfd) { assert_se(!got_a && !got_b && !got_c); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(!got_a && got_b && !got_c); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(!got_a && got_b && got_c); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(got_a && got_b && got_c); @@ -302,6 +305,8 @@ static void test_sd_event_now(void) { _cleanup_(sd_event_unrefp) sd_event *e = NULL; uint64_t event_now; + log_info("/* %s */", __func__); + assert_se(sd_event_new(&e) >= 0); assert_se(sd_event_now(e, CLOCK_MONOTONIC, &event_now) > 0); assert_se(sd_event_now(e, CLOCK_REALTIME, &event_now) > 0); @@ -339,6 +344,8 @@ static void test_rtqueue(void) { sd_event_source *u = NULL, *v = NULL, *s = NULL; sd_event *e = NULL; + log_info("/* %s */", __func__); + assert_se(sd_event_default(&e) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN+2, SIGRTMIN+3, SIGUSR2, -1) >= 0); @@ -357,19 +364,19 @@ static void test_rtqueue(void) { assert_se(n_rtqueue == 0); assert_se(last_rtqueue_sigval == 0); - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(n_rtqueue == 1); assert_se(last_rtqueue_sigval == 2); /* first SIGRTMIN+3 */ - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(n_rtqueue == 2); assert_se(last_rtqueue_sigval == 4); /* second SIGRTMIN+3 */ - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(n_rtqueue == 3); assert_se(last_rtqueue_sigval == 3); /* first SIGUSR2 */ - assert_se(sd_event_run(e, (uint64_t) -1) >= 1); + assert_se(sd_event_run(e, UINT64_MAX) >= 1); assert_se(n_rtqueue == 4); assert_se(last_rtqueue_sigval == 1); /* SIGRTMIN+2 */ @@ -479,6 +486,8 @@ static void test_inotify(unsigned n_create_events) { const char *q; unsigned i; + log_info("/* %s(%u) */", __func__, n_create_events); + assert_se(sd_event_default(&e) >= 0); assert_se(mkdtemp_malloc("/tmp/test-inotify-XXXXXX", &p) >= 0); @@ -545,6 +554,8 @@ static void test_pidfd(void) { int pidfd; pid_t pid, pid2; + log_info("/* %s */", __func__); + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); pid = fork(); @@ -589,8 +600,123 @@ static void test_pidfd(void) { sd_event_unref(e); } +static int ratelimit_io_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + unsigned *c = (unsigned*) userdata; + *c += 1; + return 0; +} + +static int ratelimit_time_handler(sd_event_source *s, uint64_t usec, void *userdata) { + int r; + + r = sd_event_source_set_enabled(s, SD_EVENT_ON); + if (r < 0) + log_warning_errno(r, "Failed to turn on notify event source: %m"); + + r = sd_event_source_set_time(s, usec + 1000); + if (r < 0) + log_error_errno(r, "Failed to restart watchdog event source: %m"); + + unsigned *c = (unsigned*) userdata; + *c += 1; + + return 0; +} + +static void test_ratelimit(void) { + _cleanup_close_pair_ int p[2] = {-1, -1}; + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; + uint64_t interval; + unsigned count, burst; + + log_info("/* %s */", __func__); + + assert_se(sd_event_default(&e) >= 0); + assert_se(pipe2(p, O_CLOEXEC|O_NONBLOCK) >= 0); + + assert_se(sd_event_add_io(e, &s, p[0], EPOLLIN, ratelimit_io_handler, &count) >= 0); + assert_se(sd_event_source_set_description(s, "test-ratelimit-io") >= 0); + assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0); + assert_se(sd_event_source_get_ratelimit(s, &interval, &burst) >= 0); + assert_se(interval == 1 * USEC_PER_SEC && burst == 5); + + assert_se(write(p[1], "1", 1) == 1); + + count = 0; + for (unsigned i = 0; i < 10; i++) { + log_debug("slow loop iteration %u", i); + assert_se(sd_event_run(e, UINT64_MAX) >= 0); + assert_se(usleep(250 * USEC_PER_MSEC) >= 0); + } + + assert_se(sd_event_source_is_ratelimited(s) == 0); + assert_se(count == 10); + log_info("ratelimit_io_handler: called %d times, event source not ratelimited", count); + + assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0); + assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 5) >= 0); + + count = 0; + for (unsigned i = 0; i < 10; i++) { + log_debug("fast event loop iteration %u", i); + assert_se(sd_event_run(e, UINT64_MAX) >= 0); + assert_se(usleep(10) >= 0); + } + log_info("ratelimit_io_handler: called %d times, event source got ratelimited", count); + assert_se(count < 10); + + s = sd_event_source_unref(s); + safe_close_pair(p); + + count = 0; + assert_se(sd_event_add_time_relative(e, &s, CLOCK_MONOTONIC, 1000, 1, ratelimit_time_handler, &count) >= 0); + assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) == 0); + + do { + assert_se(sd_event_run(e, UINT64_MAX) >= 0); + } while (!sd_event_source_is_ratelimited(s)); + + log_info("ratelimit_time_handler: called %d times, event source got ratelimited", count); + assert_se(count == 10); + + /* In order to get rid of active rate limit client needs to disable it explicitly */ + assert_se(sd_event_source_set_ratelimit(s, 0, 0) >= 0); + assert_se(!sd_event_source_is_ratelimited(s)); + + assert_se(sd_event_source_set_ratelimit(s, 1 * USEC_PER_SEC, 10) >= 0); + + do { + assert_se(sd_event_run(e, UINT64_MAX) >= 0); + } while (!sd_event_source_is_ratelimited(s)); + + log_info("ratelimit_time_handler: called 10 more times, event source got ratelimited"); + assert_se(count == 20); +} + +static void test_simple_timeout(void) { + _cleanup_(sd_event_unrefp) sd_event *e = NULL; + usec_t f, t, some_time; + + some_time = random_u64_range(2 * USEC_PER_SEC); + + assert_se(sd_event_default(&e) >= 0); + + assert_se(sd_event_prepare(e) == 0); + + f = now(CLOCK_MONOTONIC); + assert_se(sd_event_wait(e, some_time) >= 0); + t = now(CLOCK_MONOTONIC); + + /* The event loop may sleep longer than the specified time (timer accuracy, scheduling latencies, …), + * but never shorter. Let's check that. */ + assert_se(t >= usec_add(f, some_time)); +} + int main(int argc, char *argv[]) { - test_setup_logging(LOG_INFO); + test_setup_logging(LOG_DEBUG); + + test_simple_timeout(); test_basic(true); /* test with pidfd */ test_basic(false); /* test without pidfd */ @@ -603,5 +729,7 @@ int main(int argc, char *argv[]) { test_pidfd(); + test_ratelimit(); + return 0; } diff --git a/src/libsystemd/sd-hwdb/hwdb-util.c b/src/libsystemd/sd-hwdb/hwdb-util.c index 4c94ba9c8..fd45ff0f5 100644 --- a/src/libsystemd/sd-hwdb/hwdb-util.c +++ b/src/libsystemd/sd-hwdb/hwdb-util.c @@ -115,13 +115,13 @@ static void trie_node_cleanup(struct trie_node *node) { free(node); } -static void trie_free(struct trie *trie) { +static struct trie* trie_free(struct trie *trie) { if (!trie) - return; + return NULL; trie_node_cleanup(trie->root); - strbuf_cleanup(trie->strings); - free(trie); + strbuf_free(trie->strings); + return mfree(trie); } DEFINE_TRIVIAL_CLEANUP_FUNC(struct trie*, trie_free); diff --git a/src/journal/audit-type.c b/src/libsystemd/sd-journal/audit-type.c similarity index 100% rename from src/journal/audit-type.c rename to src/libsystemd/sd-journal/audit-type.c diff --git a/src/journal/audit-type.h b/src/libsystemd/sd-journal/audit-type.h similarity index 100% rename from src/journal/audit-type.h rename to src/libsystemd/sd-journal/audit-type.h diff --git a/src/journal/audit_type-to-name.awk b/src/libsystemd/sd-journal/audit_type-to-name.awk similarity index 82% rename from src/journal/audit_type-to-name.awk rename to src/libsystemd/sd-journal/audit_type-to-name.awk index 44fc702eb..1657866a6 100644 --- a/src/journal/audit_type-to-name.awk +++ b/src/libsystemd/sd-journal/audit_type-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "const char *audit_type_to_string(int type) {\n\tswitch(type) {" } diff --git a/src/journal/catalog.c b/src/libsystemd/sd-journal/catalog.c similarity index 99% rename from src/journal/catalog.c rename to src/libsystemd/sd-journal/catalog.c index 0f6ad8a29..aea3241d1 100644 --- a/src/journal/catalog.c +++ b/src/libsystemd/sd-journal/catalog.c @@ -444,7 +444,7 @@ error: int catalog_update(const char* database, const char* root, const char* const* dirs) { _cleanup_strv_free_ char **files = NULL; char **f; - _cleanup_(strbuf_cleanupp) struct strbuf *sb = NULL; + _cleanup_(strbuf_freep) struct strbuf *sb = NULL; _cleanup_ordered_hashmap_free_free_free_ OrderedHashmap *h = NULL; _cleanup_free_ CatalogItem *items = NULL; ssize_t offset; diff --git a/src/journal/catalog.h b/src/libsystemd/sd-journal/catalog.h similarity index 100% rename from src/journal/catalog.h rename to src/libsystemd/sd-journal/catalog.h diff --git a/src/journal/compress.c b/src/libsystemd/sd-journal/compress.c similarity index 97% rename from src/journal/compress.c rename to src/libsystemd/sd-journal/compress.c index aaf186ba6..bdcf47a25 100644 --- a/src/journal/compress.c +++ b/src/libsystemd/sd-journal/compress.c @@ -34,13 +34,13 @@ #include "util.h" #if HAVE_LZ4 -DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_compressionContext_t, LZ4F_freeCompressionContext); -DEFINE_TRIVIAL_CLEANUP_FUNC(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(LZ4F_compressionContext_t, LZ4F_freeCompressionContext, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(LZ4F_decompressionContext_t, LZ4F_freeDecompressionContext, NULL); #endif #if HAVE_ZSTD -DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_CCtx *, ZSTD_freeCCtx); -DEFINE_TRIVIAL_CLEANUP_FUNC(ZSTD_DCtx *, ZSTD_freeDCtx); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ZSTD_CCtx*, ZSTD_freeCCtx, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(ZSTD_DCtx*, ZSTD_freeDCtx, NULL); static int zstd_ret_to_errno(size_t ret) { switch (ZSTD_getErrorCode(ret)) { @@ -176,7 +176,7 @@ int decompress_blob_xz(const void *src, uint64_t src_size, if (ret != LZMA_OK) return -ENOMEM; - space = MIN(src_size * 2, dst_max ?: (size_t) -1); + space = MIN(src_size * 2, dst_max ?: SIZE_MAX); if (!greedy_realloc(dst, dst_alloc_size, space, 1)) return -ENOMEM; @@ -202,7 +202,7 @@ int decompress_blob_xz(const void *src, uint64_t src_size, return -ENOBUFS; used = space - s.avail_out; - space = MIN(2 * space, dst_max ?: (size_t) -1); + space = MIN(2 * space, dst_max ?: SIZE_MAX); if (!greedy_realloc(dst, dst_alloc_size, space, 1)) return -ENOMEM; @@ -554,7 +554,7 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { size_t m = sizeof(buf); ssize_t n; - if (max_bytes != (uint64_t) -1 && (uint64_t) m > max_bytes) + if (max_bytes != UINT64_MAX && (uint64_t) m > max_bytes) m = (size_t) max_bytes; n = read(fdf, buf, m); @@ -566,7 +566,7 @@ int compress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { s.next_in = buf; s.avail_in = n; - if (max_bytes != (uint64_t) -1) { + if (max_bytes != UINT64_MAX) { assert(max_bytes >= (uint64_t) n); max_bytes -= n; } @@ -664,10 +664,11 @@ int compress_stream_lz4(int fdf, int fdt, uint64_t max_bytes) { offset += n; total_out += n; - if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) - return log_debug_errno(SYNTHETIC_ERRNO(EFBIG), - "Compressed stream longer than %" PRIu64 " bytes", - max_bytes); + if (max_bytes != UINT64_MAX && total_out > (size_t) max_bytes) { + r = log_debug_errno(SYNTHETIC_ERRNO(EFBIG), + "Compressed stream longer than %" PRIu64 " bytes", max_bytes); + goto cleanup; + } if (size - offset < frame_size + 4) { k = loop_write(fdt, buf, offset, false); @@ -751,7 +752,7 @@ int decompress_stream_xz(int fdf, int fdt, uint64_t max_bytes) { n = sizeof(out) - s.avail_out; - if (max_bytes != (uint64_t) -1) { + if (max_bytes != UINT64_MAX) { if (max_bytes < (uint64_t) n) return -EFBIG; @@ -815,7 +816,7 @@ int decompress_stream_lz4(int in, int out, uint64_t max_bytes) { total_in += used; total_out += produced; - if (max_bytes != (uint64_t) -1 && total_out > (size_t) max_bytes) { + if (max_bytes != UINT64_MAX && total_out > (size_t) max_bytes) { log_debug("Decompressed stream longer than %"PRIu64" bytes", max_bytes); r = -EFBIG; goto cleanup; diff --git a/src/journal/compress.h b/src/libsystemd/sd-journal/compress.h similarity index 100% rename from src/journal/compress.h rename to src/libsystemd/sd-journal/compress.h diff --git a/src/journal/fsprg.c b/src/libsystemd/sd-journal/fsprg.c similarity index 100% rename from src/journal/fsprg.c rename to src/libsystemd/sd-journal/fsprg.c diff --git a/src/journal/fsprg.h b/src/libsystemd/sd-journal/fsprg.h similarity index 100% rename from src/journal/fsprg.h rename to src/libsystemd/sd-journal/fsprg.h diff --git a/src/journal/generate-audit_type-list.sh b/src/libsystemd/sd-journal/generate-audit_type-list.sh similarity index 85% rename from src/journal/generate-audit_type-list.sh rename to src/libsystemd/sd-journal/generate-audit_type-list.sh index 912d0c990..d5b145f31 100755 --- a/src/journal/generate-audit_type-list.sh +++ b/src/libsystemd/sd-journal/generate-audit_type-list.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu cpp="$1" diff --git a/src/journal/journal-authenticate.c b/src/libsystemd/sd-journal/journal-authenticate.c similarity index 100% rename from src/journal/journal-authenticate.c rename to src/libsystemd/sd-journal/journal-authenticate.c diff --git a/src/journal/journal-authenticate.h b/src/libsystemd/sd-journal/journal-authenticate.h similarity index 100% rename from src/journal/journal-authenticate.h rename to src/libsystemd/sd-journal/journal-authenticate.h diff --git a/src/journal/journal-def.h b/src/libsystemd/sd-journal/journal-def.h similarity index 100% rename from src/journal/journal-def.h rename to src/libsystemd/sd-journal/journal-def.h diff --git a/src/journal/journal-file.c b/src/libsystemd/sd-journal/journal-file.c similarity index 97% rename from src/journal/journal-file.c rename to src/libsystemd/sd-journal/journal-file.c index 15336bef3..f8bb708e5 100644 --- a/src/journal/journal-file.c +++ b/src/libsystemd/sd-journal/journal-file.c @@ -208,6 +208,7 @@ static bool journal_file_set_offline_try_restart(JournalFile *f) { * context without involving another thread. */ int journal_file_set_offline(JournalFile *f, bool wait) { + int target_state; bool restarted; int r; @@ -219,9 +220,13 @@ int journal_file_set_offline(JournalFile *f, bool wait) { if (f->fd < 0 || !f->header) return -EINVAL; + target_state = f->archive ? STATE_ARCHIVED : STATE_OFFLINE; + /* An offlining journal is implicitly online and may modify f->header->state, - * we must also join any potentially lingering offline thread when not online. */ - if (!journal_file_is_offlining(f) && f->header->state != STATE_ONLINE) + * we must also join any potentially lingering offline thread when already in + * the desired offline state. + */ + if (!journal_file_is_offlining(f) && f->header->state == target_state) return journal_file_set_offline_thread_join(f); /* Restart an in-flight offline thread and wait if needed, or join a lingering done one. */ @@ -724,8 +729,7 @@ static int journal_file_move_to( bool keep_always, uint64_t offset, uint64_t size, - void **ret, - size_t *ret_size) { + void **ret) { int r; @@ -751,7 +755,7 @@ static int journal_file_move_to( return -EADDRNOTAVAIL; } - return mmap_cache_get(f->mmap, f->cache_fd, f->prot, type_to_context(type), keep_always, offset, size, &f->last_stat, ret, ret_size); + return mmap_cache_get(f->mmap, f->cache_fd, type_to_context(type), keep_always, offset, size, &f->last_stat, ret); } static uint64_t minimum_header_size(Object *o) { @@ -923,7 +927,6 @@ static int journal_file_check_object(JournalFile *f, uint64_t offset, Object *o) int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset, Object **ret) { int r; void *t; - size_t tsize; Object *o; uint64_t s; @@ -942,7 +945,7 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset "Attempt to move to object located in file header: %" PRIu64, offset); - r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t, &tsize); + r = journal_file_move_to(f, type, false, offset, sizeof(ObjectHeader), &t); if (r < 0) return r; @@ -973,13 +976,11 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset "Attempt to move to object of unexpected type: %" PRIu64, offset); - if (s > tsize) { - r = journal_file_move_to(f, type, false, offset, s, &t, NULL); - if (r < 0) - return r; + r = journal_file_move_to(f, type, false, offset, s, &t); + if (r < 0) + return r; - o = (Object*) t; - } + o = (Object*) t; r = journal_file_check_object(f, offset, o); if (r < 0) @@ -989,31 +990,59 @@ int journal_file_move_to_object(JournalFile *f, ObjectType type, uint64_t offset return 0; } -static uint64_t journal_file_entry_seqnum(JournalFile *f, uint64_t *seqnum) { - uint64_t r; +static uint64_t journal_file_entry_seqnum( + JournalFile *f, + uint64_t *seqnum) { + + uint64_t ret; assert(f); assert(f->header); - r = le64toh(f->header->tail_entry_seqnum) + 1; + /* Picks a new sequence number for the entry we are about to add and returns it. */ + + ret = le64toh(f->header->tail_entry_seqnum) + 1; if (seqnum) { - /* If an external seqnum counter was passed, we update - * both the local and the external one, and set it to - * the maximum of both */ + /* If an external seqnum counter was passed, we update both the local and the external one, + * and set it to the maximum of both */ - if (*seqnum + 1 > r) - r = *seqnum + 1; + if (*seqnum + 1 > ret) + ret = *seqnum + 1; - *seqnum = r; + *seqnum = ret; } - f->header->tail_entry_seqnum = htole64(r); + f->header->tail_entry_seqnum = htole64(ret); if (f->header->head_entry_seqnum == 0) - f->header->head_entry_seqnum = htole64(r); + f->header->head_entry_seqnum = htole64(ret); - return r; + return ret; +} + +static void journal_file_revert_entry_seqnum( + JournalFile *f, + uint64_t *seqnum, + uint64_t revert_seqnum) { + + assert(f); + assert(f->header); + + if (revert_seqnum == 0) /* sequence number 0? can't go back */ + return; + + /* Undoes the effect of journal_file_entry_seqnum() above: if we fail to append an entry to a file, + * let's revert the seqnum we were about to use, so that we can use it on the next entry. */ + + if (le64toh(f->header->tail_entry_seqnum) == revert_seqnum) + f->header->tail_entry_seqnum = htole64(revert_seqnum - 1); + + if (le64toh(f->header->head_entry_seqnum) == revert_seqnum) + f->header->head_entry_seqnum = 0; + + if (seqnum && *seqnum == revert_seqnum) + *seqnum = revert_seqnum - 1; } int journal_file_append_object( @@ -1062,7 +1091,7 @@ int journal_file_append_object( if (r < 0) return r; - r = journal_file_move_to(f, type, false, p, size, &t, NULL); + r = journal_file_move_to(f, type, false, p, size, &t); if (r < 0) return r; @@ -1165,7 +1194,7 @@ int journal_file_map_data_hash_table(JournalFile *f) { OBJECT_DATA_HASH_TABLE, true, p, s, - &t, NULL); + &t); if (r < 0) return r; @@ -1191,7 +1220,7 @@ int journal_file_map_field_hash_table(JournalFile *f) { OBJECT_FIELD_HASH_TABLE, true, p, s, - &t, NULL); + &t); if (r < 0) return r; @@ -1526,15 +1555,13 @@ int journal_file_find_data_object( } bool journal_field_valid(const char *p, size_t l, bool allow_protected) { - const char *a; - /* We kinda enforce POSIX syntax recommendations for environment variables here, but make a couple of additional requirements. http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */ - if (l == (size_t) -1) + if (l == SIZE_MAX) l = strlen(p); /* No empty field names */ @@ -1554,7 +1581,7 @@ bool journal_field_valid(const char *p, size_t l, bool allow_protected) { return false; /* Only allow A-Z0-9 and '_' */ - for (a = p; a < p + l; a++) + for (const char *a = p; a < p + l; a++) if ((*a < 'A' || *a > 'Z') && (*a < '0' || *a > '9') && *a != '_') @@ -1901,7 +1928,7 @@ static int journal_file_link_entry_item(JournalFile *f, Object *o, uint64_t offs } static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) { - uint64_t n, i; + uint64_t n; int r; assert(f); @@ -1932,7 +1959,7 @@ static int journal_file_link_entry(JournalFile *f, Object *o, uint64_t offset) { /* Link up the items */ n = journal_file_entry_n_items(o); - for (i = 0; i < n; i++) { + for (uint64_t i = 0; i < n; i++) { r = journal_file_link_entry_item(f, o, offset, i); if (r < 0) return r; @@ -1977,12 +2004,12 @@ static int journal_file_append_entry_internal( #if HAVE_GCRYPT r = journal_file_hmac_put_object(f, OBJECT_ENTRY, o, np); if (r < 0) - return r; + goto fail; #endif r = journal_file_link_entry(f, o, np); if (r < 0) - return r; + goto fail; if (ret) *ret = o; @@ -1991,6 +2018,10 @@ static int journal_file_append_entry_internal( *ret_offset = np; return 0; + +fail: + journal_file_revert_entry_seqnum(f, seqnum, le64toh(o->entry.seqnum)); + return r; } void journal_file_post_change(JournalFile *f) { @@ -2087,7 +2118,6 @@ int journal_file_append_entry( uint64_t *seqnum, Object **ret, uint64_t *ret_offset) { - unsigned i; EntryItem *items; int r; uint64_t xor_hash = 0; @@ -2120,7 +2150,7 @@ int journal_file_append_entry( /* alloca() can't take 0, hence let's allocate at least one */ items = newa(EntryItem, MAX(1u, n_iovec)); - for (i = 0; i < n_iovec; i++) { + for (unsigned i = 0; i < n_iovec; i++) { uint64_t p; Object *o; @@ -2322,7 +2352,7 @@ static int generic_array_bisect( uint64_t *ret_offset, uint64_t *ret_idx) { - uint64_t a, p, t = 0, i = 0, last_p = 0, last_index = (uint64_t) -1; + uint64_t a, p, t = 0, i = 0, last_p = 0, last_index = UINT64_MAX; bool subtract_one = false; Object *o, *array = NULL; int r; @@ -2392,7 +2422,7 @@ static int generic_array_bisect( left = 0; right -= 1; - if (last_index != (uint64_t) -1) { + if (last_index != UINT64_MAX) { assert(last_index <= right); /* If we cached the last index we @@ -2492,7 +2522,7 @@ static int generic_array_bisect( n -= k; t += k; - last_index = (uint64_t) -1; + last_index = UINT64_MAX; a = le64toh(array->entry_array.next_entry_array_offset); } @@ -2503,7 +2533,7 @@ found: return 0; /* Let's cache this item for the next invocation */ - chain_cache_put(f->chain_cache, ci, first, a, le64toh(array->entry_array.items[0]), t, subtract_one ? (i > 0 ? i-1 : (uint64_t) -1) : i); + chain_cache_put(f->chain_cache, ci, first, a, le64toh(array->entry_array.items[0]), t, subtract_one ? (i > 0 ? i-1 : UINT64_MAX) : i); if (subtract_one && i == 0) p = last_p; @@ -3408,7 +3438,6 @@ int journal_file_open( .mode = mode, .flags = flags, - .prot = prot_from_flags(flags), .writable = (flags & O_ACCMODE) != O_RDONLY, #if HAVE_ZSTD @@ -3418,7 +3447,7 @@ int journal_file_open( #elif HAVE_XZ .compress_xz = compress, #endif - .compress_threshold_bytes = compress_threshold_bytes == (uint64_t) -1 ? + .compress_threshold_bytes = compress_threshold_bytes == UINT64_MAX ? DEFAULT_COMPRESS_THRESHOLD : MAX(MIN_COMPRESS_THRESHOLD, compress_threshold_bytes), #if HAVE_GCRYPT @@ -3507,7 +3536,7 @@ int journal_file_open( goto fail; } - f->cache_fd = mmap_cache_add_fd(f->mmap, f->fd); + f->cache_fd = mmap_cache_add_fd(f->mmap, f->fd, prot_from_flags(flags)); if (!f->cache_fd) { r = -ENOMEM; goto fail; @@ -3554,7 +3583,7 @@ int journal_file_open( goto fail; } - r = mmap_cache_get(f->mmap, f->cache_fd, f->prot, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h, NULL); + r = mmap_cache_get(f->mmap, f->cache_fd, CONTEXT_HEADER, true, 0, PAGE_ALIGN(sizeof(Header)), &f->last_stat, &h); if (r == -EINVAL) { /* Some file systems (jffs2 or p9fs) don't support mmap() properly (or only read-only * mmap()), and return EINVAL in that case. Let's propagate that as a more recognizable error @@ -3757,7 +3786,7 @@ int journal_file_dispose(int dir_fd, const char *fname) { assert(fname); - /* Renames a journal file to *.journal~, i.e. to mark it as corruped or otherwise uncleanly shutdown. Note that + /* Renames a journal file to *.journal~, i.e. to mark it as corrupted or otherwise uncleanly shutdown. Note that * this is done without looking into the file or changing any of its contents. The idea is that this is called * whenever something is suspicious and we want to move the file away and make clear that it is not accessed * for writing anymore. */ @@ -3836,12 +3865,11 @@ int journal_file_open_reliably( } int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint64_t p) { - uint64_t i, n; - uint64_t q, xor_hash = 0; - int r; - EntryItem *items; - dual_timestamp ts; + uint64_t q, n, xor_hash = 0; const sd_id128_t *boot_id; + dual_timestamp ts; + EntryItem *items; + int r; assert(from); assert(to); @@ -3859,7 +3887,7 @@ int journal_file_copy_entry(JournalFile *from, JournalFile *to, Object *o, uint6 /* alloca() can't take 0, hence let's allocate at least one */ items = newa(EntryItem, MAX(1u, n)); - for (i = 0; i < n; i++) { + for (uint64_t i = 0; i < n; i++) { uint64_t l, h; le64_t le_hash; size_t t; @@ -3936,12 +3964,12 @@ void journal_reset_metrics(JournalMetrics *m) { /* Set everything to "pick automatic values". */ *m = (JournalMetrics) { - .min_use = (uint64_t) -1, - .max_use = (uint64_t) -1, - .min_size = (uint64_t) -1, - .max_size = (uint64_t) -1, - .keep_free = (uint64_t) -1, - .n_max_files = (uint64_t) -1, + .min_use = UINT64_MAX, + .max_use = UINT64_MAX, + .min_size = UINT64_MAX, + .max_size = UINT64_MAX, + .keep_free = UINT64_MAX, + .n_max_files = UINT64_MAX, }; } @@ -3958,7 +3986,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) { else log_debug_errno(errno, "Failed to determine disk size: %m"); - if (m->max_use == (uint64_t) -1) { + if (m->max_use == UINT64_MAX) { if (fs_size > 0) m->max_use = CLAMP(PAGE_ALIGN(fs_size / 10), /* 10% of file system size */ @@ -3972,7 +4000,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) { m->max_use = JOURNAL_FILE_SIZE_MIN*2; } - if (m->min_use == (uint64_t) -1) { + if (m->min_use == UINT64_MAX) { if (fs_size > 0) m->min_use = CLAMP(PAGE_ALIGN(fs_size / 50), /* 2% of file system size */ MIN_USE_LOW, MIN_USE_HIGH); @@ -3983,7 +4011,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) { if (m->min_use > m->max_use) m->min_use = m->max_use; - if (m->max_size == (uint64_t) -1) + if (m->max_size == UINT64_MAX) m->max_size = MIN(PAGE_ALIGN(m->max_use / 8), /* 8 chunks */ MAX_SIZE_UPPER); else @@ -3997,14 +4025,14 @@ void journal_default_metrics(JournalMetrics *m, int fd) { m->max_use = m->max_size*2; } - if (m->min_size == (uint64_t) -1) + if (m->min_size == UINT64_MAX) m->min_size = JOURNAL_FILE_SIZE_MIN; else m->min_size = CLAMP(PAGE_ALIGN(m->min_size), JOURNAL_FILE_SIZE_MIN, m->max_size ?: UINT64_MAX); - if (m->keep_free == (uint64_t) -1) { + if (m->keep_free == UINT64_MAX) { if (fs_size > 0) m->keep_free = MIN(PAGE_ALIGN(fs_size / 20), /* 5% of file system size */ KEEP_FREE_UPPER); @@ -4012,7 +4040,7 @@ void journal_default_metrics(JournalMetrics *m, int fd) { m->keep_free = DEFAULT_KEEP_FREE; } - if (m->n_max_files == (uint64_t) -1) + if (m->n_max_files == UINT64_MAX) m->n_max_files = DEFAULT_N_MAX_FILES; log_debug("Fixed min_use=%s max_use=%s max_size=%s min_size=%s keep_free=%s n_max_files=%" PRIu64, diff --git a/src/journal/journal-file.h b/src/libsystemd/sd-journal/journal-file.h similarity index 99% rename from src/journal/journal-file.h rename to src/libsystemd/sd-journal/journal-file.h index c48d95f3a..931c87426 100644 --- a/src/journal/journal-file.h +++ b/src/libsystemd/sd-journal/journal-file.h @@ -63,7 +63,6 @@ typedef struct JournalFile { mode_t mode; int flags; - int prot; bool writable:1; bool compress_xz:1; bool compress_lz4:1; diff --git a/src/journal/journal-internal.h b/src/libsystemd/sd-journal/journal-internal.h similarity index 100% rename from src/journal/journal-internal.h rename to src/libsystemd/sd-journal/journal-internal.h diff --git a/src/journal/journal-send.c b/src/libsystemd/sd-journal/journal-send.c similarity index 100% rename from src/journal/journal-send.c rename to src/libsystemd/sd-journal/journal-send.c diff --git a/src/journal/journal-vacuum.c b/src/libsystemd/sd-journal/journal-vacuum.c similarity index 100% rename from src/journal/journal-vacuum.c rename to src/libsystemd/sd-journal/journal-vacuum.c diff --git a/src/journal/journal-vacuum.h b/src/libsystemd/sd-journal/journal-vacuum.h similarity index 100% rename from src/journal/journal-vacuum.h rename to src/libsystemd/sd-journal/journal-vacuum.h diff --git a/src/journal/journal-verify.c b/src/libsystemd/sd-journal/journal-verify.c similarity index 99% rename from src/journal/journal-verify.c rename to src/libsystemd/sd-journal/journal-verify.c index 6ea2f4c89..8c38396ea 100644 --- a/src/journal/journal-verify.c +++ b/src/libsystemd/sd-journal/journal-verify.c @@ -41,7 +41,9 @@ static void draw_progress(uint64_t p, usec_t *last_usec) { fputs("\r", stdout); if (colors_enabled()) - fputs("\x1B[?25l" ANSI_HIGHLIGHT_GREEN, stdout); + fputs("\x1B[?25l", stdout); + + fputs(ansi_highlight_green(), stdout); for (i = 0; i < j; i++) fputs("\xe2\x96\x88", stdout); @@ -377,7 +379,7 @@ static int contains_uint64(MMapCache *m, MMapFileDescriptor *f, uint64_t n, uint c = (a + b) / 2; - r = mmap_cache_get(m, f, PROT_READ|PROT_WRITE, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z, NULL); + r = mmap_cache_get(m, f, 0, false, c * sizeof(uint64_t), sizeof(uint64_t), NULL, (void **) &z); if (r < 0) return r; @@ -862,19 +864,19 @@ int journal_file_verify( goto fail; } - cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd); + cache_data_fd = mmap_cache_add_fd(f->mmap, data_fd, PROT_READ|PROT_WRITE); if (!cache_data_fd) { r = log_oom(); goto fail; } - cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd); + cache_entry_fd = mmap_cache_add_fd(f->mmap, entry_fd, PROT_READ|PROT_WRITE); if (!cache_entry_fd) { r = log_oom(); goto fail; } - cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd); + cache_entry_array_fd = mmap_cache_add_fd(f->mmap, entry_array_fd, PROT_READ|PROT_WRITE); if (!cache_entry_array_fd) { r = log_oom(); goto fail; diff --git a/src/journal/journal-verify.h b/src/libsystemd/sd-journal/journal-verify.h similarity index 100% rename from src/journal/journal-verify.h rename to src/libsystemd/sd-journal/journal-verify.h diff --git a/src/journal/lookup3.c b/src/libsystemd/sd-journal/lookup3.c similarity index 100% rename from src/journal/lookup3.c rename to src/libsystemd/sd-journal/lookup3.c diff --git a/src/journal/lookup3.h b/src/libsystemd/sd-journal/lookup3.h similarity index 100% rename from src/journal/lookup3.h rename to src/libsystemd/sd-journal/lookup3.h diff --git a/src/journal/mmap-cache.c b/src/libsystemd/sd-journal/mmap-cache.c similarity index 86% rename from src/journal/mmap-cache.c rename to src/libsystemd/sd-journal/mmap-cache.c index 988201643..9e0be01d4 100644 --- a/src/journal/mmap-cache.c +++ b/src/libsystemd/sd-journal/mmap-cache.c @@ -25,7 +25,6 @@ struct Window { bool keep_always:1; bool in_unused:1; - int prot; void *ptr; uint64_t offset; size_t size; @@ -49,6 +48,7 @@ struct Context { struct MMapFileDescriptor { MMapCache *cache; int fd; + int prot; bool sigbus; LIST_HEAD(Window, windows); }; @@ -57,7 +57,7 @@ struct MMapCache { unsigned n_ref; unsigned n_windows; - unsigned n_hit, n_missed; + unsigned n_context_cache_hit, n_window_list_hit, n_missed; Hashmap *fds; Context *contexts[MMAP_CACHE_MAX_CONTEXTS]; @@ -112,6 +112,7 @@ static void window_unlink(Window *w) { static void window_invalidate(Window *w) { assert(w); + assert(w->fd); if (w->invalidated) return; @@ -121,7 +122,7 @@ static void window_invalidate(Window *w) { * trigger any further SIGBUS, possibly overrunning the sigbus * queue. */ - assert_se(mmap(w->ptr, w->size, w->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr); + assert_se(mmap(w->ptr, w->size, w->fd->prot, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) == w->ptr); w->invalidated = true; } @@ -133,27 +134,25 @@ static void window_free(Window *w) { free(w); } -_pure_ static bool window_matches(Window *w, int prot, uint64_t offset, size_t size) { +_pure_ static bool window_matches(Window *w, uint64_t offset, size_t size) { assert(w); assert(size > 0); return - prot == w->prot && offset >= w->offset && offset + size <= w->offset + w->size; } -_pure_ static bool window_matches_fd(Window *w, MMapFileDescriptor *f, int prot, uint64_t offset, size_t size) { +_pure_ static bool window_matches_fd(Window *w, MMapFileDescriptor *f, uint64_t offset, size_t size) { assert(w); assert(f); return - w->fd && - f->fd == w->fd->fd && - window_matches(w, prot, offset, size); + w->fd == f && + window_matches(w, offset, size); } -static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool keep_always, uint64_t offset, size_t size, void *ptr) { +static Window *window_add(MMapCache *m, MMapFileDescriptor *f, bool keep_always, uint64_t offset, size_t size, void *ptr) { Window *w; assert(m); @@ -176,7 +175,6 @@ static Window *window_add(MMapCache *m, MMapFileDescriptor *f, int prot, bool ke *w = (Window) { .cache = m, .fd = f, - .prot = prot, .keep_always = keep_always, .offset = offset, .size = size, @@ -304,13 +302,11 @@ static int make_room(MMapCache *m) { static int try_context( MMapCache *m, MMapFileDescriptor *f, - int prot, unsigned context, bool keep_always, uint64_t offset, size_t size, - void **ret, - size_t *ret_size) { + void **ret) { Context *c; @@ -329,7 +325,7 @@ static int try_context( if (!c->window) return 0; - if (!window_matches_fd(c->window, f, prot, offset, size)) { + if (!window_matches_fd(c->window, f, offset, size)) { /* Drop the reference to the window, since it's unnecessary now */ context_detach_window(c); @@ -342,8 +338,6 @@ static int try_context( c->window->keep_always = c->window->keep_always || keep_always; *ret = (uint8_t*) c->window->ptr + (offset - c->window->offset); - if (ret_size) - *ret_size = c->window->size - (offset - c->window->offset); return 1; } @@ -351,13 +345,11 @@ static int try_context( static int find_mmap( MMapCache *m, MMapFileDescriptor *f, - int prot, unsigned context, bool keep_always, uint64_t offset, size_t size, - void **ret, - size_t *ret_size) { + void **ret) { Window *w; Context *c; @@ -371,7 +363,7 @@ static int find_mmap( return -EIO; LIST_FOREACH(by_fd, w, f->windows) - if (window_matches(w, prot, offset, size)) + if (window_matches(w, offset, size)) break; if (!w) @@ -385,13 +377,11 @@ static int find_mmap( w->keep_always = w->keep_always || keep_always; *ret = (uint8_t*) w->ptr + (offset - w->offset); - if (ret_size) - *ret_size = w->size - (offset - w->offset); return 1; } -static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int prot, int flags, uint64_t offset, size_t size, void **res) { +static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int flags, uint64_t offset, size_t size, void **res) { void *ptr; assert(m); @@ -401,7 +391,7 @@ static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int for (;;) { int r; - ptr = mmap(addr, size, prot, flags, f->fd, offset); + ptr = mmap(addr, size, f->prot, flags, f->fd, offset); if (ptr != MAP_FAILED) break; if (errno != ENOMEM) @@ -421,14 +411,12 @@ static int mmap_try_harder(MMapCache *m, void *addr, MMapFileDescriptor *f, int static int add_mmap( MMapCache *m, MMapFileDescriptor *f, - int prot, unsigned context, bool keep_always, uint64_t offset, size_t size, struct stat *st, - void **ret, - size_t *ret_size) { + void **ret) { uint64_t woffset, wsize; Context *c; @@ -471,7 +459,7 @@ static int add_mmap( wsize = PAGE_ALIGN(st->st_size - woffset); } - r = mmap_try_harder(m, NULL, f, prot, MAP_SHARED, woffset, wsize, &d); + r = mmap_try_harder(m, NULL, f, MAP_SHARED, woffset, wsize, &d); if (r < 0) return r; @@ -479,15 +467,13 @@ static int add_mmap( if (!c) goto outofmem; - w = window_add(m, f, prot, keep_always, woffset, wsize, d); + w = window_add(m, f, keep_always, woffset, wsize, d); if (!w) goto outofmem; context_attach_window(c, w); *ret = (uint8_t*) w->ptr + (offset - w->offset); - if (ret_size) - *ret_size = w->size - (offset - w->offset); return 1; @@ -499,14 +485,12 @@ outofmem: int mmap_cache_get( MMapCache *m, MMapFileDescriptor *f, - int prot, unsigned context, bool keep_always, uint64_t offset, size_t size, struct stat *st, - void **ret, - size_t *ret_size) { + void **ret) { int r; @@ -518,35 +502,29 @@ int mmap_cache_get( assert(context < MMAP_CACHE_MAX_CONTEXTS); /* Check whether the current context is the right one already */ - r = try_context(m, f, prot, context, keep_always, offset, size, ret, ret_size); + r = try_context(m, f, context, keep_always, offset, size, ret); if (r != 0) { - m->n_hit++; + m->n_context_cache_hit++; return r; } /* Search for a matching mmap */ - r = find_mmap(m, f, prot, context, keep_always, offset, size, ret, ret_size); + r = find_mmap(m, f, context, keep_always, offset, size, ret); if (r != 0) { - m->n_hit++; + m->n_window_list_hit++; return r; } m->n_missed++; /* Create a new mmap */ - return add_mmap(m, f, prot, context, keep_always, offset, size, st, ret, ret_size); + return add_mmap(m, f, context, keep_always, offset, size, st, ret); } -unsigned mmap_cache_get_hit(MMapCache *m) { +void mmap_cache_stats_log_debug(MMapCache *m) { assert(m); - return m->n_hit; -} - -unsigned mmap_cache_get_missed(MMapCache *m) { - assert(m); - - return m->n_missed; + log_debug("mmap cache statistics: %u context cache hit, %u window list hit, %u miss", m->n_context_cache_hit, m->n_window_list_hit, m->n_missed); } static void mmap_cache_process_sigbus(MMapCache *m) { @@ -620,7 +598,7 @@ bool mmap_cache_got_sigbus(MMapCache *m, MMapFileDescriptor *f) { return f->sigbus; } -MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) { +MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd, int prot) { MMapFileDescriptor *f; int r; @@ -641,6 +619,7 @@ MMapFileDescriptor* mmap_cache_add_fd(MMapCache *m, int fd) { f->cache = m; f->fd = fd; + f->prot = prot; r = hashmap_put(m->fds, FD_TO_PTR(fd), f); if (r < 0) diff --git a/src/journal/mmap-cache.h b/src/libsystemd/sd-journal/mmap-cache.h similarity index 77% rename from src/journal/mmap-cache.h rename to src/libsystemd/sd-journal/mmap-cache.h index 28d5ab1a5..705e56e1f 100644 --- a/src/journal/mmap-cache.h +++ b/src/libsystemd/sd-journal/mmap-cache.h @@ -17,18 +17,15 @@ MMapCache* mmap_cache_unref(MMapCache *m); int mmap_cache_get( MMapCache *m, MMapFileDescriptor *f, - int prot, unsigned context, bool keep_always, uint64_t offset, size_t size, struct stat *st, - void **ret, - size_t *ret_size); -MMapFileDescriptor * mmap_cache_add_fd(MMapCache *m, int fd); + void **ret); +MMapFileDescriptor * mmap_cache_add_fd(MMapCache *m, int fd, int prot); void mmap_cache_free_fd(MMapCache *m, MMapFileDescriptor *f); -unsigned mmap_cache_get_hit(MMapCache *m); -unsigned mmap_cache_get_missed(MMapCache *m); +void mmap_cache_stats_log_debug(MMapCache *m); bool mmap_cache_got_sigbus(MMapCache *m, MMapFileDescriptor *f); diff --git a/src/journal/sd-journal.c b/src/libsystemd/sd-journal/sd-journal.c similarity index 99% rename from src/journal/sd-journal.c rename to src/libsystemd/sd-journal/sd-journal.c index 346970d1f..be92f803c 100644 --- a/src/journal/sd-journal.c +++ b/src/libsystemd/sd-journal/sd-journal.c @@ -63,7 +63,7 @@ static bool journal_pid_changed(sd_journal *j) { } static int journal_put_error(sd_journal *j, int r, const char *path) { - char *copy; + _cleanup_free_ char *copy = NULL; int k; /* Memorize an error we encountered, and store which @@ -80,27 +80,21 @@ static int journal_put_error(sd_journal *j, int r, const char *path) { if (r >= 0) return r; - k = hashmap_ensure_allocated(&j->errors, NULL); - if (k < 0) - return k; - if (path) { copy = strdup(path); if (!copy) return -ENOMEM; - } else - copy = NULL; + } - k = hashmap_put(j->errors, INT_TO_PTR(r), copy); + k = hashmap_ensure_put(&j->errors, NULL, INT_TO_PTR(r), copy); if (k < 0) { - free(copy); - if (k == -EEXIST) return 0; return k; } + TAKE_PTR(copy); return 0; } @@ -1984,7 +1978,7 @@ _public_ int sd_journal_open_container(sd_journal **ret, const char *machine, in assert_return(machine, -EINVAL); assert_return(ret, -EINVAL); assert_return((flags & ~OPEN_CONTAINER_ALLOWED_FLAGS) == 0, -EINVAL); - assert_return(machine_name_is_valid(machine), -EINVAL); + assert_return(hostname_is_valid(machine, 0), -EINVAL); p = strjoina("/run/systemd/machines/", machine); r = parse_env_file(NULL, p, @@ -2173,7 +2167,7 @@ _public_ void sd_journal_close(sd_journal *j) { safe_close(j->inotify_fd); if (j->mmap) { - log_debug("mmap cache statistics: %u hit, %u miss", mmap_cache_get_hit(j->mmap), mmap_cache_get_missed(j->mmap)); + mmap_cache_stats_log_debug(j->mmap); mmap_cache_unref(j->mmap); } @@ -2548,7 +2542,7 @@ _public_ int sd_journal_get_timeout(sd_journal *j, uint64_t *timeout_usec) { return fd; if (!j->on_network) { - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; } @@ -2730,13 +2724,10 @@ _public_ int sd_journal_wait(sd_journal *j, uint64_t timeout_usec) { if (r < 0) return r; - if (t != (uint64_t) -1) { - usec_t n; + if (t != UINT64_MAX) { + t = usec_sub_unsigned(t, now(CLOCK_MONOTONIC)); - n = now(CLOCK_MONOTONIC); - t = t > n ? t - n : 0; - - if (timeout_usec == (uint64_t) -1 || timeout_usec > t) + if (timeout_usec == UINT64_MAX || timeout_usec > t) timeout_usec = t; } diff --git a/src/journal/test-audit-type.c b/src/libsystemd/sd-journal/test-audit-type.c similarity index 100% rename from src/journal/test-audit-type.c rename to src/libsystemd/sd-journal/test-audit-type.c diff --git a/src/journal/test-catalog.c b/src/libsystemd/sd-journal/test-catalog.c similarity index 100% rename from src/journal/test-catalog.c rename to src/libsystemd/sd-journal/test-catalog.c diff --git a/src/journal/test-compress-benchmark.c b/src/libsystemd/sd-journal/test-compress-benchmark.c similarity index 100% rename from src/journal/test-compress-benchmark.c rename to src/libsystemd/sd-journal/test-compress-benchmark.c diff --git a/src/journal/test-compress.c b/src/libsystemd/sd-journal/test-compress.c similarity index 100% rename from src/journal/test-compress.c rename to src/libsystemd/sd-journal/test-compress.c diff --git a/src/journal/test-journal-enum.c b/src/libsystemd/sd-journal/test-journal-enum.c similarity index 100% rename from src/journal/test-journal-enum.c rename to src/libsystemd/sd-journal/test-journal-enum.c diff --git a/src/journal/test-journal-flush.c b/src/libsystemd/sd-journal/test-journal-flush.c similarity index 100% rename from src/journal/test-journal-flush.c rename to src/libsystemd/sd-journal/test-journal-flush.c diff --git a/src/journal/test-journal-init.c b/src/libsystemd/sd-journal/test-journal-init.c similarity index 100% rename from src/journal/test-journal-init.c rename to src/libsystemd/sd-journal/test-journal-init.c diff --git a/src/journal/test-journal-interleaving.c b/src/libsystemd/sd-journal/test-journal-interleaving.c similarity index 96% rename from src/journal/test-journal-interleaving.c rename to src/libsystemd/sd-journal/test-journal-interleaving.c index 8c78c3bbf..62db2266c 100644 --- a/src/journal/test-journal-interleaving.c +++ b/src/libsystemd/sd-journal/test-journal-interleaving.c @@ -35,7 +35,7 @@ _noreturn_ static void log_assert_errno(const char *text, int error, const char static JournalFile *test_open(const char *name) { JournalFile *f; - assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &f)); + assert_ret(journal_file_open(-1, name, O_RDWR|O_CREAT, 0644, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f)); return f; } @@ -206,7 +206,7 @@ static void test_sequence_numbers(void) { mkdtemp_chdir_chattr(t); assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0644, - true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &one) == 0); + true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &one) == 0); append_number(one, 1, &seqnum); printf("seqnum=%"PRIu64"\n", seqnum); @@ -223,7 +223,7 @@ static void test_sequence_numbers(void) { memcpy(&seqnum_id, &one->header->seqnum_id, sizeof(sd_id128_t)); assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0644, - true, (uint64_t) -1, false, NULL, NULL, NULL, one, &two) == 0); + true, UINT64_MAX, false, NULL, NULL, NULL, one, &two) == 0); assert_se(two->header->state == STATE_ONLINE); assert_se(!sd_id128_equal(two->header->file_id, one->header->file_id)); @@ -254,7 +254,7 @@ static void test_sequence_numbers(void) { seqnum = 0; assert_se(journal_file_open(-1, "two.journal", O_RDWR, 0, - true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &two) == 0); + true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &two) == 0); assert_se(sd_id128_equal(two->header->seqnum_id, seqnum_id)); diff --git a/src/journal/test-journal-match.c b/src/libsystemd/sd-journal/test-journal-match.c similarity index 100% rename from src/journal/test-journal-match.c rename to src/libsystemd/sd-journal/test-journal-match.c diff --git a/src/journal/test-journal-send.c b/src/libsystemd/sd-journal/test-journal-send.c similarity index 100% rename from src/journal/test-journal-send.c rename to src/libsystemd/sd-journal/test-journal-send.c diff --git a/src/journal/test-journal-stream.c b/src/libsystemd/sd-journal/test-journal-stream.c similarity index 96% rename from src/journal/test-journal-stream.c rename to src/libsystemd/sd-journal/test-journal-stream.c index a121859e0..ca1eaaebf 100644 --- a/src/journal/test-journal-stream.c +++ b/src/libsystemd/sd-journal/test-journal-stream.c @@ -73,9 +73,9 @@ static void run_test(void) { assert_se(chdir(t) >= 0); (void) chattr_path(t, FS_NOCOW_FL, FS_NOCOW_FL, NULL); - assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &one) == 0); - assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &two) == 0); - assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &three) == 0); + assert_se(journal_file_open(-1, "one.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &one) == 0); + assert_se(journal_file_open(-1, "two.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &two) == 0); + assert_se(journal_file_open(-1, "three.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &three) == 0); for (i = 0; i < N_ENTRIES; i++) { char *p, *q; diff --git a/src/journal/test-journal-verify.c b/src/libsystemd/sd-journal/test-journal-verify.c similarity index 92% rename from src/journal/test-journal-verify.c rename to src/libsystemd/sd-journal/test-journal-verify.c index d208e4650..e9abfef0f 100644 --- a/src/journal/test-journal-verify.c +++ b/src/libsystemd/sd-journal/test-journal-verify.c @@ -41,7 +41,7 @@ static int raw_verify(const char *fn, const char *verification_key) { JournalFile *f; int r; - r = journal_file_open(-1, fn, O_RDONLY, 0666, true, (uint64_t) -1, !!verification_key, NULL, NULL, NULL, NULL, &f); + r = journal_file_open(-1, fn, O_RDONLY, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &f); if (r < 0) return r; @@ -75,7 +75,7 @@ int main(int argc, char *argv[]) { log_info("Generating..."); - assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); for (n = 0; n < N_ENTRIES; n++) { struct iovec iovec; @@ -97,7 +97,7 @@ int main(int argc, char *argv[]) { log_info("Verifying..."); - assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, (uint64_t) -1, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDONLY, 0666, true, UINT64_MAX, !!verification_key, NULL, NULL, NULL, NULL, &f) == 0); /* journal_file_print_header(f); */ journal_file_dump(f); diff --git a/src/journal/test-journal.c b/src/libsystemd/sd-journal/test-journal.c similarity index 92% rename from src/journal/test-journal.c rename to src/libsystemd/sd-journal/test-journal.c index f8f08b5af..fd3c4d995 100644 --- a/src/journal/test-journal.c +++ b/src/libsystemd/sd-journal/test-journal.c @@ -37,7 +37,7 @@ static void test_non_empty(void) { mkdtemp_chdir_chattr(t); - assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, true, NULL, NULL, NULL, NULL, &f) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f) == 0); assert_se(dual_timestamp_get(&ts)); assert_se(sd_id128_randomize(&fake_boot_id) == 0); @@ -98,8 +98,8 @@ static void test_non_empty(void) { assert_se(journal_file_move_to_entry_by_seqnum(f, 10, DIRECTION_DOWN, &o, NULL) == 0); - journal_file_rotate(&f, true, (uint64_t) -1, true, NULL); - journal_file_rotate(&f, true, (uint64_t) -1, true, NULL); + journal_file_rotate(&f, true, UINT64_MAX, true, NULL); + journal_file_rotate(&f, true, UINT64_MAX, true, NULL); (void) journal_file_close(f); @@ -124,13 +124,13 @@ static void test_empty(void) { mkdtemp_chdir_chattr(t); - assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &f1) == 0); + assert_se(journal_file_open(-1, "test.journal", O_RDWR|O_CREAT, 0666, false, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f1) == 0); - assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, false, NULL, NULL, NULL, NULL, &f2) == 0); + assert_se(journal_file_open(-1, "test-compress.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, false, NULL, NULL, NULL, NULL, &f2) == 0); - assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, (uint64_t) -1, true, NULL, NULL, NULL, NULL, &f3) == 0); + assert_se(journal_file_open(-1, "test-seal.journal", O_RDWR|O_CREAT, 0666, false, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f3) == 0); - assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, (uint64_t) -1, true, NULL, NULL, NULL, NULL, &f4) == 0); + assert_se(journal_file_open(-1, "test-seal-compress.journal", O_RDWR|O_CREAT, 0666, true, UINT64_MAX, true, NULL, NULL, NULL, NULL, &f4) == 0); journal_file_print_header(f1); puts(""); @@ -224,8 +224,8 @@ static void test_min_compress_size(void) { * carefully */ /* DEFAULT_MIN_COMPRESS_SIZE is 512 */ - assert_se(!check_compressed((uint64_t) -1, 255)); - assert_se(check_compressed((uint64_t) -1, 513)); + assert_se(!check_compressed(UINT64_MAX, 255)); + assert_se(check_compressed(UINT64_MAX, 513)); /* compress everything */ assert_se(check_compressed(0, 96)); diff --git a/src/journal/test-mmap-cache.c b/src/libsystemd/sd-journal/test-mmap-cache.c similarity index 71% rename from src/journal/test-mmap-cache.c rename to src/libsystemd/sd-journal/test-mmap-cache.c index d1d28768f..c3212fe17 100644 --- a/src/journal/test-mmap-cache.c +++ b/src/libsystemd/sd-journal/test-mmap-cache.c @@ -24,7 +24,7 @@ int main(int argc, char *argv[]) { assert_se(x >= 0); unlink(px); - assert_se(fx = mmap_cache_add_fd(m, x)); + assert_se(fx = mmap_cache_add_fd(m, x, PROT_READ)); y = mkostemp_safe(py); assert_se(y >= 0); @@ -34,23 +34,23 @@ int main(int argc, char *argv[]) { assert_se(z >= 0); unlink(pz); - r = mmap_cache_get(m, fx, PROT_READ, 0, false, 1, 2, NULL, &p, NULL); + r = mmap_cache_get(m, fx, 0, false, 1, 2, NULL, &p); assert_se(r >= 0); - r = mmap_cache_get(m, fx, PROT_READ, 0, false, 2, 2, NULL, &q, NULL); + r = mmap_cache_get(m, fx, 0, false, 2, 2, NULL, &q); assert_se(r >= 0); assert_se((uint8_t*) p + 1 == (uint8_t*) q); - r = mmap_cache_get(m, fx, PROT_READ, 1, false, 3, 2, NULL, &q, NULL); + r = mmap_cache_get(m, fx, 1, false, 3, 2, NULL, &q); assert_se(r >= 0); assert_se((uint8_t*) p + 2 == (uint8_t*) q); - r = mmap_cache_get(m, fx, PROT_READ, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p, NULL); + r = mmap_cache_get(m, fx, 0, false, 16ULL*1024ULL*1024ULL, 2, NULL, &p); assert_se(r >= 0); - r = mmap_cache_get(m, fx, PROT_READ, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q, NULL); + r = mmap_cache_get(m, fx, 1, false, 16ULL*1024ULL*1024ULL+1, 2, NULL, &q); assert_se(r >= 0); assert_se((uint8_t*) p + 1 == (uint8_t*) q); diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index 1fc379512..a3da2e3f2 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -847,7 +847,7 @@ _public_ int sd_get_machine_names(char ***machines) { /* Filter out the unit: symlinks */ for (a = b = l; *a; a++) { - if (startswith(*a, "unit:") || !machine_name_is_valid(*a)) + if (startswith(*a, "unit:") || !hostname_is_valid(*a, 0)) free(*a); else { *b = *a; @@ -877,7 +877,7 @@ _public_ int sd_machine_get_class(const char *machine, char **class) { if (!c) return -ENOMEM; } else { - if (!machine_name_is_valid(machine)) + if (!hostname_is_valid(machine, 0)) return -EINVAL; p = strjoina("/run/systemd/machines/", machine); @@ -899,7 +899,7 @@ _public_ int sd_machine_get_ifindices(const char *machine, int **ret_ifindices) const char *p; int r; - assert_return(machine_name_is_valid(machine), -EINVAL); + assert_return(hostname_is_valid(machine, 0), -EINVAL); p = strjoina("/run/systemd/machines/", machine); r = parse_env_file(NULL, p, "NETIF", &netif_line); @@ -1043,9 +1043,9 @@ _public_ int sd_login_monitor_get_timeout(sd_login_monitor *m, uint64_t *timeout assert_return(m, -EINVAL); assert_return(timeout_usec, -EINVAL); - /* For now we will only return (uint64_t) -1, since we don't + /* For now we will only return UINT64_MAX, since we don't * need any timeout. However, let's have this API to keep our * options open should we later on need it. */ - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; } diff --git a/src/libsystemd/sd-login/test-login.c b/src/libsystemd/sd-login/test-login.c index d850323ba..3fc394d5e 100644 --- a/src/libsystemd/sd-login/test-login.c +++ b/src/libsystemd/sd-login/test-login.c @@ -277,7 +277,7 @@ static void test_monitor(void) { nw = now(CLOCK_MONOTONIC); r = poll(&pollfd, 1, - timeout == (uint64_t) -1 ? -1 : + timeout == UINT64_MAX ? -1 : timeout > nw ? (int) ((timeout - nw) / 1000) : 0); diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c index f295fa9e8..cd5a0104a 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.c +++ b/src/libsystemd/sd-netlink/generic-netlink.c @@ -20,18 +20,18 @@ static const genl_family genl_families[] = { [SD_GENL_L2TP] = { .name = "l2tp", .version = 1 }, [SD_GENL_MACSEC] = { .name = "macsec", .version = 1 }, [SD_GENL_NL80211] = { .name = "nl80211", .version = 1 }, + [SD_GENL_BATADV] = { .name = "batadv", .version = 1 }, }; int sd_genl_socket_open(sd_netlink **ret) { return netlink_open_family(ret, NETLINK_GENERIC); } -static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id); +static int lookup_id(sd_netlink *nl, sd_genl_family_t family, uint16_t *id); -static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) { +static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nlmsg_type, uint8_t cmd, sd_netlink_message **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; const NLType *genl_cmd_type, *nl_type; const NLTypeSystem *type_system; - struct genlmsghdr *genl; size_t size; int r; @@ -62,16 +62,18 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family family, uint16_t nlms m->hdr->nlmsg_type = nlmsg_type; type_get_type_system(nl_type, &m->containers[0].type_system); - genl = NLMSG_DATA(m->hdr); - genl->cmd = cmd; - genl->version = genl_families[family].version; + + *(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) { + .cmd = cmd, + .version = genl_families[family].version, + }; *ret = TAKE_PTR(m); return 0; } -int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **ret) { +int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **ret) { uint16_t id; int r; @@ -82,7 +84,7 @@ int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_n return genl_message_new(nl, family, id, cmd, ret); } -static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { +static int lookup_id(sd_netlink *nl, sd_genl_family_t family, uint16_t *id) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; uint16_t u; void *v; @@ -115,19 +117,11 @@ static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { if (r < 0) return r; - r = hashmap_ensure_allocated(&nl->genl_family_to_nlmsg_type, NULL); + r = hashmap_ensure_put(&nl->genl_family_to_nlmsg_type, NULL, INT_TO_PTR(family), UINT_TO_PTR(u)); if (r < 0) return r; - r = hashmap_ensure_allocated(&nl->nlmsg_type_to_genl_family, NULL); - if (r < 0) - return r; - - r = hashmap_put(nl->genl_family_to_nlmsg_type, INT_TO_PTR(family), UINT_TO_PTR(u)); - if (r < 0) - return r; - - r = hashmap_put(nl->nlmsg_type_to_genl_family, UINT_TO_PTR(u), INT_TO_PTR(family)); + r = hashmap_ensure_put(&nl->nlmsg_type_to_genl_family, NULL, UINT_TO_PTR(u), INT_TO_PTR(family)); if (r < 0) return r; @@ -135,7 +129,7 @@ static int lookup_id(sd_netlink *nl, sd_genl_family family, uint16_t *id) { return 0; } -int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family *ret) { +int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret) { void *p; assert_return(nl, -EINVAL); @@ -159,7 +153,7 @@ int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_famil return 0; } -int sd_genl_message_get_family(const sd_netlink *nl, const sd_netlink_message *m, sd_genl_family *family) { +int sd_genl_message_get_family(const sd_netlink *nl, const sd_netlink_message *m, sd_genl_family_t *family) { uint16_t type; int r; diff --git a/src/libsystemd/sd-netlink/generic-netlink.h b/src/libsystemd/sd-netlink/generic-netlink.h index 72001e88d..fd0461426 100644 --- a/src/libsystemd/sd-netlink/generic-netlink.h +++ b/src/libsystemd/sd-netlink/generic-netlink.h @@ -3,4 +3,4 @@ #include "sd-netlink.h" -int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family *ret); +int nlmsg_type_to_genl_family(const sd_netlink *nl, uint16_t type, sd_genl_family_t *ret); diff --git a/src/libsystemd/sd-netlink/netlink-internal.h b/src/libsystemd/sd-netlink/netlink-internal.h index 1240f0d66..fd7f07a6c 100644 --- a/src/libsystemd/sd-netlink/netlink-internal.h +++ b/src/libsystemd/sd-netlink/netlink-internal.h @@ -19,7 +19,7 @@ struct reply_callback { sd_netlink_message_handler_t callback; usec_t timeout; - uint64_t serial; + uint32_t serial; unsigned prioq_idx; }; @@ -33,17 +33,17 @@ struct match_callback { typedef enum NetlinkSlotType { NETLINK_REPLY_CALLBACK, NETLINK_MATCH_CALLBACK, - _NETLINK_SLOT_INVALID = -1, + _NETLINK_SLOT_INVALID = -EINVAL, } NetlinkSlotType; struct sd_netlink_slot { unsigned n_ref; + NetlinkSlotType type:8; + bool floating; sd_netlink *netlink; void *userdata; sd_netlink_destroy_t destroy_callback; - NetlinkSlotType type:2; - bool floating:1; char *description; LIST_FIELDS(sd_netlink_slot, slots); @@ -139,6 +139,7 @@ int socket_bind(sd_netlink *nl); int socket_broadcast_group_ref(sd_netlink *nl, unsigned group); int socket_broadcast_group_unref(sd_netlink *nl, unsigned group); int socket_write_message(sd_netlink *nl, sd_netlink_message *m); +int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount); int socket_read_message(sd_netlink *nl); int rtnl_rqueue_make_room(sd_netlink *rtnl); diff --git a/src/libsystemd/sd-netlink/netlink-message.c b/src/libsystemd/sd-netlink/netlink-message.c index bd5653606..90915fd15 100644 --- a/src/libsystemd/sd-netlink/netlink-message.c +++ b/src/libsystemd/sd-netlink/netlink-message.c @@ -144,7 +144,6 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da size_t message_length; struct nlmsghdr *new_hdr; struct rtattr *rta; - unsigned i; int offset; assert(m); @@ -172,7 +171,7 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da rtattr_append_attribute_internal(rta, type, data, data_length); /* if we are inside containers, extend them */ - for (i = 0; i < m->n_containers; i++) + for (unsigned i = 0; i < m->n_containers; i++) GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length); /* update message size */ @@ -643,7 +642,6 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) { } int sd_netlink_message_cancel_array(sd_netlink_message *m) { - unsigned i; uint32_t rta_len; assert_return(m, -EINVAL); @@ -652,7 +650,7 @@ int sd_netlink_message_cancel_array(sd_netlink_message *m) { rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len; - for (i = 0; i < m->n_containers; i++) + for (unsigned i = 0; i < m->n_containers; i++) GET_CONTAINER(m, i)->rta_len -= rta_len; m->hdr->nlmsg_len -= rta_len; @@ -663,13 +661,17 @@ int sd_netlink_message_cancel_array(sd_netlink_message *m) { return 0; } -static int netlink_message_read_internal(sd_netlink_message *m, unsigned short type, void **data, bool *net_byteorder) { +static int netlink_message_read_internal( + sd_netlink_message *m, + unsigned short type, + void **ret_data, + bool *ret_net_byteorder) { + struct netlink_attribute *attribute; struct rtattr *rta; assert_return(m, -EINVAL); assert_return(m->sealed, -EPERM); - assert_return(data, -EINVAL); assert(m->n_containers < RTNL_CONTAINER_DEPTH); @@ -686,10 +688,11 @@ static int netlink_message_read_internal(sd_netlink_message *m, unsigned short t rta = (struct rtattr*)((uint8_t *) m->hdr + attribute->offset); - *data = RTA_DATA(rta); + if (ret_data) + *ret_data = RTA_DATA(rta); - if (net_byteorder) - *net_byteorder = attribute->net_byteorder; + if (ret_net_byteorder) + *ret_net_byteorder = attribute->net_byteorder; return RTA_PAYLOAD(rta); } @@ -974,6 +977,27 @@ int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, return r; } +int sd_netlink_message_has_flag(sd_netlink_message *m, unsigned short type) { + void *attr_data; + int r; + + assert_return(m, -EINVAL); + + /* This returns 1 when the flag is set, 0 when not set, negative errno on error. */ + + r = message_attribute_has_type(m, NULL, type, NETLINK_TYPE_FLAG); + if (r < 0) + return r; + + r = netlink_message_read_internal(m, type, &attr_data, NULL); + if (r == -ENODATA) + return 0; + if (r < 0) + return r; + + return 1; +} + int sd_netlink_message_read_strv(sd_netlink_message *m, unsigned short container_type, unsigned short type_id, char ***ret) { _cleanup_strv_free_ char **s = NULL; const NLTypeSystem *type_system; @@ -1257,7 +1281,6 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) { const NLType *nl_type; uint16_t type; size_t size; - unsigned i; int r; assert_return(m, -EINVAL); @@ -1267,7 +1290,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) { if (!m->sealed) rtnl_message_seal(m); - for (i = 1; i <= m->n_containers; i++) + for (unsigned i = 1; i <= m->n_containers; i++) m->containers[i].attributes = mfree(m->containers[i].attributes); m->n_containers = 0; diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 228e38df9..7af9a94e3 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -29,7 +29,6 @@ int socket_open(int family) { static int broadcast_groups_get(sd_netlink *nl) { _cleanup_free_ uint32_t *groups = NULL; socklen_t len = 0, old_len; - unsigned i, j; int r; assert(nl); @@ -37,11 +36,11 @@ static int broadcast_groups_get(sd_netlink *nl) { r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len); if (r < 0) { - if (errno == ENOPROTOOPT) { - nl->broadcast_group_dont_leave = true; - return 0; - } else + if (errno != ENOPROTOOPT) return -errno; + + nl->broadcast_group_dont_leave = true; + return 0; } if (len == 0) @@ -64,23 +63,15 @@ static int broadcast_groups_get(sd_netlink *nl) { if (r < 0) return r; - for (i = 0; i < len; i++) { - for (j = 0; j < sizeof(uint32_t) * 8; j++) { - uint32_t offset; - unsigned group; + for (unsigned i = 0; i < len; i++) + for (unsigned j = 0; j < sizeof(uint32_t) * 8; j++) + if (groups[i] & (1U << j)) { + unsigned group = i * sizeof(uint32_t) * 8 + j + 1; - offset = 1U << j; - - if (!(groups[i] & offset)) - continue; - - group = i * sizeof(uint32_t) * 8 + j + 1; - - r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1)); - if (r < 0) - return r; - } - } + r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1)); + if (r < 0) + return r; + } return 0; } @@ -104,11 +95,7 @@ int socket_bind(sd_netlink *nl) { if (r < 0) return -errno; - r = broadcast_groups_get(nl); - if (r < 0) - return r; - - return 0; + return broadcast_groups_get(nl); } static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) { @@ -130,17 +117,12 @@ static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_re } static int broadcast_group_join(sd_netlink *nl, unsigned group) { - int r; - assert(nl); assert(nl->fd >= 0); assert(group > 0); - r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group)); - if (r < 0) - return -errno; - - return 0; + /* group is "unsigned", but netlink(7) says the argument for NETLINK_ADD_MEMBERSHIP is "int" */ + return setsockopt_int(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, group); } int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { @@ -173,8 +155,6 @@ int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { } static int broadcast_group_leave(sd_netlink *nl, unsigned group) { - int r; - assert(nl); assert(nl->fd >= 0); assert(group > 0); @@ -182,11 +162,8 @@ static int broadcast_group_leave(sd_netlink *nl, unsigned group) { if (nl->broadcast_group_dont_leave) return 0; - r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group)); - if (r < 0) - return -errno; - - return 0; + /* group is "unsigned", but netlink(7) says the argument for NETLINK_DROP_MEMBERSHIP is "int" */ + return setsockopt_int(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, group); } int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) { @@ -238,6 +215,30 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) { return k; } +int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount) { + _cleanup_free_ struct iovec *iovs = NULL; + + assert(nl); + assert(m); + assert(msgcount > 0); + + iovs = new0(struct iovec, msgcount); + if (!iovs) + return -ENOMEM; + + for (size_t i = 0; i < msgcount; i++) { + assert(m[i]->hdr != NULL); + assert(m[i]->hdr->nlmsg_len > 0); + iovs[i] = IOVEC_MAKE(m[i]->hdr, m[i]->hdr->nlmsg_len); + } + + ssize_t k = writev(nl->fd, iovs, msgcount); + if (k < 0) + return -errno; + + return k; +} + static int socket_recv_message(int fd, struct iovec *iov, uint32_t *ret_mcast_group, bool peek) { union sockaddr_union sender; CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct nl_pktinfo))) control; @@ -299,7 +300,6 @@ int socket_read_message(sd_netlink *rtnl) { struct iovec iov = {}; uint32_t group = 0; bool multi_part = false, done = false; - struct nlmsghdr *new_msg; size_t len; int r; unsigned i = 0; @@ -346,7 +346,7 @@ int socket_read_message(sd_netlink *rtnl) { } } - for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { + for (struct nlmsghdr *new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; const NLType *nl_type; diff --git a/src/libsystemd/sd-netlink/netlink-types.c b/src/libsystemd/sd-netlink/netlink-types.c index 6fb6c147d..ed7b9a8cd 100644 --- a/src/libsystemd/sd-netlink/netlink-types.c +++ b/src/libsystemd/sd-netlink/netlink-types.c @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,8 @@ #include #include #include +#include +#include #include #include #include @@ -80,6 +83,10 @@ static const NLTypeSystem empty_type_system = { .types = empty_types, }; +static const NLType rtnl_link_info_data_batadv_types[] = { + [IFLA_BATADV_ALGO_NAME] = { .type = NETLINK_TYPE_STRING, .size = 20 }, +}; + static const NLType rtnl_link_info_data_veth_types[] = { [VETH_INFO_PEER] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_link_type_system, .size = sizeof(struct ifinfomsg) }, }; @@ -103,10 +110,13 @@ static const NLTypeSystem rtnl_macvlan_macaddr_type_system = { }; static const NLType rtnl_link_info_data_macvlan_types[] = { - [IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, - [IFLA_MACVLAN_MACADDR_MODE] = { .type = NETLINK_TYPE_U32 }, - [IFLA_MACVLAN_MACADDR_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_macvlan_macaddr_type_system }, + [IFLA_MACVLAN_MODE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_FLAGS] = { .type = NETLINK_TYPE_U16 }, + [IFLA_MACVLAN_MACADDR_MODE] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_MACADDR_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_macvlan_macaddr_type_system }, + [IFLA_MACVLAN_MACADDR_COUNT] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_BC_QUEUE_LEN] = { .type = NETLINK_TYPE_U32 }, + [IFLA_MACVLAN_BC_QUEUE_LEN_USED] = { .type = NETLINK_TYPE_REJECT }, }; static const NLType rtnl_link_info_data_bridge_types[] = { @@ -150,13 +160,20 @@ static const NLType rtnl_link_info_data_bridge_types[] = { [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NETLINK_TYPE_U8 }, }; +static const NLType rtnl_vlan_qos_map_types[] = { + [IFLA_VLAN_QOS_MAPPING] = { .size = sizeof(struct ifla_vlan_qos_mapping) }, +}; + +static const NLTypeSystem rtnl_vlan_qos_map_type_system = { + .count = ELEMENTSOF(rtnl_vlan_qos_map_types), + .types = rtnl_vlan_qos_map_types, +}; + static const NLType rtnl_link_info_data_vlan_types[] = { [IFLA_VLAN_ID] = { .type = NETLINK_TYPE_U16 }, -/* - [IFLA_VLAN_FLAGS] = { .len = sizeof(struct ifla_vlan_flags) }, - [IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED }, - [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED }, -*/ + [IFLA_VLAN_FLAGS] = { .size = sizeof(struct ifla_vlan_flags) }, + [IFLA_VLAN_EGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system }, + [IFLA_VLAN_INGRESS_QOS] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_vlan_qos_map_type_system }, [IFLA_VLAN_PROTOCOL] = { .type = NETLINK_TYPE_U16 }, }; @@ -391,6 +408,7 @@ static const char* const nl_union_link_info_data_table[] = { [NL_UNION_LINK_INFO_DATA_XFRM] = "xfrm", [NL_UNION_LINK_INFO_DATA_IFB] = "ifb", [NL_UNION_LINK_INFO_DATA_BAREUDP] = "bareudp", + [NL_UNION_LINK_INFO_DATA_BATADV] = "batadv", }; DEFINE_STRING_TABLE_LOOKUP(nl_union_link_info_data, NLUnionLinkInfoData); @@ -448,6 +466,8 @@ static const NLTypeSystem rtnl_link_info_data_type_systems[] = { .types = rtnl_link_info_data_xfrm_types }, [NL_UNION_LINK_INFO_DATA_BAREUDP] = { .count = ELEMENTSOF(rtnl_link_info_data_bareudp_types), .types = rtnl_link_info_data_bareudp_types }, + [NL_UNION_LINK_INFO_DATA_BATADV] = { .count = ELEMENTSOF(rtnl_link_info_data_batadv_types), + .types = rtnl_link_info_data_batadv_types }, }; static const NLTypeSystemUnion rtnl_link_info_data_type_system_union = { @@ -640,6 +660,8 @@ static const NLType rtnl_link_types[] = { [IFLA_PROMISCUITY] = { .type = NETLINK_TYPE_U32 }, [IFLA_NUM_TX_QUEUES] = { .type = NETLINK_TYPE_U32 }, [IFLA_NUM_RX_QUEUES] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GSO_MAX_SEGS] = { .type = NETLINK_TYPE_U32 }, + [IFLA_GSO_MAX_SIZE] = { .type = NETLINK_TYPE_U32 }, [IFLA_CARRIER] = { .type = NETLINK_TYPE_U8 }, /* [IFLA_PHYS_PORT_ID] = { .type = NETLINK_TYPE_BINARY, .len = MAX_PHYS_PORT_ID_LEN }, @@ -719,14 +741,15 @@ static const NLType rtnl_route_types[] = { [RTA_VIA] = { /* See struct rtvia */ }, [RTA_NEWDST] = { .type = NETLINK_TYPE_U32 }, [RTA_PREF] = { .type = NETLINK_TYPE_U8 }, - [RTA_EXPIRES] = { .type = NETLINK_TYPE_U32 }, [RTA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, [RTA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, /* Multiple type systems i.e. LWTUNNEL_ENCAP_MPLS/LWTUNNEL_ENCAP_IP/LWTUNNEL_ENCAP_ILA etc... */ + [RTA_EXPIRES] = { .type = NETLINK_TYPE_U32 }, [RTA_UID] = { .type = NETLINK_TYPE_U32 }, [RTA_TTL_PROPAGATE] = { .type = NETLINK_TYPE_U8 }, [RTA_IP_PROTO] = { .type = NETLINK_TYPE_U8 }, [RTA_SPORT] = { .type = NETLINK_TYPE_U16 }, [RTA_DPORT] = { .type = NETLINK_TYPE_U16 }, + [RTA_NH_ID] = { .type = NETLINK_TYPE_U32 }, }; static const NLTypeSystem rtnl_route_type_system = { @@ -790,8 +813,16 @@ static const NLTypeSystem rtnl_routing_policy_rule_type_system = { static const NLType rtnl_nexthop_types[] = { [NHA_ID] = { .type = NETLINK_TYPE_U32 }, + [NHA_GROUP] = { /* array of struct nexthop_grp */ }, + [NHA_GROUP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [NHA_BLACKHOLE] = { .type = NETLINK_TYPE_FLAG }, [NHA_OIF] = { .type = NETLINK_TYPE_U32 }, [NHA_GATEWAY] = { .type = NETLINK_TYPE_IN_ADDR }, + [NHA_ENCAP_TYPE] = { .type = NETLINK_TYPE_U16 }, + [NHA_ENCAP] = { .type = NETLINK_TYPE_NESTED }, + [NHA_GROUPS] = { .type = NETLINK_TYPE_FLAG }, + [NHA_MASTER] = { .type = NETLINK_TYPE_U32 }, + [NHA_FDB] = { .type = NETLINK_TYPE_FLAG }, }; static const NLTypeSystem rtnl_nexthop_type_system = { @@ -1025,9 +1056,9 @@ static const NLType rtnl_types[] = { [RTM_NEWADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, [RTM_DELADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, [RTM_GETADDRLABEL] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_addrlabel_type_system, .size = sizeof(struct ifaddrlblmsg) }, - [RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) }, - [RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) }, - [RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct rtmsg) }, + [RTM_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, + [RTM_DELRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, + [RTM_GETRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_routing_policy_rule_type_system, .size = sizeof(struct fib_rule_hdr) }, [RTM_NEWNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, [RTM_DELNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, [RTM_GETNEXTHOP] = { .type = NETLINK_TYPE_NESTED, .type_system = &rtnl_nexthop_type_system, .size = sizeof(struct nhmsg) }, @@ -1303,6 +1334,83 @@ static const NLTypeSystem genl_nl80211_cmds_type_system = { .types = genl_nl80211_cmds, }; +static const NLType genl_batadv_types[] = { + [BATADV_ATTR_VERSION] = { .type = NETLINK_TYPE_STRING }, + [BATADV_ATTR_ALGO_NAME] = { .type = NETLINK_TYPE_STRING }, + [BATADV_ATTR_MESH_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_MESH_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ }, + [BATADV_ATTR_MESH_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_HARD_IFINDEX] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_HARD_IFNAME] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ }, + [BATADV_ATTR_HARD_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_ORIG_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_TPMETER_RESULT] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_TPMETER_TEST_TIME] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_TPMETER_BYTES] = { .type = NETLINK_TYPE_U64 }, + [BATADV_ATTR_TPMETER_COOKIE] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_PAD] = { .type = NETLINK_TYPE_UNSPEC }, + [BATADV_ATTR_ACTIVE] = { .type = NETLINK_TYPE_FLAG }, + [BATADV_ATTR_TT_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_TT_TTVN] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_TT_LAST_TTVN] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_TT_CRC32] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_TT_VID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_TT_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_FLAG_BEST] = { .type = NETLINK_TYPE_FLAG }, + [BATADV_ATTR_LAST_SEEN_MSECS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_NEIGH_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_TQ] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_THROUGHPUT] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_ROUTER] = { .size = ETH_ALEN }, + [BATADV_ATTR_BLA_OWN] = { .type = NETLINK_TYPE_FLAG }, + [BATADV_ATTR_BLA_ADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_BLA_VID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_BLA_BACKBONE] = { .size = ETH_ALEN }, + [BATADV_ATTR_BLA_CRC] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_DAT_CACHE_IP4ADDRESS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_DAT_CACHE_HWADDRESS] = { .size = ETH_ALEN }, + [BATADV_ATTR_DAT_CACHE_VID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_MCAST_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_MCAST_FLAGS_PRIV] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_VLANID] = { .type = NETLINK_TYPE_U16 }, + [BATADV_ATTR_AGGREGATED_OGMS_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_AP_ISOLATION_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_ISOLATION_MARK] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_ISOLATION_MASK] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_BONDING_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_FRAGMENTATION_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_GW_BANDWIDTH_DOWN] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_GW_BANDWIDTH_UP] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_GW_MODE] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_GW_SEL_CLASS] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_HOP_PENALTY] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_LOG_LEVEL] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_MULTICAST_FORCEFLOOD_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_MULTICAST_FANOUT] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_NETWORK_CODING_ENABLED] = { .type = NETLINK_TYPE_U8 }, + [BATADV_ATTR_ORIG_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_ELP_INTERVAL] = { .type = NETLINK_TYPE_U32 }, + [BATADV_ATTR_THROUGHPUT_OVERRIDE] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystem genl_batadv_type_system = { + .count = ELEMENTSOF(genl_batadv_types), + .types = genl_batadv_types, +}; + +static const NLType genl_batadv_cmds[] = { + [BATADV_CMD_SET_MESH] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_batadv_type_system }, +}; + +static const NLTypeSystem genl_batadv_cmds_type_system = { + .count = ELEMENTSOF(genl_batadv_cmds), + .types = genl_batadv_cmds, +}; + static const NLType genl_families[] = { [SD_GENL_ID_CTRL] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_ctrl_id_ctrl_type_system }, [SD_GENL_WIREGUARD] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_wireguard_type_system }, @@ -1310,6 +1418,244 @@ static const NLType genl_families[] = { [SD_GENL_L2TP] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_l2tp_tunnel_session_type_system }, [SD_GENL_MACSEC] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_macsec_device_type_system }, [SD_GENL_NL80211] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_nl80211_cmds_type_system }, + [SD_GENL_BATADV] = { .type = NETLINK_TYPE_NESTED, .type_system = &genl_batadv_cmds_type_system }, +}; + +static const NLType nfnl_nft_table_types[] = { + [NFTA_TABLE_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_TABLE_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystem nfnl_nft_table_type_system = { + .count = ELEMENTSOF(nfnl_nft_table_types), + .types = nfnl_nft_table_types, +}; + +static const NLType nfnl_nft_chain_hook_types[] = { + [NFTA_HOOK_HOOKNUM] = { .type = NETLINK_TYPE_U32 }, + [NFTA_HOOK_PRIORITY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_HOOK_DEV] = { .type = NETLINK_TYPE_STRING, .size = IFNAMSIZ - 1 }, +}; + +static const NLTypeSystem nfnl_nft_chain_hook_type_system = { + .count = ELEMENTSOF(nfnl_nft_chain_hook_types), + .types = nfnl_nft_chain_hook_types, +}; + +static const NLType nfnl_nft_chain_types[] = { + [NFTA_CHAIN_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_CHAIN_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_CHAIN_HOOK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_hook_type_system }, + [NFTA_CHAIN_TYPE] = { .type = NETLINK_TYPE_STRING, .size = 16 }, + [NFTA_CHAIN_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystem nfnl_nft_chain_type_system = { + .count = ELEMENTSOF(nfnl_nft_chain_types), + .types = nfnl_nft_chain_types, +}; + +static const NLType nfnl_nft_expr_meta_types[] = { + [NFTA_META_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_META_KEY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_META_SREG] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_payload_types[] = { + [NFTA_PAYLOAD_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_PAYLOAD_BASE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_PAYLOAD_OFFSET] = { .type = NETLINK_TYPE_U32 }, + [NFTA_PAYLOAD_LEN] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_nat_types[] = { + [NFTA_NAT_TYPE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_FAMILY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_ADDR_MIN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_ADDR_MAX] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 }, + [NFTA_NAT_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_data_types[] = { + [NFTA_DATA_VALUE] = { .type = NETLINK_TYPE_BINARY }, +}; + +static const NLTypeSystem nfnl_nft_data_type_system = { + .count = ELEMENTSOF(nfnl_nft_data_types), + .types = nfnl_nft_data_types, +}; + +static const NLType nfnl_nft_expr_bitwise_types[] = { + [NFTA_BITWISE_SREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_BITWISE_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_BITWISE_LEN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_BITWISE_MASK] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, + [NFTA_BITWISE_XOR] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, +}; + +static const NLType nfnl_nft_expr_cmp_types[] = { + [NFTA_CMP_SREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_CMP_OP] = { .type = NETLINK_TYPE_U32 }, + [NFTA_CMP_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, +}; + +static const NLType nfnl_nft_expr_fib_types[] = { + [NFTA_FIB_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_FIB_RESULT] = { .type = NETLINK_TYPE_U32 }, + [NFTA_FIB_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_lookup_types[] = { + [NFTA_LOOKUP_SET] = { .type = NETLINK_TYPE_STRING }, + [NFTA_LOOKUP_SREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_LOOKUP_DREG] = { .type = NETLINK_TYPE_U32 }, + [NFTA_LOOKUP_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLType nfnl_nft_expr_masq_types[] = { + [NFTA_MASQ_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [NFTA_MASQ_REG_PROTO_MIN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_MASQ_REG_PROTO_MAX] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystem nfnl_expr_data_type_systems[] = { + [NL_UNION_NFT_EXPR_DATA_BITWISE] = { .count = ELEMENTSOF(nfnl_nft_expr_bitwise_types), + .types = nfnl_nft_expr_bitwise_types }, + [NL_UNION_NFT_EXPR_DATA_CMP] = { .count = ELEMENTSOF(nfnl_nft_expr_cmp_types), + .types = nfnl_nft_expr_cmp_types }, + [NL_UNION_NFT_EXPR_DATA_FIB] = { .count = ELEMENTSOF(nfnl_nft_expr_fib_types), + .types = nfnl_nft_expr_fib_types }, + [NL_UNION_NFT_EXPR_DATA_LOOKUP] = { .count = ELEMENTSOF(nfnl_nft_expr_lookup_types), + .types = nfnl_nft_expr_lookup_types }, + [NL_UNION_NFT_EXPR_DATA_MASQ] = { .count = ELEMENTSOF(nfnl_nft_expr_masq_types), + .types = nfnl_nft_expr_masq_types }, + [NL_UNION_NFT_EXPR_DATA_META] = { .count = ELEMENTSOF(nfnl_nft_expr_meta_types), + .types = nfnl_nft_expr_meta_types }, + [NL_UNION_NFT_EXPR_DATA_NAT] = { .count = ELEMENTSOF(nfnl_nft_expr_nat_types), + .types = nfnl_nft_expr_nat_types }, + [NL_UNION_NFT_EXPR_DATA_PAYLOAD] = { .count = ELEMENTSOF(nfnl_nft_expr_payload_types), + .types = nfnl_nft_expr_payload_types }, +}; + +static const char* const nl_union_nft_expr_data_table[] = { + [NL_UNION_NFT_EXPR_DATA_BITWISE] = "bitwise", + [NL_UNION_NFT_EXPR_DATA_CMP] = "cmp", + [NL_UNION_NFT_EXPR_DATA_LOOKUP] = "lookup", + [NL_UNION_NFT_EXPR_DATA_META] = "meta", + [NL_UNION_NFT_EXPR_DATA_FIB] = "fib", + [NL_UNION_NFT_EXPR_DATA_MASQ] = "masq", + [NL_UNION_NFT_EXPR_DATA_NAT] = "nat", + [NL_UNION_NFT_EXPR_DATA_PAYLOAD] = "payload", +}; + +DEFINE_STRING_TABLE_LOOKUP(nl_union_nft_expr_data, NLUnionNFTExprData); + +static const NLTypeSystemUnion nfnl_nft_data_expr_type_system_union = { + .num = _NL_UNION_NFT_EXPR_DATA_MAX, + .lookup = nl_union_nft_expr_data_from_string, + .type_systems = nfnl_expr_data_type_systems, + .match_type = NL_MATCH_SIBLING, + .match = NFTA_EXPR_NAME, +}; + +static const NLType nfnl_nft_rule_expr_types[] = { + [NFTA_EXPR_NAME] = { .type = NETLINK_TYPE_STRING, .size = 16 }, + [NFTA_EXPR_DATA] = { .type = NETLINK_TYPE_UNION, + .type_system_union = &nfnl_nft_data_expr_type_system_union }, +}; + +static const NLTypeSystem nfnl_nft_rule_expr_type_system = { + .count = ELEMENTSOF(nfnl_nft_rule_expr_types), + .types = nfnl_nft_rule_expr_types, +}; + +static const NLType nfnl_nft_rule_types[] = { + [NFTA_RULE_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_RULE_CHAIN] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_RULE_EXPRESSIONS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_expr_type_system } +}; + +static const NLTypeSystem nfnl_nft_rule_type_system = { + .count = ELEMENTSOF(nfnl_nft_rule_types), + .types = nfnl_nft_rule_types, +}; + +static const NLType nfnl_nft_set_types[] = { + [NFTA_SET_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_NAME] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_FLAGS] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_KEY_TYPE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_KEY_LEN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_DATA_TYPE] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_DATA_LEN] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_POLICY] = { .type = NETLINK_TYPE_U32 }, + [NFTA_SET_ID] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystem nfnl_nft_set_type_system = { + .count = ELEMENTSOF(nfnl_nft_set_types), + .types = nfnl_nft_set_types, +}; + +static const NLType nfnl_nft_setelem_types[] = { + [NFTA_SET_ELEM_KEY] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, + [NFTA_SET_ELEM_DATA] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_data_type_system }, + [NFTA_SET_ELEM_FLAGS] = { .type = NETLINK_TYPE_U32 }, +}; + +static const NLTypeSystem nfnl_nft_setelem_type_system = { + .count = ELEMENTSOF(nfnl_nft_setelem_types), + .types = nfnl_nft_setelem_types, +}; + +static const NLType nfnl_nft_setelem_list_types[] = { + [NFTA_SET_ELEM_LIST_TABLE] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_ELEM_LIST_SET] = { .type = NETLINK_TYPE_STRING, .size = NFT_TABLE_MAXNAMELEN - 1 }, + [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_type_system }, +}; + +static const NLTypeSystem nfnl_nft_setelem_list_type_system = { + .count = ELEMENTSOF(nfnl_nft_setelem_list_types), + .types = nfnl_nft_setelem_list_types, +}; + +static const NLType nfnl_nft_msg_types [] = { + [NFT_MSG_DELTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWTABLE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_table_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWCHAIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_chain_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWRULE] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_rule_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWSET] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_set_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_NEWSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) }, + [NFT_MSG_DELSETELEM] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_setelem_list_type_system, .size = sizeof(struct nfgenmsg) }, +}; + +static const NLTypeSystem nfnl_nft_msg_type_system = { + .count = ELEMENTSOF(nfnl_nft_msg_types), + .types = nfnl_nft_msg_types, +}; + +static const NLType nfnl_msg_batch_types [] = { + [NFNL_BATCH_GENID] = { .type = NETLINK_TYPE_U32 } +}; + +static const NLTypeSystem nfnl_msg_batch_type_system = { + .count = ELEMENTSOF(nfnl_msg_batch_types), + .types = nfnl_msg_batch_types, +}; + +static const NLType nfnl_types[] = { + [NLMSG_DONE] = { .type = NETLINK_TYPE_NESTED, .type_system = &empty_type_system, .size = 0 }, + [NLMSG_ERROR] = { .type = NETLINK_TYPE_NESTED, .type_system = &error_type_system, .size = sizeof(struct nlmsgerr) }, + [NFNL_MSG_BATCH_BEGIN] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) }, + [NFNL_MSG_BATCH_END] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_msg_batch_type_system, .size = sizeof(struct nfgenmsg) }, + [NFNL_SUBSYS_NFTABLES] = { .type = NETLINK_TYPE_NESTED, .type_system = &nfnl_nft_msg_type_system, .size = sizeof(struct nfgenmsg) }, +}; + +const NLTypeSystem nfnl_type_system_root = { + .count = ELEMENTSOF(nfnl_types), + .types = nfnl_types, }; /* Mainly used when sending message */ @@ -1368,19 +1714,24 @@ const NLTypeSystem *type_system_get_root(int protocol) { switch (protocol) { case NETLINK_GENERIC: return &genl_type_system_root; + case NETLINK_NETFILTER: + return &nfnl_type_system_root; default: /* NETLINK_ROUTE: */ return &rtnl_type_system_root; } } int type_system_root_get_type(sd_netlink *nl, const NLType **ret, uint16_t type) { - sd_genl_family family; + sd_genl_family_t family; const NLType *nl_type; int r; - if (!nl || nl->protocol != NETLINK_GENERIC) + if (!nl) return type_system_get_type(&rtnl_type_system_root, ret, type); + if (nl->protocol != NETLINK_GENERIC) + return type_system_get_type(type_system_get_root(nl->protocol), ret, type); + r = nlmsg_type_to_genl_family(nl, type, &family); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-types.h b/src/libsystemd/sd-netlink/netlink-types.h index b14e66fbb..316d7f1b8 100644 --- a/src/libsystemd/sd-netlink/netlink-types.h +++ b/src/libsystemd/sd-netlink/netlink-types.h @@ -21,6 +21,9 @@ enum { NETLINK_TYPE_NESTED, /* NLA_NESTED */ NETLINK_TYPE_UNION, NETLINK_TYPE_SOCKADDR, + NETLINK_TYPE_BINARY, + NETLINK_TYPE_BITFIELD32, /* NLA_BITFIELD32 */ + NETLINK_TYPE_REJECT, /* NLA_REJECT */ }; typedef enum NLMatchType { @@ -89,8 +92,9 @@ typedef enum NLUnionLinkInfoData { NL_UNION_LINK_INFO_DATA_XFRM, NL_UNION_LINK_INFO_DATA_IFB, NL_UNION_LINK_INFO_DATA_BAREUDP, + NL_UNION_LINK_INFO_DATA_BATADV, _NL_UNION_LINK_INFO_DATA_MAX, - _NL_UNION_LINK_INFO_DATA_INVALID = -1 + _NL_UNION_LINK_INFO_DATA_INVALID = -EINVAL, } NLUnionLinkInfoData; const char *nl_union_link_info_data_to_string(NLUnionLinkInfoData p) _const_; @@ -112,8 +116,24 @@ typedef enum NLUnionTCAOptionData { NL_UNION_TCA_OPTION_DATA_SFB, NL_UNION_TCA_OPTION_DATA_TBF, _NL_UNION_TCA_OPTION_DATA_MAX, - _NL_UNION_TCA_OPTION_DATA_INVALID = -1, + _NL_UNION_TCA_OPTION_DATA_INVALID = -EINVAL, } NLUnionTCAOptionData; const char *nl_union_tca_option_data_to_string(NLUnionTCAOptionData p) _const_; NLUnionTCAOptionData nl_union_tca_option_data_from_string(const char *p) _pure_; + +typedef enum NLUnionNFTExprData { + NL_UNION_NFT_EXPR_DATA_BITWISE, + NL_UNION_NFT_EXPR_DATA_CMP, + NL_UNION_NFT_EXPR_DATA_FIB, + NL_UNION_NFT_EXPR_DATA_LOOKUP, + NL_UNION_NFT_EXPR_DATA_PAYLOAD, + NL_UNION_NFT_EXPR_DATA_MASQ, + NL_UNION_NFT_EXPR_DATA_META, + NL_UNION_NFT_EXPR_DATA_NAT, + _NL_UNION_NFT_EXPR_DATA_MAX, + _NL_UNION_NFT_EXPR_DATA_INVALID = -EINVAL, +} NLUnionNFTExprData; + +const char *nl_union_nft_expr_data_to_string(NLUnionNFTExprData p) _const_; +NLUnionNFTExprData nl_union_nft_expr_data_from_string(const char *p) _pure_; diff --git a/src/libsystemd/sd-netlink/netlink-util.c b/src/libsystemd/sd-netlink/netlink-util.c index 09e2158c9..448c50d4a 100644 --- a/src/libsystemd/sd-netlink/netlink-util.c +++ b/src/libsystemd/sd-netlink/netlink-util.c @@ -57,15 +57,25 @@ int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name) { return 0; } -int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, - const struct ether_addr *mac, uint32_t mtu) { +int rtnl_set_link_properties( + sd_netlink **rtnl, + int ifindex, + const char *alias, + const struct ether_addr *mac, + uint32_t txqueues, + uint32_t rxqueues, + uint32_t txqueuelen, + uint32_t mtu, + uint32_t gso_max_size, + size_t gso_max_segments) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; int r; assert(rtnl); assert(ifindex > 0); - if (!alias && !mac && mtu == 0) + if (!alias && !mac && txqueues == 0 && rxqueues == 0 && txqueuelen == UINT32_MAX && mtu == 0 && + gso_max_size == 0 && gso_max_segments == 0) return 0; if (!*rtnl) { @@ -90,12 +100,42 @@ int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, return r; } + if (txqueues > 0) { + r = sd_netlink_message_append_u32(message, IFLA_NUM_TX_QUEUES, txqueues); + if (r < 0) + return r; + } + + if (rxqueues > 0) { + r = sd_netlink_message_append_u32(message, IFLA_NUM_RX_QUEUES, rxqueues); + if (r < 0) + return r; + } + + if (txqueuelen < UINT32_MAX) { + r = sd_netlink_message_append_u32(message, IFLA_TXQLEN, txqueuelen); + if (r < 0) + return r; + } + if (mtu != 0) { r = sd_netlink_message_append_u32(message, IFLA_MTU, mtu); if (r < 0) return r; } + if (gso_max_size > 0) { + r = sd_netlink_message_append_u32(message, IFLA_GSO_MAX_SIZE, gso_max_size); + if (r < 0) + return r; + } + + if (gso_max_segments > 0) { + r = sd_netlink_message_append_u32(message, IFLA_GSO_MAX_SEGS, gso_max_segments); + if (r < 0) + return r; + } + r = sd_netlink_call(*rtnl, message, 0, NULL); if (r < 0) return r; diff --git a/src/libsystemd/sd-netlink/netlink-util.h b/src/libsystemd/sd-netlink/netlink-util.h index d28d07a9f..a3a3951ff 100644 --- a/src/libsystemd/sd-netlink/netlink-util.h +++ b/src/libsystemd/sd-netlink/netlink-util.h @@ -70,7 +70,17 @@ static inline bool rtnl_message_type_is_mdb(uint16_t type) { } int rtnl_set_link_name(sd_netlink **rtnl, int ifindex, const char *name); -int rtnl_set_link_properties(sd_netlink **rtnl, int ifindex, const char *alias, const struct ether_addr *mac, uint32_t mtu); +int rtnl_set_link_properties( + sd_netlink **rtnl, + int ifindex, + const char *alias, + const struct ether_addr *mac, + uint32_t txqueues, + uint32_t rxqueues, + uint32_t txqueuelen, + uint32_t mtu, + uint32_t gso_max_size, + size_t gso_max_segments); int rtnl_get_link_alternative_names(sd_netlink **rtnl, int ifindex, char ***ret); int rtnl_set_link_alternative_names(sd_netlink **rtnl, int ifindex, char * const *alternative_names); int rtnl_set_link_alternative_names_by_ifname(sd_netlink **rtnl, const char *ifname, char * const *alternative_names); diff --git a/src/libsystemd/sd-netlink/nfnl-message.c b/src/libsystemd/sd-netlink/nfnl-message.c new file mode 100644 index 000000000..5f669f750 --- /dev/null +++ b/src/libsystemd/sd-netlink/nfnl-message.c @@ -0,0 +1,316 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include +#include +#include +#include + +#include "sd-netlink.h" + +#include "format-util.h" +#include "netlink-internal.h" +#include "netlink-types.h" +#include "netlink-util.h" +#include "socket-util.h" +#include "util.h" + +static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + const NLType *nl_type; + size_t size; + int r; + + assert_return(nfnl, -EINVAL); + + r = type_system_root_get_type(nfnl, &nl_type, NFNL_SUBSYS_NFTABLES); + if (r < 0) + return r; + + if (type_get_type(nl_type) != NETLINK_TYPE_NESTED) + return -EINVAL; + + r = message_new_empty(nfnl, &m); + if (r < 0) + return r; + + size = NLMSG_SPACE(type_get_size(nl_type)); + + assert(size >= sizeof(struct nlmsghdr)); + m->hdr = malloc0(size); + if (!m->hdr) + return -ENOMEM; + + m->hdr->nlmsg_flags = NLM_F_REQUEST | flags; + + type_get_type_system(nl_type, &m->containers[0].type_system); + + r = type_system_get_type_system(m->containers[0].type_system, + &m->containers[0].type_system, + type); + if (r < 0) + return r; + + m->hdr->nlmsg_len = size; + m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type; + + *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { + .nfgen_family = family, + .version = NFNETLINK_V0, + .res_id = nfnl->serial, + }; + + *ret = TAKE_PTR(m); + return 0; +} + +static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = message_new(nfnl, &m, v); + if (r < 0) + return r; + + *(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { + .nfgen_family = AF_UNSPEC, + .version = NFNETLINK_V0, + .res_id = NFNL_SUBSYS_NFTABLES, + }; + + *ret = TAKE_PTR(m); + return r; +} + +int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret) { + return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_BEGIN); +} + +int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret) { + return sd_nfnl_message_batch(nfnl, ret, NFNL_MSG_BATCH_END); +} + +int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, + int family, + const char *table, const char *chain, + const char *type, + uint8_t hook, int prio) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWCHAIN, NLM_F_CREATE | NLM_F_ACK); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_CHAIN_TABLE, table); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_CHAIN_NAME, chain); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_CHAIN_TYPE, type); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, NFTA_CHAIN_HOOK); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_HOOK_HOOKNUM, htobe32(hook)); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_HOOK_PRIORITY, htobe32(prio)); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return 0; +} + +int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_DELTABLE, NLM_F_CREATE | NLM_F_ACK); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return r; +} + +int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, uint16_t flags) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWTABLE, NLM_F_CREATE | flags); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_TABLE_NAME, table); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return r; +} + +int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *chain) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWRULE, NLM_F_CREATE | NLM_F_ACK); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_RULE_TABLE, table); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_RULE_CHAIN, chain); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return r; +} + +int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *set_name, + uint32_t set_id, uint32_t klen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSET, NLM_F_CREATE | NLM_F_ACK); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_SET_TABLE, table); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_SET_NAME, set_name); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_SET_ID, ++set_id); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_LEN, htobe32(klen)); + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return r; +} + +int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *set_name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_NEWSETELEM, NLM_F_CREATE | NLM_F_ACK); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return r; +} + +int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *set_name) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_message_new(nfnl, &m, family, NFT_MSG_DELSETELEM, NLM_F_ACK); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_TABLE, table); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_SET_ELEM_LIST_SET, set_name); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, NFTA_SET_ELEM_LIST_ELEMENTS); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return r; +} + +static int sd_nfnl_add_data(sd_netlink_message *m, uint16_t attr, const void *data, uint32_t dlen) { + int r = sd_netlink_message_open_container(m, attr); + if (r < 0) + return r; + + r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen); + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); /* attr */ +} + +int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, uint32_t num, + const void *key, uint32_t klen, + const void *data, uint32_t dlen) { + int r; + + r = sd_netlink_message_open_array(m, num); + if (r < 0) + return r; + + r = sd_nfnl_add_data(m, NFTA_SET_ELEM_KEY, key, klen); + if (r < 0) + goto cancel; + + if (data) { + r = sd_nfnl_add_data(m, NFTA_SET_ELEM_DATA, data, dlen); + if (r < 0) + goto cancel; + } + + return r; +cancel: + sd_netlink_message_cancel_array(m); + return r; +} + +int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m) { + return sd_netlink_message_close_container(m); /* NFTA_SET_ELEM_LIST_ELEMENTS */ +} + +int sd_nfnl_socket_open(sd_netlink **ret) { + return netlink_open_family(ret, NETLINK_NETFILTER); +} diff --git a/src/libsystemd/sd-netlink/rtnl-message.c b/src/libsystemd/sd-netlink/rtnl-message.c index 4cabbabba..d14fa1a5c 100644 --- a/src/libsystemd/sd-netlink/rtnl-message.c +++ b/src/libsystemd/sd-netlink/rtnl-message.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include #include @@ -124,20 +125,6 @@ int sd_rtnl_message_route_get_family(const sd_netlink_message *m, int *family) { return 0; } -int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family) { - struct rtmsg *rtm; - - assert_return(m, -EINVAL); - assert_return(m->hdr, -EINVAL); - assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL); - - rtm = NLMSG_DATA(m->hdr); - - rtm->rtm_family = family; - - return 0; -} - int sd_rtnl_message_route_get_type(const sd_netlink_message *m, unsigned char *type) { struct rtmsg *rtm; @@ -197,7 +184,7 @@ int sd_rtnl_message_route_get_scope(const sd_netlink_message *m, unsigned char * return 0; } -int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, unsigned char *tos) { +int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, uint8_t *tos) { struct rtmsg *rtm; assert_return(m, -EINVAL); @@ -293,8 +280,19 @@ int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, int r; assert_return(rtnl_message_type_is_nexthop(nhmsg_type), -EINVAL); - assert_return((nhmsg_type == RTM_GETNEXTHOP && nh_family == AF_UNSPEC) || - IN_SET(nh_family, AF_INET, AF_INET6), -EINVAL); + switch(nhmsg_type) { + case RTM_DELNEXTHOP: + assert_return(nh_family == AF_UNSPEC, -EINVAL); + _fallthrough_; + case RTM_GETNEXTHOP: + assert_return(nh_protocol == RTPROT_UNSPEC, -EINVAL); + break; + case RTM_NEWNEXTHOP: + assert_return(IN_SET(nh_family, AF_UNSPEC, AF_INET, AF_INET6), -EINVAL); + break; + default: + assert_not_reached("Invalid message type."); + } assert_return(ret, -EINVAL); r = message_new(rtnl, ret, nhmsg_type); @@ -318,7 +316,7 @@ int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags) { assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); - assert_return(rtnl_message_type_is_nexthop(m->hdr->nlmsg_type), -EINVAL); + assert_return(m->hdr->nlmsg_type == RTM_NEWNEXTHOP, -EINVAL); nhm = NLMSG_DATA(m->hdr); nhm->nh_flags |= flags; @@ -326,26 +324,30 @@ int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags) { return 0; } -int sd_rtnl_message_nexthop_set_family(sd_netlink_message *m, uint8_t family) { - struct nhmsg *nhm; - - assert_return(m, -EINVAL); - assert_return(m->hdr, -EINVAL); - - nhm = NLMSG_DATA(m->hdr); - nhm->nh_family = family; - - return 0; -} - int sd_rtnl_message_nexthop_get_family(const sd_netlink_message *m, uint8_t *family) { struct nhmsg *nhm; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_nexthop(m->hdr->nlmsg_type), -EINVAL); + assert_return(family, -EINVAL); nhm = NLMSG_DATA(m->hdr); - *family = nhm->nh_family ; + *family = nhm->nh_family; + + return 0; +} + +int sd_rtnl_message_nexthop_get_protocol(const sd_netlink_message *m, uint8_t *protocol) { + struct nhmsg *nhm; + + assert_return(m, -EINVAL); + assert_return(m->hdr, -EINVAL); + assert_return(rtnl_message_type_is_nexthop(m->hdr->nlmsg_type), -EINVAL); + assert_return(protocol, -EINVAL); + + nhm = NLMSG_DATA(m->hdr); + *protocol = nhm->nh_protocol; return 0; } @@ -461,7 +463,7 @@ int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsign assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL); - assert_return(change, -EINVAL); + assert_return(change != 0, -EINVAL); ifi = NLMSG_DATA(m->hdr); @@ -678,7 +680,7 @@ int sd_rtnl_message_new_addr(sd_netlink *rtnl, sd_netlink_message **ret, } int sd_rtnl_message_new_addr_update(sd_netlink *rtnl, sd_netlink_message **ret, - int index, int family) { + int index, int family) { int r; r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family); @@ -848,7 +850,7 @@ int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigne } int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family) { - struct rtmsg *rtm; + struct fib_rule_hdr *frh; int r; assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL); @@ -861,177 +863,175 @@ int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message if (nlmsg_type == RTM_NEWRULE) (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL; - rtm = NLMSG_DATA((*ret)->hdr); - rtm->rtm_family = ifal_family; - rtm->rtm_protocol = RTPROT_BOOT; - rtm->rtm_scope = RT_SCOPE_UNIVERSE; - rtm->rtm_type = RTN_UNICAST; + frh = NLMSG_DATA((*ret)->hdr); + frh->family = ifal_family; + frh->action = FR_ACT_TO_TBL; return 0; } -int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t tos) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - routing_policy_rule->rtm_tos = tos; + frh->tos = tos; return 0; } -int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, unsigned char *tos) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, uint8_t *tos) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - *tos = routing_policy_rule->rtm_tos; + *tos = frh->tos; return 0; } -int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t table) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - routing_policy_rule->rtm_table = table; + frh->table = table; return 0; } -int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, unsigned char *table) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, uint8_t *table) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - *table = routing_policy_rule->rtm_table; + *table = frh->table; return 0; } -int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, unsigned flags) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_t flags) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); - routing_policy_rule->rtm_flags |= flags; + frh = NLMSG_DATA(m->hdr); + frh->flags |= flags; return 0; } -int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, unsigned *flags) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, uint32_t *flags) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); - *flags = routing_policy_rule->rtm_flags; + frh = NLMSG_DATA(m->hdr); + *flags = frh->flags; return 0; } -int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint8_t type) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - routing_policy_rule->rtm_type = type; + frh->action = type; return 0; } -int sd_rtnl_message_routing_policy_rule_get_rtm_type(const sd_netlink_message *m, unsigned char *type) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_get_fib_type(const sd_netlink_message *m, uint8_t *type) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - *type = routing_policy_rule->rtm_type; + *type = frh->action; return 0; } -int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message *m, uint8_t len) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - routing_policy_rule->rtm_dst_len = len; + frh->dst_len = len; return 0; } -int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(const sd_netlink_message *m, unsigned char *len) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(const sd_netlink_message *m, uint8_t *len) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - *len = routing_policy_rule->rtm_dst_len; + *len = frh->dst_len; return 0; } -int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message *m, uint8_t len) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - routing_policy_rule->rtm_src_len = len; + frh->src_len = len; return 0; } -int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(const sd_netlink_message *m, unsigned char *len) { - struct rtmsg *routing_policy_rule; +int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(const sd_netlink_message *m, uint8_t *len) { + struct fib_rule_hdr *frh; assert_return(m, -EINVAL); assert_return(m->hdr, -EINVAL); assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL); - routing_policy_rule = NLMSG_DATA(m->hdr); + frh = NLMSG_DATA(m->hdr); - *len = routing_policy_rule->rtm_src_len; + *len = frh->src_len; return 0; } diff --git a/src/libsystemd/sd-netlink/sd-netlink.c b/src/libsystemd/sd-netlink/sd-netlink.c index 780110180..f862d4825 100644 --- a/src/libsystemd/sd-netlink/sd-netlink.c +++ b/src/libsystemd/sd-netlink/sd-netlink.c @@ -17,6 +17,9 @@ #include "string-util.h" #include "util.h" +/* Some really high limit, to catch programming errors */ +#define REPLY_CALLBACKS_MAX UINT16_MAX + static int sd_netlink_new(sd_netlink **ret) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; @@ -33,11 +36,29 @@ static int sd_netlink_new(sd_netlink **ret) { .original_pid = getpid_cached(), .protocol = -1, - /* Change notification responses have sequence 0, so we must - * start our request sequence numbers at 1, or we may confuse our - * responses with notifications from the kernel */ - .serial = 1, - + /* Kernel change notification messages have sequence number 0. We want to avoid that with our + * own serials, in order not to get confused when matching up kernel replies to our earlier + * requests. + * + * Moreover, when using netlink socket activation (i.e. where PID 1 binds an AF_NETLINK + * socket for us and passes it to us across execve()) and we get restarted multiple times + * while the socket sticks around we might get confused by replies from earlier runs coming + * in late — which is pretty likely if we'd start our sequence numbers always from 1. Hence, + * let's start with a value based on the system clock. This should make collisions much less + * likely (though still theoretically possible). We use a 32 bit µs counter starting at boot + * for this (and explicitly exclude the zero, see above). This counter will wrap around after + * a bit more than 1h, but that's hopefully OK as the kernel shouldn't take that long to + * reply to our requests. + * + * We only pick the initial start value this way. For each message we simply increase the + * sequence number by 1. This means we could enqueue 1 netlink message per µs without risking + * collisions, which should be OK. + * + * Note this means the serials will be in the range 1…UINT32_MAX here. + * + * (In an ideal world we'd attach the current serial counter to the netlink socket itself + * somehow, to avoid all this, but I couldn't come up with a nice way to do this) */ + .serial = (uint32_t) (now(CLOCK_MONOTONIC) % UINT32_MAX) + 1, }; /* We guarantee that the read buffer has at least space for @@ -89,9 +110,7 @@ static bool rtnl_pid_changed(const sd_netlink *rtnl) { int sd_netlink_open_fd(sd_netlink **ret, int fd) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - int r; - int protocol; - socklen_t l; + int r, protocol; assert_return(ret, -EINVAL); assert_return(fd >= 0, -EBADF); @@ -100,8 +119,7 @@ int sd_netlink_open_fd(sd_netlink **ret, int fd) { if (r < 0) return r; - l = sizeof(protocol); - r = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &protocol, &l); + r = getsockopt_int(fd, SOL_SOCKET, SO_PROTOCOL, &protocol); if (r < 0) return r; @@ -190,18 +208,25 @@ static sd_netlink *netlink_free(sd_netlink *rtnl) { DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_netlink, sd_netlink, netlink_free); static void rtnl_seal_message(sd_netlink *rtnl, sd_netlink_message *m) { + uint32_t picked; + assert(rtnl); assert(!rtnl_pid_changed(rtnl)); assert(m); assert(m->hdr); - /* don't use seq == 0, as that is used for broadcasts, so we - would get confused by replies to such messages */ - m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++; + /* Avoid collisions with outstanding requests */ + do { + picked = rtnl->serial; + /* Don't use seq == 0, as that is used for broadcasts, so we would get confused by replies to + such messages */ + rtnl->serial = rtnl->serial == UINT32_MAX ? 1 : rtnl->serial + 1; + + } while (hashmap_contains(rtnl->reply_callbacks, UINT32_TO_PTR(picked))); + + m->hdr->nlmsg_seq = picked; rtnl_message_seal(m); - - return; } int sd_netlink_send(sd_netlink *nl, @@ -226,6 +251,42 @@ int sd_netlink_send(sd_netlink *nl, return 1; } +int sd_netlink_sendv(sd_netlink *nl, + sd_netlink_message **messages, + size_t msgcount, + uint32_t **ret_serial) { + _cleanup_free_ uint32_t *serials = NULL; + unsigned i; + int r; + + assert_return(nl, -EINVAL); + assert_return(!rtnl_pid_changed(nl), -ECHILD); + assert_return(messages, -EINVAL); + assert_return(msgcount > 0, -EINVAL); + + if (ret_serial) { + serials = new0(uint32_t, msgcount); + if (!serials) + return -ENOMEM; + } + + for (i = 0; i < msgcount; i++) { + assert_return(!messages[i]->sealed, -EPERM); + rtnl_seal_message(nl, messages[i]); + if (serials) + serials[i] = rtnl_message_get_serial(messages[i]); + } + + r = socket_writev_message(nl, messages, msgcount); + if (r < 0) + return r; + + if (ret_serial) + *ret_serial = TAKE_PTR(serials); + + return r; +} + int rtnl_rqueue_make_room(sd_netlink *rtnl) { assert(rtnl); @@ -303,7 +364,7 @@ static int process_timeout(sd_netlink *rtnl) { assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c); c->timeout = 0; - hashmap_remove(rtnl->reply_callbacks, &c->serial); + hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(c->serial)); slot = container_of(c, sd_netlink_slot, reply_callback); @@ -323,7 +384,7 @@ static int process_timeout(sd_netlink *rtnl) { static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) { struct reply_callback *c; sd_netlink_slot *slot; - uint64_t serial; + uint32_t serial; uint16_t type; int r; @@ -331,7 +392,7 @@ static int process_reply(sd_netlink *rtnl, sd_netlink_message *m) { assert(m); serial = rtnl_message_get_serial(m); - c = hashmap_remove(rtnl->reply_callbacks, &serial); + c = hashmap_remove(rtnl->reply_callbacks, UINT32_TO_PTR(serial)); if (!c) return 0; @@ -376,20 +437,19 @@ static int process_match(sd_netlink *rtnl, sd_netlink_message *m) { return r; LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) { - if (type == c->type) { - slot = container_of(c, sd_netlink_slot, match_callback); + if (type != c->type) + continue; - r = c->callback(rtnl, m, slot->userdata); - if (r != 0) { - if (r < 0) - log_debug_errno(r, "sd-netlink: match callback %s%s%sfailed: %m", - slot->description ? "'" : "", - strempty(slot->description), - slot->description ? "' " : ""); + slot = container_of(c, sd_netlink_slot, match_callback); - break; - } - } + r = c->callback(rtnl, m, slot->userdata); + if (r < 0) + log_debug_errno(r, "sd-netlink: match callback %s%s%sfailed: %m", + slot->description ? "'" : "", + strempty(slot->description), + slot->description ? "' " : ""); + if (r != 0) + break; } return 1; @@ -452,13 +512,13 @@ int sd_netlink_process(sd_netlink *rtnl, sd_netlink_message **ret) { } static usec_t calc_elapse(uint64_t usec) { - if (usec == (uint64_t) -1) + if (usec == UINT64_MAX) return 0; if (usec == 0) usec = RTNL_DEFAULT_TIMEOUT; - return now(CLOCK_MONOTONIC) + usec; + return usec_add(now(CLOCK_MONOTONIC), usec); } static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) { @@ -490,7 +550,7 @@ static int rtnl_poll(sd_netlink *rtnl, bool need_more, uint64_t timeout_usec) { } } - if (timeout_usec != (uint64_t) -1 && (m == USEC_INFINITY || timeout_usec < m)) + if (timeout_usec != UINT64_MAX && (m == USEC_INFINITY || timeout_usec < m)) m = timeout_usec; r = fd_wait_for_event(rtnl->fd, e, m); @@ -532,7 +592,6 @@ int sd_netlink_call_async( uint64_t usec, const char *description) { _cleanup_free_ sd_netlink_slot *slot = NULL; - uint32_t s; int r, k; assert_return(nl, -EINVAL); @@ -540,11 +599,14 @@ int sd_netlink_call_async( assert_return(callback, -EINVAL); assert_return(!rtnl_pid_changed(nl), -ECHILD); - r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops); + if (hashmap_size(nl->reply_callbacks) >= REPLY_CALLBACKS_MAX) + return -ERANGE; + + r = hashmap_ensure_allocated(&nl->reply_callbacks, &trivial_hash_ops); if (r < 0) return r; - if (usec != (uint64_t) -1) { + if (usec != UINT64_MAX) { r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare); if (r < 0) return r; @@ -557,20 +619,18 @@ int sd_netlink_call_async( slot->reply_callback.callback = callback; slot->reply_callback.timeout = calc_elapse(usec); - k = sd_netlink_send(nl, m, &s); + k = sd_netlink_send(nl, m, &slot->reply_callback.serial); if (k < 0) return k; - slot->reply_callback.serial = s; - - r = hashmap_put(nl->reply_callbacks, &slot->reply_callback.serial, &slot->reply_callback); + r = hashmap_put(nl->reply_callbacks, UINT32_TO_PTR(slot->reply_callback.serial), &slot->reply_callback); if (r < 0) return r; if (slot->reply_callback.timeout != 0) { r = prioq_put(nl->reply_callbacks_prioq, &slot->reply_callback, &slot->reply_callback.prioq_idx); if (r < 0) { - (void) hashmap_remove(nl->reply_callbacks, &slot->reply_callback.serial); + (void) hashmap_remove(nl->reply_callbacks, UINT32_TO_PTR(slot->reply_callback.serial)); return r; } } @@ -586,21 +646,15 @@ int sd_netlink_call_async( return k; } -int sd_netlink_call(sd_netlink *rtnl, - sd_netlink_message *message, - uint64_t usec, - sd_netlink_message **ret) { +int sd_netlink_read(sd_netlink *rtnl, + uint32_t serial, + uint64_t usec, + sd_netlink_message **ret) { usec_t timeout; - uint32_t serial; int r; assert_return(rtnl, -EINVAL); assert_return(!rtnl_pid_changed(rtnl), -ECHILD); - assert_return(message, -EINVAL); - - r = sd_netlink_send(rtnl, message, &serial); - if (r < 0) - return r; timeout = calc_elapse(usec); @@ -660,7 +714,7 @@ int sd_netlink_call(sd_netlink *rtnl, left = timeout - n; } else - left = (uint64_t) -1; + left = UINT64_MAX; r = rtnl_poll(rtnl, true, left); if (r < 0) @@ -670,6 +724,24 @@ int sd_netlink_call(sd_netlink *rtnl, } } +int sd_netlink_call(sd_netlink *rtnl, + sd_netlink_message *message, + uint64_t usec, + sd_netlink_message **ret) { + uint32_t serial; + int r; + + assert_return(rtnl, -EINVAL); + assert_return(!rtnl_pid_changed(rtnl), -ECHILD); + assert_return(message, -EINVAL); + + r = sd_netlink_send(rtnl, message, &serial); + if (r < 0) + return r; + + return sd_netlink_read(rtnl, serial, usec, ret); +} + int sd_netlink_get_events(const sd_netlink *rtnl) { assert_return(rtnl, -EINVAL); assert_return(!rtnl_pid_changed(rtnl), -ECHILD); @@ -694,7 +766,7 @@ int sd_netlink_get_timeout(const sd_netlink *rtnl, uint64_t *timeout_usec) { c = prioq_peek(rtnl->reply_callbacks_prioq); if (!c) { - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; } diff --git a/src/libsystemd/sd-network/network-util.c b/src/libsystemd/sd-network/network-util.c index 7753431fc..acf750097 100644 --- a/src/libsystemd/sd-network/network-util.c +++ b/src/libsystemd/sd-network/network-util.c @@ -1,8 +1,14 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "sd-id128.h" + #include "alloc-util.h" +#include "arphrd-list.h" +#include "device-util.h" #include "fd-util.h" #include "network-util.h" +#include "siphash24.h" +#include "sparse-endian.h" #include "string-table.h" #include "strv.h" @@ -103,3 +109,72 @@ int parse_operational_state_range(const char *str, LinkOperationalStateRange *ou return 0; } + +char *link_get_type_string(sd_device *device, unsigned short iftype) { + const char *t; + char *p; + + if (device && + sd_device_get_devtype(device, &t) >= 0 && + !isempty(t)) + return strdup(t); + + t = arphrd_to_name(iftype); + if (!t) + return NULL; + + p = strdup(t); + if (!p) + return NULL; + + return ascii_strlower(p); +} + +const char *net_get_name_persistent(sd_device *device) { + const char *name, *field; + + assert(device); + + /* fetch some persistent data unique (on this machine) to this device */ + FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") + if (sd_device_get_property_value(device, field, &name) >= 0) + return name; + + return NULL; +} + +#define HASH_KEY SD_ID128_MAKE(d3,1e,48,fa,90,fe,4b,4c,9d,af,d5,d7,a1,b1,2e,8a) + +int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result) { + size_t l, sz = 0; + const char *name; + int r; + uint8_t *v; + + assert(device); + + /* net_get_name_persistent() will return one of the device names based on stable information about + * the device. If this is not available, we fall back to using the actual device name. */ + name = net_get_name_persistent(device); + if (!name && use_sysname) + (void) sd_device_get_sysname(device, &name); + if (!name) + return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA), + "No stable identifying information found"); + + log_device_debug(device, "Using \"%s\" as stable identifying information", name); + l = strlen(name); + sz = sizeof(sd_id128_t) + l; + v = newa(uint8_t, sz); + + /* Fetch some persistent data unique to this machine */ + r = sd_id128_get_machine((sd_id128_t*) v); + if (r < 0) + return r; + memcpy(v + sizeof(sd_id128_t), name, l); + + /* Let's hash the machine ID plus the device name. We use + * a fixed, but originally randomly created hash key here. */ + *result = htole64(siphash24(v, sz, HASH_KEY.bytes)); + return 0; +} diff --git a/src/libsystemd/sd-network/network-util.h b/src/libsystemd/sd-network/network-util.h index 8cfd894b5..dd6a7dbe8 100644 --- a/src/libsystemd/sd-network/network-util.h +++ b/src/libsystemd/sd-network/network-util.h @@ -1,6 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include +#include + +#include "sd-device.h" #include "sd-network.h" #include "macro.h" @@ -18,7 +22,7 @@ typedef enum LinkOperationalState { LINK_OPERSTATE_ENSLAVED, LINK_OPERSTATE_ROUTABLE, _LINK_OPERSTATE_MAX, - _LINK_OPERSTATE_INVALID = -1 + _LINK_OPERSTATE_INVALID = -EINVAL, } LinkOperationalState; typedef enum LinkCarrierState { @@ -29,7 +33,7 @@ typedef enum LinkCarrierState { LINK_CARRIER_STATE_CARRIER = LINK_OPERSTATE_CARRIER, LINK_CARRIER_STATE_ENSLAVED = LINK_OPERSTATE_ENSLAVED, _LINK_CARRIER_STATE_MAX, - _LINK_CARRIER_STATE_INVALID = -1 + _LINK_CARRIER_STATE_INVALID = -EINVAL, } LinkCarrierState; typedef enum LinkAddressState { @@ -37,7 +41,7 @@ typedef enum LinkAddressState { LINK_ADDRESS_STATE_DEGRADED, LINK_ADDRESS_STATE_ROUTABLE, _LINK_ADDRESS_STATE_MAX, - _LINK_ADDRESS_STATE_INVALID = -1 + _LINK_ADDRESS_STATE_INVALID = -EINVAL, } LinkAddressState; const char* link_operstate_to_string(LinkOperationalState s) _const_; @@ -58,3 +62,7 @@ typedef struct LinkOperationalStateRange { LINK_OPERSTATE_ROUTABLE } int parse_operational_state_range(const char *str, LinkOperationalStateRange *out); + +char *link_get_type_string(sd_device *device, unsigned short iftype); +int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *result); +const char *net_get_name_persistent(sd_device *device); diff --git a/src/libsystemd/sd-network/sd-network.c b/src/libsystemd/sd-network/sd-network.c index b9b109939..ccdfde913 100644 --- a/src/libsystemd/sd-network/sd-network.c +++ b/src/libsystemd/sd-network/sd-network.c @@ -212,6 +212,27 @@ _public_ int sd_network_link_get_required_operstate_for_online(int ifindex, char return 0; } +_public_ int sd_network_link_get_activation_policy(int ifindex, char **policy) { + _cleanup_free_ char *s = NULL; + int r; + + assert_return(policy, -EINVAL); + + r = network_link_get_string(ifindex, "ACTIVATION_POLICY", &s); + if (r < 0) { + if (r != -ENODATA) + return r; + + /* For compatibility, assuming up. */ + s = strdup("up"); + if (!s) + return -ENOMEM; + } + + *policy = TAKE_PTR(s); + return 0; +} + _public_ int sd_network_link_get_llmnr(int ifindex, char **llmnr) { return network_link_get_string(ifindex, "LLMNR", llmnr); } @@ -440,9 +461,9 @@ _public_ int sd_network_monitor_get_timeout(sd_network_monitor *m, uint64_t *tim assert_return(m, -EINVAL); assert_return(timeout_usec, -EINVAL); - /* For now we will only return (uint64_t) -1, since we don't + /* For now we will only return UINT64_MAX, since we don't * need any timeout. However, let's have this API to keep our * options open should we later on need it. */ - *timeout_usec = (uint64_t) -1; + *timeout_usec = UINT64_MAX; return 0; } diff --git a/src/libsystemd/sd-resolve/sd-resolve.c b/src/libsystemd/sd-resolve/sd-resolve.c index 2cfa22d28..ee973c069 100644 --- a/src/libsystemd/sd-resolve/sd-resolve.c +++ b/src/libsystemd/sd-resolve/sd-resolve.c @@ -15,7 +15,7 @@ #include "sd-resolve.h" #include "alloc-util.h" -#include "dns-domain.h" +#include "dns-def.h" #include "errno-util.h" #include "fd-util.h" #include "io-util.h" @@ -621,7 +621,7 @@ _public_ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *usec) { assert_return(usec, -EINVAL); assert_return(!resolve_pid_changed(resolve), -ECHILD); - *usec = (uint64_t) -1; + *usec = UINT64_MAX; return 0; } diff --git a/src/libudev/libudev-device.c b/src/libudev/libudev-device.c index 34543a8b2..8091ff1d6 100644 --- a/src/libudev/libudev-device.c +++ b/src/libudev/libudev-device.c @@ -82,7 +82,7 @@ _public_ unsigned long long udev_device_get_seqnum(struct udev_device *udev_devi assert_return_errno(udev_device, 0, EINVAL); - if (device_get_seqnum(udev_device->device, &seqnum) < 0) + if (sd_device_get_seqnum(udev_device->device, &seqnum) < 0) return 0; return seqnum; @@ -351,7 +351,7 @@ _public_ struct udev_device *udev_device_new_from_subsystem_sysname(struct udev * @udev: udev library context * * Create new udev device, and fill in information from the - * current process environment. This only works reliable if + * current process environment. This only works reliably if * the process is called from a udev rule. It is usually used * for tools executed from IMPORT= rules. * @@ -693,11 +693,11 @@ _public_ struct udev_list_entry *udev_device_get_properties_list_entry(struct ud * Returns: the kernel action value, or #NULL if there is no action value available. **/ _public_ const char *udev_device_get_action(struct udev_device *udev_device) { - DeviceAction action; + sd_device_action_t action; assert_return_errno(udev_device, NULL, EINVAL); - if (device_get_action(udev_device->device, &action) < 0) + if (sd_device_get_action(udev_device->device, &action) < 0) return NULL; return device_action_to_string(action); diff --git a/src/libudev/libudev-list.c b/src/libudev/libudev-list.c index 3b2a2cdee..69efc1013 100644 --- a/src/libudev/libudev-list.c +++ b/src/libudev/libudev-list.c @@ -39,9 +39,10 @@ static struct udev_list_entry *udev_list_entry_free(struct udev_list_entry *entr return NULL; if (entry->list) { - if (entry->list->unique) + if (entry->list->unique && entry->name) hashmap_remove(entry->list->unique_entries, entry->name); - else + + if (!entry->list->unique || entry->list->uptodate) LIST_REMOVE(entries, entry->list->entries, entry); } @@ -70,9 +71,9 @@ struct udev_list *udev_list_new(bool unique) { struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char *_name, const char *_value) { _cleanup_(udev_list_entry_freep) struct udev_list_entry *entry = NULL; _cleanup_free_ char *name = NULL, *value = NULL; - int r; assert(list); + assert(_name); name = strdup(_name); if (!name) @@ -89,26 +90,22 @@ struct udev_list_entry *udev_list_entry_add(struct udev_list *list, const char * return NULL; *entry = (struct udev_list_entry) { - .list = list, .name = TAKE_PTR(name), .value = TAKE_PTR(value), }; if (list->unique) { - r = hashmap_ensure_allocated(&list->unique_entries, &string_hash_ops); - if (r < 0) - return NULL; - udev_list_entry_free(hashmap_get(list->unique_entries, entry->name)); - r = hashmap_put(list->unique_entries, entry->name, entry); - if (r < 0) + if (hashmap_ensure_put(&list->unique_entries, &string_hash_ops, entry->name, entry) < 0) return NULL; list->uptodate = false; } else LIST_APPEND(entries, list->entries, entry); + entry->list = list; + return TAKE_PTR(entry); } @@ -119,8 +116,8 @@ void udev_list_cleanup(struct udev_list *list) { return; if (list->unique) { - hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); list->uptodate = false; + hashmap_clear_with_destructor(list->unique_entries, udev_list_entry_free); } else LIST_FOREACH_SAFE(entries, i, n, list->entries) udev_list_entry_free(i); diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c index a93adbd7a..4ddcf95d0 100644 --- a/src/libudev/libudev-monitor.c +++ b/src/libudev/libudev-monitor.c @@ -206,12 +206,10 @@ static int udev_monitor_receive_sd_device(struct udev_monitor *udev_monitor, sd_ for (;;) { /* Wait for next message */ r = fd_wait_for_event(device_monitor_get_fd(udev_monitor->monitor), POLLIN, 0); - if (r < 0) { - if (IN_SET(r, -EINTR, -EAGAIN)) - continue; - + if (r == -EINTR) + continue; + if (r < 0) return r; - } if (r == 0) return -EAGAIN; diff --git a/src/libudev/libudev-queue.c b/src/libudev/libudev-queue.c index 01b237fde..7ca17fa6c 100644 --- a/src/libudev/libudev-queue.c +++ b/src/libudev/libudev-queue.c @@ -4,9 +4,6 @@ ***/ #include -#include -#include -#include #include #include "libudev.h" @@ -14,6 +11,7 @@ #include "alloc-util.h" #include "fd-util.h" #include "io-util.h" +#include "udev-util.h" /** * SECTION:libudev-queue @@ -144,7 +142,7 @@ _public_ int udev_queue_get_udev_is_active(struct udev_queue *udev_queue) { * Returns: a flag indicating if udev is currently handling events. **/ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) { - return access("/run/udev/queue", F_OK) < 0; + return udev_queue_is_empty() > 0; } /** @@ -153,14 +151,13 @@ _public_ int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue) { * @start: first event sequence number * @end: last event sequence number * - * This function is deprecated, it just returns the result of - * udev_queue_get_queue_is_empty(). + * This function is deprecated, and equivalent to udev_queue_get_queue_is_empty(). * * Returns: a flag indicating if udev is currently handling events. **/ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_queue, unsigned long long int start, unsigned long long int end) { - return udev_queue_get_queue_is_empty(udev_queue); + return udev_queue_is_empty() > 0; } /** @@ -168,13 +165,12 @@ _public_ int udev_queue_get_seqnum_sequence_is_finished(struct udev_queue *udev_ * @udev_queue: udev queue context * @seqnum: sequence number * - * This function is deprecated, it just returns the result of - * udev_queue_get_queue_is_empty(). + * This function is deprecated, and equivalent to udev_queue_get_queue_is_empty(). * * Returns: a flag indicating if udev is currently handling events. **/ _public_ int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) { - return udev_queue_get_queue_is_empty(udev_queue); + return udev_queue_is_empty() > 0; } /** @@ -196,22 +192,18 @@ _public_ struct udev_list_entry *udev_queue_get_queued_list_entry(struct udev_qu * Returns: a file descriptor to watch for a queue to become empty. */ _public_ int udev_queue_get_fd(struct udev_queue *udev_queue) { - _cleanup_close_ int fd = -1; + int r; assert_return(udev_queue, -EINVAL); if (udev_queue->fd >= 0) return udev_queue->fd; - fd = inotify_init1(IN_CLOEXEC); - if (fd < 0) - return -errno; + r = udev_queue_init(); + if (r < 0) + return r; - if (inotify_add_watch(fd, "/run/udev" , IN_DELETE) < 0) - return -errno; - - udev_queue->fd = TAKE_FD(fd); - return udev_queue->fd; + return udev_queue->fd = r; } /** diff --git a/src/libudev/libudev-util.c b/src/libudev/libudev-util.c index bbb287976..8c5187766 100644 --- a/src/libudev/libudev-util.c +++ b/src/libudev/libudev-util.c @@ -1,15 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include -#include - -#include "sd-device.h" - #include "device-nodes.h" #include "libudev-util.h" -#include "string-util.h" -#include "strxcpyx.h" -#include "utf8.h" /** * SECTION:libudev-util @@ -18,185 +10,6 @@ * Utilities useful when dealing with devices and device node names. */ -/* handle "[/]" format */ -int util_resolve_subsys_kernel(const char *string, char *result, size_t maxsize, bool read_value) { - char temp[UTIL_PATH_SIZE], *subsys, *sysname, *attr; - _cleanup_(sd_device_unrefp) sd_device *dev = NULL; - const char *val; - int r; - - if (string[0] != '[') - return -EINVAL; - - strscpy(temp, sizeof(temp), string); - - subsys = &temp[1]; - - sysname = strchr(subsys, '/'); - if (!sysname) - return -EINVAL; - sysname[0] = '\0'; - sysname = &sysname[1]; - - attr = strchr(sysname, ']'); - if (!attr) - return -EINVAL; - attr[0] = '\0'; - attr = &attr[1]; - if (attr[0] == '/') - attr = &attr[1]; - if (attr[0] == '\0') - attr = NULL; - - if (read_value && !attr) - return -EINVAL; - - r = sd_device_new_from_subsystem_sysname(&dev, subsys, sysname); - if (r < 0) - return r; - - if (read_value) { - r = sd_device_get_sysattr_value(dev, attr, &val); - if (r < 0 && r != -ENOENT) - return r; - if (r == -ENOENT) - result[0] = '\0'; - else - strscpy(result, maxsize, val); - log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); - } else { - r = sd_device_get_syspath(dev, &val); - if (r < 0) - return r; - - strscpyl(result, maxsize, val, attr ? "/" : NULL, attr ?: NULL, NULL); - log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, strempty(attr), result); - } - return 0; -} - -size_t util_path_encode(const char *src, char *dest, size_t size) { - size_t i, j; - - assert(src); - assert(dest); - - for (i = 0, j = 0; src[i] != '\0'; i++) { - if (src[i] == '/') { - if (j+4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x2f", 4); - j += 4; - } else if (src[i] == '\\') { - if (j+4 >= size) { - j = 0; - break; - } - memcpy(&dest[j], "\\x5c", 4); - j += 4; - } else { - if (j+1 >= size) { - j = 0; - break; - } - dest[j] = src[i]; - j++; - } - } - dest[j] = '\0'; - return j; -} - -/* - * Copy from 'str' to 'to', while removing all leading and trailing whitespace, - * and replacing each run of consecutive whitespace with a single underscore. - * The chars from 'str' are copied up to the \0 at the end of the string, or - * at most 'len' chars. This appends \0 to 'to', at the end of the copied - * characters. - * - * If 'len' chars are copied into 'to', the final \0 is placed at len+1 - * (i.e. 'to[len] = \0'), so the 'to' buffer must have at least len+1 - * chars available. - * - * Note this may be called with 'str' == 'to', i.e. to replace whitespace - * in-place in a buffer. This function can handle that situation. - * - * Note that only 'len' characters are read from 'str'. - */ -size_t util_replace_whitespace(const char *str, char *to, size_t len) { - bool is_space = false; - size_t i, j; - - assert(str); - assert(to); - - i = strspn(str, WHITESPACE); - - for (j = 0; j < len && i < len && str[i] != '\0'; i++) { - if (isspace(str[i])) { - is_space = true; - continue; - } - - if (is_space) { - if (j + 1 >= len) - break; - - to[j++] = '_'; - is_space = false; - } - to[j++] = str[i]; - } - - to[j] = '\0'; - return j; -} - -/* allow chars in allow list, plain ascii, hex-escaping and valid utf8 */ -size_t util_replace_chars(char *str, const char *allow) { - size_t i = 0, replaced = 0; - - assert(str); - - while (str[i] != '\0') { - int len; - - if (allow_listed_char_for_devnode(str[i], allow)) { - i++; - continue; - } - - /* accept hex encoding */ - if (str[i] == '\\' && str[i+1] == 'x') { - i += 2; - continue; - } - - /* accept valid utf8 */ - len = utf8_encoded_valid_unichar(str + i, (size_t) -1); - if (len > 1) { - i += len; - continue; - } - - /* if space is allowed, replace whitespace with ordinary space */ - if (isspace(str[i]) && allow && strchr(allow, ' ')) { - str[i] = ' '; - i++; - replaced++; - continue; - } - - /* everything else is replaced with '_' */ - str[i] = '_'; - i++; - replaced++; - } - return replaced; -} - /** * udev_util_encode_string: * @str: input string to be encoded diff --git a/src/libudev/libudev-util.h b/src/libudev/libudev-util.h index 15e6214b0..0dc18d44b 100644 --- a/src/libudev/libudev-util.h +++ b/src/libudev/libudev-util.h @@ -5,16 +5,6 @@ #include "macro.h" -/* libudev-util.c */ -#define UTIL_PATH_SIZE 1024 -#define UTIL_NAME_SIZE 512 -#define UTIL_LINE_SIZE 16384 -#define UDEV_ALLOWED_CHARS_INPUT "/ $%?," -size_t util_path_encode(const char *src, char *dest, size_t size); -size_t util_replace_whitespace(const char *str, char *to, size_t len); -size_t util_replace_chars(char *str, const char *white); -int util_resolve_subsys_kernel(const char *string, char *result, size_t maxsize, bool read_value); - /* Cleanup functions */ DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev*, udev_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_device*, udev_device_unref); diff --git a/src/libudev/libudev.h b/src/libudev/libudev.h index 55036de86..aef4a55a8 100644 --- a/src/libudev/libudev.h +++ b/src/libudev/libudev.h @@ -156,7 +156,7 @@ struct udev_queue *udev_queue_unref(struct udev_queue *udev_queue); struct udev *udev_queue_get_udev(struct udev_queue *udev_queue); struct udev_queue *udev_queue_new(struct udev *udev); unsigned long long int udev_queue_get_kernel_seqnum(struct udev_queue *udev_queue) __attribute__((__deprecated__)); - unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) __attribute__((__deprecated__)); +unsigned long long int udev_queue_get_udev_seqnum(struct udev_queue *udev_queue) __attribute__((__deprecated__)); int udev_queue_get_udev_is_active(struct udev_queue *udev_queue); int udev_queue_get_queue_is_empty(struct udev_queue *udev_queue); int udev_queue_get_seqnum_is_finished(struct udev_queue *udev_queue, unsigned long long int seqnum) __attribute__((__deprecated__)); diff --git a/src/libudev/meson.build b/src/libudev/meson.build index 3bd00ff4c..b3ffb8b10 100644 --- a/src/libudev/meson.build +++ b/src/libudev/meson.build @@ -1,29 +1,54 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -libudev_sources = files(''' - libudev.c - libudev-device.c - libudev-device-internal.h - libudev-enumerate.c - libudev-hwdb.c - libudev-list.c - libudev-list-internal.h - libudev-monitor.c - libudev-queue.c - libudev-util.c - libudev-util.h -'''.split()) +libudev_sources = files( + 'libudev-device.c', + 'libudev-device-internal.h', + 'libudev-enumerate.c', + 'libudev-hwdb.c', + 'libudev-list.c', + 'libudev-list-internal.h', + 'libudev-monitor.c', + 'libudev-queue.c', + 'libudev-util.c', + 'libudev-util.h', + 'libudev.c', + 'libudev.h') ############################################################ +libudev_includes = [includes, include_directories('.')] + libudev_sym = files('libudev.sym') -libudev_sym_path = meson.current_source_dir() + '/libudev.sym' +libudev_sym_path = join_paths(meson.current_source_dir(), 'libudev.sym') install_headers('libudev.h') -libudev_h_path = '@0@/libudev.h'.format(meson.current_source_dir()) +libudev_h_path = join_paths(meson.current_source_dir(), 'libudev.h') + +libudev_basic = static_library( + 'udev-basic', + libudev_sources, + include_directories : includes, + c_args : ['-fvisibility=default']) + +libudev_static = static_library( + 'udev_static', + include_directories : includes, + link_with : udev_link_with, + link_whole : libudev_basic) + +static_libudev = get_option('static-libudev') +static_libudev_pic = static_libudev == 'true' or static_libudev == 'pic' configure_file( input : 'libudev.pc.in', output : 'libudev.pc', configuration : substs, install_dir : pkgconfiglibdir == 'no' ? '' : pkgconfiglibdir) + +############################################################ + +tests += [ + [['src/libudev/test-libudev.c'], + [libshared, + libudev_static]], +] diff --git a/src/test/test-libudev.c b/src/libudev/test-libudev.c similarity index 78% rename from src/test/test-libudev.c rename to src/libudev/test-libudev.c index d162abaea..12bd0d629 100644 --- a/src/test/test-libudev.c +++ b/src/libudev/test-libudev.c @@ -345,92 +345,6 @@ static void test_hwdb(struct udev *udev, const char *modalias) { assert_se(hwdb == NULL); } -static void test_util_replace_whitespace_one_len(const char *str, size_t len, const char *expected) { - _cleanup_free_ char *result = NULL; - int r; - - result = new(char, len + 1); - assert_se(result); - r = util_replace_whitespace(str, result, len); - assert_se((size_t) r == strlen(expected)); - assert_se(streq(result, expected)); -} - -static void test_util_replace_whitespace_one(const char *str, const char *expected) { - test_util_replace_whitespace_one_len(str, strlen(str), expected); -} - -static void test_util_replace_whitespace(void) { - log_info("/* %s */", __func__); - - test_util_replace_whitespace_one("hogehoge", "hogehoge"); - test_util_replace_whitespace_one("hoge hoge", "hoge_hoge"); - test_util_replace_whitespace_one(" hoge hoge ", "hoge_hoge"); - test_util_replace_whitespace_one(" ", ""); - test_util_replace_whitespace_one("hoge ", "hoge"); - - test_util_replace_whitespace_one_len("hoge hoge ", 9, "hoge_hoge"); - test_util_replace_whitespace_one_len("hoge hoge ", 8, "hoge_hog"); - test_util_replace_whitespace_one_len("hoge hoge ", 7, "hoge_ho"); - test_util_replace_whitespace_one_len("hoge hoge ", 6, "hoge_h"); - test_util_replace_whitespace_one_len("hoge hoge ", 5, "hoge"); - test_util_replace_whitespace_one_len("hoge hoge ", 4, "hoge"); - test_util_replace_whitespace_one_len("hoge hoge ", 3, "hog"); - test_util_replace_whitespace_one_len("hoge hoge ", 2, "ho"); - test_util_replace_whitespace_one_len("hoge hoge ", 1, "h"); - test_util_replace_whitespace_one_len("hoge hoge ", 0, ""); - - test_util_replace_whitespace_one_len(" hoge hoge ", 16, "hoge_hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 15, "hoge_hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 14, "hoge_hog"); - test_util_replace_whitespace_one_len(" hoge hoge ", 13, "hoge_ho"); - test_util_replace_whitespace_one_len(" hoge hoge ", 12, "hoge_h"); - test_util_replace_whitespace_one_len(" hoge hoge ", 11, "hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 10, "hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 9, "hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 8, "hoge"); - test_util_replace_whitespace_one_len(" hoge hoge ", 7, "hog"); - test_util_replace_whitespace_one_len(" hoge hoge ", 6, "ho"); - test_util_replace_whitespace_one_len(" hoge hoge ", 5, "h"); - test_util_replace_whitespace_one_len(" hoge hoge ", 4, ""); - test_util_replace_whitespace_one_len(" hoge hoge ", 3, ""); - test_util_replace_whitespace_one_len(" hoge hoge ", 2, ""); - test_util_replace_whitespace_one_len(" hoge hoge ", 1, ""); - test_util_replace_whitespace_one_len(" hoge hoge ", 0, ""); -} - -static void test_util_resolve_subsys_kernel_one(const char *str, bool read_value, int retval, const char *expected) { - char result[UTIL_PATH_SIZE] = ""; - int r; - - r = util_resolve_subsys_kernel(str, result, sizeof(result), read_value); - log_info("\"%s\" → expect: \"%s\", %d, actual: \"%s\", %d", str, strnull(expected), retval, result, r); - assert_se(r == retval); - if (r >= 0) - assert_se(streq(result, expected)); -} - -static void test_util_resolve_subsys_kernel(void) { - log_info("/* %s */", __func__); - - test_util_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL); - test_util_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL); - test_util_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL); - test_util_resolve_subsys_kernel_one("[hoge/]", false, -ENODEV, NULL); - - test_util_resolve_subsys_kernel_one("[net/lo]", false, 0, "/sys/devices/virtual/net/lo"); - test_util_resolve_subsys_kernel_one("[net/lo]/", false, 0, "/sys/devices/virtual/net/lo"); - test_util_resolve_subsys_kernel_one("[net/lo]hoge", false, 0, "/sys/devices/virtual/net/lo/hoge"); - test_util_resolve_subsys_kernel_one("[net/lo]/hoge", false, 0, "/sys/devices/virtual/net/lo/hoge"); - - test_util_resolve_subsys_kernel_one("[net/lo]", true, -EINVAL, NULL); - test_util_resolve_subsys_kernel_one("[net/lo]/", true, -EINVAL, NULL); - test_util_resolve_subsys_kernel_one("[net/lo]hoge", true, 0, ""); - test_util_resolve_subsys_kernel_one("[net/lo]/hoge", true, 0, ""); - test_util_resolve_subsys_kernel_one("[net/lo]address", true, 0, "00:00:00:00:00:00"); - test_util_resolve_subsys_kernel_one("[net/lo]/address", true, 0, "00:00:00:00:00:00"); -} - static void test_list(void) { _cleanup_(udev_list_freep) struct udev_list *list = NULL; struct udev_list_entry *e; @@ -573,9 +487,6 @@ static int run(int argc, char *argv[]) { if (arg_monitor) test_monitor(udev); - test_util_replace_whitespace(); - test_util_resolve_subsys_kernel(); - test_list(); return 0; diff --git a/src/libudev/test-udev-device-thread.c b/src/libudev/test-udev-device-thread.c new file mode 100644 index 000000000..c082fdca4 --- /dev/null +++ b/src/libudev/test-udev-device-thread.c @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include + +#include "libudev.h" + +#define handle_error_errno(error, msg) \ + ({ \ + errno = abs(error); \ + perror(msg); \ + EXIT_FAILURE; \ + }) + +static void* thread(void *p) { + struct udev_device **d = p; + + *d = udev_device_unref(*d); + + return NULL; +} + +int main(int argc, char *argv[]) { + struct udev_device *loopback; + struct udev_list_entry *entry, *e; + pthread_t t; + int r; + + loopback = udev_device_new_from_syspath(NULL, "/sys/class/net/lo"); + if (!loopback) + return handle_error_errno(errno, "Failed to create loopback device object"); + + entry = udev_device_get_properties_list_entry(loopback); + udev_list_entry_foreach(e, entry) + printf("%s=%s\n", udev_list_entry_get_name(e), udev_list_entry_get_value(e)); + + r = pthread_create(&t, NULL, thread, &loopback); + if (r != 0) + return handle_error_errno(r, "Failed to create thread"); + + r = pthread_join(t, NULL); + if (r != 0) + return handle_error_errno(r, "Failed to wait thread finished"); + + if (loopback) + return handle_error_errno(r, "loopback device is not unref()ed"); + + return 0; +} diff --git a/src/locale/keymap-util.c b/src/locale/keymap-util.c index cb8153f4f..e8de1b789 100644 --- a/src/locale/keymap-util.c +++ b/src/locale/keymap-util.c @@ -6,18 +6,21 @@ #include #include "bus-polkit.h" +#include "copy.h" #include "env-file-label.h" #include "env-file.h" #include "env-util.h" #include "fd-util.h" #include "fileio-label.h" #include "fileio.h" +#include "fs-util.h" #include "kbd-util.h" #include "keymap-util.h" #include "locale-util.h" #include "macro.h" #include "mkdir.h" #include "nulstr-util.h" +#include "process-util.h" #include "string-util.h" #include "strv.h" #include "tmpfile-util.h" @@ -63,9 +66,7 @@ static void context_free_vconsole(Context *c) { } static void context_free_locale(Context *c) { - int p; - - for (p = 0; p < _VARIABLE_LC_MAX; p++) + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) c->locale[p] = mfree(c->locale[p]); } @@ -82,9 +83,7 @@ void context_clear(Context *c) { }; void locale_simplify(char *locale[_VARIABLE_LC_MAX]) { - int p; - - for (p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) + for (LocaleVariable p = VARIABLE_LANG+1; p < _VARIABLE_LC_MAX; p++) if (isempty(locale[p]) || streq_ptr(locale[VARIABLE_LANG], locale[p])) locale[p] = mfree(locale[p]); } @@ -135,13 +134,11 @@ int locale_read_data(Context *c, sd_bus_message *m) { if (r < 0) return r; } else { - int p; - c->locale_mtime = USEC_INFINITY; context_free_locale(c); /* Fill in what we got passed from systemd. */ - for (p = 0; p < _VARIABLE_LC_MAX; p++) { + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { const char *name; name = locale_variable_to_string(p); @@ -291,30 +288,16 @@ int x11_read_data(Context *c, sd_bus_message *m) { int locale_write_data(Context *c, char ***settings) { _cleanup_strv_free_ char **l = NULL; struct stat st; - int r, p; + int r; /* Set values will be returned as strv in *settings on success. */ - for (p = 0; p < _VARIABLE_LC_MAX; p++) { - _cleanup_free_ char *t = NULL; - char **u; - const char *name; - - name = locale_variable_to_string(p); - assert(name); - - if (isempty(c->locale[p])) - continue; - - if (asprintf(&t, "%s=%s", name, c->locale[p]) < 0) - return -ENOMEM; - - u = strv_env_set(l, t); - if (!u) - return -ENOMEM; - - strv_free_and_replace(l, u); - } + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) + if (!isempty(c->locale[p])) { + r = strv_env_assign(&l, locale_variable_to_string(p), c->locale[p]); + if (r < 0) + return r; + } if (strv_isempty(l)) { if (unlink("/etc/locale.conf") < 0) @@ -345,39 +328,13 @@ int vconsole_write_data(Context *c) { if (r < 0 && r != -ENOENT) return r; - if (isempty(c->vc_keymap)) - l = strv_env_unset(l, "KEYMAP"); - else { - _cleanup_free_ char *s = NULL; - char **u; + r = strv_env_assign(&l, "KEYMAP", empty_to_null(c->vc_keymap)); + if (r < 0) + return r; - s = strjoin("KEYMAP=", c->vc_keymap); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free_and_replace(l, u); - } - - if (isempty(c->vc_keymap_toggle)) - l = strv_env_unset(l, "KEYMAP_TOGGLE"); - else { - _cleanup_free_ char *s = NULL; - char **u; - - s = strjoin("KEYMAP_TOGGLE=", c->vc_keymap_toggle); - if (!s) - return -ENOMEM; - - u = strv_env_set(l, s); - if (!u) - return -ENOMEM; - - strv_free_and_replace(l, u); - } + r = strv_env_assign(&l, "KEYMAP_TOGGLE", empty_to_null(c->vc_keymap_toggle)); + if (r < 0) + return r; if (strv_isempty(l)) { if (unlink("/etc/vconsole.conf") < 0) @@ -780,3 +737,211 @@ int x11_convert_to_vconsole(Context *c) { return modified; } + +bool locale_gen_check_available(void) { +#if HAVE_LOCALEGEN + if (access(LOCALEGEN_PATH, X_OK) < 0) { + if (errno != ENOENT) + log_warning_errno(errno, "Unable to determine whether " LOCALEGEN_PATH " exists and is executable, assuming it is not: %m"); + return false; + } + if (access("/etc/locale.gen", F_OK) < 0) { + if (errno != ENOENT) + log_warning_errno(errno, "Unable to determine whether /etc/locale.gen exists, assuming it does not: %m"); + return false; + } + return true; +#else + return false; +#endif +} + +#if HAVE_LOCALEGEN +static bool locale_encoding_is_utf8_or_unspecified(const char *locale) { + const char *c = strchr(locale, '.'); + return !c || strcaseeq(c, ".UTF-8") || strcasestr(locale, ".UTF-8@"); +} + +static int locale_gen_locale_supported(const char *locale_entry) { + /* Returns an error valus <= 0 if the locale-gen entry is invalid or unsupported, + * 1 in case the locale entry is valid, and -EOPNOTSUPP specifically in case + * the distributor has not provided us with a SUPPORTED file to check + * locale for validity. */ + + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(locale_entry); + + /* Locale templates without country code are never supported */ + if (!strstr(locale_entry, "_")) + return -EINVAL; + + f = fopen("/usr/share/i18n/SUPPORTED", "re"); + if (!f) { + if (errno == ENOENT) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Unable to check validity of locale entry %s: /usr/share/i18n/SUPPORTED does not exist", + locale_entry); + return -errno; + } + + for (;;) { + _cleanup_free_ char *line = NULL; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_debug_errno(r, "Failed to read /usr/share/i18n/SUPPORTED: %m"); + if (r == 0) + return 0; + + line = strstrip(line); + if (strcaseeq_ptr(line, locale_entry)) + return 1; + } +} +#endif + +int locale_gen_enable_locale(const char *locale) { +#if HAVE_LOCALEGEN + _cleanup_fclose_ FILE *fr = NULL, *fw = NULL; + _cleanup_(unlink_and_freep) char *temp_path = NULL; + _cleanup_free_ char *locale_entry = NULL; + bool locale_enabled = false, first_line = false; + bool write_new = false; + int r; + + if (isempty(locale)) + return 0; + + if (locale_encoding_is_utf8_or_unspecified(locale)) { + locale_entry = strjoin(locale, " UTF-8"); + if (!locale_entry) + return -ENOMEM; + } else + return -ENOEXEC; /* We do not process non-UTF-8 locale */ + + r = locale_gen_locale_supported(locale_entry); + if (r == 0) + return -EINVAL; + if (r < 0 && r != -EOPNOTSUPP) + return r; + + fr = fopen("/etc/locale.gen", "re"); + if (!fr) { + if (errno != ENOENT) + return -errno; + write_new = true; + } + + r = fopen_temporary("/etc/locale.gen", &fw, &temp_path); + if (r < 0) + return r; + + if (write_new) + (void) fchmod(fileno(fw), 0644); + else { + /* apply mode & xattrs of the original file to new file */ + r = copy_access(fileno(fr), fileno(fw)); + if (r < 0) + return r; + r = copy_xattr(fileno(fr), fileno(fw)); + if (r < 0) + return r; + } + + if (!write_new) { + /* The config file ends with a line break, which we do not want to include before potentially appending a new locale + * instead of uncommenting an existing line. By prepending linebreaks, we can avoid buffering this file but can still write + * a nice config file without empty lines */ + first_line = true; + for (;;) { + _cleanup_free_ char *line = NULL; + char *line_locale; + + r = read_line(fr, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) + break; + + if (locale_enabled) { + /* Just complete writing the file if the new locale was already enabled */ + if (!first_line) + fputc('\n', fw); + fputs(line, fw); + first_line = false; + continue; + } + + line = strstrip(line); + if (isempty(line)) { + fputc('\n', fw); + first_line = false; + continue; + } + + line_locale = line; + if (line_locale[0] == '#') + line_locale = strstrip(line_locale + 1); + else if (strcaseeq_ptr(line_locale, locale_entry)) + return 0; /* the file already had our locale activated, so skip updating it */ + + if (strcaseeq_ptr(line_locale, locale_entry)) { + /* Uncomment existing line for new locale */ + if (!first_line) + fputc('\n', fw); + fputs(locale_entry, fw); + locale_enabled = true; + first_line = false; + continue; + } + + /* The line was not for the locale we want to enable, just copy it */ + if (!first_line) + fputc('\n', fw); + fputs(line, fw); + first_line = false; + } + } + + /* Add locale to enable to the end of the file if it was not found as commented line */ + if (!locale_enabled) { + if (!write_new) + fputc('\n', fw); + fputs(locale_entry, fw); + } + fputc('\n', fw); + + r = fflush_sync_and_check(fw); + if (r < 0) + return r; + + if (rename(temp_path, "/etc/locale.gen") < 0) + return -errno; + temp_path = mfree(temp_path); + + return 0; +#else + return -EOPNOTSUPP; +#endif +} + +int locale_gen_run(void) { +#if HAVE_LOCALEGEN + pid_t pid; + int r; + + r = safe_fork("(sd-localegen)", FORK_RESET_SIGNALS|FORK_RLIMIT_NOFILE_SAFE|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_WAIT, &pid); + if (r < 0) + return r; + if (r == 0) { + execl(LOCALEGEN_PATH, LOCALEGEN_PATH, NULL); + _exit(EXIT_FAILURE); + } + + return 0; +#else + return -EOPNOTSUPP; +#endif +} diff --git a/src/locale/keymap-util.h b/src/locale/keymap-util.h index 49976472e..c087dbcbb 100644 --- a/src/locale/keymap-util.h +++ b/src/locale/keymap-util.h @@ -42,3 +42,7 @@ int x11_convert_to_vconsole(Context *c); int x11_write_data(Context *c); void locale_simplify(char *locale[_VARIABLE_LC_MAX]); int locale_write_data(Context *c, char ***settings); + +bool locale_gen_check_available(void); +int locale_gen_enable_locale(const char *locale); +int locale_gen_run(void); diff --git a/src/locale/localectl.c b/src/locale/localectl.c index 7d2e88766..548ac8eb2 100644 --- a/src/locale/localectl.c +++ b/src/locale/localectl.c @@ -26,6 +26,9 @@ #include "verbs.h" #include "virt.h" +/* Enough time for locale-gen to finish server-side (in case it is in use) */ +#define LOCALE_SLOW_BUS_CALL_TIMEOUT_USEC (2*USEC_PER_MINUTE) + static PagerFlags arg_pager_flags = 0; static bool arg_ask_password = true; static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; @@ -52,7 +55,6 @@ static void status_info_clear(StatusInfo *info) { static void print_overridden_variables(void) { _cleanup_(locale_variables_freep) char *variables[_VARIABLE_LC_MAX] = {}; bool print_warning = true; - LocaleVariable j; int r; if (arg_transport != BUS_TRANSPORT_LOCAL) @@ -79,7 +81,7 @@ static void print_overridden_variables(void) { return; } - for (j = 0; j < _VARIABLE_LC_MAX; j++) + for (LocaleVariable j = 0; j < _VARIABLE_LC_MAX; j++) if (variables[j]) { if (print_warning) { log_warning("Warning: Settings on kernel command line override system locale settings in /etc/locale.conf.\n" @@ -176,7 +178,8 @@ static int set_locale(int argc, char **argv, void *userdata) { if (r < 0) return bus_log_create_error(r); - r = sd_bus_call(bus, m, 0, &error, NULL); + /* We use a longer timeout for the method call in case localed is running locale-gen */ + r = sd_bus_call(bus, m, LOCALE_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL); if (r < 0) return log_error_errno(r, "Failed to issue method call: %s", bus_error_message(&error, r)); @@ -397,12 +400,11 @@ static int help(void) { " -H --host=[USER@]HOST Operate on remote host\n" " -M --machine=CONTAINER Operate on local container\n" " --no-convert Don't convert keyboard mappings\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -503,7 +505,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/locale/localed.c b/src/locale/localed.c index 736dacdee..f44c0bab2 100644 --- a/src/locale/localed.c +++ b/src/locale/localed.c @@ -19,6 +19,7 @@ #include "bus-polkit.h" #include "def.h" #include "dlfcn-util.h" +#include "kbd-util.h" #include "keymap-util.h" #include "locale-util.h" #include "macro.h" @@ -37,8 +38,7 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { _cleanup_strv_free_ char **l_set = NULL; _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - size_t c_set, c_unset; - LocaleVariable p; + size_t c_set = 0, c_unset = 0; int r; assert(bus); @@ -51,7 +51,7 @@ static int locale_update_system_manager(Context *c, sd_bus *bus) { if (!l_set) return log_oom(); - for (p = 0, c_set = 0, c_unset = 0; p < _VARIABLE_LC_MAX; p++) { + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { const char *name; name = locale_variable_to_string(p); @@ -178,7 +178,7 @@ static int property_get_locale( Context *c = userdata; _cleanup_strv_free_ char **l = NULL; - int p, q, r; + int r; r = locale_read_data(c, reply); if (r < 0) @@ -188,7 +188,7 @@ static int property_get_locale( if (!l) return -ENOMEM; - for (p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) { + for (LocaleVariable p = 0, q = 0; p < _VARIABLE_LC_MAX; p++) { char *t; const char *name; @@ -262,6 +262,7 @@ static int property_get_xkb( static int process_locale_list_item( const char *assignment, char *new_locale[static _VARIABLE_LC_MAX], + bool use_localegen, sd_bus_error *error) { assert(assignment); @@ -283,7 +284,7 @@ static int process_locale_list_item( if (!locale_is_valid(e)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s is not valid, refusing.", e); - if (locale_is_installed(e) <= 0) + if (!use_localegen && locale_is_installed(e) <= 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale %s not installed, refusing.", e); if (new_locale[p]) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale variable %s set twice, refusing.", name); @@ -298,6 +299,47 @@ static int process_locale_list_item( return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Locale assignment %s not valid, refusing.", assignment); } +static int locale_gen_process_locale(char *new_locale[static _VARIABLE_LC_MAX], + sd_bus_error *error) { + int r; + assert(new_locale); + + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { + if (p == VARIABLE_LANGUAGE) + continue; + if (isempty(new_locale[p])) + continue; + if (locale_is_installed(new_locale[p])) + continue; + + r = locale_gen_enable_locale(new_locale[p]); + if (r == -ENOEXEC) { + log_error_errno(r, "Refused to enable locale for generation: %m"); + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Specified locale is not installed and non-UTF-8 locale will not be auto-generated: %s", + new_locale[p]); + } else if (r == -EINVAL) { + log_error_errno(r, "Failed to enable invalid locale %s for generation.", new_locale[p]); + return sd_bus_error_setf(error, + SD_BUS_ERROR_INVALID_ARGS, + "Can not enable locale generation for invalid locale: %s", + new_locale[p]); + } else if (r < 0) { + log_error_errno(r, "Failed to enable locale for generation: %m"); + return sd_bus_error_set_errnof(error, r, "Failed to enable locale generation: %m"); + } + + r = locale_gen_run(); + if (r < 0) { + log_error_errno(r, "Failed to generate locale: %m"); + return sd_bus_error_set_errnof(error, r, "Failed to generate locale: %m"); + } + } + + return 0; +} + static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *error) { _cleanup_(locale_variables_freep) char *new_locale[_VARIABLE_LC_MAX] = {}; _cleanup_strv_free_ char **settings = NULL, **l = NULL; @@ -305,6 +347,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er bool modified = false; int interactive, r; char **i; + bool use_localegen; assert(m); assert(c); @@ -317,11 +360,13 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er if (r < 0) return r; + use_localegen = locale_gen_check_available(); + /* If single locale without variable name is provided, then we assume it is LANG=. */ if (strv_length(l) == 1 && !strchr(l[0], '=')) { if (!locale_is_valid(l[0])) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid locale specification: %s", l[0]); - if (locale_is_installed(l[0]) <= 0) + if (!use_localegen && locale_is_installed(l[0]) <= 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified locale is not installed: %s", l[0]); new_locale[VARIABLE_LANG] = strdup(l[0]); @@ -333,7 +378,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er /* Check whether a variable is valid */ STRV_FOREACH(i, l) { - r = process_locale_list_item(*i, new_locale, error); + r = process_locale_list_item(*i, new_locale, use_localegen, error); if (r < 0) return r; } @@ -392,9 +437,17 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er if (r == 0) return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + /* Generate locale in case it is missing and the system is using locale-gen */ + if (use_localegen) { + r = locale_gen_process_locale(new_locale, error); + if (r < 0) + return r; + } + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) free_and_replace(c->locale[p], new_locale[p]); + /* Write locale configuration */ r = locale_write_data(c, &settings); if (r < 0) { log_error_errno(r, "Failed to set locale: %m"); @@ -422,7 +475,7 @@ static int method_set_locale(sd_bus_message *m, void *userdata, sd_bus_error *er static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_error *error) { Context *c = userdata; - const char *keymap, *keymap_toggle; + const char *name, *keymap, *keymap_toggle; int convert, interactive, r; assert(m); @@ -438,17 +491,23 @@ static int method_set_vc_keyboard(sd_bus_message *m, void *userdata, sd_bus_erro r = vconsole_read_data(c, m); if (r < 0) { log_error_errno(r, "Failed to read virtual console keymap data: %m"); - return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Failed to read virtual console keymap data"); + return sd_bus_error_set_errnof(error, r, "Failed to read virtual console keymap data: %m"); + } + + FOREACH_STRING(name, keymap ?: keymap_toggle, keymap ? keymap_toggle : NULL) { + r = keymap_exists(name); /* This also verifies that the keymap name is kosher. */ + if (r < 0) { + log_error_errno(r, "Failed to check keymap %s: %m", name); + return sd_bus_error_set_errnof(error, r, "Failed to check keymap %s: %m", name); + } + if (r == 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Keymap %s is not installed.", name); } if (streq_ptr(keymap, c->vc_keymap) && streq_ptr(keymap_toggle, c->vc_keymap_toggle)) return sd_bus_reply_method_return(m, NULL); - if ((keymap && (!filename_is_valid(keymap) || !string_is_safe(keymap))) || - (keymap_toggle && (!filename_is_valid(keymap_toggle) || !string_is_safe(keymap_toggle)))) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Received invalid keymap data"); - r = bus_verify_polkit_async( m, CAP_SYS_ADMIN, @@ -777,7 +836,7 @@ static int run(int argc, char *argv[]) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-localed.service", "Manage system locale settings and key mappings.", diff --git a/src/locale/meson.build b/src/locale/meson.build index 6e3500d09..4cbf2d278 100644 --- a/src/locale/meson.build +++ b/src/locale/meson.build @@ -32,7 +32,5 @@ endif tests += [ [['src/locale/test-keymap-util.c', 'src/locale/keymap-util.c', - 'src/locale/keymap-util.h'], - [libshared], - []], + 'src/locale/keymap-util.h']], ] diff --git a/src/login/inhibit.c b/src/login/inhibit.c index e18dbc513..e871628b9 100644 --- a/src/login/inhibit.c +++ b/src/login/inhibit.c @@ -90,6 +90,7 @@ static int print_inhibitors(sd_bus *bus) { /* If there's not enough space, shorten the "WHY" column, as it's little more than an explaining comment. */ (void) table_set_weight(table, TABLE_HEADER_CELL(6), 20); + (void) table_set_maximum_width(table, TABLE_HEADER_CELL(0), columns()/2); r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)"); if (r < 0) @@ -130,7 +131,7 @@ static int print_inhibitors(sd_bus *bus) { return bus_log_parse_error(r); if (table_get_rows(table) > 1) { - r = table_set_sort(table, (size_t) 1, (size_t) 0, (size_t) 5, (size_t) 6, (size_t) -1); + r = table_set_sort(table, (size_t) 1, (size_t) 0, (size_t) 5, (size_t) 6); if (r < 0) return table_log_sort_error(r); @@ -173,11 +174,11 @@ static int help(void) { " --why=STRING A descriptive string why is being inhibited\n" " --mode=MODE One of block or delay\n" " --list List active inhibitors\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -294,7 +295,7 @@ static int run(int argc, char *argv[]) { pid_t pid; /* Ignore SIGINT and allow the forked process to receive it */ - (void) ignore_signals(SIGINT, -1); + (void) ignore_signals(SIGINT); if (!arg_who) { w = strv_join(argv + optind, " "); diff --git a/src/login/loginctl.c b/src/login/loginctl.c index 695d18bba..4ece3fda5 100644 --- a/src/login/loginctl.c +++ b/src/login/loginctl.c @@ -22,6 +22,7 @@ #include "main-func.h" #include "memory-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "pretty-print.h" #include "process-util.h" @@ -89,7 +90,7 @@ static int show_table(Table *table, const char *word) { assert(word); if (table_get_rows(table) > 1 || OUTPUT_MODE_IS_JSON(arg_output)) { - r = table_set_sort(table, (size_t) 0, (size_t) -1); + r = table_set_sort(table, (size_t) 0); if (r < 0) return table_log_sort_error(r); @@ -1276,12 +1277,11 @@ static int help(int argc, char *argv[], void *userdata) { " short-monotonic, short-unix, verbose, export,\n" " json, json-pretty, json-sse, json-seq, cat,\n" " with-unit)\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -1372,8 +1372,7 @@ static int parse_argv(int argc, char *argv[]) { arg_output = output_mode_from_string(optarg); if (arg_output < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown output '%s'.", optarg); + return log_error_errno(arg_output, "Unknown output '%s'.", optarg); if (OUTPUT_MODE_IS_JSON(arg_output)) arg_legend = false; @@ -1397,15 +1396,9 @@ static int parse_argv(int argc, char *argv[]) { break; case 's': - if (streq(optarg, "help")) { - DUMP_STRING_TABLE(signal, int, _NSIG); - return 0; - } - - arg_signal = signal_from_string(optarg); - if (arg_signal < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse signal string %s.", optarg); + r = parse_signal_argument(optarg, &arg_signal); + if (r <= 0) + return r; break; case 'H': @@ -1465,7 +1458,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/login/logind-action.h b/src/login/logind-action.h index 73aa20bbb..0baad37a8 100644 --- a/src/login/logind-action.h +++ b/src/login/logind-action.h @@ -15,7 +15,7 @@ typedef enum HandleAction { HANDLE_SUSPEND_THEN_HIBERNATE, HANDLE_LOCK, _HANDLE_ACTION_MAX, - _HANDLE_ACTION_INVALID = -1 + _HANDLE_ACTION_INVALID = -EINVAL, } HandleAction; #include "logind-inhibit.h" diff --git a/src/login/logind-brightness.c b/src/login/logind-brightness.c index a6a160339..d6b9289ea 100644 --- a/src/login/logind-brightness.c +++ b/src/login/logind-brightness.c @@ -44,9 +44,9 @@ typedef struct BrightnessWriter { sd_event_source* child_event_source; } BrightnessWriter; -static void brightness_writer_free(BrightnessWriter *w) { +static BrightnessWriter* brightness_writer_free(BrightnessWriter *w) { if (!w) - return; + return NULL; if (w->manager && w->path) (void) hashmap_remove_value(w->manager->brightness_writers, w->path, w); @@ -59,7 +59,7 @@ static void brightness_writer_free(BrightnessWriter *w) { w->child_event_source = sd_event_source_unref(w->child_event_source); - free(w); + return mfree(w); } DEFINE_TRIVIAL_CLEANUP_FUNC(BrightnessWriter*, brightness_writer_free); @@ -137,7 +137,7 @@ static int brightness_writer_fork(BrightnessWriter *w) { assert(w->child == 0); assert(!w->child_event_source); - r = safe_fork("(sd-bright)", FORK_DEATHSIG|FORK_NULL_STDIO|FORK_CLOSE_ALL_FDS|FORK_LOG, &w->child); + r = safe_fork("(sd-bright)", FORK_DEATHSIG|FORK_NULL_STDIO|FORK_CLOSE_ALL_FDS|FORK_LOG|FORK_REOPEN_LOG, &w->child); if (r < 0) return r; if (r == 0) { @@ -217,10 +217,6 @@ int manager_write_brightness( return 0; } - r = hashmap_ensure_allocated(&m->brightness_writers, &brightness_writer_hash_ops); - if (r < 0) - return log_oom(); - w = new(BrightnessWriter, 1); if (!w) return log_oom(); @@ -234,9 +230,12 @@ int manager_write_brightness( if (!w->path) return log_oom(); - r = hashmap_put(m->brightness_writers, w->path, w); + r = hashmap_ensure_put(&m->brightness_writers, &brightness_writer_hash_ops, w->path, w); + if (r == -ENOMEM) + return log_oom(); if (r < 0) return log_error_errno(r, "Failed to add brightness writer to hashmap: %m"); + w->manager = m; r = set_add_message(&w->current_messages, message); diff --git a/src/login/logind-button.c b/src/login/logind-button.c index 0e38b5f57..0ee670206 100644 --- a/src/login/logind-button.c +++ b/src/login/logind-button.c @@ -68,19 +68,9 @@ void button_free(Button *b) { } int button_set_seat(Button *b, const char *sn) { - char *s; - assert(b); - assert(sn); - s = strdup(sn); - if (!s) - return -ENOMEM; - - free(b->seat); - b->seat = s; - - return 0; + return free_and_strdup(&b->seat, sn); } static void button_lid_switch_handle_action(Manager *manager, bool is_edge) { diff --git a/src/login/logind-core.c b/src/login/logind-core.c index 3595d7a77..2ecf2120f 100644 --- a/src/login/logind-core.c +++ b/src/login/logind-core.c @@ -246,7 +246,7 @@ int manager_process_seat_device(Manager *m, sd_device *d) { assert(m); - if (device_for_action(d, DEVICE_ACTION_REMOVE) || + if (device_for_action(d, SD_DEVICE_REMOVE) || sd_device_has_current_tag(d, "seat") <= 0) { const char *syspath; @@ -317,7 +317,7 @@ int manager_process_button_device(Manager *m, sd_device *d) { if (r < 0) return r; - if (device_for_action(d, DEVICE_ACTION_REMOVE) || + if (device_for_action(d, SD_DEVICE_REMOVE) || sd_device_has_current_tag(d, "power-switch") <= 0) { b = hashmap_get(m->buttons, sysname); diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index b95af1a9f..a539a2e97 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -30,6 +30,7 @@ #include "format-util.h" #include "fs-util.h" #include "logind-dbus.h" +#include "logind-polkit.h" #include "logind-seat-dbus.h" #include "logind-session-dbus.h" #include "logind-user-dbus.h" @@ -1047,15 +1048,7 @@ static int method_activate_session_on_seat(sd_bus_message *message, void *userda return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", session_name, seat_name); - r = bus_verify_polkit_async( - message, - CAP_SYS_ADMIN, - "org.freedesktop.login1.chvt", - NULL, - false, - UID_INVALID, - &m->polkit_registry, - error); + r = check_polkit_chvt(message, m, error); if (r < 0) return r; if (r == 0) @@ -1644,7 +1637,7 @@ static int execute_shutdown_or_sleep( m->action_what = w; /* Make sure the lid switch is ignored for a while */ - manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec); + manager_set_lid_switch_ignore(m, usec_add(now(CLOCK_MONOTONIC), m->holdoff_timeout_usec)); return 0; @@ -1793,14 +1786,14 @@ static int verify_shutdown_creds( Manager *m, sd_bus_message *message, InhibitWhat w, - bool interactive, const char *action, const char *action_multiple_sessions, const char *action_ignore_inhibit, + uint64_t flags, sd_bus_error *error) { _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; - bool multiple_sessions, blocked; + bool multiple_sessions, blocked, interactive; uid_t uid; int r; @@ -1823,6 +1816,7 @@ static int verify_shutdown_creds( multiple_sessions = r > 0; blocked = manager_is_inhibited(m, w, INHIBIT_BLOCK, NULL, false, true, uid, NULL); + interactive = flags & SD_LOGIND_INTERACTIVE; if (multiple_sessions && action_multiple_sessions) { r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_multiple_sessions, NULL, interactive, UID_INVALID, &m->polkit_registry, error); @@ -1832,12 +1826,19 @@ static int verify_shutdown_creds( return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ } - if (blocked && action_ignore_inhibit) { - r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); - if (r < 0) - return r; - if (r == 0) - return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + if (blocked) { + /* We don't check polkit for root here, because you can't be more privileged than root */ + if (uid == 0 && (flags & SD_LOGIND_ROOT_CHECK_INHIBITORS)) + return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, + "Access denied to root due to active block inhibitor"); + + if (action_ignore_inhibit) { + r = bus_verify_polkit_async(message, CAP_SYS_BOOT, action_ignore_inhibit, NULL, interactive, UID_INVALID, &m->polkit_registry, error); + if (r < 0) + return r; + if (r == 0) + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ + } } if (!multiple_sessions && !blocked && action) { @@ -1860,9 +1861,11 @@ static int method_do_shutdown_or_sleep( const char *action_multiple_sessions, const char *action_ignore_inhibit, const char *sleep_verb, + bool with_flags, sd_bus_error *error) { - int interactive, r; + uint64_t flags; + int r; assert(m); assert(message); @@ -1870,9 +1873,25 @@ static int method_do_shutdown_or_sleep( assert(w >= 0); assert(w <= _INHIBIT_WHAT_MAX); - r = sd_bus_message_read(message, "b", &interactive); - if (r < 0) - return r; + if (with_flags) { + /* New style method: with flags parameter (and interactive bool in the bus message header) */ + r = sd_bus_message_read(message, "t", &flags); + if (r < 0) + return r; + if ((flags & ~SD_LOGIND_SHUTDOWN_AND_SLEEP_FLAGS_PUBLIC) != 0) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); + } else { + /* Old style method: no flags parameter, but interactive bool passed as boolean in + * payload. Let's convert this argument to the new-style flags parameter for our internal + * use. */ + int interactive; + + r = sd_bus_message_read(message, "b", &interactive); + if (r < 0) + return r; + + flags = interactive ? SD_LOGIND_INTERACTIVE : 0; + } /* Don't allow multiple jobs being executed at the same time */ if (m->action_what > 0) @@ -1891,8 +1910,8 @@ static int method_do_shutdown_or_sleep( return r; } - r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions, - action_ignore_inhibit, error); + r = verify_shutdown_creds(m, message, w, action, action_multiple_sessions, + action_ignore_inhibit, flags, error); if (r != 0) return r; @@ -1914,6 +1933,7 @@ static int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error "org.freedesktop.login1.power-off-multiple-sessions", "org.freedesktop.login1.power-off-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "PowerOffWithFlags"), error); } @@ -1928,6 +1948,7 @@ static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error * "org.freedesktop.login1.reboot-multiple-sessions", "org.freedesktop.login1.reboot-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "RebootWithFlags"), error); } @@ -1942,6 +1963,7 @@ static int method_halt(sd_bus_message *message, void *userdata, sd_bus_error *er "org.freedesktop.login1.halt-multiple-sessions", "org.freedesktop.login1.halt-ignore-inhibit", NULL, + sd_bus_message_is_method_call(message, NULL, "HaltWithFlags"), error); } @@ -1956,6 +1978,7 @@ static int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error "org.freedesktop.login1.suspend-multiple-sessions", "org.freedesktop.login1.suspend-ignore-inhibit", "suspend", + sd_bus_message_is_method_call(message, NULL, "SuspendWithFlags"), error); } @@ -1970,6 +1993,7 @@ static int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_erro "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hibernate", + sd_bus_message_is_method_call(message, NULL, "HibernateWithFlags"), error); } @@ -1984,6 +2008,7 @@ static int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_e "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hybrid-sleep", + sd_bus_message_is_method_call(message, NULL, "HybridSleepWithFlags"), error); } @@ -1998,6 +2023,7 @@ static int method_suspend_then_hibernate(sd_bus_message *message, void *userdata "org.freedesktop.login1.hibernate-multiple-sessions", "org.freedesktop.login1.hibernate-ignore-inhibit", "hybrid-sleep", + sd_bus_message_is_method_call(message, NULL, "SuspendThenHibernateWithFlags"), error); } @@ -2185,8 +2211,8 @@ static int method_schedule_shutdown(sd_bus_message *message, void *userdata, sd_ } else return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unsupported shutdown type"); - r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, false, - action, action_multiple_sessions, action_ignore_inhibit, error); + r = verify_shutdown_creds(m, message, INHIBIT_SHUTDOWN, action, action_multiple_sessions, + action_ignore_inhibit, 0, error); if (r != 0) return r; @@ -3538,42 +3564,84 @@ static const sd_bus_vtable manager_vtable[] = { NULL,, method_poweroff, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("PowerOffWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_poweroff, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Reboot", "b", SD_BUS_PARAM(interactive), NULL,, method_reboot, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("RebootWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_reboot, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Halt", "b", SD_BUS_PARAM(interactive), NULL,, method_halt, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HaltWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_halt, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Suspend", "b", SD_BUS_PARAM(interactive), NULL,, method_suspend, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SuspendWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_suspend, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("Hibernate", "b", SD_BUS_PARAM(interactive), NULL,, method_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HibernateWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_hibernate, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("HybridSleep", "b", SD_BUS_PARAM(interactive), NULL,, method_hybrid_sleep, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("HybridSleepWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_hybrid_sleep, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernate", "b", SD_BUS_PARAM(interactive), NULL,, method_suspend_then_hibernate, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_NAMES("SuspendThenHibernateWithFlags", + "t", + SD_BUS_PARAM(flags), + NULL,, + method_suspend_then_hibernate, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD_WITH_NAMES("CanPowerOff", NULL,, "s", @@ -4016,7 +4084,7 @@ int manager_start_scope( return r; /* disable TasksMax= for the session scope, rely on the slice setting for it */ - r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", (uint64_t)-1); + r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", UINT64_MAX); if (r < 0) return bus_log_create_error(r); diff --git a/src/login/logind-gperf.gperf b/src/login/logind-gperf.gperf index 2c152d2ce..25e429c5a 100644 --- a/src/login/logind-gperf.gperf +++ b/src/login/logind-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") diff --git a/src/login/logind-inhibit.h b/src/login/logind-inhibit.h index 124bdb662..871e69a03 100644 --- a/src/login/logind-inhibit.h +++ b/src/login/logind-inhibit.h @@ -13,14 +13,14 @@ typedef enum InhibitWhat { INHIBIT_HANDLE_LID_SWITCH = 1 << 6, INHIBIT_HANDLE_REBOOT_KEY = 1 << 7, _INHIBIT_WHAT_MAX = 1 << 8, - _INHIBIT_WHAT_INVALID = -1 + _INHIBIT_WHAT_INVALID = -EINVAL, } InhibitWhat; typedef enum InhibitMode { INHIBIT_BLOCK, INHIBIT_DELAY, _INHIBIT_MODE_MAX, - _INHIBIT_MODE_INVALID = -1 + _INHIBIT_MODE_INVALID = -EINVAL, } InhibitMode; #include "logind.h" diff --git a/src/login/logind-polkit.c b/src/login/logind-polkit.c new file mode 100644 index 000000000..d221bee8c --- /dev/null +++ b/src/login/logind-polkit.c @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "bus-polkit.h" +#include "logind-polkit.h" +#include "missing_capability.h" +#include "user-util.h" + +int check_polkit_chvt(sd_bus_message *message, Manager *manager, sd_bus_error *error) { +#if ENABLE_POLKIT + return bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.login1.chvt", + NULL, + false, + UID_INVALID, + &manager->polkit_registry, + error); +#else + /* Allow chvt when polkit is not present. This allows a service to start a graphical session as a + * non-root user when polkit is not compiled in, more closely matching the default polkit policy */ + return 1; +#endif +} diff --git a/src/login/logind-polkit.h b/src/login/logind-polkit.h new file mode 100644 index 000000000..8c124f834 --- /dev/null +++ b/src/login/logind-polkit.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +#include "sd-bus.h" + +#include "bus-object.h" +#include "logind.h" + +int check_polkit_chvt(sd_bus_message *message, Manager *manager, sd_bus_error *error); diff --git a/src/login/logind-seat-dbus.c b/src/login/logind-seat-dbus.c index a60ed2d3c..9c2625cdc 100644 --- a/src/login/logind-seat-dbus.c +++ b/src/login/logind-seat-dbus.c @@ -9,6 +9,7 @@ #include "bus-polkit.h" #include "bus-util.h" #include "logind-dbus.h" +#include "logind-polkit.h" #include "logind-seat-dbus.h" #include "logind-seat.h" #include "logind-session-dbus.h" @@ -179,15 +180,7 @@ static int method_activate_session(sd_bus_message *message, void *userdata, sd_b if (session->seat != s) return sd_bus_error_setf(error, BUS_ERROR_SESSION_NOT_ON_SEAT, "Session %s not on seat %s", name, s->id); - r = bus_verify_polkit_async( - message, - CAP_SYS_ADMIN, - "org.freedesktop.login1.chvt", - NULL, - false, - UID_INVALID, - &s->manager->polkit_registry, - error); + r = check_polkit_chvt(message, s->manager, error); if (r < 0) return r; if (r == 0) @@ -215,15 +208,7 @@ static int method_switch_to(sd_bus_message *message, void *userdata, sd_bus_erro if (to <= 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid virtual terminal"); - r = bus_verify_polkit_async( - message, - CAP_SYS_ADMIN, - "org.freedesktop.login1.chvt", - NULL, - false, - UID_INVALID, - &s->manager->polkit_registry, - error); + r = check_polkit_chvt(message, s->manager, error); if (r < 0) return r; if (r == 0) @@ -243,15 +228,7 @@ static int method_switch_to_next(sd_bus_message *message, void *userdata, sd_bus assert(message); assert(s); - r = bus_verify_polkit_async( - message, - CAP_SYS_ADMIN, - "org.freedesktop.login1.chvt", - NULL, - false, - UID_INVALID, - &s->manager->polkit_registry, - error); + r = check_polkit_chvt(message, s->manager, error); if (r < 0) return r; if (r == 0) @@ -271,15 +248,7 @@ static int method_switch_to_previous(sd_bus_message *message, void *userdata, sd assert(message); assert(s); - r = bus_verify_polkit_async( - message, - CAP_SYS_ADMIN, - "org.freedesktop.login1.chvt", - NULL, - false, - UID_INVALID, - &s->manager->polkit_registry, - error); + r = check_polkit_chvt(message, s->manager, error); if (r < 0) return r; if (r == 0) diff --git a/src/login/logind-seat.c b/src/login/logind-seat.c index 10cc7d960..b70afea62 100644 --- a/src/login/logind-seat.c +++ b/src/login/logind-seat.c @@ -8,11 +8,11 @@ #include "sd-messages.h" #include "alloc-util.h" +#include "devnode-acl.h" #include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "format-util.h" -#include "logind-acl.h" #include "logind-seat-dbus.h" #include "logind-seat.h" #include "logind-session-dbus.h" diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index b5d240be6..d342dc419 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -11,6 +11,7 @@ #include "fd-util.h" #include "logind-brightness.h" #include "logind-dbus.h" +#include "logind-polkit.h" #include "logind-seat-dbus.h" #include "logind-session-dbus.h" #include "logind-session-device.h" @@ -192,15 +193,7 @@ int bus_session_method_activate(sd_bus_message *message, void *userdata, sd_bus_ assert(message); assert(s); - r = bus_verify_polkit_async( - message, - CAP_SYS_ADMIN, - "org.freedesktop.login1.chvt", - NULL, - false, - UID_INVALID, - &s->manager->polkit_registry, - error); + r = check_polkit_chvt(message, s->manager, error); if (r < 0) return r; if (r == 0) diff --git a/src/login/logind-session.h b/src/login/logind-session.h index 1b59bdbe7..5c35071dc 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -15,7 +15,7 @@ typedef enum SessionState { SESSION_ACTIVE, /* Logged in and in the fg */ SESSION_CLOSING, /* Logged out, but scope is still there */ _SESSION_STATE_MAX, - _SESSION_STATE_INVALID = -1 + _SESSION_STATE_INVALID = -EINVAL, } SessionState; typedef enum SessionClass { @@ -24,7 +24,7 @@ typedef enum SessionClass { SESSION_LOCK_SCREEN, SESSION_BACKGROUND, _SESSION_CLASS_MAX, - _SESSION_CLASS_INVALID = -1 + _SESSION_CLASS_INVALID = -EINVAL, } SessionClass; typedef enum SessionType { @@ -35,7 +35,7 @@ typedef enum SessionType { SESSION_MIR, SESSION_WEB, _SESSION_TYPE_MAX, - _SESSION_TYPE_INVALID = -1 + _SESSION_TYPE_INVALID = -EINVAL, } SessionType; #define SESSION_TYPE_IS_GRAPHICAL(type) IN_SET(type, SESSION_X11, SESSION_WAYLAND, SESSION_MIR) @@ -44,7 +44,7 @@ enum KillWho { KILL_LEADER, KILL_ALL, _KILL_WHO_MAX, - _KILL_WHO_INVALID = -1 + _KILL_WHO_INVALID = -EINVAL, }; typedef enum TTYValidity { @@ -52,7 +52,7 @@ typedef enum TTYValidity { TTY_FROM_UTMP, TTY_UTMP_INCONSISTENT, /* may happen on ssh sessions with multiplexed TTYs */ _TTY_VALIDITY_MAX, - _TTY_VALIDITY_INVALID = -1, + _TTY_VALIDITY_INVALID = -EINVAL, } TTYValidity; struct Session { diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 9b3ec0790..a2c468e8d 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -19,11 +19,12 @@ #include "label.h" #include "limits-util.h" #include "logind-dbus.h" -#include "logind-user.h" #include "logind-user-dbus.h" +#include "logind-user.h" #include "mkdir.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "rm-rf.h" #include "serialize.h" #include "special.h" @@ -907,9 +908,9 @@ int config_parse_tmpfs_size( assert(data); /* First, try to parse as percentage */ - r = parse_permille(rvalue); - if (r > 0 && r < 1000) - *sz = physical_memory_scale(r, 1000U); + r = parse_permyriad(rvalue); + if (r > 0) + *sz = physical_memory_scale(r, 10000U); else { uint64_t k; diff --git a/src/login/logind-user.h b/src/login/logind-user.h index 2c5f993fa..21b9f8f34 100644 --- a/src/login/logind-user.h +++ b/src/login/logind-user.h @@ -16,7 +16,7 @@ typedef enum UserState { USER_ACTIVE, /* User logged in and has a session in the fg */ USER_CLOSING, /* User logged out, but processes still remain and lingering is not enabled */ _USER_STATE_MAX, - _USER_STATE_INVALID = -1 + _USER_STATE_INVALID = -EINVAL, } UserState; struct User { diff --git a/src/login/logind.c b/src/login/logind.c index 3ddc7a074..4887889fa 100644 --- a/src/login/logind.c +++ b/src/login/logind.c @@ -578,7 +578,7 @@ static int manager_dispatch_vcsa_udev(sd_device_monitor *monitor, sd_device *dev if (sd_device_get_sysname(device, &name) >= 0 && startswith(name, "vcsa") && - device_for_action(device, DEVICE_ACTION_REMOVE)) + device_for_action(device, SD_DEVICE_REMOVE)) seat_preallocate_vts(m->seat0); return 0; @@ -788,7 +788,7 @@ static int manager_connect_console(Manager *m) { "Not enough real-time signals available: %u-%u", SIGRTMIN, SIGRTMAX); - assert_se(ignore_signals(SIGRTMIN + 1, -1) >= 0); + assert_se(ignore_signals(SIGRTMIN + 1) >= 0); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGRTMIN, -1) >= 0); r = sd_event_add_signal(m->event, NULL, SIGRTMIN, manager_vt_switch, m); @@ -1148,7 +1148,7 @@ static int manager_run(Manager *m) { if (r > 0) continue; - r = sd_event_run(m->event, (uint64_t) -1); + r = sd_event_run(m->event, UINT64_MAX); if (r < 0) return r; } @@ -1160,7 +1160,7 @@ static int run(int argc, char *argv[]) { int r; log_set_facility(LOG_AUTH); - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-logind.service", "Manager for user logins and devices and privileged operations.", diff --git a/src/login/logind.conf.in b/src/login/logind.conf.in index 8b220267f..76f529c17 100644 --- a/src/login/logind.conf.in +++ b/src/login/logind.conf.in @@ -1,13 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. +# +# Use 'systemd-analyze cat-config systemd/logind.conf' to display the full config. # # See logind.conf(5) for details. diff --git a/src/login/meson.build b/src/login/meson.build index e09610960..156c391d8 100644 --- a/src/login/meson.build +++ b/src/login/meson.build @@ -12,7 +12,6 @@ logind_gperf_c = custom_target( command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) liblogind_core_sources = files(''' - logind-acl.h logind-action.c logind-action.h logind-brightness.c @@ -26,6 +25,8 @@ liblogind_core_sources = files(''' logind-device.h logind-inhibit.c logind-inhibit.h + logind-polkit.c + logind-polkit.h logind-seat-dbus.c logind-seat-dbus.h logind-seat.c @@ -45,11 +46,6 @@ liblogind_core_sources = files(''' liblogind_core_sources += [logind_gperf_c] -logind_acl_c = files('logind-acl.c') -if conf.get('HAVE_ACL') == 1 - liblogind_core_sources += logind_acl_c -endif - liblogind_core = static_library( 'logind-core', liblogind_core_sources, @@ -74,7 +70,7 @@ if conf.get('ENABLE_LOGIND') == 1 input : 'logind.conf.in', output : 'logind.conf', configuration : substs) - if install_sysconfdir + if install_sysconfdir_samples install_data(logind_conf, install_dir : pkgsysconfdir) endif @@ -122,3 +118,17 @@ if conf.get('ENABLE_LOGIND') == 1 install : pamconfdir != 'no', install_dir : pamconfdir) endif + +############################################################ + +tests += [ + [['src/login/test-login-shared.c']], + + [['src/login/test-inhibit.c'], + [], [], [], '', 'manual'], + + [['src/login/test-login-tables.c'], + [liblogind_core, + libshared], + [threads]], +] diff --git a/src/login/org.freedesktop.login1.conf b/src/login/org.freedesktop.login1.conf index ac14942ba..95d2ef0f0 100644 --- a/src/login/org.freedesktop.login1.conf +++ b/src/login/org.freedesktop.login1.conf @@ -130,30 +130,58 @@ send_interface="org.freedesktop.login1.Manager" send_member="PowerOff"/> + + + + + + + + + + + + + + diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 8e7a94db5..2021c31bd 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -34,6 +34,7 @@ #include "pam-util.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "process-util.h" #include "rlimit-util.h" #include "socket-util.h" @@ -327,16 +328,16 @@ static int append_session_memory_max(pam_handle_t *handle, sd_bus_message *m, co return PAM_SUCCESS; if (streq(limit, "infinity")) { - r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", (uint64_t)-1); + r = sd_bus_message_append(m, "(sv)", "MemoryMax", "t", UINT64_MAX); if (r < 0) return pam_bus_log_create_error(handle, r); return PAM_SUCCESS; } - r = parse_permille(limit); + r = parse_permyriad(limit); if (r >= 0) { - r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U)); + r = sd_bus_message_append(m, "(sv)", "MemoryMaxScale", "u", UINT32_SCALE_FROM_PERMYRIAD(r)); if (r < 0) return pam_bus_log_create_error(handle, r); diff --git a/src/login/sysfs-show.c b/src/login/sysfs-show.c index 5a19dbfef..5c3af06ca 100644 --- a/src/login/sysfs-show.c +++ b/src/login/sysfs-show.c @@ -32,7 +32,7 @@ static int show_sysfs_one( assert(prefix); if (flags & OUTPUT_FULL_WIDTH) - max_width = (size_t) -1; + max_width = SIZE_MAX; else if (n_columns < 10) max_width = 10; else @@ -113,7 +113,7 @@ static int show_sysfs_one( return -ENOMEM; r = show_sysfs_one(seat, dev_list, i_dev, n_dev, sysfs, p, - n_columns == (unsigned) -1 || n_columns < 2 ? n_columns : n_columns - 2, + n_columns == UINT_MAX || n_columns < 2 ? n_columns : n_columns - 2, flags); if (r < 0) return r; diff --git a/src/machine-id-setup/machine-id-setup-main.c b/src/machine-id-setup/machine-id-setup-main.c index c35da05ff..69fb71cdc 100644 --- a/src/machine-id-setup/machine-id-setup-main.c +++ b/src/machine-id-setup/machine-id-setup-main.c @@ -10,6 +10,7 @@ #include "log.h" #include "machine-id-setup.h" #include "main-func.h" +#include "parse-argument.h" #include "path-util.h" #include "pretty-print.h" #include "util.h" @@ -35,10 +36,9 @@ static int help(void) { " --root=ROOT Filesystem root\n" " --commit Commit transient ID\n" " --print Print used machine ID\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -77,7 +77,7 @@ static int parse_argv(int argc, char *argv[]) { return version(); case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, true, &arg_root); + r = parse_path_argument(optarg, true, &arg_root); if (r < 0) return r; break; diff --git a/src/machine/image-dbus.c b/src/machine/image-dbus.c index c157aaf33..309de0b11 100644 --- a/src/machine/image-dbus.c +++ b/src/machine/image-dbus.c @@ -8,6 +8,7 @@ #include "bus-label.h" #include "bus-polkit.h" #include "copy.h" +#include "discover-image.h" #include "dissect-image.h" #include "fd-util.h" #include "fileio.h" @@ -15,9 +16,9 @@ #include "image-dbus.h" #include "io-util.h" #include "loop-util.h" -#include "machine-image.h" #include "missing_capability.h" #include "mount-util.h" +#include "os-util.h" #include "process-util.h" #include "raw-clone.h" #include "strv.h" @@ -390,10 +391,6 @@ static int image_object_find(sd_bus *bus, const char *path, const char *interfac return 1; } - r = hashmap_ensure_allocated(&m->image_cache, &image_hash_ops); - if (r < 0) - return r; - if (!m->image_cache_defer_event) { r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m); if (r < 0) @@ -408,7 +405,7 @@ static int image_object_find(sd_bus *bus, const char *path, const char *interfac if (r < 0) return r; - r = image_find(IMAGE_MACHINE, e, &image); + r = image_find(IMAGE_MACHINE, e, NULL, &image); if (r == -ENOENT) return 0; if (r < 0) @@ -416,7 +413,7 @@ static int image_object_find(sd_bus *bus, const char *path, const char *interfac image->userdata = m; - r = hashmap_put(m->image_cache, image->name, image); + r = hashmap_ensure_put(&m->image_cache, &image_hash_ops, image->name, image); if (r < 0) { image_unref(image); return r; @@ -452,7 +449,7 @@ static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, images); + r = image_discover(IMAGE_MACHINE, NULL, images); if (r < 0) return r; diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index bb67beb66..e7c4ed3c7 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -32,6 +32,7 @@ #include "missing_capability.h" #include "mkdir.h" #include "mount-util.h" +#include "mountpoint-util.h" #include "namespace-util.h" #include "os-util.h" #include "path-util.h" @@ -393,7 +394,7 @@ int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, s if (r < 0) _exit(EXIT_FAILURE); - r = copy_bytes(fd, pair[1], (uint64_t) -1, 0); + r = copy_bytes(fd, pair[1], UINT64_MAX, 0); if (r < 0) _exit(EXIT_FAILURE); @@ -487,7 +488,7 @@ static int container_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) { if (r < 0) return r; - if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0) + if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader) < 0) return -ENOMEM; bus->address = address; @@ -809,17 +810,9 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu } int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bus_error *error) { - _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; - char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p; - bool mount_slave_created = false, mount_slave_mounted = false, - mount_tmp_created = false, mount_tmp_mounted = false, - mount_outside_created = false, mount_outside_mounted = false; - _cleanup_free_ char *chased_src = NULL; int read_only, make_file_or_directory; - const char *dest, *src; + const char *dest, *src, *propagate_directory; Machine *m = userdata; - struct stat st; - pid_t child; uid_t uid; int r; @@ -834,12 +827,12 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu return r; if (!path_is_absolute(src) || !path_is_normalized(src)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../."); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and normalized."); if (isempty(dest)) dest = src; else if (!path_is_absolute(dest) || !path_is_normalized(dest)) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../."); + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and normalized."); r = bus_verify_polkit_async( message, @@ -861,212 +854,15 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu if (uid != 0) return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Can't bind mount on container with user namespacing applied."); - /* One day, when bind mounting /proc/self/fd/n works across - * namespace boundaries we should rework this logic to make - * use of it... */ - - p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/"); - if (laccess(p, F_OK) < 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points."); - - r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, &chased_src, NULL); + propagate_directory = strjoina("/run/systemd/nspawn/propagate/", m->name); + r = bind_mount_in_namespace(m->leader, + propagate_directory, + "/run/host/incoming/", + src, dest, read_only, make_file_or_directory); if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to resolve source path: %m"); + return sd_bus_error_set_errnof(error, r, "Failed to mount %s on %s in machine's namespace: %m", src, dest); - if (lstat(chased_src, &st) < 0) - return sd_bus_error_set_errnof(error, errno, "Failed to stat() source path: %m"); - if (S_ISLNK(st.st_mode)) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safe… */ - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Source directory can't be a symbolic link"); - - /* Our goal is to install a new bind mount into the container, - possibly read-only. This is irritatingly complex - unfortunately, currently. - - First, we start by creating a private playground in /tmp, - that we can mount MS_SLAVE. (Which is necessary, since - MS_MOVE cannot be applied to mounts with MS_SHARED parent - mounts.) */ - - if (!mkdtemp(mount_slave)) - return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave); - - mount_slave_created = true; - - r = mount_nofollow_verbose(LOG_DEBUG, mount_slave, mount_slave, NULL, MS_BIND, NULL); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to make bind mount %s: %m", mount_slave); - goto finish; - } - - mount_slave_mounted = true; - - r = mount_nofollow_verbose(LOG_DEBUG, NULL, mount_slave, NULL, MS_SLAVE, NULL); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to remount slave %s: %m", mount_slave); - goto finish; - } - - /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */ - mount_tmp = strjoina(mount_slave, "/mount"); - if (S_ISDIR(st.st_mode)) - r = mkdir_errno_wrapper(mount_tmp, 0700); - else - r = touch(mount_tmp); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to create temporary mount point %s: %m", mount_tmp); - goto finish; - } - - mount_tmp_created = true; - - r = mount_nofollow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to mount %s: %m", chased_src); - goto finish; - } - - mount_tmp_mounted = true; - - /* Third, we remount the new bind mount read-only if requested. */ - if (read_only) { - r = mount_nofollow_verbose(LOG_DEBUG, NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to remount read-only %s: %m", mount_tmp); - goto finish; - } - } - - /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only - * right-away. */ - - mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX"); - if (S_ISDIR(st.st_mode)) - r = mkdtemp(mount_outside) ? 0 : -errno; - else { - r = mkostemp_safe(mount_outside); - safe_close(r); - } - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Cannot create propagation file or directory %s: %m", mount_outside); - goto finish; - } - - mount_outside_created = true; - - r = mount_nofollow_verbose(LOG_DEBUG, mount_tmp, mount_outside, NULL, MS_MOVE, NULL); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to move %s to %s: %m", mount_tmp, mount_outside); - goto finish; - } - - mount_outside_mounted = true; - mount_tmp_mounted = false; - - if (S_ISDIR(st.st_mode)) - (void) rmdir(mount_tmp); - else - (void) unlink(mount_tmp); - mount_tmp_created = false; - - (void) umount_verbose(LOG_DEBUG, mount_slave, UMOUNT_NOFOLLOW); - mount_slave_mounted = false; - - (void) rmdir(mount_slave); - mount_slave_created = false; - - if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) { - r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m"); - goto finish; - } - - r = safe_fork("(sd-bindmnt)", FORK_RESET_SIGNALS, &child); - if (r < 0) { - sd_bus_error_set_errnof(error, r, "Failed to fork(): %m"); - goto finish; - } - if (r == 0) { - const char *mount_inside, *q; - int mntfd; - - errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); - - q = procfs_file_alloca(m->leader, "ns/mnt"); - mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC); - if (mntfd < 0) { - r = log_error_errno(errno, "Failed to open mount namespace of leader: %m"); - goto child_fail; - } - - if (setns(mntfd, CLONE_NEWNS) < 0) { - r = log_error_errno(errno, "Failed to join namespace of leader: %m"); - goto child_fail; - } - - if (make_file_or_directory) { - if (S_ISDIR(st.st_mode)) - (void) mkdir_p(dest, 0755); - else { - (void) mkdir_parents(dest, 0755); - (void) mknod(dest, S_IFREG|0600, 0); - } - } - - mount_inside = strjoina("/run/host/incoming/", basename(mount_outside)); - r = mount_nofollow_verbose(LOG_ERR, mount_inside, dest, NULL, MS_MOVE, NULL); - if (r < 0) - goto child_fail; - - _exit(EXIT_SUCCESS); - - child_fail: - (void) write(errno_pipe_fd[1], &r, sizeof(r)); - errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - - _exit(EXIT_FAILURE); - } - - errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); - - r = wait_for_terminate_and_check("(sd-bindmnt)", child, 0); - if (r < 0) { - r = sd_bus_error_set_errnof(error, r, "Failed to wait for child: %m"); - goto finish; - } - if (r != EXIT_SUCCESS) { - if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r)) - r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m"); - else - r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Child failed."); - goto finish; - } - - r = sd_bus_reply_method_return(message, NULL); - -finish: - if (mount_outside_mounted) - (void) umount_verbose(LOG_DEBUG, mount_outside, UMOUNT_NOFOLLOW); - if (mount_outside_created) { - if (S_ISDIR(st.st_mode)) - (void) rmdir(mount_outside); - else - (void) unlink(mount_outside); - } - - if (mount_tmp_mounted) - (void) umount_verbose(LOG_DEBUG, mount_tmp, UMOUNT_NOFOLLOW); - if (mount_tmp_created) { - if (S_ISDIR(st.st_mode)) - (void) rmdir(mount_tmp); - else - (void) unlink(mount_tmp); - } - - if (mount_slave_mounted) - (void) umount_verbose(LOG_DEBUG, mount_slave, UMOUNT_NOFOLLOW); - if (mount_slave_created) - (void) rmdir(mount_slave); - - return r; + return sd_bus_reply_method_return(message, NULL); } int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_error *error) { diff --git a/src/machine/machine.h b/src/machine/machine.h index 2f627157a..5e0e52956 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -14,7 +14,7 @@ typedef enum MachineState { MACHINE_RUNNING, /* Machine is running */ MACHINE_CLOSING, /* Machine is terminating */ _MACHINE_STATE_MAX, - _MACHINE_STATE_INVALID = -1 + _MACHINE_STATE_INVALID = -EINVAL, } MachineState; typedef enum MachineClass { @@ -22,14 +22,14 @@ typedef enum MachineClass { MACHINE_VM, MACHINE_HOST, _MACHINE_CLASS_MAX, - _MACHINE_CLASS_INVALID = -1 + _MACHINE_CLASS_INVALID = -EINVAL, } MachineClass; enum KillWho { KILL_LEADER, KILL_ALL, _KILL_WHO_MAX, - _KILL_WHO_INVALID = -1 + _KILL_WHO_INVALID = -EINVAL, }; struct Machine { diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 4a3279d26..d7849973b 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -39,6 +39,7 @@ #include "mkdir.h" #include "nulstr-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -206,7 +207,10 @@ static int call_get_addresses( else strcpy(buf_ifi, ""); - if (!strextend(&addresses, prefix, inet_ntop(family, a, buffer, sizeof(buffer)), buf_ifi, NULL)) + if (!strextend(&addresses, + prefix, + inet_ntop(family, a, buffer, sizeof(buffer)), + buf_ifi)) return log_oom(); r = sd_bus_message_exit_container(reply); @@ -235,7 +239,7 @@ static int show_table(Table *table, const char *word) { assert(word); if (table_get_rows(table) > 1 || OUTPUT_MODE_IS_JSON(arg_output)) { - r = table_set_sort(table, (size_t) 0, (size_t) -1); + r = table_set_sort(table, (size_t) 0); if (r < 0) return table_log_sort_error(r); @@ -960,8 +964,8 @@ static int show_pool_info(sd_bus *bus) { }; PoolStatusInfo info = { - .usage = (uint64_t) -1, - .limit = (uint64_t) -1, + .usage = UINT64_MAX, + .limit = UINT64_MAX, }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -1561,7 +1565,7 @@ static int make_service_name(const char *name, char **ret) { assert(name); assert(ret); - if (!machine_name_is_valid(name)) + if (!hostname_is_valid(name, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid machine name %s.", name); @@ -1868,6 +1872,9 @@ static int import_tar(int argc, char *argv[], void *userdata) { r = path_extract_filename(path, &fn); if (r < 0) return log_error_errno(r, "Cannot extract container name from filename: %m"); + if (r == O_DIRECTORY) + return log_error_errno(SYNTHETIC_ERRNO(EISDIR), + "Path '%s' refers to directory, but we need a regular file: %m", path); local = fn; } @@ -1881,7 +1888,7 @@ static int import_tar(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local name %s is not a suitable machine name.", local); @@ -1928,6 +1935,9 @@ static int import_raw(int argc, char *argv[], void *userdata) { r = path_extract_filename(path, &fn); if (r < 0) return log_error_errno(r, "Cannot extract container name from filename: %m"); + if (r == O_DIRECTORY) + return log_error_errno(SYNTHETIC_ERRNO(EISDIR), + "Path '%s' refers to directory, but we need a regular file: %m", path); local = fn; } @@ -1941,7 +1951,7 @@ static int import_raw(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local name %s is not a suitable machine name.", local); @@ -1995,7 +2005,7 @@ static int import_fs(int argc, char *argv[], void *userdata) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Need either path or local name."); - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local name %s is not a suitable machine name.", local); @@ -2048,7 +2058,7 @@ static int export_tar(int argc, char *argv[], void *userdata) { assert(bus); local = argv[1]; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine name %s is not valid.", local); @@ -2090,7 +2100,7 @@ static int export_raw(int argc, char *argv[], void *userdata) { assert(bus); local = argv[1]; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Machine name %s is not valid.", local); @@ -2155,7 +2165,7 @@ static int pull_tar(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local name %s is not a suitable machine name.", local); @@ -2211,7 +2221,7 @@ static int pull_raw(int argc, char *argv[], void *userdata) { local = ll; - if (!machine_name_is_valid(local)) + if (!hostname_is_valid(local, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Local name %s is not a suitable machine name.", local); @@ -2374,7 +2384,7 @@ static int set_limit(int argc, char *argv[], void *userdata) { polkit_agent_open_if_enabled(arg_transport, arg_ask_password); if (STR_IN_SET(argv[argc-1], "-", "none", "infinity")) - limit = (uint64_t) -1; + limit = UINT64_MAX; else { r = parse_size(argv[argc-1], 1024, &limit); if (r < 0) @@ -2531,14 +2541,13 @@ static int help(int argc, char *argv[], void *userdata) { " --verify=MODE Verification mode for downloaded images (no,\n" " checksum, signature)\n" " --force Download image even if already exists\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -2691,10 +2700,10 @@ static int parse_argv(int argc, char *argv[]) { return 0; } - arg_output = output_mode_from_string(optarg); - if (arg_output < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown output '%s'.", optarg); + r = output_mode_from_string(optarg); + if (r < 0) + return log_error_errno(r, "Unknown output '%s'.", optarg); + arg_output = r; if (OUTPUT_MODE_IS_JSON(arg_output)) arg_legend = false; @@ -2713,15 +2722,9 @@ static int parse_argv(int argc, char *argv[]) { break; case 's': - if (streq(optarg, "help")) { - DUMP_STRING_TABLE(signal, int, _NSIG); - return 0; - } - - arg_signal = signal_from_string(optarg); - if (arg_signal < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse signal string %s.", optarg); + r = parse_signal_argument(optarg, &arg_signal); + if (r <= 0) + return r; break; case ARG_NO_ASK_PASSWORD: @@ -2756,10 +2759,10 @@ static int parse_argv(int argc, char *argv[]) { return 0; } - arg_verify = import_verify_from_string(optarg); - if (arg_verify < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse --verify= setting: %s", optarg); + r = import_verify_from_string(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --verify= setting: %s", optarg); + arg_verify = r; break; case ARG_FORCE: @@ -2874,7 +2877,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); /* The journal merging logic potentially needs a lot of fds. */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); diff --git a/src/machine/machined-core.c b/src/machine/machined-core.c index 1416fbf82..ffca20949 100644 --- a/src/machine/machined-core.c +++ b/src/machine/machined-core.c @@ -5,6 +5,7 @@ #include "strv.h" #include "user-util.h" +#if ENABLE_NSCD static int on_nscd_cache_flush_event(sd_event_source *s, void *userdata) { /* Let's ask glibc's nscd daemon to flush its caches. We request this for the three database machines may show * up in: the hosts database (for resolvable machine names) and the user and group databases (for the user ns @@ -35,6 +36,7 @@ int manager_enqueue_nscd_cache_flush(Manager *m) { return 0; } +#endif int manager_find_machine_for_uid(Manager *m, uid_t uid, Machine **ret_machine, uid_t *ret_internal_uid) { Machine *machine; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 494813e33..0a6ae96bc 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -12,6 +12,7 @@ #include "bus-locator.h" #include "bus-polkit.h" #include "cgroup-util.h" +#include "discover-image.h" #include "errno-util.h" #include "fd-util.h" #include "fileio.h" @@ -20,10 +21,10 @@ #include "image-dbus.h" #include "io-util.h" #include "machine-dbus.h" -#include "machine-image.h" #include "machine-pool.h" #include "machined.h" #include "missing_capability.h" +#include "os-util.h" #include "path-util.h" #include "process-util.h" #include "stdio-util.h" @@ -44,7 +45,7 @@ static int property_get_pool_usage( sd_bus_error *error) { _cleanup_close_ int fd = -1; - uint64_t usage = (uint64_t) -1; + uint64_t usage = UINT64_MAX; assert(bus); assert(reply); @@ -70,7 +71,7 @@ static int property_get_pool_limit( sd_bus_error *error) { _cleanup_close_ int fd = -1; - uint64_t size = (uint64_t) -1; + uint64_t size = UINT64_MAX; assert(bus); assert(reply); @@ -124,7 +125,7 @@ static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_erro if (r < 0) return r; - r = image_find(IMAGE_MACHINE, name, NULL); + r = image_find(IMAGE_MACHINE, name, NULL, NULL); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name); if (r < 0) @@ -239,7 +240,7 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m r = sd_bus_message_read(message, "s", &name); if (r < 0) return r; - if (!machine_name_is_valid(name)) + if (!hostname_is_valid(name, 0)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name"); r = sd_bus_message_read_array(message, 'y', &v, &n); @@ -257,15 +258,13 @@ static int method_create_or_register_machine(Manager *manager, sd_bus_message *m return r; if (read_network) { - size_t i; - r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif); if (r < 0) return r; n_netif /= sizeof(int32_t); - for (i = 0; i < n_netif; i++) { + for (size_t i = 0; i < n_netif; i++) { if (netif[i] <= 0) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]); } @@ -482,7 +481,7 @@ static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_er if (!images) return -ENOMEM; - r = image_discover(IMAGE_MACHINE, images); + r = image_discover(IMAGE_MACHINE, NULL, images); if (r < 0) return r; @@ -564,7 +563,7 @@ static int redirect_method_to_image(sd_bus_message *message, Manager *m, sd_bus_ if (!image_name_is_valid(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name); - r = image_find(IMAGE_MACHINE, name, &i); + r = image_find(IMAGE_MACHINE, name, NULL, &i); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name); if (r < 0) @@ -757,7 +756,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err goto child_fail; } - r = image_discover(IMAGE_MACHINE, images); + r = image_discover(IMAGE_MACHINE, NULL, images); if (r < 0) goto child_fail; diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c index 2d6c1991a..009d283ac 100644 --- a/src/machine/machined-varlink.c +++ b/src/machine/machined-varlink.c @@ -388,7 +388,7 @@ int manager_varlink_init(Manager *m) { if (m->varlink_server) return 0; - r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID); + r = varlink_server_new(&s, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA); if (r < 0) return log_error_errno(r, "Failed to allocate varlink server object: %m"); diff --git a/src/machine/machined.c b/src/machine/machined.c index c3c08d181..241be42c9 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -15,11 +15,11 @@ #include "bus-polkit.h" #include "cgroup-util.h" #include "dirent-util.h" +#include "discover-image.h" #include "fd-util.h" #include "format-util.h" #include "hostname-util.h" #include "label.h" -#include "machine-image.h" #include "machined-varlink.h" #include "machined.h" #include "main-func.h" @@ -83,7 +83,9 @@ static Manager* manager_unref(Manager *m) { hashmap_free(m->image_cache); sd_event_source_unref(m->image_cache_defer_event); +#if ENABLE_NSCD sd_event_source_unref(m->nscd_cache_flush_event); +#endif bus_verify_polkit_async_registry_free(m->polkit_registry); @@ -164,7 +166,7 @@ static int manager_enumerate_machines(Manager *m) { if (startswith(de->d_name, "unit:")) continue; - if (!machine_name_is_valid(de->d_name)) + if (!hostname_is_valid(de->d_name, 0)) continue; k = manager_add_machine(m, de->d_name, &machine); @@ -322,7 +324,7 @@ static int run(int argc, char *argv[]) { int r; log_set_facility(LOG_AUTH); - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-machined.service", "Manage registrations of local VMs and containers.", diff --git a/src/machine/machined.h b/src/machine/machined.h index 6e4182bbd..280c32bab 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -36,7 +36,9 @@ struct Manager { LIST_HEAD(Operation, operations); unsigned n_operations; +#if ENABLE_NSCD sd_event_source *nscd_cache_flush_event; +#endif VarlinkServer *varlink_server; }; @@ -57,7 +59,11 @@ int manager_unref_unit(Manager *m, const char *unit, sd_bus_error *error); int manager_unit_is_active(Manager *manager, const char *unit); int manager_job_is_active(Manager *manager, const char *path); +#if ENABLE_NSCD int manager_enqueue_nscd_cache_flush(Manager *m); +#else +static inline void manager_enqueue_nscd_cache_flush(Manager *m) {} +#endif int manager_find_machine_for_uid(Manager *m, uid_t host_uid, Machine **ret_machine, uid_t *ret_internal_uid); int manager_find_machine_for_gid(Manager *m, gid_t host_gid, Machine **ret_machine, gid_t *ret_internal_gid); diff --git a/src/machine/meson.build b/src/machine/meson.build index ebbd46d4f..9b9ad1d8a 100644 --- a/src/machine/meson.build +++ b/src/machine/meson.build @@ -39,6 +39,5 @@ tests += [ [['src/machine/test-machine-tables.c'], [libmachine_core, libshared], - [threads], - 'ENABLE_MACHINED'], + [threads]], ] diff --git a/src/modules-load/modules-load.c b/src/modules-load/modules-load.c index 2f0cef5ff..9cfd29201 100644 --- a/src/modules-load/modules-load.c +++ b/src/modules-load/modules-load.c @@ -115,10 +115,9 @@ static int help(void) { "Loads statically configured kernel modules.\n\n" " -h --help Show this help\n" " --version Show package version\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -166,7 +165,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/mount/mount-tool.c b/src/mount/mount-tool.c index 673f85519..8c36dec12 100644 --- a/src/mount/mount-tool.c +++ b/src/mount/mount-tool.c @@ -23,9 +23,11 @@ #include "mount-util.h" #include "mountpoint-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" +#include "process-util.h" #include "sort-util.h" #include "spawn-polkit-agent.h" #include "stat-util.h" @@ -114,11 +116,10 @@ static int help(void) { " --list List mountable block devices\n" " -u --umount Unmount mount points\n" " -G --collect Unload unit after it stopped, even when failed\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount " - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + streq(program_invocation_short_name, "systemd-umount") ? "" : "--umount ", + link); return 0; } @@ -182,8 +183,8 @@ static int parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - if (strstr(program_invocation_short_name, "systemd-umount")) - arg_action = ACTION_UMOUNT; + if (invoked_as(argv, "systemd-umount")) + arg_action = ACTION_UMOUNT; while ((c = getopt_long(argc, argv, "hqH:M:t:o:p:AuGl", options, NULL)) >= 0) @@ -242,13 +243,15 @@ static int parse_argv(int argc, char *argv[]) { break; case 't': - if (free_and_strdup(&arg_mount_type, optarg) < 0) - return log_oom(); + r = free_and_strdup_warn(&arg_mount_type, optarg); + if (r < 0) + return r; break; case 'o': - if (free_and_strdup(&arg_mount_options, optarg) < 0) - return log_oom(); + r = free_and_strdup_warn(&arg_mount_options, optarg); + if (r < 0) + return r; break; case ARG_OWNER: { @@ -264,16 +267,15 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_FSCK: - r = parse_boolean(optarg); + r = parse_boolean_argument("--fsck=", optarg, &arg_fsck); if (r < 0) - return log_error_errno(r, "Failed to parse --fsck= argument: %s", optarg); - - arg_fsck = r; + return r; break; case ARG_DESCRIPTION: - if (free_and_strdup(&arg_description, optarg) < 0) - return log_oom(); + r = free_and_strdup_warn(&arg_description, optarg); + if (r < 0) + return r; break; case 'p': @@ -287,9 +289,9 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_AUTOMOUNT: - r = parse_boolean(optarg); + r = parse_boolean_argument("--automount=", optarg, NULL); if (r < 0) - return log_error_errno(r, "--automount= expects a valid boolean parameter: %s", optarg); + return r; arg_action = r ? ACTION_AUTOMOUNT : ACTION_MOUNT; break; @@ -927,7 +929,7 @@ static int umount_by_device(sd_bus *bus, const char *what) { return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "Not a block device: %s", what); - r = sd_device_new_from_devnum(&d, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) return log_error_errno(r, "Failed to get device from device number: %m"); @@ -1195,7 +1197,7 @@ static int acquire_removable(sd_device *d) { return 0; for (;;) { - if (sd_device_get_sysattr_value(d, "removable", &v) > 0) + if (sd_device_get_sysattr_value(d, "removable", &v) >= 0) break; if (sd_device_get_parent(d, &d) < 0) @@ -1268,7 +1270,7 @@ static int discover_loop_backing_file(void) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid file type: %s", loop_dev); - r = sd_device_new_from_devnum(&d, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) return log_error_errno(r, "Failed to get device from device number: %m"); @@ -1312,7 +1314,7 @@ static int discover_device(void) { "Invalid file type: %s", arg_mount_what); - r = sd_device_new_from_devnum(&d, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) return log_error_errno(r, "Failed to get device from device number: %m"); @@ -1381,7 +1383,7 @@ static int list_devices(void) { if (arg_full) table_set_width(table, 0); - r = table_set_sort(table, (size_t) 0, (size_t) SIZE_MAX); + r = table_set_sort(table, (size_t) 0); if (r < 0) return log_error_errno(r, "Failed to set sort index: %m"); diff --git a/src/network/generator/main.c b/src/network/generator/main.c index f9cace70f..1ac8bf01c 100644 --- a/src/network/generator/main.c +++ b/src/network/generator/main.c @@ -117,9 +117,8 @@ static int help(void) { printf("%s [OPTIONS...] [-- KERNEL_CMDLINE]\n" " -h --help Show this help\n" " --version Show package version\n" - " --root=PATH Operate on an alternate filesystem root\n" - , program_invocation_short_name - ); + " --root=PATH Operate on an alternate filesystem root\n", + program_invocation_short_name); return 0; } @@ -166,7 +165,7 @@ static int parse_argv(int argc, char *argv[]) { static int run(int argc, char *argv[]) { _cleanup_(context_clear) Context context = {}; - int i, r; + int r; r = parse_argv(argc, argv); if (r <= 0) @@ -177,7 +176,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_warning_errno(r, "Failed to parse kernel command line: %m"); } else { - for (i = optind; i < argc; i++) { + for (int i = optind; i < argc; i++) { _cleanup_free_ char *word = NULL; char *value; diff --git a/src/network/generator/network-generator.c b/src/network/generator/network-generator.c index 2fa21a067..ae673ddf5 100644 --- a/src/network/generator/network-generator.c +++ b/src/network/generator/network-generator.c @@ -190,11 +190,7 @@ static int network_new(Context *context, const char *name, Network **ret) { .dhcp_use_dns = -1, }; - r = hashmap_ensure_allocated(&context->networks_by_name, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(context->networks_by_name, network->ifname, network); + r = hashmap_ensure_put(&context->networks_by_name, &string_hash_ops, network->ifname, network); if (r < 0) return r; @@ -247,11 +243,7 @@ static int netdev_new(Context *context, const char *_kind, const char *_ifname, .ifname = TAKE_PTR(ifname), }; - r = hashmap_ensure_allocated(&context->netdevs_by_name, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(context->netdevs_by_name, netdev->ifname, netdev); + r = hashmap_ensure_put(&context->netdevs_by_name, &string_hash_ops, netdev->ifname, netdev); if (r < 0) return r; @@ -299,11 +291,7 @@ static int link_new(Context *context, const char *name, struct ether_addr *mac, .mac = *mac, }; - r = hashmap_ensure_allocated(&context->links_by_name, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(context->links_by_name, link->ifname, link); + r = hashmap_ensure_put(&context->links_by_name, &string_hash_ops, link->ifname, link); if (r < 0) return r; @@ -325,7 +313,7 @@ static int network_set_dhcp_type(Context *context, const char *ifname, const cha t = dracut_dhcp_type_from_string(dhcp_type); if (t < 0) - return -EINVAL; + return t; network = network_get(context, ifname); if (!network) { @@ -372,7 +360,7 @@ static int network_set_address(Context *context, const char *ifname, int family, union in_addr_union *addr, union in_addr_union *peer) { Network *network; - if (in_addr_is_null(family, addr) != 0) + if (!in_addr_is_set(family, addr)) return 0; network = network_get(context, ifname); @@ -387,7 +375,7 @@ static int network_set_route(Context *context, const char *ifname, int family, u Network *network; int r; - if (in_addr_is_null(family, gateway) != 0) + if (!in_addr_is_set(family, gateway)) return 0; network = network_get(context, ifname); @@ -601,7 +589,7 @@ static int parse_cmdline_ip_address(Context *context, int family, const char *va if (p != value) { hostname = strndupa(value, p - value); - if (!hostname_is_valid(hostname, false)) + if (!hostname_is_valid(hostname, 0)) return -EINVAL; } @@ -1012,7 +1000,7 @@ static int address_dump(Address *address, FILE *f) { if (r < 0) return r; - if (in_addr_is_null(address->family, &address->peer) == 0) { + if (in_addr_is_set(address->family, &address->peer)) { r = in_addr_to_string(address->family, &address->peer, &peer); if (r < 0) return r; @@ -1033,7 +1021,7 @@ static int route_dump(Route *route, FILE *f) { _cleanup_free_ char *dest = NULL, *gateway = NULL; int r; - if (in_addr_is_null(route->family, &route->dest) == 0) { + if (in_addr_is_set(route->family, &route->dest)) { r = in_addr_prefix_to_string(route->family, &route->dest, route->prefixlen, &dest); if (r < 0) return r; diff --git a/src/network/generator/network-generator.h b/src/network/generator/network-generator.h index 86bcaec11..5131b20bc 100644 --- a/src/network/generator/network-generator.h +++ b/src/network/generator/network-generator.h @@ -19,7 +19,7 @@ typedef enum DHCPType { DHCP_TYPE_EITHER6, DHCP_TYPE_IBFT, _DHCP_TYPE_MAX, - _DHCP_TYPE_INVALID = -1, + _DHCP_TYPE_INVALID = -EINVAL, } DHCPType; typedef struct Address Address; diff --git a/src/network/meson.build b/src/network/meson.build index f5ca18308..4fca3106d 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -3,6 +3,8 @@ sources = files(''' netdev/bareudp.c netdev/bareudp.h + netdev/batadv.c + netdev/batadv.h netdev/bond.c netdev/bond.h netdev/bridge.c @@ -111,6 +113,8 @@ sources = files(''' networkd-speed-meter.h networkd-sriov.c networkd-sriov.h + networkd-state-file.c + networkd-state-file.h networkd-sysctl.c networkd-sysctl.h networkd-util.c @@ -171,7 +175,7 @@ systemd_networkd_wait_online_sources = files(''' wait-online/manager.c wait-online/manager.h wait-online/wait-online.c -'''.split()) + network_internal_h +'''.split()) networkctl_sources = files('networkctl.c') @@ -181,46 +185,41 @@ network_generator_sources = files(''' generator/network-generator.h '''.split()) -network_include_dir = [includes, include_directories(['.', 'netdev', 'tc'])] +sources += custom_target( + 'networkd-gperf.c', + input : 'networkd-gperf.gperf', + output : 'networkd-gperf.c', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + +sources += custom_target( + 'networkd-network-gperf.c', + input : 'networkd-network-gperf.gperf', + output : 'networkd-network-gperf.c', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + +sources += custom_target( + 'netdev-gperf.c', + input : 'netdev/netdev-gperf.gperf', + output : 'netdev-gperf.c', + command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) + +if get_option('link-networkd-shared') + networkd_link_with = [libshared] +else + networkd_link_with = [libsystemd_static, + libshared_static, + libbasic_gcrypt] +endif + +network_includes = [libsystemd_network_includes, include_directories(['.', 'netdev', 'tc'])] + +libnetworkd_core = static_library( + 'networkd-core', + sources, + include_directories : network_includes, + link_with : [networkd_link_with]) if conf.get('ENABLE_NETWORKD') == 1 - if get_option('link-networkd-shared') - networkd_link_with = [libshared] - else - networkd_link_with = [libsystemd_static, - libshared_static, - libjournal_client, - libbasic_gcrypt] - endif - - networkd_gperf_c = custom_target( - 'networkd-gperf.c', - input : 'networkd-gperf.gperf', - output : 'networkd-gperf.c', - command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) - - networkd_network_gperf_c = custom_target( - 'networkd-network-gperf.c', - input : 'networkd-network-gperf.gperf', - output : 'networkd-network-gperf.c', - command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) - - netdev_gperf_c = custom_target( - 'netdev-gperf.c', - input : 'netdev/netdev-gperf.gperf', - output : 'netdev-gperf.c', - command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) - - libnetworkd_core = static_library( - 'networkd-core', - sources, - network_internal_h, - networkd_gperf_c, - networkd_network_gperf_c, - netdev_gperf_c, - include_directories : network_include_dir, - link_with : [networkd_link_with]) - install_data('org.freedesktop.network1.conf', install_dir : dbuspolicydir) install_data('org.freedesktop.network1.service', @@ -236,68 +235,48 @@ if conf.get('ENABLE_NETWORKD') == 1 install_dir : polkitpkladir) endif - if install_sysconfdir + if install_sysconfdir_samples install_data('networkd.conf', install_dir : pkgsysconfdir) endif - - fuzzers += [ - [['src/network/fuzz-netdev-parser.c', - 'src/fuzz/fuzz.h'], - [libnetworkd_core, - libudev_static, - libsystemd_network, - networkd_link_with], - [threads], - [], - network_include_dir], - - [['src/network/fuzz-network-parser.c', - 'src/fuzz/fuzz.h'], - [libnetworkd_core, - libudev_static, - libsystemd_network, - networkd_link_with], - [threads], - [], - network_include_dir], - ] - - tests += [ - [['src/network/test-networkd-conf.c'], - [libnetworkd_core, - libsystemd_network, - libudev], - [], '', '', [], network_include_dir], - - [['src/network/test-network.c'], - [libnetworkd_core, - libudev_static, - libsystemd_network, - networkd_link_with], - [threads], - '', '', [], network_include_dir], - - [['src/network/test-routing-policy-rule.c'], - [libnetworkd_core, - libsystemd_network, - libudev], - [], '', '', [], network_include_dir], - - [['src/network/test-network-tables.c', - test_tables_h], - [libnetworkd_core, - libudev_static, - libsystemd_network, - networkd_link_with], - [threads], - '', '', [], - [network_include_dir]], - - [['src/network/generator/test-network-generator.c', - 'src/network/generator/network-generator.c', - 'src/network/generator/network-generator.h'], - [networkd_link_with], - [], '', '', [], network_include_dir], - ] endif + +fuzzers += [ + [['src/network/fuzz-netdev-parser.c'], + [libnetworkd_core, + libsystemd_network, + networkd_link_with], + [threads], + network_includes], + + [['src/network/fuzz-network-parser.c'], + [libnetworkd_core, + libsystemd_network, + networkd_link_with], + [threads], + network_includes], +] + +tests += [ + [['src/network/test-networkd-conf.c'], + [libnetworkd_core, + libsystemd_network], + [], + network_includes], + + [['src/network/test-network.c'], + [libnetworkd_core, + libsystemd_network], + [threads], + network_includes], + + [['src/network/test-network-tables.c'], + [libnetworkd_core, + libsystemd_network], + [threads], + network_includes], + + [['src/network/generator/test-network-generator.c', + 'src/network/generator/network-generator.c', + 'src/network/generator/network-generator.h']], +] diff --git a/src/network/netdev/bareudp.h b/src/network/netdev/bareudp.h index ea80bbf80..8d8863ccc 100644 --- a/src/network/netdev/bareudp.h +++ b/src/network/netdev/bareudp.h @@ -15,7 +15,7 @@ typedef enum BareUDPProtocol { BARE_UDP_PROTOCOL_MPLS_UC = ETH_P_MPLS_UC, BARE_UDP_PROTOCOL_MPLS_MC = ETH_P_MPLS_MC, _BARE_UDP_PROTOCOL_MAX, - _BARE_UDP_PROTOCOL_INVALID = -1 + _BARE_UDP_PROTOCOL_INVALID = -EINVAL, } BareUDPProtocol; struct BareUDP { diff --git a/src/network/netdev/batadv.c b/src/network/netdev/batadv.c new file mode 100644 index 000000000..1f899e90f --- /dev/null +++ b/src/network/netdev/batadv.c @@ -0,0 +1,203 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "batadv.h" +#include "fileio.h" +#include "netlink-util.h" +#include "network-internal.h" +#include "networkd-manager.h" +#include "parse-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" + +static void batadv_init(NetDev *n) { + BatmanAdvanced *b; + + b = BATADV(n); + + /* Set defaults */ + b->aggregation = true; + b->gateway_bandwidth_down = 10000; + b->gateway_bandwidth_up = 2000; + b->bridge_loop_avoidance = true; + b->distributed_arp_table = true; + b->fragmentation = true; + b->hop_penalty = 15; + b->originator_interval = 1000; + b->routing_algorithm = BATADV_ROUTING_ALGORITHM_BATMAN_V; +} + +static const char* const batadv_gateway_mode_table[_BATADV_GATEWAY_MODE_MAX] = { + [BATADV_GATEWAY_MODE_OFF] = "off", + [BATADV_GATEWAY_MODE_CLIENT] = "client", + [BATADV_GATEWAY_MODE_SERVER] = "server", +}; + +static const char* const batadv_routing_algorithm_table[_BATADV_ROUTING_ALGORITHM_MAX] = { + [BATADV_ROUTING_ALGORITHM_BATMAN_V] = "batman-v", + [BATADV_ROUTING_ALGORITHM_BATMAN_IV] = "batman-iv", +}; + +static const char* const batadv_routing_algorithm_kernel_table[_BATADV_ROUTING_ALGORITHM_MAX] = { + [BATADV_ROUTING_ALGORITHM_BATMAN_V] = "BATMAN_V", + [BATADV_ROUTING_ALGORITHM_BATMAN_IV] = "BATMAN_IV", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(batadv_gateway_mode, BatadvGatewayModes); +DEFINE_CONFIG_PARSE_ENUM(config_parse_batadv_gateway_mode, batadv_gateway_mode, BatadvGatewayModes, + "Failed to parse GatewayMode="); + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(batadv_routing_algorithm, BatadvRoutingAlgorithm); +DEFINE_CONFIG_PARSE_ENUM(config_parse_batadv_routing_algorithm, batadv_routing_algorithm, BatadvRoutingAlgorithm, + "Failed to parse RoutingAlgorithm="); + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(batadv_routing_algorithm_kernel, BatadvRoutingAlgorithm); + +int config_parse_badadv_bandwidth ( + 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) { + + uint64_t k; + uint32_t *bandwidth = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + + r = parse_size(rvalue, 1000, &k); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse '%s=', ignoring assignment: %s", + lvalue, rvalue); + return 0; + } + + if (k/1000/100 > UINT32_MAX) + log_syntax(unit, LOG_WARNING, filename, line, 0, + "The value of '%s=', is outside of 0...429496729500000 range: %s", + lvalue, rvalue); + + *bandwidth = k/1000/100; + + return 0; +} + +/* callback for batman netdev's parameter set */ +static int netdev_batman_set_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) { + int r; + + assert(netdev); + assert(m); + + r = sd_netlink_message_get_errno(m); + if (r < 0) { + log_netdev_warning_errno(netdev, r, "BATADV parameters could not be set: %m"); + return 1; + } + + log_netdev_debug(netdev, "BATADV parameters set success"); + + return 1; +} + +static int netdev_batadv_post_create(NetDev *netdev, Link *link, sd_netlink_message *m) { + BatmanAdvanced *b; + int r; + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *message = NULL; + + assert(netdev); + + b = BATADV(netdev); + assert(b); + + r = sd_genl_message_new(netdev->manager->genl, SD_GENL_BATADV, BATADV_CMD_SET_MESH, &message); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to allocate generic netlink message: %m"); + + r = sd_netlink_message_append_u32(message, BATADV_ATTR_MESH_IFINDEX, netdev->ifindex); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set ifindex: %m"); + + r = sd_netlink_message_append_u8(message, BATADV_ATTR_GW_MODE, b->gateway_mode); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set gateway_mode: %m"); + + r = sd_netlink_message_append_u8(message, BATADV_ATTR_AGGREGATED_OGMS_ENABLED, b->aggregation); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set aggregation: %m"); + + r = sd_netlink_message_append_u8(message, BATADV_ATTR_BRIDGE_LOOP_AVOIDANCE_ENABLED, b->bridge_loop_avoidance); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set bridge_loop_avoidance: %m"); + + r = sd_netlink_message_append_u8(message, BATADV_ATTR_DISTRIBUTED_ARP_TABLE_ENABLED, b->distributed_arp_table); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set distributed_arp_table: %m"); + + r = sd_netlink_message_append_u8(message, BATADV_ATTR_FRAGMENTATION_ENABLED, b->fragmentation); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set fragmentation: %m"); + + r = sd_netlink_message_append_u8(message, BATADV_ATTR_HOP_PENALTY, b->hop_penalty); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set hop_penalty: %m"); + + r = sd_netlink_message_append_u32(message, BATADV_ATTR_ORIG_INTERVAL, DIV_ROUND_UP(b->originator_interval, USEC_PER_MSEC)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set orig_interval: %m"); + + r = sd_netlink_message_append_u32(message, BATADV_ATTR_GW_BANDWIDTH_DOWN, b->gateway_bandwidth_down); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set gateway_bandwidth_down: %m"); + + r = sd_netlink_message_append_u32(message, BATADV_ATTR_GW_BANDWIDTH_UP, b->gateway_bandwidth_up); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Failed to set gateway_bandwidth_up: %m"); + + r = netlink_call_async(netdev->manager->genl, NULL, message, netdev_batman_set_handler, + netdev_destroy_callback, netdev); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not send batman device message: %m"); + + netdev_ref(netdev); + + return r; +} + +static int netdev_batadv_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) { + BatmanAdvanced *b; + int r; + + assert(netdev); + assert(m); + + b = BATADV(netdev); + assert(b); + + r = sd_netlink_message_append_string(m, IFLA_BATADV_ALGO_NAME, batadv_routing_algorithm_kernel_to_string(b->routing_algorithm)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_BATADV_ALGO_NAME attribute: %m"); + + return r; +} + +const NetDevVTable batadv_vtable = { + .object_size = sizeof(BatmanAdvanced), + .init = batadv_init, + .sections = NETDEV_COMMON_SECTIONS "BatmanAdvanced\0", + .fill_message_create = netdev_batadv_fill_message_create, + .post_create = netdev_batadv_post_create, + .create_type = NETDEV_CREATE_MASTER, +}; diff --git a/src/network/netdev/batadv.h b/src/network/netdev/batadv.h new file mode 100644 index 000000000..f1f9b4688 --- /dev/null +++ b/src/network/netdev/batadv.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#pragma once + +#include + +#include "conf-parser.h" +#include "netdev.h" + +#define BATADV_GENL_NAME "batadv" + +typedef enum BatadvGatewayModes { + BATADV_GATEWAY_MODE_OFF = BATADV_GW_MODE_OFF, + BATADV_GATEWAY_MODE_CLIENT = BATADV_GW_MODE_CLIENT, + BATADV_GATEWAY_MODE_SERVER = BATADV_GW_MODE_SERVER, + _BATADV_GATEWAY_MODE_MAX, + _BATADV_GATEWAY_MODE_INVALID = -EINVAL, +} BatadvGatewayModes; + +typedef enum BatadvRoutingAlgorithm { + BATADV_ROUTING_ALGORITHM_BATMAN_V, + BATADV_ROUTING_ALGORITHM_BATMAN_IV, + _BATADV_ROUTING_ALGORITHM_MAX, + _BATADV_ROUTING_ALGORITHM_INVALID = -EINVAL, +} BatadvRoutingAlgorithm; + +typedef struct Batadv { + NetDev meta; + + BatadvGatewayModes gateway_mode; + uint32_t gateway_bandwidth_down; + uint32_t gateway_bandwidth_up; + uint8_t hop_penalty; + BatadvRoutingAlgorithm routing_algorithm; + usec_t originator_interval; + bool aggregation; + bool bridge_loop_avoidance; + bool distributed_arp_table; + bool fragmentation; +} BatmanAdvanced; + +DEFINE_NETDEV_CAST(BATADV, BatmanAdvanced); +extern const NetDevVTable batadv_vtable; + +CONFIG_PARSER_PROTOTYPE(config_parse_batadv_gateway_mode); +CONFIG_PARSER_PROTOTYPE(config_parse_batadv_routing_algorithm); +CONFIG_PARSER_PROTOTYPE(config_parse_badadv_bandwidth); diff --git a/src/network/netdev/bond.c b/src/network/netdev/bond.c index e27f36067..cf7ca88d6 100644 --- a/src/network/netdev/bond.c +++ b/src/network/netdev/bond.c @@ -342,10 +342,6 @@ int config_parse_arp_ip_target_address( continue; } - r = ordered_set_ensure_allocated(&b->arp_ip_targets, NULL); - if (r < 0) - return log_oom(); - if (ordered_set_size(b->arp_ip_targets) >= NETDEV_BOND_ARP_TARGETS_MAX) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Too many ARP IP targets are specified. The maximum number is %d. Ignoring assignment: %s", @@ -353,7 +349,9 @@ int config_parse_arp_ip_target_address( continue; } - r = ordered_set_put(b->arp_ip_targets, UINT32_TO_PTR(ip.in.s_addr)); + r = ordered_set_ensure_put(&b->arp_ip_targets, NULL, UINT32_TO_PTR(ip.in.s_addr)); + if (r == -ENOMEM) + return log_oom(); if (r == -EEXIST) log_syntax(unit, LOG_WARNING, filename, line, r, "Bond ARP IP target address is duplicated, ignoring assignment: %s", n); diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index 1f59cd8b4..38432f157 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -4,7 +4,6 @@ #include "bridge.h" #include "netlink-util.h" -#include "network-internal.h" #include "networkd-manager.h" #include "string-table.h" #include "vlan-util.h" @@ -342,6 +341,47 @@ int config_parse_bridge_igmp_version( return 0; } +int config_parse_bridge_port_priority( + 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) { + + uint16_t i; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + /* This is used in networkd-network-gperf.gperf. */ + + r = safe_atou16(rvalue, &i); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse bridge port priority, ignoring: %s", rvalue); + return 0; + } + + if (i > LINK_BRIDGE_PORT_PRIORITY_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Bridge port priority is larger than maximum %u, ignoring: %s", + LINK_BRIDGE_PORT_PRIORITY_MAX, rvalue); + return 0; + } + + *((uint16_t *)data) = i; + + return 0; +} + static void bridge_init(NetDev *n) { Bridge *b; diff --git a/src/network/netdev/bridge.h b/src/network/netdev/bridge.h index d6abda99e..459a5eed6 100644 --- a/src/network/netdev/bridge.h +++ b/src/network/netdev/bridge.h @@ -7,6 +7,9 @@ #include "conf-parser.h" #include "netdev.h" +#define LINK_BRIDGE_PORT_PRIORITY_INVALID 128 +#define LINK_BRIDGE_PORT_PRIORITY_MAX 63 + typedef struct Bridge { NetDev meta; @@ -32,7 +35,7 @@ typedef enum MulticastRouter { MULTICAST_ROUTER_PERMANENT = MDB_RTR_TYPE_PERM, MULTICAST_ROUTER_TEMPORARY = MDB_RTR_TYPE_TEMP, _MULTICAST_ROUTER_MAX, - _MULTICAST_ROUTER_INVALID = -1, + _MULTICAST_ROUTER_INVALID = -EINVAL, } MulticastRouter; DEFINE_NETDEV_CAST(BRIDGE, Bridge); @@ -45,3 +48,4 @@ MulticastRouter multicast_router_from_string(const char *s) _pure_; CONFIG_PARSER_PROTOTYPE(config_parse_multicast_router); CONFIG_PARSER_PROTOTYPE(config_parse_bridge_igmp_version); +CONFIG_PARSER_PROTOTYPE(config_parse_bridge_port_priority); diff --git a/src/network/netdev/fou-tunnel.h b/src/network/netdev/fou-tunnel.h index a6f10dfca..576d82ed6 100644 --- a/src/network/netdev/fou-tunnel.h +++ b/src/network/netdev/fou-tunnel.h @@ -12,7 +12,7 @@ typedef enum FooOverUDPEncapType { NETDEV_FOO_OVER_UDP_ENCAP_DIRECT = FOU_ENCAP_DIRECT, NETDEV_FOO_OVER_UDP_ENCAP_GUE = FOU_ENCAP_GUE, _NETDEV_FOO_OVER_UDP_ENCAP_MAX, - _NETDEV_FOO_OVER_UDP_ENCAP_INVALID = -1, + _NETDEV_FOO_OVER_UDP_ENCAP_INVALID = -EINVAL, } FooOverUDPEncapType; typedef struct FouTunnel { diff --git a/src/network/netdev/geneve.c b/src/network/netdev/geneve.c index edf92ec93..fd0b5119e 100644 --- a/src/network/netdev/geneve.c +++ b/src/network/netdev/geneve.c @@ -90,7 +90,7 @@ static int netdev_geneve_create(NetDev *netdev) { return log_netdev_error_errno(netdev, r, "Could not append IFLA_GENEVE_ID attribute: %m"); } - if (in_addr_is_null(v->remote_family, &v->remote) == 0) { + if (in_addr_is_set(v->remote_family, &v->remote)) { if (v->remote_family == AF_INET) r = sd_netlink_message_append_in_addr(m, IFLA_GENEVE_REMOTE, &v->remote.in); else diff --git a/src/network/netdev/geneve.h b/src/network/netdev/geneve.h index b62eb7b76..1f0f15c2a 100644 --- a/src/network/netdev/geneve.h +++ b/src/network/netdev/geneve.h @@ -14,7 +14,7 @@ typedef enum GeneveDF { NETDEV_GENEVE_DF_YES = GENEVE_DF_SET, NETDEV_GENEVE_DF_INHERIT = GENEVE_DF_INHERIT, _NETDEV_GENEVE_DF_MAX, - _NETDEV_GENEVE_DF_INVALID = -1 + _NETDEV_GENEVE_DF_INVALID = -EINVAL, } GeneveDF; struct Geneve { diff --git a/src/network/netdev/l2tp-tunnel.c b/src/network/netdev/l2tp-tunnel.c index eeea19764..32ec02455 100644 --- a/src/network/netdev/l2tp-tunnel.c +++ b/src/network/netdev/l2tp-tunnel.c @@ -39,18 +39,16 @@ static const char* const l2tp_local_address_type_table[_NETDEV_L2TP_LOCAL_ADDRES DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(l2tp_local_address_type, L2tpLocalAddressType); -static void l2tp_session_free(L2tpSession *s) { +static L2tpSession* l2tp_session_free(L2tpSession *s) { if (!s) - return; + return NULL; if (s->tunnel && s->section) ordered_hashmap_remove(s->tunnel->sessions_by_section, s->section); network_config_section_free(s->section); - free(s->name); - - free(s); + return mfree(s); } DEFINE_NETWORK_SECTION_FUNCTIONS(L2tpSession, l2tp_session_free); @@ -85,11 +83,7 @@ static int l2tp_session_new_static(L2tpTunnel *t, const char *filename, unsigned .section = TAKE_PTR(n), }; - r = ordered_hashmap_ensure_allocated(&t->sessions_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(t->sessions_by_section, s->section, s); + r = ordered_hashmap_ensure_put(&t->sessions_by_section, &network_config_hash_ops, s->section, s); if (r < 0) return r; @@ -258,7 +252,7 @@ static int l2tp_acquire_local_address_one(L2tpTunnel *t, Address *a, union in_ad if (a->family != t->family) return -EINVAL; - if (in_addr_is_null(a->family, &a->in_addr_peer) <= 0) + if (in_addr_is_set(a->family, &a->in_addr_peer)) return -EINVAL; if (t->local_address_type == NETDEV_L2TP_LOCAL_ADDRESS_STATIC && @@ -281,7 +275,7 @@ static int l2tp_acquire_local_address(L2tpTunnel *t, Link *link, union in_addr_u assert(ret); assert(IN_SET(t->family, AF_INET, AF_INET6)); - if (!in_addr_is_null(t->family, &t->local)) { + if (in_addr_is_set(t->family, &t->local)) { /* local address is explicitly specified. */ *ret = t->local; return 0; @@ -441,7 +435,7 @@ int config_parse_l2tp_tunnel_address( addr_type = l2tp_local_address_type_from_string(rvalue); if (addr_type >= 0) { - if (in_addr_is_null(t->family, &t->remote) != 0) + if (!in_addr_is_set(t->family, &t->remote)) /* If Remote= is not specified yet, then also clear family. */ t->family = AF_UNSPEC; @@ -581,7 +575,7 @@ int config_parse_l2tp_session_l2spec( spec = l2tp_l2spec_type_from_string(rvalue); if (spec < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, spec, "Failed to parse layer2 specific header type. Ignoring assignment: %s", rvalue); return 0; } @@ -688,7 +682,7 @@ static int netdev_l2tp_tunnel_verify(NetDev *netdev, const char *filename) { "%s: L2TP tunnel with invalid address family configured. Ignoring", filename); - if (in_addr_is_null(t->family, &t->remote)) + if (!in_addr_is_set(t->family, &t->remote)) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "%s: L2TP tunnel without a remote address configured. Ignoring", filename); diff --git a/src/network/netdev/l2tp-tunnel.h b/src/network/netdev/l2tp-tunnel.h index 048318d6d..a884d2100 100644 --- a/src/network/netdev/l2tp-tunnel.h +++ b/src/network/netdev/l2tp-tunnel.h @@ -12,14 +12,14 @@ typedef enum L2tpL2specType { NETDEV_L2TP_L2SPECTYPE_NONE = L2TP_L2SPECTYPE_NONE, NETDEV_L2TP_L2SPECTYPE_DEFAULT = L2TP_L2SPECTYPE_DEFAULT, _NETDEV_L2TP_L2SPECTYPE_MAX, - _NETDEV_L2TP_L2SPECTYPE_INVALID = -1, + _NETDEV_L2TP_L2SPECTYPE_INVALID = -EINVAL, } L2tpL2specType; typedef enum L2tpEncapType { NETDEV_L2TP_ENCAPTYPE_UDP = L2TP_ENCAPTYPE_UDP, NETDEV_L2TP_ENCAPTYPE_IP = L2TP_ENCAPTYPE_IP, _NETDEV_L2TP_ENCAPTYPE_MAX, - _NETDEV_L2TP_ENCAPTYPE_INVALID = -1, + _NETDEV_L2TP_ENCAPTYPE_INVALID = -EINVAL, } L2tpEncapType; typedef enum L2tpLocalAddressType { @@ -27,7 +27,7 @@ typedef enum L2tpLocalAddressType { NETDEV_L2TP_LOCAL_ADDRESS_STATIC, NETDEV_L2TP_LOCAL_ADDRESS_DYNAMIC, _NETDEV_L2TP_LOCAL_ADDRESS_MAX, - _NETDEV_L2TP_LOCAL_ADDRESS_INVALID = -1, + _NETDEV_L2TP_LOCAL_ADDRESS_INVALID = -EINVAL, } L2tpLocalAddressType; typedef struct L2tpTunnel L2tpTunnel; diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c index 82e71c392..77c5f8c4e 100644 --- a/src/network/netdev/macsec.c +++ b/src/network/netdev/macsec.c @@ -12,7 +12,6 @@ #include "macsec.h" #include "memory-util.h" #include "netlink-util.h" -#include "network-internal.h" #include "networkd-manager.h" #include "path-util.h" #include "socket-util.h" @@ -36,9 +35,9 @@ static void security_association_init(SecurityAssociation *sa) { sa->use_for_encoding = -1; } -static void macsec_receive_association_free(ReceiveAssociation *c) { +static ReceiveAssociation* macsec_receive_association_free(ReceiveAssociation *c) { if (!c) - return; + return NULL; if (c->macsec && c->section) ordered_hashmap_remove(c->macsec->receive_associations_by_section, c->section); @@ -46,7 +45,7 @@ static void macsec_receive_association_free(ReceiveAssociation *c) { network_config_section_free(c->section); security_association_clear(&c->sa); - free(c); + return mfree(c); } DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveAssociation, macsec_receive_association_free); @@ -82,11 +81,7 @@ static int macsec_receive_association_new_static(MACsec *s, const char *filename security_association_init(&c->sa); - r = ordered_hashmap_ensure_allocated(&s->receive_associations_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(s->receive_associations_by_section, c->section, c); + r = ordered_hashmap_ensure_put(&s->receive_associations_by_section, &network_config_hash_ops, c->section, c); if (r < 0) return r; @@ -95,9 +90,9 @@ static int macsec_receive_association_new_static(MACsec *s, const char *filename return 0; } -static void macsec_receive_channel_free(ReceiveChannel *c) { +static ReceiveChannel* macsec_receive_channel_free(ReceiveChannel *c) { if (!c) - return; + return NULL; if (c->macsec) { if (c->sci.as_uint64 > 0) @@ -109,7 +104,7 @@ static void macsec_receive_channel_free(ReceiveChannel *c) { network_config_section_free(c->section); - free(c); + return mfree(c); } DEFINE_NETWORK_SECTION_FUNCTIONS(ReceiveChannel, macsec_receive_channel_free); @@ -158,11 +153,7 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un c->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_allocated(&s->receive_channels_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(s->receive_channels_by_section, c->section, c); + r = ordered_hashmap_ensure_put(&s->receive_channels_by_section, &network_config_hash_ops, c->section, c); if (r < 0) return r; @@ -171,9 +162,9 @@ static int macsec_receive_channel_new_static(MACsec *s, const char *filename, un return 0; } -static void macsec_transmit_association_free(TransmitAssociation *a) { +static TransmitAssociation* macsec_transmit_association_free(TransmitAssociation *a) { if (!a) - return; + return NULL; if (a->macsec && a->section) ordered_hashmap_remove(a->macsec->transmit_associations_by_section, a->section); @@ -181,7 +172,7 @@ static void macsec_transmit_association_free(TransmitAssociation *a) { network_config_section_free(a->section); security_association_clear(&a->sa); - free(a); + return mfree(a); } DEFINE_NETWORK_SECTION_FUNCTIONS(TransmitAssociation, macsec_transmit_association_free); @@ -217,11 +208,7 @@ static int macsec_transmit_association_new_static(MACsec *s, const char *filenam security_association_init(&a->sa); - r = ordered_hashmap_ensure_allocated(&s->transmit_associations_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(s->transmit_associations_by_section, a->section, a); + r = ordered_hashmap_ensure_put(&s->transmit_associations_by_section, &network_config_hash_ops, a->section, a); if (r < 0) return r; @@ -371,7 +358,6 @@ static int netdev_macsec_configure_receive_association(NetDev *netdev, ReceiveAs static int macsec_receive_channel_handler(sd_netlink *rtnl, sd_netlink_message *m, ReceiveChannel *c) { NetDev *netdev; - unsigned i; int r; assert(c); @@ -396,7 +382,7 @@ static int macsec_receive_channel_handler(sd_netlink *rtnl, sd_netlink_message * log_netdev_debug(netdev, "Receive channel is configured"); - for (i = 0; i < c->n_rxsa; i++) { + for (unsigned i = 0; i < c->n_rxsa; i++) { r = netdev_macsec_configure_receive_association(netdev, c->rxsa[i]); if (r < 0) { log_netdev_warning_errno(netdev, r, @@ -987,7 +973,7 @@ static int macsec_read_key_file(NetDev *netdev, SecurityAssociation *sa) { (void) warn_file_is_world_accessible(sa->key_file, NULL, NULL, 0); r = read_full_file_full( - AT_FDCWD, sa->key_file, + AT_FDCWD, sa->key_file, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNHEX | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET, NULL, (char **) &key, &key_len); if (r < 0) @@ -1030,11 +1016,9 @@ static int macsec_receive_channel_verify(ReceiveChannel *c) { "Ignoring [MACsecReceiveChannel] section from line %u", c->section->filename, c->section->line); - r = ordered_hashmap_ensure_allocated(&c->macsec->receive_channels, &uint64_hash_ops); - if (r < 0) + r = ordered_hashmap_ensure_put(&c->macsec->receive_channels, &uint64_hash_ops, &c->sci.as_uint64, c); + if (r == -ENOMEM) return log_oom(); - - r = ordered_hashmap_put(c->macsec->receive_channels, &c->sci.as_uint64, c); if (r == -EEXIST) return log_netdev_error_errno(netdev, r, "%s: Multiple [MACsecReceiveChannel] sections have same SCI, " @@ -1122,11 +1106,9 @@ static int macsec_receive_association_verify(ReceiveAssociation *a) { if (r < 0) return log_oom(); - r = ordered_hashmap_ensure_allocated(&a->macsec->receive_channels, &uint64_hash_ops); - if (r < 0) + r = ordered_hashmap_ensure_put(&a->macsec->receive_channels, &uint64_hash_ops, &new_channel->sci.as_uint64, new_channel); + if (r == -ENOMEM) return log_oom(); - - r = ordered_hashmap_put(a->macsec->receive_channels, &new_channel->sci.as_uint64, new_channel); if (r < 0) return log_netdev_error_errno(netdev, r, "%s: Failed to store receive channel at hashmap, " diff --git a/src/network/netdev/macvlan.c b/src/network/netdev/macvlan.c index 9bdcf627b..46b082614 100644 --- a/src/network/netdev/macvlan.c +++ b/src/network/netdev/macvlan.c @@ -5,6 +5,7 @@ #include "conf-parser.h" #include "macvlan.h" #include "macvlan-util.h" +#include "parse-util.h" DEFINE_CONFIG_PARSE_ENUM(config_parse_macvlan_mode, macvlan_mode, MacVlanMode, "Failed to parse macvlan mode"); @@ -51,6 +52,57 @@ static int netdev_macvlan_fill_message_create(NetDev *netdev, Link *link, sd_net return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_MODE attribute: %m"); } + if (m->bc_queue_length != UINT32_MAX) { + r = sd_netlink_message_append_u32(req, IFLA_MACVLAN_BC_QUEUE_LEN, m->bc_queue_length); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_MACVLAN_BC_QUEUE_LEN attribute: %m"); + } + + return 0; +} + +int config_parse_macvlan_broadcast_queue_size( + 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) { + + MacVlan *m = userdata; + uint32_t v; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + assert(userdata); + + if (isempty(rvalue)) { + m->bc_queue_length = UINT32_MAX; + return 0; + } + + r = safe_atou32(rvalue, &v); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse BroadcastMulticastQueueLength=%s, ignoring assignment: %m", rvalue); + return 0; + } + + if (v == UINT32_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid BroadcastMulticastQueueLength=%s, ignoring assignment: %m", rvalue); + return 0; + } + + m->bc_queue_length = v; return 0; } @@ -82,6 +134,7 @@ static void macvlan_init(NetDev *n) { assert(m); m->mode = _NETDEV_MACVLAN_MODE_INVALID; + m->bc_queue_length = UINT32_MAX; } const NetDevVTable macvtap_vtable = { diff --git a/src/network/netdev/macvlan.h b/src/network/netdev/macvlan.h index cb7eece67..c45fc4fd3 100644 --- a/src/network/netdev/macvlan.h +++ b/src/network/netdev/macvlan.h @@ -12,6 +12,8 @@ struct MacVlan { MacVlanMode mode; Set *match_source_mac; + + uint32_t bc_queue_length; }; DEFINE_NETDEV_CAST(MACVLAN, MacVlan); @@ -20,3 +22,4 @@ extern const NetDevVTable macvlan_vtable; extern const NetDevVTable macvtap_vtable; CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_mode); +CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_broadcast_queue_size); diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index 4e89761f2..8abe04489 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -1,29 +1,31 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #endif #include #include "bareudp.h" +#include "batadv.h" #include "bond.h" #include "bridge.h" #include "conf-parser.h" +#include "fou-tunnel.h" #include "geneve.h" #include "ipvlan.h" +#include "l2tp-tunnel.h" #include "macsec.h" #include "macvlan.h" +#include "net-condition.h" +#include "netdev.h" #include "tunnel.h" #include "tuntap.h" #include "veth.h" #include "vlan-util.h" #include "vlan.h" -#include "vxlan.h" #include "vrf.h" -#include "netdev.h" -#include "network-internal.h" #include "vxcan.h" +#include "vxlan.h" #include "wireguard.h" -#include "fou-tunnel.h" -#include "l2tp-tunnel.h" #include "xfrm.h" %} struct ConfigPerfItem; @@ -48,12 +50,16 @@ NetDev.Kind, config_parse_netdev_kind, NetDev.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(NetDev, mtu) NetDev.MACAddress, config_parse_hwaddr, 0, offsetof(NetDev, mac) VLAN.Id, config_parse_vlanid, 0, offsetof(VLan, id) +VLAN.Protocol, config_parse_vlanprotocol, 0, offsetof(VLan, protocol) VLAN.GVRP, config_parse_tristate, 0, offsetof(VLan, gvrp) VLAN.MVRP, config_parse_tristate, 0, offsetof(VLan, mvrp) VLAN.LooseBinding, config_parse_tristate, 0, offsetof(VLan, loose_binding) VLAN.ReorderHeader, config_parse_tristate, 0, offsetof(VLan, reorder_hdr) +VLAN.EgressQOSMaps, config_parse_vlan_qos_maps, 0, offsetof(VLan, egress_qos_maps) +VLAN.IngressQOSMaps, config_parse_vlan_qos_maps, 0, offsetof(VLan, ingress_qos_maps) MACVLAN.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) MACVLAN.SourceMACAddress, config_parse_hwaddrs, 0, offsetof(MacVlan, match_source_mac) +MACVLAN.BroadcastMulticastQueueLength, config_parse_macvlan_broadcast_queue_size, 0, offsetof(MacVlan, bc_queue_length) MACVTAP.Mode, config_parse_macvlan_mode, 0, offsetof(MacVlan, mode) MACVTAP.SourceMACAddress, config_parse_hwaddrs, 0, offsetof(MacVlan, match_source_mac) IPVLAN.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode) @@ -230,3 +236,13 @@ WireGuardPeer.PresharedKeyFile, config_parse_wireguard_preshared_key_f WireGuardPeer.PersistentKeepalive, config_parse_wireguard_keepalive, 0, 0 Xfrm.InterfaceId, config_parse_uint32, 0, offsetof(Xfrm, if_id) Xfrm.Independent, config_parse_bool, 0, offsetof(Xfrm, independent) +BatmanAdvanced.Aggregation, config_parse_bool, 0, offsetof(BatmanAdvanced, aggregation) +BatmanAdvanced.BridgeLoopAvoidance, config_parse_bool, 0, offsetof(BatmanAdvanced, bridge_loop_avoidance) +BatmanAdvanced.DistributedArpTable, config_parse_bool, 0, offsetof(BatmanAdvanced, distributed_arp_table) +BatmanAdvanced.Fragmentation, config_parse_bool, 0, offsetof(BatmanAdvanced, fragmentation) +BatmanAdvanced.GatewayMode, config_parse_batadv_gateway_mode, 0, offsetof(BatmanAdvanced, gateway_mode) +BatmanAdvanced.GatewayBandwithDown, config_parse_badadv_bandwidth, 0, offsetof(BatmanAdvanced, gateway_bandwidth_down) +BatmanAdvanced.GatewayBandwithUp, config_parse_badadv_bandwidth, 0, offsetof(BatmanAdvanced, gateway_bandwidth_up) +BatmanAdvanced.HopPenalty, config_parse_uint8, 0, offsetof(BatmanAdvanced, hop_penalty) +BatmanAdvanced.OriginatorIntervalSec, config_parse_sec, 0, offsetof(BatmanAdvanced, originator_interval) +BatmanAdvanced.RoutingAlgorithm, config_parse_batadv_routing_algorithm, 0, offsetof(BatmanAdvanced, routing_algorithm) diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 9f390b578..b31f0fa81 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -6,6 +6,7 @@ #include "alloc-util.h" #include "bareudp.h" +#include "batadv.h" #include "bond.h" #include "bridge.h" #include "conf-files.h" @@ -23,7 +24,6 @@ #include "netdev.h" #include "netdevsim.h" #include "netlink-util.h" -#include "network-internal.h" #include "networkd-manager.h" #include "nlmon.h" #include "path-lookup.h" @@ -44,6 +44,7 @@ #include "xfrm.h" const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { + [NETDEV_KIND_BATADV] = &batadv_vtable, [NETDEV_KIND_BRIDGE] = &bridge_vtable, [NETDEV_KIND_BOND] = &bond_vtable, [NETDEV_KIND_VLAN] = &vlan_vtable, @@ -83,6 +84,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = { static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { [NETDEV_KIND_BAREUDP] = "bareudp", + [NETDEV_KIND_BATADV] = "batadv", [NETDEV_KIND_BRIDGE] = "bridge", [NETDEV_KIND_BOND] = "bond", [NETDEV_KIND_VLAN] = "vlan", @@ -140,7 +142,7 @@ int config_parse_netdev_kind( k = netdev_kind_from_string(rvalue); if (k < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse netdev kind, ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse netdev kind, ignoring assignment: %s", rvalue); return 0; } @@ -263,7 +265,7 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message assert(netdev->state == NETDEV_STATE_READY); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF, NETDEV_KIND_BATADV)); assert(link); assert(callback); @@ -354,7 +356,7 @@ static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handl assert(netdev); assert(netdev->manager); assert(netdev->manager->rtnl); - assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)); + assert(IN_SET(netdev->kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF, NETDEV_KIND_BATADV)); if (netdev->state == NETDEV_STATE_READY) { r = netdev_enslave_ready(netdev, link, callback); @@ -401,10 +403,8 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) { if (r < 0) return log_netdev_error_errno(netdev, r, "Could not get rtnl message type: %m"); - if (type != RTM_NEWLINK) { - log_netdev_error(netdev, "Cannot set ifindex from unexpected rtnl message type."); - return -EINVAL; - } + if (type != RTM_NEWLINK) + return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "Cannot set ifindex from unexpected rtnl message type."); r = sd_rtnl_message_link_get_ifindex(message, &ifindex); if (r < 0) { @@ -435,7 +435,7 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) { if (!streq(netdev->ifname, received_name)) { log_netdev_error(netdev, "Received newlink with wrong IFNAME %s", received_name); netdev_enter_failed(netdev); - return r; + return -EINVAL; } r = sd_netlink_message_enter_container(message, IFLA_LINKINFO); @@ -463,11 +463,10 @@ int netdev_set_ifindex(NetDev *netdev, sd_netlink_message *message) { } if (!streq(kind, received_kind)) { - log_netdev_error(netdev, - "Received newlink with wrong KIND %s, " - "expected %s", received_kind, kind); + log_netdev_error(netdev, "Received newlink with wrong KIND %s, expected %s", + received_kind, kind); netdev_enter_failed(netdev); - return r; + return -EINVAL; } netdev->ifindex = ifindex; @@ -556,7 +555,7 @@ static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handle return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m"); } - if (netdev->mtu) { + if (netdev->mtu != 0) { r = sd_netlink_message_append_u32(m, IFLA_MTU, netdev->mtu); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_MTU attribute: %m"); @@ -657,7 +656,6 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb int netdev_load_one(Manager *manager, const char *filename) { _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL; - _cleanup_fclose_ FILE *file = NULL; const char *dropin_dirname; bool independent = false; int r; @@ -665,15 +663,12 @@ int netdev_load_one(Manager *manager, const char *filename) { assert(manager); assert(filename); - file = fopen(filename, "re"); - if (!file) { - if (errno == ENOENT) - return 0; - - return -errno; - } - - if (null_or_empty_fd(fileno(file))) { + r = null_or_empty_path(filename); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + if (r > 0) { log_debug("Skipping empty file: %s", filename); return 0; } @@ -690,7 +685,7 @@ int netdev_load_one(Manager *manager, const char *filename) { dropin_dirname = strjoina(basename(filename), ".d"); r = config_parse_many( - filename, NETWORK_DIRS, dropin_dirname, + STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, NETDEV_COMMON_SECTIONS NETDEV_OTHER_SECTIONS, config_item_perf_lookup, network_netdev_gperf_lookup, CONFIG_PARSE_WARN, @@ -715,10 +710,6 @@ int netdev_load_one(Manager *manager, const char *filename) { return 0; } - r = fseek(file, 0, SEEK_SET); - if (r < 0) - return -errno; - netdev = malloc0(NETDEV_VTABLE(netdev_raw)->object_size); if (!netdev) return log_oom(); @@ -733,7 +724,7 @@ int netdev_load_one(Manager *manager, const char *filename) { NETDEV_VTABLE(netdev)->init(netdev); r = config_parse_many( - filename, NETWORK_DIRS, dropin_dirname, + STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, NETDEV_VTABLE(netdev)->sections, config_item_perf_lookup, network_netdev_gperf_lookup, CONFIG_PARSE_WARN, @@ -760,11 +751,9 @@ int netdev_load_one(Manager *manager, const char *filename) { netdev->ifname); } - r = hashmap_ensure_allocated(&netdev->manager->netdevs, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev); + r = hashmap_ensure_put(&netdev->manager->netdevs, &string_hash_ops, netdev->ifname, netdev); + if (r == -ENOMEM) + return log_oom(); if (r == -EEXIST) { NetDev *n = hashmap_get(netdev->manager->netdevs, netdev->ifname); diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index 468fae591..6d149da2e 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -12,6 +12,7 @@ /* This is the list of known sections. We need to ignore them in the initial parsing phase. */ #define NETDEV_OTHER_SECTIONS \ "-BareUDP\0" \ + "-BatmanAdvanced\0" \ "-Bond\0" \ "-Bridge\0" \ "-FooOverUDP\0" \ @@ -83,9 +84,10 @@ typedef enum NetDevKind { NETDEV_KIND_XFRM, NETDEV_KIND_IFB, NETDEV_KIND_BAREUDP, + NETDEV_KIND_BATADV, _NETDEV_KIND_MAX, _NETDEV_KIND_TUNNEL, /* Used by config_parse_stacked_netdev() */ - _NETDEV_KIND_INVALID = -1 + _NETDEV_KIND_INVALID = -EINVAL, } NetDevKind; typedef enum NetDevState { @@ -95,7 +97,7 @@ typedef enum NetDevState { NETDEV_STATE_READY, NETDEV_STATE_LINGER, _NETDEV_STATE_MAX, - _NETDEV_STATE_INVALID = -1, + _NETDEV_STATE_INVALID = -EINVAL, } NetDevState; typedef enum NetDevCreateType { @@ -104,7 +106,7 @@ typedef enum NetDevCreateType { NETDEV_CREATE_STACKED, NETDEV_CREATE_AFTER_CONFIGURED, _NETDEV_CREATE_MAX, - _NETDEV_CREATE_INVALID = -1, + _NETDEV_CREATE_INVALID = -EINVAL, } NetDevCreateType; typedef struct Manager Manager; diff --git a/src/network/netdev/tunnel.c b/src/network/netdev/tunnel.c index 66e886828..23718081b 100644 --- a/src/network/netdev/tunnel.c +++ b/src/network/netdev/tunnel.c @@ -389,7 +389,7 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl if (t->allow_localremote >= 0) SET_FLAG(t->flags, IP6_TNL_F_ALLOW_LOCAL_REMOTE, t->allow_localremote); - if (t->encap_limit != IPV6_DEFAULT_TNL_ENCAP_LIMIT) { + if (t->encap_limit != 0) { r = sd_netlink_message_append_u8(m, IFLA_IPTUN_ENCAP_LIMIT, t->encap_limit); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_ENCAP_LIMIT attribute: %m"); @@ -468,7 +468,7 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { "vti/ipip/sit/gre tunnel without a local/remote IPv4 address configured in %s. Ignoring", filename); if (IN_SET(netdev->kind, NETDEV_KIND_GRETAP, NETDEV_KIND_ERSPAN) && - (t->family != AF_INET || in_addr_is_null(t->family, &t->remote))) + (t->family != AF_INET || !in_addr_is_set(t->family, &t->remote))) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "gretap/erspan tunnel without a remote IPv4 address configured in %s. Ignoring", filename); @@ -478,7 +478,7 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) { "vti6/ip6tnl/ip6gre tunnel without a local/remote IPv6 address configured in %s. Ignoring", filename); if (netdev->kind == NETDEV_KIND_IP6GRETAP && - (t->family != AF_INET6 || in_addr_is_null(t->family, &t->remote))) + (t->family != AF_INET6 || !in_addr_is_set(t->family, &t->remote))) return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "ip6gretap tunnel without a remote IPv6 address configured in %s. Ignoring", filename); @@ -530,11 +530,9 @@ int config_parse_tunnel_address(const char *unit, *addr = IN_ADDR_NULL; /* As a special case, if both the local and remote addresses are - * unspecified, also clear the address family. - */ - if (t->family != AF_UNSPEC && - in_addr_is_null(t->family, &t->local) != 0 && - in_addr_is_null(t->family, &t->remote) != 0) + * unspecified, also clear the address family. */ + if (!in_addr_is_set(t->family, &t->local) && + !in_addr_is_set(t->family, &t->remote)) t->family = AF_UNSPEC; return 0; } @@ -581,7 +579,8 @@ int config_parse_tunnel_key(const char *unit, if (r < 0) { r = safe_atou32(rvalue, &k); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse tunnel key ignoring assignment: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse tunnel key ignoring assignment: %s", rvalue); return 0; } } else diff --git a/src/network/netdev/tunnel.h b/src/network/netdev/tunnel.h index d58ded757..35021e940 100644 --- a/src/network/netdev/tunnel.h +++ b/src/network/netdev/tunnel.h @@ -12,13 +12,13 @@ typedef enum Ip6TnlMode { NETDEV_IP6_TNL_MODE_IPIP6, NETDEV_IP6_TNL_MODE_ANYIP6, _NETDEV_IP6_TNL_MODE_MAX, - _NETDEV_IP6_TNL_MODE_INVALID = -1, + _NETDEV_IP6_TNL_MODE_INVALID = -EINVAL, } Ip6TnlMode; typedef enum IPv6FlowLabel { NETDEV_IPV6_FLOWLABEL_INHERIT = 0xFFFFF + 1, _NETDEV_IPV6_FLOWLABEL_MAX, - _NETDEV_IPV6_FLOWLABEL_INVALID = -1, + _NETDEV_IPV6_FLOWLABEL_INVALID = -EINVAL, } IPv6FlowLabel; typedef struct Tunnel { diff --git a/src/network/netdev/vlan.c b/src/network/netdev/vlan.c index e7f03f06f..de3eb721e 100644 --- a/src/network/netdev/vlan.c +++ b/src/network/netdev/vlan.c @@ -4,6 +4,7 @@ #include #include +#include "parse-util.h" #include "vlan-util.h" #include "vlan.h" @@ -24,6 +25,12 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_ID attribute: %m"); + if (v->protocol >= 0) { + r = sd_netlink_message_append_u16(req, IFLA_VLAN_PROTOCOL, htobe16(v->protocol)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_PROTOCOL attribute: %m"); + } + if (v->gvrp != -1) { flags.mask |= VLAN_FLAG_GVRP; SET_FLAG(flags.flags, VLAN_FLAG_GVRP, v->gvrp); @@ -48,9 +55,129 @@ static int netdev_vlan_fill_message_create(NetDev *netdev, Link *link, sd_netlin if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_FLAGS attribute: %m"); + if (!set_isempty(v->egress_qos_maps)) { + struct ifla_vlan_qos_mapping *m; + + r = sd_netlink_message_open_container(req, IFLA_VLAN_EGRESS_QOS); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not open container IFLA_VLAN_EGRESS_QOS: %m"); + + SET_FOREACH(m, v->egress_qos_maps) { + r = sd_netlink_message_append_data(req, IFLA_VLAN_QOS_MAPPING, m, sizeof(struct ifla_vlan_qos_mapping)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_QOS_MAPPING attribute: %m"); + } + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not close container IFLA_VLAN_EGRESS_QOS: %m"); + } + + if (!set_isempty(v->ingress_qos_maps)) { + struct ifla_vlan_qos_mapping *m; + + r = sd_netlink_message_open_container(req, IFLA_VLAN_INGRESS_QOS); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not open container IFLA_VLAN_INGRESS_QOS: %m"); + + SET_FOREACH(m, v->ingress_qos_maps) { + r = sd_netlink_message_append_data(req, IFLA_VLAN_QOS_MAPPING, m, sizeof(struct ifla_vlan_qos_mapping)); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not append IFLA_VLAN_QOS_MAPPING attribute: %m"); + } + + r = sd_netlink_message_close_container(req); + if (r < 0) + return log_netdev_error_errno(netdev, r, "Could not close container IFLA_VLAN_INGRESS_QOS: %m"); + } + return 0; } +static void vlan_qos_maps_hash_func(const struct ifla_vlan_qos_mapping *x, struct siphash *state) { + siphash24_compress(&x->from, sizeof(x->from), state); + siphash24_compress(&x->to, sizeof(x->to), state); +} + +static int vlan_qos_maps_compare_func(const struct ifla_vlan_qos_mapping *a, const struct ifla_vlan_qos_mapping *b) { + int r; + + r = CMP(a->from, b->from); + if (r != 0) + return r; + + return CMP(a->to, b->to); +} + +DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( + vlan_qos_maps_hash_ops, + struct ifla_vlan_qos_mapping, + vlan_qos_maps_hash_func, + vlan_qos_maps_compare_func, + free); + +int config_parse_vlan_qos_maps( + 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) { + + Set **s = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *s = set_free(*s); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ struct ifla_vlan_qos_mapping *m = NULL; + _cleanup_free_ char *w = NULL; + + r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, rvalue); + return 0; + } + if (r == 0) + return 0; + + m = new0(struct ifla_vlan_qos_mapping, 1); + if (!m) + return log_oom(); + + r = parse_range(w, &m->from, &m->to); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s, ignoring: %s", lvalue, w); + continue; + } + + if (m->to > m->from || m->to == 0 || m->from == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s, ignoring: %s", lvalue, w); + continue; + } + + r = set_ensure_consume(s, &vlan_qos_maps_hash_ops, TAKE_PTR(m)); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to store %s, ignoring: %s", lvalue, w); + continue; + } + } +} + static int netdev_vlan_verify(NetDev *netdev, const char *filename) { VLan *v; @@ -69,6 +196,17 @@ static int netdev_vlan_verify(NetDev *netdev, const char *filename) { return 0; } +static void vlan_done(NetDev *n) { + VLan *v; + + v = VLAN(n); + + assert(v); + + set_free(v->egress_qos_maps); + set_free(v->ingress_qos_maps); +} + static void vlan_init(NetDev *netdev) { VLan *v = VLAN(netdev); @@ -76,6 +214,7 @@ static void vlan_init(NetDev *netdev) { assert(v); v->id = VLANID_INVALID; + v->protocol = -1; v->gvrp = -1; v->mvrp = -1; v->loose_binding = -1; @@ -89,4 +228,5 @@ const NetDevVTable vlan_vtable = { .fill_message_create = netdev_vlan_fill_message_create, .create_type = NETDEV_CREATE_STACKED, .config_verify = netdev_vlan_verify, + .done = vlan_done, }; diff --git a/src/network/netdev/vlan.h b/src/network/netdev/vlan.h index 9dff924cd..1e5e5904f 100644 --- a/src/network/netdev/vlan.h +++ b/src/network/netdev/vlan.h @@ -4,17 +4,24 @@ typedef struct VLan VLan; #include "netdev.h" +#include "set.h" struct VLan { NetDev meta; uint16_t id; + int protocol; int gvrp; int mvrp; int loose_binding; int reorder_hdr; + + Set *egress_qos_maps; + Set *ingress_qos_maps; }; DEFINE_NETDEV_CAST(VLAN, VLan); extern const NetDevVTable vlan_vtable; + +CONFIG_PARSER_PROTOTYPE(config_parse_vlan_qos_maps); diff --git a/src/network/netdev/vxlan.c b/src/network/netdev/vxlan.c index 6748f67f8..52d8b3736 100644 --- a/src/network/netdev/vxlan.c +++ b/src/network/netdev/vxlan.c @@ -37,14 +37,14 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_ID attribute: %m"); } - if (in_addr_is_null(v->group_family, &v->group) == 0) { + if (in_addr_is_set(v->group_family, &v->group)) { if (v->group_family == AF_INET) r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->group.in); else r = sd_netlink_message_append_in6_addr(m, IFLA_VXLAN_GROUP6, &v->group.in6); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m"); - } else if (in_addr_is_null(v->remote_family, &v->remote) == 0) { + } else if (in_addr_is_set(v->remote_family, &v->remote)) { if (v->remote_family == AF_INET) r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_GROUP, &v->remote.in); else @@ -53,7 +53,7 @@ static int netdev_vxlan_fill_message_create(NetDev *netdev, Link *link, sd_netli return log_netdev_error_errno(netdev, r, "Could not append IFLA_VXLAN_GROUP attribute: %m"); } - if (in_addr_is_null(v->local_family, &v->local) == 0) { + if (in_addr_is_set(v->local_family, &v->local)) { if (v->local_family == AF_INET) r = sd_netlink_message_append_in_addr(m, IFLA_VXLAN_LOCAL, &v->local.in); else @@ -354,7 +354,7 @@ static int netdev_vxlan_verify(NetDev *netdev, const char *filename) { if (!v->dest_port && v->generic_protocol_extension) v->dest_port = 4790; - if (in_addr_is_null(v->group_family, &v->group) == 0 && in_addr_is_null(v->remote_family, &v->remote) == 0) + if (in_addr_is_set(v->group_family, &v->group) && in_addr_is_set(v->remote_family, &v->remote)) return log_netdev_warning_errno(netdev, SYNTHETIC_ERRNO(EINVAL), "%s: VXLAN both 'Group=' and 'Remote=' cannot be specified. Ignoring.", filename); diff --git a/src/network/netdev/vxlan.h b/src/network/netdev/vxlan.h index 371653cad..12ef46ef9 100644 --- a/src/network/netdev/vxlan.h +++ b/src/network/netdev/vxlan.h @@ -16,7 +16,7 @@ typedef enum VxLanDF { NETDEV_VXLAN_DF_YES = VXLAN_DF_SET, NETDEV_VXLAN_DF_INHERIT = VXLAN_DF_INHERIT, _NETDEV_VXLAN_DF_MAX, - _NETDEV_VXLAN_DF_INVALID = -1 + _NETDEV_VXLAN_DF_INVALID = -EINVAL, } VxLanDF; struct VxLan { diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c index 416e9b92d..75d6d376a 100644 --- a/src/network/netdev/wireguard.c +++ b/src/network/netdev/wireguard.c @@ -26,11 +26,11 @@ static void resolve_endpoints(NetDev *netdev); -static void wireguard_peer_free(WireguardPeer *peer) { +static WireguardPeer* wireguard_peer_free(WireguardPeer *peer) { WireguardIPmask *mask; if (!peer) - return; + return NULL; if (peer->wireguard) { LIST_REMOVE(peers, peer->wireguard->peers, peer); @@ -54,7 +54,7 @@ static void wireguard_peer_free(WireguardPeer *peer) { free(peer->preshared_key_file); explicit_bzero_safe(peer->preshared_key, WG_KEY_LEN); - free(peer); + return mfree(peer); } DEFINE_NETWORK_SECTION_FUNCTIONS(WireguardPeer, wireguard_peer_free); @@ -91,11 +91,7 @@ static int wireguard_peer_new_static(Wireguard *w, const char *filename, unsigne LIST_PREPEND(peers, w->peers, peer); - r = hashmap_ensure_allocated(&w->peers_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(w->peers_by_section, peer->section, peer); + r = hashmap_ensure_put(&w->peers_by_section, &network_config_hash_ops, peer->section, peer); if (r < 0) return r; @@ -869,7 +865,7 @@ static int wireguard_read_key_file(const char *filename, uint8_t dest[static WG_ (void) warn_file_is_world_accessible(filename, NULL, NULL, 0); r = read_full_file_full( - AT_FDCWD, filename, + AT_FDCWD, filename, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_SECURE | READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_WARN_WORLD_READABLE | READ_FULL_FILE_CONNECT_SOCKET, NULL, &key, &key_len); if (r < 0) diff --git a/src/network/networkctl.c b/src/network/networkctl.c index 63a90bc13..faaa6a7b6 100644 --- a/src/network/networkctl.c +++ b/src/network/networkctl.c @@ -44,6 +44,7 @@ #include "main-func.h" #include "netlink-util.h" #include "network-internal.h" +#include "network-util.h" #include "pager.h" #include "parse-util.h" #include "pretty-print.h" @@ -229,7 +230,7 @@ static int link_info_compare(const LinkInfo *a, const LinkInfo *b) { return CMP(a->ifindex, b->ifindex); } -static const LinkInfo* link_info_array_free(LinkInfo *array) { +static LinkInfo* link_info_array_free(LinkInfo *array) { for (unsigned i = 0; array && array[i].needs_freeing; i++) { sd_device_unref(array[i].sd_device); free(array[i].ssid); @@ -579,8 +580,7 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(link_info_array_freep) LinkInfo *links = NULL; _cleanup_close_ int fd = -1; - size_t allocated = 0, c = 0, j; - sd_netlink_message *i; + size_t allocated = 0, c = 0; int r; assert(rtnl); @@ -605,7 +605,7 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin return log_oom(); } - for (i = reply; i; i = sd_netlink_message_next(i)) { + for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) { if (!GREEDY_REALLOC0(links, allocated, c + 2)) /* We keep one trailing one as marker */ return -ENOMEM; @@ -644,7 +644,7 @@ static int acquire_link_info(sd_bus *bus, sd_netlink *rtnl, char **patterns, Lin typesafe_qsort(links, c, link_info_compare); if (bus) - for (j = 0; j < c; j++) + for (size_t j = 0; j < c; j++) (void) acquire_link_bitrates(bus, links + j); *ret = TAKE_PTR(links); @@ -660,7 +660,7 @@ static int list_links(int argc, char *argv[], void *userdata) { _cleanup_(link_info_array_freep) LinkInfo *links = NULL; _cleanup_(table_unrefp) Table *table = NULL; TableCell *cell; - int c, i, r; + int c, r; r = sd_netlink_open(&rtnl); if (r < 0) @@ -690,7 +690,7 @@ static int list_links(int argc, char *argv[], void *userdata) { assert_se(cell = table_get_cell(table, 0, 1)); (void) table_set_ellipsize_percent(table, cell, 100); - for (i = 0; i < c; i++) { + for (int i = 0; i < c; i++) { _cleanup_free_ char *setup_state = NULL, *operational_state = NULL; const char *on_color_operational, *off_color_operational, *on_color_setup, *off_color_setup; @@ -704,7 +704,7 @@ static int list_links(int argc, char *argv[], void *userdata) { setup_state = strdup("unmanaged"); setup_state_to_color(setup_state, &on_color_setup, &off_color_setup); - t = link_get_type_string(links[i].iftype, links[i].sd_device); + t = link_get_type_string(links[i].sd_device, links[i].iftype); r = table_add_many(table, TABLE_INT, links[i].ifindex, @@ -770,7 +770,6 @@ static int get_gateway_description( union in_addr_union *gateway, char **gateway_description) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - sd_netlink_message *m; int r; assert(rtnl); @@ -791,7 +790,7 @@ static int get_gateway_description( if (r < 0) return r; - for (m = reply; m; m = sd_netlink_message_next(m)) { + for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) { union in_addr_union gw = IN_ADDR_NULL; struct ether_addr mac = ETHER_ADDR_NULL; uint16_t type; @@ -891,7 +890,7 @@ static int dump_gateways( int ifindex) { _cleanup_free_ struct local_address *local = NULL; _cleanup_strv_free_ char **buf = NULL; - int r, n, i; + int r, n; assert(rtnl); assert(table); @@ -900,7 +899,7 @@ static int dump_gateways( if (n <= 0) return n; - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { _cleanup_free_ char *gateway = NULL, *description = NULL, *with_description = NULL; char name[IF_NAMESIZE+1]; @@ -939,7 +938,7 @@ static int dump_addresses( _cleanup_free_ struct local_address *local = NULL; _cleanup_strv_free_ char **buf = NULL; struct in_addr dhcp4_address = {}; - int r, n, i; + int r, n; assert(rtnl); assert(table); @@ -951,7 +950,7 @@ static int dump_addresses( if (lease) (void) sd_dhcp_lease_get_address(lease, &dhcp4_address); - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { _cleanup_free_ char *pretty = NULL; char name[IF_NAMESIZE+1]; @@ -988,7 +987,6 @@ static int dump_addresses( static int dump_address_labels(sd_netlink *rtnl) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; _cleanup_(table_unrefp) Table *table = NULL; - sd_netlink_message *m; TableCell *cell; int r; @@ -1013,7 +1011,7 @@ static int dump_address_labels(sd_netlink *rtnl) { if (arg_full) table_set_width(table, 0); - r = table_set_sort(table, (size_t) 0, (size_t) SIZE_MAX); + r = table_set_sort(table, (size_t) 0); if (r < 0) return r; @@ -1024,7 +1022,7 @@ static int dump_address_labels(sd_netlink *rtnl) { assert_se(cell = table_get_cell(table, 0, 1)); (void) table_set_align_percent(table, cell, 100); - for (m = reply; m; m = sd_netlink_message_next(m)) { + for (sd_netlink_message *m = reply; m; m = sd_netlink_message_next(m)) { _cleanup_free_ char *pretty = NULL; union in_addr_union prefix = IN_ADDR_NULL; uint8_t prefixlen; @@ -1264,7 +1262,6 @@ static int dump_dhcp_leases(Table *table, const char *prefix, sd_bus *bus, const } static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes) { - unsigned c; int r; assert(prefix); @@ -1272,7 +1269,7 @@ static int dump_ifindexes(Table *table, const char *prefix, const int *ifindexes if (!ifindexes || ifindexes[0] <= 0) return 0; - for (c = 0; ifindexes[c] > 0; c++) { + for (unsigned c = 0; ifindexes[c] > 0; c++) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, c == 0 ? prefix : "", @@ -1390,7 +1387,7 @@ static int link_status_one( _cleanup_strv_free_ char **dns = NULL, **ntp = NULL, **sip = NULL, **search_domains = NULL, **route_domains = NULL; _cleanup_free_ char *t = NULL, *network = NULL, *iaid = NULL, *duid = NULL, - *setup_state = NULL, *operational_state = NULL, *lease_file = NULL; + *setup_state = NULL, *operational_state = NULL, *lease_file = NULL, *activation_policy = 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; @@ -1428,7 +1425,7 @@ static int link_status_one( (void) sd_device_get_property_value(info->sd_device, "ID_MODEL", &model); } - t = link_get_type_string(info->iftype, info->sd_device); + t = link_get_type_string(info->sd_device, info->iftype); (void) sd_network_link_get_network_file(info->ifindex, &network); @@ -1790,7 +1787,7 @@ static int link_status_one( if (r < 0) return table_log_add_error(r); } else if (STRPTR_IN_SET(info->netdev_kind, "ipip", "sit", "gre", "gretap", "erspan", "vti")) { - if (!in_addr_is_null(AF_INET, &info->local)) { + if (in_addr_is_set(AF_INET, &info->local)) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Local:", @@ -1799,7 +1796,7 @@ static int link_status_one( return table_log_add_error(r); } - if (!in_addr_is_null(AF_INET, &info->remote)) { + if (in_addr_is_set(AF_INET, &info->remote)) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Remote:", @@ -1808,7 +1805,7 @@ static int link_status_one( return table_log_add_error(r); } } else if (STRPTR_IN_SET(info->netdev_kind, "ip6gre", "ip6gretap", "ip6erspan", "vti6")) { - if (!in_addr_is_null(AF_INET6, &info->local)) { + if (in_addr_is_set(AF_INET6, &info->local)) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Local:", @@ -1817,7 +1814,7 @@ static int link_status_one( return table_log_add_error(r); } - if (!in_addr_is_null(AF_INET6, &info->remote)) { + if (in_addr_is_set(AF_INET6, &info->remote)) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Remote:", @@ -1833,14 +1830,14 @@ static int link_status_one( if (r < 0) return table_log_add_error(r); - if (info->has_tunnel_ipv4 && !in_addr_is_null(AF_INET, &info->remote)) { + if (info->has_tunnel_ipv4 && in_addr_is_set(AF_INET, &info->remote)) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Remote:", TABLE_IN_ADDR, &info->remote); if (r < 0) return table_log_add_error(r); - } else if (!in_addr_is_null(AF_INET6, &info->remote)) { + } else if (in_addr_is_set(AF_INET6, &info->remote)) { r = table_add_many(table, TABLE_EMPTY, TABLE_STRING, "Remote:", @@ -2065,6 +2062,16 @@ static int link_status_one( if (r < 0) return r; + r = sd_network_link_get_activation_policy(info->ifindex, &activation_policy); + if (r >= 0) { + r = table_add_many(table, + TABLE_EMPTY, + TABLE_STRING, "Activation Policy:", + TABLE_STRING, activation_policy); + if (r < 0) + return table_log_add_error(r); + } + if (lease) { const void *client_id; size_t client_id_len; @@ -2212,7 +2219,7 @@ static int link_status(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_hwdb_unrefp) sd_hwdb *hwdb = NULL; _cleanup_(link_info_array_freep) LinkInfo *links = NULL; - int r, c, i; + int r, c; (void) pager_open(arg_pager_flags); @@ -2237,7 +2244,7 @@ static int link_status(int argc, char *argv[], void *userdata) { if (c < 0) return c; - for (i = 0; i < c; i++) { + for (int i = 0; i < c; i++) { if (i > 0) fputc('\n', stdout); @@ -2266,7 +2273,7 @@ static char *lldp_capabilities_to_string(uint16_t x) { } static void lldp_capabilities_legend(uint16_t x) { - unsigned w, i, cols = columns(); + unsigned cols = columns(); static const char* const table[] = { "o - Other", "p - Repeater", @@ -2285,7 +2292,7 @@ static void lldp_capabilities_legend(uint16_t x) { return; printf("\nCapability Flags:\n"); - for (w = 0, i = 0; i < ELEMENTSOF(table); i++) + for (unsigned w = 0, i = 0; i < ELEMENTSOF(table); i++) if (x & (1U << i) || arg_all) { bool newline; @@ -2301,7 +2308,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(link_info_array_freep) LinkInfo *links = NULL; _cleanup_(table_unrefp) Table *table = NULL; - int i, r, c, m = 0; + int r, c, m = 0; uint16_t all = 0; TableCell *cell; @@ -2347,7 +2354,7 @@ static int link_lldp_status(int argc, char *argv[], void *userdata) { assert_se(cell = table_get_cell(table, 0, 5)); table_set_minimum_width(table, cell, 16); - for (i = 0; i < c; i++) { + for (int i = 0; i < c; i++) { _cleanup_fclose_ FILE *f = NULL; r = open_lldp_neighbors(links[i].ifindex, &f); @@ -2476,7 +2483,7 @@ static int link_up_down_send_message(sd_netlink *rtnl, char *command, int index) static int link_up_down(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_set_free_ Set *indexes = NULL; - int index, r, i; + int index, r; void *p; r = sd_netlink_open(&rtnl); @@ -2487,7 +2494,7 @@ static int link_up_down(int argc, char *argv[], void *userdata) { if (!indexes) return log_oom(); - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { index = resolve_interface_or_warn(&rtnl, argv[i]); if (index < 0) return index; @@ -2503,8 +2510,8 @@ static int link_up_down(int argc, char *argv[], void *userdata) { if (r < 0) { char ifname[IF_NAMESIZE + 1]; - return log_error_errno(r, "Failed to %s interface %s: %m", - argv[1], format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX)); + return log_error_errno(r, "Failed to bring %s interface %s: %m", + argv[0], format_ifname_full(index, ifname, FORMAT_IFNAME_IFINDEX)); } } @@ -2514,7 +2521,7 @@ static int link_up_down(int argc, char *argv[], void *userdata) { static int link_delete(int argc, char *argv[], void *userdata) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_set_free_ Set *indexes = NULL; - int index, r, i; + int index, r; void *p; r = sd_netlink_open(&rtnl); @@ -2525,7 +2532,7 @@ static int link_delete(int argc, char *argv[], void *userdata) { if (!indexes) return log_oom(); - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { index = resolve_interface_or_warn(&rtnl, argv[i]); if (index < 0) return index; @@ -2564,13 +2571,13 @@ static int link_renew_one(sd_bus *bus, int index, const char *name) { static int link_renew(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - int index, i, k = 0, r; + int index, k = 0, r; r = sd_bus_open_system(&bus); if (r < 0) return log_error_errno(r, "Failed to connect system bus: %m"); - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { index = resolve_interface_or_warn(&rtnl, argv[i]); if (index < 0) return index; @@ -2598,14 +2605,14 @@ static int link_force_renew_one(sd_bus *bus, int index, const char *name) { static int link_force_renew(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; - int index, i, k = 0, r; + int k = 0, r; r = sd_bus_open_system(&bus); if (r < 0) return log_error_errno(r, "Failed to connect system bus: %m"); - for (i = 1; i < argc; i++) { - index = resolve_interface_or_warn(&rtnl, argv[i]); + for (int i = 1; i < argc; i++) { + int index = resolve_interface_or_warn(&rtnl, argv[i]); if (index < 0) return index; @@ -2638,7 +2645,7 @@ static int verb_reconfigure(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_set_free_ Set *indexes = NULL; - int index, i, r; + int index, r; void *p; r = sd_bus_open_system(&bus); @@ -2649,7 +2656,7 @@ static int verb_reconfigure(int argc, char *argv[], void *userdata) { if (!indexes) return log_oom(); - for (i = 1; i < argc; i++) { + for (int i = 1; i < argc; i++) { index = resolve_interface_or_warn(&rtnl, argv[i]); if (index < 0) return index; @@ -2704,12 +2711,11 @@ static int help(void) { " -s --stats Show detailed link statics\n" " -l --full Do not ellipsize output\n" " -n --lines=INTEGER Number of journal entries to show\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -2816,7 +2822,7 @@ static void warn_networkd_missing(void) { static int run(int argc, char* argv[]) { int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/network/networkd-address-label.c b/src/network/networkd-address-label.c index f933a1da9..7b7b72469 100644 --- a/src/network/networkd-address-label.c +++ b/src/network/networkd-address-label.c @@ -55,11 +55,7 @@ static int address_label_new_static(Network *network, const char *filename, unsi .section = TAKE_PTR(n), }; - r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->address_labels_by_section, label->section, label); + r = hashmap_ensure_put(&network->address_labels_by_section, &network_config_hash_ops, label->section, label); if (r < 0) return r; @@ -192,8 +188,7 @@ int config_parse_address_label_prefix(const char *unit, return 0; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -236,7 +231,7 @@ int config_parse_address_label( } n->label = k; - n = NULL; + TAKE_PTR(n); return 0; } diff --git a/src/network/networkd-address-pool.c b/src/network/networkd-address-pool.c index 7e27db661..79a1c1b84 100644 --- a/src/network/networkd-address-pool.c +++ b/src/network/networkd-address-pool.c @@ -107,6 +107,15 @@ static bool address_pool_prefix_is_taken( return true; } + /* Don't clash with assigned foreign addresses */ + SET_FOREACH(a, l->addresses_foreign) { + if (a->family != p->family) + continue; + + if (in_addr_prefix_intersect(p->family, u, prefixlen, &a->in_addr, a->prefixlen)) + return true; + } + /* Don't clash with addresses already pulled from the pool, but not assigned yet */ SET_FOREACH(a, l->pool_addresses) { if (a->family != p->family) @@ -135,7 +144,6 @@ static bool address_pool_prefix_is_taken( static int address_pool_acquire_one(AddressPool *p, int family, unsigned prefixlen, union in_addr_union *found) { union in_addr_union u; - unsigned i; int r; assert(p); @@ -150,7 +158,7 @@ static int address_pool_acquire_one(AddressPool *p, int family, unsigned prefixl u = p->in_addr; - for (i = 0; i < RANDOM_PREFIX_TRIAL_MAX; i++) { + for (unsigned i = 0; i < RANDOM_PREFIX_TRIAL_MAX; i++) { r = in_addr_random_prefix(p->family, &u, p->prefixlen, prefixlen); if (r <= 0) return r; @@ -159,8 +167,8 @@ static int address_pool_acquire_one(AddressPool *p, int family, unsigned prefixl if (DEBUG_LOGGING) { _cleanup_free_ char *s = NULL; - (void) in_addr_to_string(p->family, &u, &s); - log_debug("Found range %s/%u", strna(s), prefixlen); + (void) in_addr_prefix_to_string(p->family, &u, prefixlen, &s); + log_debug("Found range %s", strna(s)); } *found = u; diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 961b24838..58b089901 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -9,6 +9,7 @@ #include "netlink-util.h" #include "networkd-address-pool.h" #include "networkd-address.h" +#include "networkd-ipv6-proxy-ndp.h" #include "networkd-manager.h" #include "networkd-network.h" #include "parse-util.h" @@ -56,6 +57,7 @@ int address_new(Address **ret) { .scope = RT_SCOPE_UNIVERSE, .cinfo.ifa_prefered = CACHE_INFO_INFINITY_LIFE_TIME, .cinfo.ifa_valid = CACHE_INFO_INFINITY_LIFE_TIME, + .set_broadcast = -1, .duplicate_address_detection = ADDRESS_FAMILY_IPV6, }; @@ -94,11 +96,7 @@ static int address_new_static(Network *network, const char *filename, unsigned s address->network = network; address->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_allocated(&network->addresses_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(network->addresses_by_section, address->section, address); + r = ordered_hashmap_ensure_put(&network->addresses_by_section, &network_config_hash_ops, address->section, address); if (r < 0) return r; @@ -133,7 +131,8 @@ Address *address_free(Address *address) { if (n->address == address) free(set_remove(address->link->ndisc_addresses, n)); - if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address)) + if (address->family == AF_INET6 && + in6_addr_equal(&address->in_addr.in6, &address->link->ipv6ll_address)) memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); } @@ -150,7 +149,23 @@ static bool address_may_have_broadcast(const Address *a) { /* A /31 or /32 IPv4 address does not have a broadcast address. * See https://tools.ietf.org/html/rfc3021 */ - return a->family == AF_INET && in4_addr_is_null(&a->in_addr_peer.in) && a->prefixlen <= 30; + return a->family == AF_INET && + in_addr_is_null(AF_INET, &a->in_addr_peer) && + a->prefixlen <= 30; +} + +static bool address_may_set_broadcast(const Address *a, const Link *link) { + assert(a); + assert(link); + + if (!address_may_have_broadcast(a)) + return false; + + if (a->set_broadcast >= 0) + return a->set_broadcast; + + /* Typical configuration for wireguard does not set broadcast. */ + return !streq_ptr(link->kind, "wireguard"); } static uint32_t address_prefix(const Address *a) { @@ -265,10 +280,12 @@ static int address_set_masquerade(Address *address, bool add) { if (!address->link->network) return 0; - if (!address->link->network->ip_masquerade) + if (address->family == AF_INET && + !FLAGS_SET(address->link->network->ip_masquerade, ADDRESS_FAMILY_IPV4)) return 0; - if (address->family != AF_INET) + if (address->family == AF_INET6 && + !FLAGS_SET(address->link->network->ip_masquerade, ADDRESS_FAMILY_IPV6)) return 0; if (address->scope >= RT_SCOPE_LINK) @@ -282,7 +299,7 @@ static int address_set_masquerade(Address *address, bool add) { if (r < 0) return r; - r = fw_add_masquerade(add, AF_INET, 0, &masked, address->prefixlen, NULL, NULL, 0); + r = fw_add_masquerade(&address->link->manager->fw_ctx, add, address->family, &masked, address->prefixlen); if (r < 0) return r; @@ -329,6 +346,7 @@ static int address_add_foreign(Link *link, const Address *in, Address **ret) { } static int address_add(Link *link, const Address *in, Address **ret) { + bool is_new = false; Address *address; int r; @@ -341,6 +359,7 @@ static int address_add(Link *link, const Address *in, Address **ret) { r = address_add_internal(link, &link->addresses, in, &address); if (r < 0) return r; + is_new = true; } else if (r == 0) { /* Take over a foreign address */ r = set_ensure_put(&link->addresses, &address_hash_ops, address); @@ -356,8 +375,7 @@ static int address_add(Link *link, const Address *in, Address **ret) { if (ret) *ret = address; - - return 0; + return is_new; } static int address_update(Address *address, const Address *src) { @@ -389,7 +407,7 @@ static int address_update(Address *address, const Address *src) { if (address->family == AF_INET6 && in_addr_is_link_local(AF_INET6, &address->in_addr) > 0 && - IN6_IS_ADDR_UNSPECIFIED(&address->link->ipv6ll_address) > 0) { + in6_addr_is_null(&address->link->ipv6ll_address)) { r = link_ipv6ll_gained(address->link, &address->in_addr.in6); if (r < 0) @@ -405,7 +423,8 @@ static int address_drop(Address *address) { bool ready; int r; - assert(address); + if (!address) + return 0; ready = address_is_ready(address); link = address->link; @@ -447,29 +466,57 @@ int address_get(Link *link, const Address *in, Address **ret) { return -ENOENT; } -static bool address_exists_internal(Set *addresses, int family, const union in_addr_union *in_addr) { - Address *address; +int link_has_ipv6_address(Link *link, const struct in6_addr *address) { + _cleanup_(address_freep) Address *a = NULL; + int r; - SET_FOREACH(address, addresses) { - if (address->family != family) - continue; - if (in_addr_equal(address->family, &address->in_addr, in_addr)) - return true; - } + assert(link); + assert(address); - return false; + r = address_new(&a); + if (r < 0) + return r; + + /* address_compare_func() only compares the local address for IPv6 case. So, it is enough to + * set only family and the address. */ + a->family = AF_INET6; + a->in_addr.in6 = *address; + + return address_get(link, a, NULL) >= 0; } -bool address_exists(Link *link, int family, const union in_addr_union *in_addr) { +static void log_address_debug(const Address *address, const char *str, const Link *link) { + assert(address); + assert(str); assert(link); - assert(IN_SET(family, AF_INET, AF_INET6)); - assert(in_addr); - if (address_exists_internal(link->addresses, family, in_addr)) - return true; - if (address_exists_internal(link->addresses_foreign, family, in_addr)) - return true; - return false; + if (DEBUG_LOGGING) { + _cleanup_free_ char *addr = NULL, *peer = NULL; + char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX]; + const char *valid_str = NULL, *preferred_str = NULL; + bool has_peer; + + (void) in_addr_to_string(address->family, &address->in_addr, &addr); + has_peer = in_addr_is_set(address->family, &address->in_addr_peer); + if (has_peer) + (void) in_addr_to_string(address->family, &address->in_addr_peer, &peer); + + if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME) + valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, + address->cinfo.ifa_valid * USEC_PER_SEC, + USEC_PER_SEC); + + if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME) + preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX, + address->cinfo.ifa_prefered * USEC_PER_SEC, + USEC_PER_SEC); + + log_link_debug(link, "%s address: %s%s%s/%u (valid %s%s, preferred %s%s)", + str, strnull(addr), has_peer ? " peer " : "", + has_peer ? strnull(peer) : "", address->prefixlen, + valid_str ? "for " : "forever", strempty(valid_str), + preferred_str ? "for " : "forever", strempty(preferred_str)); + } } static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { @@ -491,6 +538,37 @@ static int address_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link return 1; } +static int address_set_netlink_message(const Address *address, sd_netlink_message *req, Link *link) { + int r; + + assert(address); + assert(req); + assert(link); + + r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + if (r < 0) + return log_link_error_errno(link, r, "Could not set prefixlen: %m"); + + /* On remove, only IFA_F_MANAGETEMPADDR flag for IPv6 addresses are used. But anyway, set all + * flags here unconditionally. Without setting the flag, the template addresses generated by + * kernel will not be removed automatically when the main address is removed. */ + r = sd_rtnl_message_addr_set_flags(req, address->flags & 0xff); + if (r < 0) + return log_link_error_errno(link, r, "Could not set flags: %m"); + + if ((address->flags & ~0xff) != 0) { + r = sd_netlink_message_append_u32(req, IFA_FLAGS, address->flags); + if (r < 0) + return log_link_error_errno(link, r, "Could not set extended flags: %m"); + } + + r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr); + if (r < 0) + return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m"); + + return 0; +} + int address_remove( const Address *address, Link *link, @@ -506,25 +584,16 @@ int address_remove( assert(link->manager); assert(link->manager->rtnl); - if (DEBUG_LOGGING) { - _cleanup_free_ char *b = NULL; - - (void) in_addr_to_string(address->family, &address->in_addr, &b); - log_link_debug(link, "Removing address %s", strna(b)); - } + log_address_debug(address, "Removing", link); r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_DELADDR, link->ifindex, address->family); if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_DELADDR message: %m"); - r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + r = address_set_netlink_message(address, req, link); if (r < 0) - return log_link_error_errno(link, r, "Could not set prefixlen: %m"); - - r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m"); + return r; r = netlink_call_async(link->manager->rtnl, NULL, req, callback ?: address_remove_handler, @@ -553,7 +622,7 @@ static bool link_is_static_address_configured(const Link *link, const Address *a return false; } -static bool link_address_is_dynamic(const Link *link, const Address *address) { +bool link_address_is_dynamic(const Link *link, const Address *address) { Route *route; assert(link); @@ -581,7 +650,6 @@ static bool link_address_is_dynamic(const Link *link, const Address *address) { static int link_enumerate_ipv6_tentative_addresses(Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - sd_netlink_message *addr; int r; assert(link); @@ -596,7 +664,7 @@ static int link_enumerate_ipv6_tentative_addresses(Link *link) { if (r < 0) return r; - for (addr = reply; addr; addr = sd_netlink_message_next(addr)) { + for (sd_netlink_message *addr = reply; addr; addr = sd_netlink_message_next(addr)) { unsigned char flags; int ifindex; @@ -730,10 +798,7 @@ static int address_acquire(Link *link, const Address *original, Address **ret) { assert(ret); /* Something useful was configured? just use it */ - r = in_addr_is_null(original->family, &original->in_addr); - if (r < 0) - return r; - if (r == 0) { + if (in_addr_is_set(original->family, &original->in_addr)) { *ret = NULL; return 0; } @@ -785,13 +850,12 @@ int address_configure( const Address *address, Link *link, link_netlink_message_handler_t callback, - bool update, Address **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; Address *acquired_address, *a; - uint32_t flags; - int r; + bool update; + int r, k; assert(address); assert(IN_SET(address->family, AF_INET, AF_INET6)); @@ -813,12 +877,9 @@ int address_configure( if (acquired_address) address = acquired_address; - if (DEBUG_LOGGING) { - _cleanup_free_ char *str = NULL; + update = address_get(link, address, NULL) >= 0; - (void) in_addr_to_string(address->family, &address->in_addr, &str); - log_link_debug(link, "%s address: %s", update ? "Updating" : "Configuring", strna(str)); - } + log_address_debug(address, update ? "Updating" : "Configuring", link); if (update) r = sd_rtnl_message_new_addr_update(link->manager->rtnl, &req, @@ -829,34 +890,19 @@ int address_configure( if (r < 0) return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m"); - r = sd_rtnl_message_addr_set_prefixlen(req, address->prefixlen); + r = address_set_netlink_message(address, req, link); if (r < 0) - return log_link_error_errno(link, r, "Could not set prefixlen: %m"); - - flags = address->flags | IFA_F_PERMANENT; - r = sd_rtnl_message_addr_set_flags(req, flags & 0xff); - if (r < 0) - return log_link_error_errno(link, r, "Could not set flags: %m"); - - if (flags & ~0xff) { - r = sd_netlink_message_append_u32(req, IFA_FLAGS, flags); - if (r < 0) - return log_link_error_errno(link, r, "Could not set extended flags: %m"); - } + return r; r = sd_rtnl_message_addr_set_scope(req, address->scope); if (r < 0) return log_link_error_errno(link, r, "Could not set scope: %m"); - r = netlink_message_append_in_addr_union(req, IFA_LOCAL, address->family, &address->in_addr); - if (r < 0) - return log_link_error_errno(link, r, "Could not append IFA_LOCAL attribute: %m"); - - if (in_addr_is_null(address->family, &address->in_addr_peer) == 0) { + if (in_addr_is_set(address->family, &address->in_addr_peer)) { r = netlink_message_append_in_addr_union(req, IFA_ADDRESS, address->family, &address->in_addr_peer); if (r < 0) return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m"); - } else if (address_may_have_broadcast(address)) { + } else if (address_may_set_broadcast(address, link)) { r = sd_netlink_message_append_in_addr(req, IFA_BROADCAST, &address->broadcast); if (r < 0) return log_link_error_errno(link, r, "Could not append IFA_BROADCAST attribute: %m"); @@ -872,9 +918,9 @@ int address_configure( if (r < 0) return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m"); - r = address_add(link, address, &a); - if (r < 0) - return log_link_error_errno(link, r, "Could not add address: %m"); + k = address_add(link, address, &a); + if (k < 0) + return log_link_error_errno(link, k, "Could not add address: %m"); r = address_set_masquerade(a, true); if (r < 0) @@ -897,12 +943,13 @@ int address_configure( if (ret) *ret = a; - return 1; + return k; } static int static_address_ready_callback(Address *address) { Address *a; Link *link; + int r; assert(address); assert(address->link); @@ -916,8 +963,8 @@ static int static_address_ready_callback(Address *address) { if (!address_is_ready(a)) { _cleanup_free_ char *str = NULL; - (void) in_addr_to_string(a->family, &a->in_addr, &str); - log_link_debug(link, "an address %s/%u is not ready", strnull(str), a->prefixlen); + (void) in_addr_prefix_to_string(a->family, &a->in_addr, a->prefixlen, &str); + log_link_debug(link, "an address %s is not ready", strnull(str)); return 0; } @@ -927,6 +974,10 @@ static int static_address_ready_callback(Address *address) { link->addresses_ready = true; + r = link_set_ipv6_proxy_ndp_addresses(link); + if (r < 0) + return r; + return link_set_routes(link); } @@ -974,14 +1025,14 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) return 1; } -static int static_address_configure(const Address *address, Link *link, bool update) { +static int static_address_configure(const Address *address, Link *link) { Address *ret; int r; assert(address); assert(link); - r = address_configure(address, link, address_handler, update, &ret); + r = address_configure(address, link, address_handler, &ret); if (r < 0) return log_link_warning_errno(link, r, "Could not configure static address: %m"); @@ -1010,11 +1061,13 @@ int link_set_addresses(Link *link) { return 0; } - ORDERED_HASHMAP_FOREACH(ad, link->network->addresses_by_section) { - bool update; + if (link->address_messages != 0) { + log_link_debug(link, "Static addresses are configuring."); + return 0; + } - update = address_get(link, ad, NULL) > 0; - r = static_address_configure(ad, link, update); + ORDERED_HASHMAP_FOREACH(ad, link->network->addresses_by_section) { + r = static_address_configure(ad, link); if (r < 0) return r; } @@ -1038,7 +1091,7 @@ int link_set_addresses(Link *link) { return log_link_warning_errno(link, r, "Could not generate EUI64 address: %m"); address->family = AF_INET6; - r = static_address_configure(address, link, true); + r = static_address_configure(address, link); if (r < 0) return r; } @@ -1046,6 +1099,11 @@ int link_set_addresses(Link *link) { if (link->address_messages == 0) { link->addresses_configured = true; link->addresses_ready = true; + + r = link_set_ipv6_proxy_ndp_addresses(link); + if (r < 0) + return r; + r = link_set_routes(link); if (r < 0) return r; @@ -1059,15 +1117,11 @@ int link_set_addresses(Link *link) { int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { _cleanup_(address_freep) Address *tmp = NULL; - _cleanup_free_ char *buf = NULL, *buf_peer = NULL; Link *link = NULL; uint16_t type; unsigned char flags; Address *address = NULL; - char valid_buf[FORMAT_TIMESPAN_MAX]; - const char *valid_str = NULL; int ifindex, r; - bool has_peer = false; assert(rtnl); assert(message); @@ -1155,8 +1209,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, } else if (r >= 0) { if (in4_addr_equal(&tmp->in_addr.in, &tmp->in_addr_peer.in)) tmp->in_addr_peer = IN_ADDR_NULL; - else - has_peer = true; } r = sd_netlink_message_read_in_addr(message, IFA_BROADCAST, &tmp->broadcast); @@ -1183,7 +1235,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m"); return 0; } - has_peer = true; } else if (r == -ENODATA) { /* Does not have peer address. */ r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr.in6); @@ -1202,39 +1253,28 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, assert_not_reached("Received unsupported address family"); } - (void) in_addr_to_string(tmp->family, &tmp->in_addr, &buf); - (void) in_addr_to_string(tmp->family, &tmp->in_addr_peer, &buf_peer); - r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &tmp->cinfo); if (r < 0 && r != -ENODATA) { log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m"); return 0; - } else if (r >= 0 && tmp->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME) - valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, - tmp->cinfo.ifa_valid * USEC_PER_SEC, - USEC_PER_SEC); + } (void) address_get(link, tmp, &address); switch (type) { case RTM_NEWADDR: - if (address) - log_link_debug(link, "Remembering updated address: %s%s%s/%u (valid %s%s)", - strnull(buf), has_peer ? " peer " : "", - has_peer ? strnull(buf_peer) : "", tmp->prefixlen, - valid_str ? "for " : "forever", strempty(valid_str)); - else { + log_address_debug(tmp, address ? "Remembering updated" : "Remembering foreign", link); + if (!address) { /* An address appeared that we did not request */ r = address_add_foreign(link, tmp, &address); if (r < 0) { - log_link_warning_errno(link, r, "Failed to remember foreign address %s/%u, ignoring: %m", - strnull(buf), tmp->prefixlen); + _cleanup_free_ char *buf = NULL; + + (void) in_addr_prefix_to_string(tmp->family, &tmp->in_addr, tmp->prefixlen, &buf); + log_link_warning_errno(link, r, "Failed to remember foreign address %s, ignoring: %m", + strnull(buf)); return 0; - } else - log_link_debug(link, "Remembering foreign address: %s%s%s/%u (valid %s%s)", - strnull(buf), has_peer ? " peer " : "", - has_peer ? strnull(buf_peer) : "", tmp->prefixlen, - valid_str ? "for " : "forever", strempty(valid_str)); + } } /* address_update() logs internally, so we don't need to here. */ @@ -1245,17 +1285,8 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, break; case RTM_DELADDR: - if (address) { - log_link_debug(link, "Forgetting address: %s%s%s/%u (valid %s%s)", - strnull(buf), has_peer ? " peer " : "", - has_peer ? strnull(buf_peer) : "", tmp->prefixlen, - valid_str ? "for " : "forever", strempty(valid_str)); - (void) address_drop(address); - } else - log_link_debug(link, "Kernel removed an address we don't remember: %s%s%s/%u (valid %s%s), ignoring.", - strnull(buf), has_peer ? " peer " : "", - has_peer ? strnull(buf_peer) : "", tmp->prefixlen, - valid_str ? "for " : "forever", strempty(valid_str)); + log_address_debug(tmp, address ? "Forgetting" : "Kernel removed unknown", link); + (void) address_drop(address); break; @@ -1266,60 +1297,6 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, return 1; } -int link_serialize_addresses(Link *link, FILE *f) { - bool space = false; - Address *a; - - assert(link); - - fputs("ADDRESSES=", f); - SET_FOREACH(a, link->addresses) { - _cleanup_free_ char *address_str = NULL; - - if (in_addr_to_string(a->family, &a->in_addr, &address_str) < 0) - continue; - - fprintf(f, "%s%s/%u", space ? " " : "", address_str, a->prefixlen); - space = true; - } - fputc('\n', f); - - return 0; -} - -int link_deserialize_addresses(Link *link, const char *addresses) { - int r; - - assert(link); - - for (const char *p = addresses;; ) { - _cleanup_(address_freep) Address *tmp = NULL; - _cleanup_free_ char *address_str = NULL; - - r = extract_first_word(&p, &address_str, NULL, 0); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to parse ADDRESSES=: %m"); - if (r == 0) - return 0; - - r = address_new(&tmp); - if (r < 0) - return log_oom(); - - r = in_addr_prefix_from_string_auto(address_str, &tmp->family, &tmp->in_addr, &tmp->prefixlen); - if (r < 0) { - log_link_debug_errno(link, r, "Failed to parse address, ignoring: %s", address_str); - continue; - } - - r = address_add(link, tmp, NULL); - if (r < 0) - log_link_debug_errno(link, r, "Failed to add address %s, ignoring: %m", address_str); - } - - return 0; -} - static void static_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) { _cleanup_free_ char *pretty = NULL; Address *address; @@ -1487,6 +1464,7 @@ int config_parse_broadcast( Network *network = userdata; _cleanup_(address_free_or_set_invalidp) Address *n = NULL; + union in_addr_union u; int r; assert(filename); @@ -1504,21 +1482,47 @@ int config_parse_broadcast( return 0; } + if (isempty(rvalue)) { + /* The broadcast address will be calculated based on Address=, and set if the link is + * not a wireguard interface. Here, we do not check or set n->family. */ + n->broadcast = (struct in_addr) {}; + n->set_broadcast = -1; + TAKE_PTR(n); + return 0; + } + + r = parse_boolean(rvalue); + if (r >= 0) { + /* The broadcast address will be calculated based on Address=. Here, we do not check or + * set n->family. */ + n->broadcast = (struct in_addr) {}; + n->set_broadcast = r; + TAKE_PTR(n); + return 0; + } + if (n->family == AF_INET6) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Broadcast is not valid for IPv6 addresses, ignoring assignment: %s", rvalue); return 0; } - r = in_addr_from_string(AF_INET, rvalue, (union in_addr_union*) &n->broadcast); + r = in_addr_from_string(AF_INET, rvalue, &u); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Broadcast is invalid, ignoring assignment: %s", rvalue); return 0; } + if (in4_addr_is_null(&u.in)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Broadcast cannot be ANY address, ignoring assignment: %s", rvalue); + return 0; + } + n->broadcast = u.in; + n->set_broadcast = true; n->family = AF_INET; - n = NULL; + TAKE_PTR(n); return 0; } @@ -1601,8 +1605,7 @@ int config_parse_address( else n->in_addr_peer = buffer; - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1647,7 +1650,7 @@ int config_parse_label( if (r < 0) return log_oom(); - n = NULL; + TAKE_PTR(n); return 0; } @@ -1743,7 +1746,7 @@ int config_parse_address_flags( SET_FLAG(n->flags, ltype, r); - n = NULL; + TAKE_PTR(n); return 0; } @@ -1794,7 +1797,7 @@ int config_parse_address_scope( } n->scope_set = true; - n = NULL; + TAKE_PTR(n); return 0; } @@ -1812,7 +1815,6 @@ int config_parse_duplicate_address_detection( Network *network = userdata; _cleanup_(address_free_or_set_invalidp) Address *n = NULL; - AddressFamily a; int r; assert(filename); @@ -1841,15 +1843,15 @@ int config_parse_duplicate_address_detection( return 0; } - a = duplicate_address_detection_address_family_from_string(rvalue); + AddressFamily a = duplicate_address_detection_address_family_from_string(rvalue); if (a < 0) { - log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL), + log_syntax(unit, LOG_WARNING, filename, line, a, "Failed to parse %s=, ignoring: %s", lvalue, rvalue); return 0; } - n->duplicate_address_detection = a; - n = NULL; + + TAKE_PTR(n); return 0; } @@ -1873,7 +1875,7 @@ static int address_section_verify(Address *address) { } if (address_may_have_broadcast(address)) { - if (address->broadcast.s_addr == 0) + if (address->broadcast.s_addr == 0 && address->set_broadcast != 0) address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen); } else if (address->broadcast.s_addr != 0) { log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. " diff --git a/src/network/networkd-address.h b/src/network/networkd-address.h index 56e81da82..e3ca868c2 100644 --- a/src/network/networkd-address.h +++ b/src/network/networkd-address.h @@ -30,6 +30,7 @@ typedef struct Address { uint32_t flags; char *label; + int set_broadcast; struct in_addr broadcast; struct ifa_cacheinfo cinfo; @@ -49,8 +50,7 @@ typedef struct Address { int address_new(Address **ret); Address *address_free(Address *address); int address_get(Link *link, const Address *in, Address **ret); -bool address_exists(Link *link, int family, const union in_addr_union *in_addr); -int address_configure(const Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret); +int address_configure(const Address *address, Link *link, link_netlink_message_handler_t callback, Address **ret); int address_remove(const Address *address, Link *link, link_netlink_message_handler_t callback); bool address_equal(const Address *a1, const Address *a2); bool address_is_ready(const Address *a); @@ -62,8 +62,8 @@ DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free); int link_set_addresses(Link *link); int link_drop_addresses(Link *link); int link_drop_foreign_addresses(Link *link); -int link_serialize_addresses(Link *link, FILE *f); -int link_deserialize_addresses(Link *link, const char *addresses); +bool link_address_is_dynamic(const Link *link, const Address *address); +int link_has_ipv6_address(Link *link, const struct in6_addr *address); void ipv4_dad_unref(Link *link); int ipv4_dad_stop(Link *link); diff --git a/src/network/networkd-brvlan.c b/src/network/networkd-brvlan.c index e53c73c30..2847b336c 100644 --- a/src/network/networkd-brvlan.c +++ b/src/network/networkd-brvlan.c @@ -44,9 +44,9 @@ static int find_next_bit(int i, uint32_t x) { static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint16_t pvid, const uint32_t *br_vid_bitmap, const uint32_t *br_untagged_bitmap) { struct bridge_vlan_info br_vlan; - int i, j, k, r, cnt; - uint16_t begin, end; bool done, untagged = false; + uint16_t begin, end; + int r, cnt; assert(link); assert(req); @@ -56,16 +56,17 @@ static int append_vlan_info_data(Link *const link, sd_netlink_message *req, uint cnt = 0; begin = end = UINT16_MAX; - for (k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) { - unsigned base_bit; - uint32_t vid_map = br_vid_bitmap[k]; + for (int k = 0; k < BRIDGE_VLAN_BITMAP_LEN; k++) { uint32_t untagged_map = br_untagged_bitmap[k]; + uint32_t vid_map = br_vid_bitmap[k]; + unsigned base_bit; + int i; base_bit = k * 32; i = -1; done = false; do { - j = find_next_bit(i, vid_map); + int j = find_next_bit(i, vid_map); if (j > 0) { /* first hit of any bit */ if (begin == UINT16_MAX && end == UINT16_MAX) { diff --git a/src/network/networkd-can.c b/src/network/networkd-can.c index 7e31d2fc8..c0018c306 100644 --- a/src/network/networkd-can.c +++ b/src/network/networkd-can.c @@ -174,14 +174,14 @@ static int link_set_can(Link *link) { if (link->network->can_fd_mode >= 0) { cm.mask |= CAN_CTRLMODE_FD; - SET_FLAG(cm.flags, CAN_CTRLMODE_FD, link->network->can_fd_mode > 0); - log_link_debug(link, "%sabling FD mode", link->network->can_fd_mode > 0 ? "En" : "Dis"); + SET_FLAG(cm.flags, CAN_CTRLMODE_FD, link->network->can_fd_mode); + log_link_debug(link, "Setting FD mode to '%s'.", yes_no(link->network->can_fd_mode)); } if (link->network->can_non_iso >= 0) { cm.mask |= CAN_CTRLMODE_FD_NON_ISO; - SET_FLAG(cm.flags, CAN_CTRLMODE_FD_NON_ISO, link->network->can_non_iso > 0); - log_link_debug(link, "%sabling FD non-ISO mode", link->network->can_non_iso > 0 ? "En" : "Dis"); + SET_FLAG(cm.flags, CAN_CTRLMODE_FD_NON_ISO, link->network->can_non_iso); + log_link_debug(link, "Setting FD non-ISO mode to '%s'.", yes_no(link->network->can_non_iso)); } if (link->network->can_restart_us > 0) { @@ -195,10 +195,8 @@ static int link_set_can(Link *link) { format_timespan(time_string, FORMAT_TIMESPAN_MAX, restart_ms * 1000, MSEC_PER_SEC); - if (restart_ms > UINT32_MAX) { - log_link_error(link, "restart timeout (%s) too big.", time_string); - return -ERANGE; - } + if (restart_ms > UINT32_MAX) + return log_link_error_errno(link, SYNTHETIC_ERRNO(ERANGE), "restart timeout (%s) too big.", time_string); log_link_debug(link, "Setting restart = %s", time_string); @@ -210,13 +208,19 @@ static int link_set_can(Link *link) { if (link->network->can_triple_sampling >= 0) { cm.mask |= CAN_CTRLMODE_3_SAMPLES; SET_FLAG(cm.flags, CAN_CTRLMODE_3_SAMPLES, link->network->can_triple_sampling); - log_link_debug(link, "%sabling triple-sampling", link->network->can_triple_sampling ? "En" : "Dis"); + log_link_debug(link, "Setting triple-sampling to '%s'.", yes_no(link->network->can_triple_sampling)); + } + + if (link->network->can_berr_reporting >= 0) { + cm.mask |= CAN_CTRLMODE_BERR_REPORTING; + SET_FLAG(cm.flags, CAN_CTRLMODE_BERR_REPORTING, link->network->can_berr_reporting); + log_link_debug(link, "Setting bus error reporting to '%s'.", yes_no(link->network->can_berr_reporting)); } if (link->network->can_listen_only >= 0) { cm.mask |= CAN_CTRLMODE_LISTENONLY; SET_FLAG(cm.flags, CAN_CTRLMODE_LISTENONLY, link->network->can_listen_only); - log_link_debug(link, "%sabling listen-only mode", link->network->can_listen_only ? "En" : "Dis"); + log_link_debug(link, "Setting listen-only mode to '%s'.", yes_no(link->network->can_listen_only)); } if (cm.mask != 0) { @@ -227,7 +231,7 @@ static int link_set_can(Link *link) { if (link->network->can_termination >= 0) { - log_link_debug(link, "%sabling can-termination", link->network->can_termination ? "En" : "Dis"); + log_link_debug(link, "Setting can-termination to '%s'.", yes_no(link->network->can_termination)); r = sd_netlink_message_append_u16(m, IFLA_CAN_TERMINATION, link->network->can_termination ? CAN_TERMINATION_OHM_VALUE : 0); diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index bf51624ec..c413f1673 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -93,7 +93,7 @@ int config_parse_duid_type( type = duid_type_from_string(type_string); if (type < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, type, "Failed to parse DUID type '%s', ignoring.", type_string); return 0; } diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index 9f5812135..00d055cf8 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -3,6 +3,7 @@ #include #include +#include "bus-error.h" #include "dhcp-internal.h" #include "dhcp6-internal.h" #include "escape.h" @@ -62,11 +63,9 @@ static struct DUID fallback_duid = { .type = DUID_TYPE_EN }; DUID* link_get_duid(Link *link) { if (link->network->duid.type != _DUID_TYPE_INVALID) return &link->network->duid; - else if (link->hw_addr.length == 0 && - (link->manager->duid.type == DUID_TYPE_LLT || - link->manager->duid.type == DUID_TYPE_LL)) - /* Fallback to DUID that works without mac addresses. - * This is useful for tunnel devices without mac address. */ + else if (link->hw_addr.length == 0 && IN_SET(link->manager->duid.type, DUID_TYPE_LLT, DUID_TYPE_LL)) + /* Fallback to DUID that works without MAC address. + * This is useful for tunnel devices without MAC address. */ return &fallback_duid; else return &link->manager->duid; @@ -101,18 +100,20 @@ static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_er e = sd_bus_message_get_error(m); if (e) { - log_error_errno(sd_bus_error_get_errno(e), - "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s", - e->message); + r = sd_bus_error_get_errno(e); + log_warning_errno(r, "Could not get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %s", + bus_error_message(e, r)); goto configure; } r = sd_bus_message_read_array(m, 'y', &a, &sz); - if (r < 0) + if (r < 0) { + log_warning_errno(r, "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m"); goto configure; + } if (sz != sizeof(sd_id128_t)) { - log_error("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID."); + log_warning("Invalid product UUID. Falling back to use machine-app-specific ID as DUID-UUID."); goto configure; } @@ -282,16 +283,9 @@ int config_parse_dhcp( /* Previously, we had a slightly different enum here, * support its values for compatibility. */ - if (streq(rvalue, "none")) - s = ADDRESS_FAMILY_NO; - else if (streq(rvalue, "v4")) - s = ADDRESS_FAMILY_IPV4; - else if (streq(rvalue, "v6")) - s = ADDRESS_FAMILY_IPV6; - else if (streq(rvalue, "both")) - s = ADDRESS_FAMILY_YES; - else { - log_syntax(unit, LOG_WARNING, filename, line, 0, + s = dhcp_deprecated_address_family_from_string(rvalue); + if (s < 0) { + log_syntax(unit, LOG_WARNING, filename, line, s, "Failed to parse DHCP option, ignoring: %s", rvalue); return 0; } @@ -506,7 +500,7 @@ int config_parse_iaid(const char *unit, return 0; } -int config_parse_dhcp_user_class( +int config_parse_dhcp_user_or_vendor_class( const char *unit, const char *filename, unsigned line, @@ -524,6 +518,7 @@ int config_parse_dhcp_user_class( assert(l); assert(lvalue); assert(rvalue); + assert(IN_SET(ltype, AF_INET, AF_INET6)); if (isempty(rvalue)) { *l = strv_free(*l); @@ -549,13 +544,13 @@ int config_parse_dhcp_user_class( if (ltype == AF_INET) { if (len > UINT8_MAX || len == 0) { log_syntax(unit, LOG_WARNING, filename, line, 0, - "%s length is not in the range 1-255, ignoring.", w); + "%s length is not in the range 1…255, ignoring.", w); continue; } } else { if (len > UINT16_MAX || len == 0) { log_syntax(unit, LOG_WARNING, filename, line, 0, - "%s length is not in the range 1-65535, ignoring.", w); + "%s length is not in the range 1…65535, ignoring.", w); continue; } } @@ -566,57 +561,6 @@ int config_parse_dhcp_user_class( } } -int config_parse_dhcp_vendor_class( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - char ***l = data; - int r; - - assert(l); - assert(lvalue); - assert(rvalue); - - if (isempty(rvalue)) { - *l = strv_free(*l); - return 0; - } - - for (const char *p = rvalue;;) { - _cleanup_free_ char *w = NULL; - - r = extract_first_word(&p, &w, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to split vendor classes option, ignoring: %s", rvalue); - return 0; - } - if (r == 0) - return 0; - - if (strlen(w) > UINT8_MAX) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "%s length is not in the range 1-255, ignoring.", w); - continue; - } - - r = strv_push(l, w); - if (r < 0) - return log_oom(); - - w = NULL; - } -} - int config_parse_dhcp_send_option( const char *unit, const char *filename, @@ -720,7 +664,7 @@ int config_parse_dhcp_send_option( type = dhcp_option_data_type_from_string(word); if (type < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, type, "Invalid DHCP option data type, ignoring assignment: %s", p); return 0; } @@ -739,25 +683,31 @@ int config_parse_dhcp_send_option( break; } case DHCP_OPTION_DATA_UINT16:{ - r = safe_atou16(p, &uint16_data); + uint16_t k; + + r = safe_atou16(p, &k); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse DHCP uint16 data, ignoring assignment: %s", p); return 0; } + uint16_data = htobe16(k); udata = &uint16_data; sz = sizeof(uint16_t); break; } case DHCP_OPTION_DATA_UINT32: { - r = safe_atou32(p, &uint32_data); + uint32_t k; + + r = safe_atou32(p, &k); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse DHCP uint32 data, ignoring assignment: %s", p); return 0; } + uint32_data = htobe32(k); udata = &uint32_data; sz = sizeof(uint32_t); @@ -858,7 +808,6 @@ int config_parse_dhcp_request_options( void *userdata) { Network *network = data; - const char *p; int r; assert(filename); @@ -875,7 +824,7 @@ int config_parse_dhcp_request_options( return 0; } - for (p = rvalue;;) { + for (const char *p = rvalue;;) { _cleanup_free_ char *n = NULL; uint32_t i; diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index 78c149ebc..acf80e625 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -16,7 +16,7 @@ typedef enum DHCPUseDomains { DHCP_USE_DOMAINS_YES, DHCP_USE_DOMAINS_ROUTE, _DHCP_USE_DOMAINS_MAX, - _DHCP_USE_DOMAINS_INVALID = -1, + _DHCP_USE_DOMAINS_INVALID = -EINVAL, } DHCPUseDomains; typedef enum DHCPOptionDataType { @@ -66,7 +66,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_domains); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_use_ntp); CONFIG_PARSER_PROTOTYPE(config_parse_iaid); CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table); -CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_class); -CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_vendor_class); +CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_or_vendor_class); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options); diff --git a/src/network/networkd-dhcp-server.c b/src/network/networkd-dhcp-server.c index cf279c640..ad979fb2c 100644 --- a/src/network/networkd-dhcp-server.c +++ b/src/network/networkd-dhcp-server.c @@ -10,6 +10,7 @@ #include "fileio.h" #include "networkd-address.h" #include "networkd-dhcp-server.h" +#include "networkd-dhcp-server-bus.h" #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-network.h" @@ -46,7 +47,7 @@ static Address* link_find_dhcp_server_address(Link *link) { /* The first statically configured address if there is any */ ORDERED_HASHMAP_FOREACH(address, link->network->addresses_by_section) if (address->family == AF_INET && - !in_addr_is_null(address->family, &address->in_addr)) + in_addr_is_set(address->family, &address->in_addr)) return address; /* If that didn't work, find a suitable address we got from the pool */ @@ -59,7 +60,7 @@ static Address* link_find_dhcp_server_address(Link *link) { static int link_push_uplink_to_dhcp_server( Link *link, - sd_dhcp_lease_server_type what, + sd_dhcp_lease_server_type_t what, sd_dhcp_server *s) { _cleanup_free_ struct in_addr *addresses = NULL; @@ -271,6 +272,10 @@ int dhcp4_server_configure(Link *link) { return r; } + r = sd_dhcp_server_set_callback(link->dhcp_server, dhcp_server_callback, link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to set callback for DHCPv4 server instance: %m"); + address = link_find_dhcp_server_address(link); if (!address) return log_link_error_errno(link, SYNTHETIC_ERRNO(EBUSY), @@ -302,7 +307,7 @@ int dhcp4_server_configure(Link *link) { return log_link_error_errno(link, r, "Failed to set default lease time for DHCPv4 server instance: %m"); } - for (sd_dhcp_lease_server_type type = 0; type < _SD_DHCP_LEASE_SERVER_TYPE_MAX; type ++) { + for (sd_dhcp_lease_server_type_t type = 0; type < _SD_DHCP_LEASE_SERVER_TYPE_MAX; type ++) { if (!link->network->dhcp_server_emit[type].emit) continue; diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index f3c1e5f60..6f06e2218 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -8,6 +8,7 @@ #include "escape.h" #include "alloc-util.h" #include "dhcp-client-internal.h" +#include "hostname-setup.h" #include "hostname-util.h" #include "parse-util.h" #include "network-internal.h" @@ -16,8 +17,9 @@ #include "networkd-link.h" #include "networkd-manager.h" #include "networkd-network.h" +#include "networkd-state-file.h" #include "string-table.h" -#include "string-util.h" +#include "strv.h" #include "sysctl-util.h" #include "web-util.h" @@ -35,8 +37,6 @@ static int dhcp4_release_old_lease(Link *link) { log_link_debug(link, "Removing old DHCPv4 address and routes."); - link_dirty(link); - SET_FOREACH(route, link->dhcp_routes_old) { k = route_remove(route, NULL, link, NULL); if (k < 0) @@ -70,6 +70,10 @@ static void dhcp4_check_ready(Link *link) { return; } + r = sd_ipv4ll_stop(link->ipv4ll); + if (r < 0) + log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m"); + link_check_ready(link); } @@ -119,7 +123,7 @@ static int route_scope_from_address(const Route *route, const struct in_addr *se assert(self_addr); if (in4_addr_is_localhost(&route->dst.in) || - (!in4_addr_is_null(self_addr) && in4_addr_equal(&route->dst.in, self_addr))) + (in4_addr_is_set(self_addr) && in4_addr_equal(&route->dst.in, self_addr))) return RT_SCOPE_HOST; else if (in4_addr_is_null(&route->gw.in)) return RT_SCOPE_LINK; @@ -158,7 +162,7 @@ static int dhcp_route_configure(Route *route, Link *link) { static int link_set_dns_routes(Link *link, const struct in_addr *address) { const struct in_addr *dns; uint32_t table; - int i, n, r; + int n, r; assert(link); assert(link->dhcp_lease); @@ -176,7 +180,7 @@ static int link_set_dns_routes(Link *link, const struct in_addr *address) { table = link_get_dhcp_route_table(link); - for (i = 0; i < n; i ++) { + for (int i = 0; i < n; i ++) { _cleanup_(route_freep) Route *route = NULL; r = route_new(&route); @@ -832,7 +836,7 @@ static int dhcp4_update_address(Link *link, bool announce) { if (r < 0 && r != -ENODATA) return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m"); - if (r > 0 && !in4_addr_is_null(&router[0])) + if (r > 0 && in4_addr_is_set(&router[0])) log_struct(LOG_INFO, LOG_LINK_INTERFACE(link), LOG_LINK_MESSAGE(link, "DHCPv4 address "IPV4_ADDRESS_FMT_STR"/%u via "IPV4_ADDRESS_FMT_STR, @@ -867,7 +871,7 @@ static int dhcp4_update_address(Link *link, bool announce) { /* allow reusing an existing address and simply update its lifetime * in case it already exists */ - r = address_configure(addr, link, dhcp4_address_handler, true, &ret); + r = address_configure(addr, link, dhcp4_address_handler, &ret); if (r < 0) return log_link_error_errno(link, r, "Failed to set DHCPv4 address: %m"); @@ -1049,10 +1053,7 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { switch (event) { case SD_DHCP_CLIENT_EVENT_STOP: - - if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4)) { - assert(link->ipv4ll); - + if (link->ipv4ll) { log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address"); r = sd_ipv4ll_start(link->ipv4ll); @@ -1137,6 +1138,17 @@ static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) { return -ENOMSG; } break; + + case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE: + if (link->ipv4ll && !sd_ipv4ll_is_running(link->ipv4ll)) { + log_link_debug(link, "Problems acquiring DHCP lease, acquiring IPv4 link-local address"); + + r = sd_ipv4ll_start(link->ipv4ll); + if (r < 0) + return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); + } + break; + default: if (event < 0) log_link_warning_errno(link, event, "DHCP error: Client failed: %m"); @@ -1162,7 +1174,7 @@ static int dhcp4_set_hostname(Link *link) { else { r = gethostname_strict(&hostname); if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */ - return r; + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m"); hn = hostname; } @@ -1170,60 +1182,9 @@ static int dhcp4_set_hostname(Link *link) { r = sd_dhcp_client_set_hostname(link->dhcp_client, hn); if (r == -EINVAL && hostname) /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */ - log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m"); + log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m"); else if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m"); - - return 0; -} - -static bool promote_secondaries_enabled(const char *ifname) { - _cleanup_free_ char *promote_secondaries_sysctl = NULL; - char *promote_secondaries_path; - int r; - - promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries"); - r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl); - if (r < 0) { - log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path); - return false; - } - - truncate_nl(promote_secondaries_sysctl); - r = parse_boolean(promote_secondaries_sysctl); - if (r < 0) - log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl); - return r > 0; -} - -/* dhcp4_set_promote_secondaries will ensure this interface has - * the "promote_secondaries" option in the kernel set. If this sysctl - * is not set DHCP will work only as long as the IP address does not - * changes between leases. The kernel will remove all secondary IP - * addresses of an interface otherwise. The way systemd-network works - * is that the new IP of a lease is added as a secondary IP and when - * the primary one expires it relies on the kernel to promote the - * secondary IP. See also https://github.com/systemd/systemd/issues/7163 - */ -static int dhcp4_set_promote_secondaries(Link *link) { - int r; - - assert(link); - - /* check if the kernel has promote_secondaries enabled for our - * interface. If it is not globally enabled or enabled for the - * specific interface we must either enable it. - */ - if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) { - char *promote_secondaries_path = NULL; - - log_link_debug(link, "promote_secondaries is unset, setting it"); - promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries"); - r = sysctl_write(promote_secondaries_path, "1"); - if (r < 0) - log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path); - return r > 0; - } + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m"); return 0; } @@ -1253,7 +1214,7 @@ static int dhcp4_set_client_identifier(Link *link) { duid->raw_data_len > 0 ? duid->raw_data : NULL, duid->raw_data_len); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m"); break; } case DHCP_CLIENT_ID_DUID_ONLY: { @@ -1269,7 +1230,7 @@ static int dhcp4_set_client_identifier(Link *link) { duid->raw_data_len > 0 ? duid->raw_data : NULL, duid->raw_data_len); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m"); break; } case DHCP_CLIENT_ID_MAC: { @@ -1287,7 +1248,7 @@ static int dhcp4_set_client_identifier(Link *link) { hw_addr, hw_addr_len); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m"); break; } default: @@ -1297,23 +1258,29 @@ static int dhcp4_set_client_identifier(Link *link) { return 0; } -static int dhcp4_init(Link *link) { - int r; +static int dhcp4_set_request_address(Link *link) { + Address *a; assert(link); + assert(link->network); + assert(link->dhcp_client); - if (link->dhcp_client) + if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) return 0; - r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize); - if (r < 0) - return r; + SET_FOREACH(a, link->addresses_foreign) { + if (a->family != AF_INET) + continue; + if (link_address_is_dynamic(link, a)) + break; + } - r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0); - if (r < 0) - return r; + if (!a) + return 0; - return 0; + log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in)); + + return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in); } int dhcp4_configure(Link *link) { @@ -1327,45 +1294,45 @@ int dhcp4_configure(Link *link) { if (!link_dhcp4_enabled(link)) return 0; - r = dhcp4_set_promote_secondaries(link); - if (r < 0) - return r; + if (!link->dhcp_client) { + r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m"); - r = dhcp4_init(link); - if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to initialize DHCP4 client: %m"); + r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m"); + } r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes, link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL, link->hw_addr.length, link->iftype); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m"); r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m"); r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m"); - r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, - link->network->dhcp_broadcast); + r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link->network->dhcp_broadcast); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m"); - if (link->mtu) { + if (link->mtu > 0) { r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m"); } if (link->network->dhcp_use_mtu) { - r = sd_dhcp_client_set_request_option(link->dhcp_client, - SD_DHCP_OPTION_INTERFACE_MTU); + r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m"); } /* NOTE: even if this variable is called "use", it also "sends" PRL @@ -1374,39 +1341,37 @@ int dhcp4_configure(Link *link) { /* NOTE: when using Anonymize=yes, routes PRL options are sent * by default, so they don't need to be added here. */ if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) { - r = sd_dhcp_client_set_request_option(link->dhcp_client, - SD_DHCP_OPTION_STATIC_ROUTE); + r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m"); - r = sd_dhcp_client_set_request_option(link->dhcp_client, - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE); + r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m"); } if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO && !link->network->dhcp_anonymize) { r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m"); } if (link->network->dhcp_use_ntp) { r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m"); } if (link->network->dhcp_use_sip) { r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m"); } if (link->network->dhcp_use_timezone) { r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m"); } SET_FOREACH(request_options, link->network->dhcp_request_options) { @@ -1414,7 +1379,7 @@ int dhcp4_configure(Link *link) { r = sd_dhcp_client_set_request_option(link->dhcp_client, option); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option); } ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) { @@ -1422,7 +1387,7 @@ int dhcp4_configure(Link *link) { if (r == -EEXIST) continue; if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m"); } ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) { @@ -1430,7 +1395,7 @@ int dhcp4_configure(Link *link) { if (r == -EEXIST) continue; if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m"); } r = dhcp4_set_hostname(link); @@ -1441,49 +1406,52 @@ int dhcp4_configure(Link *link) { r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client, link->network->dhcp_vendor_class_identifier); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m"); } if (link->network->dhcp_mudurl) { - r = sd_dhcp_client_set_mud_url(link->dhcp_client, - link->network->dhcp_mudurl); + r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m"); } if (link->network->dhcp_user_class) { r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m"); } - if (link->network->dhcp_client_port) { + if (link->network->dhcp_client_port > 0) { r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m"); } if (link->network->dhcp_max_attempts > 0) { r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m"); } if (link->network->dhcp_ip_service_type > 0) { r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m"); } if (link->network->dhcp_fallback_lease_lifetime > 0) { r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m"); } + r = dhcp4_set_request_address(link); + if (r < 0) + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m"); + r = dhcp4_configure_dad(link); if (r < 0) - return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m"); + return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m"); return dhcp4_set_client_identifier(link); } @@ -1513,30 +1481,6 @@ int dhcp4_update_mac(Link *link) { return 0; } -int link_deserialize_dhcp4(Link *link, const char *dhcp4_address) { - union in_addr_union address; - int r; - - assert(link); - - if (isempty(dhcp4_address)) - return 0; - - r = in_addr_from_string(AF_INET, dhcp4_address, &address); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to parse DHCPv4 address: %s", dhcp4_address); - - r = dhcp4_init(link); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to initialize DHCPv4 client: %m"); - - r = sd_dhcp_client_set_request_address(link->dhcp_client, &address.in); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to set initial DHCPv4 address %s: %m", dhcp4_address); - - return 0; -} - int config_parse_dhcp_max_attempts( const char *unit, const char *filename, @@ -1563,7 +1507,7 @@ int config_parse_dhcp_max_attempts( } if (streq(rvalue, "infinity")) { - network->dhcp_max_attempts = (uint64_t) -1; + network->dhcp_max_attempts = UINT64_MAX; return 0; } diff --git a/src/network/networkd-dhcp4.h b/src/network/networkd-dhcp4.h index daab5b1d7..5ec2f88b7 100644 --- a/src/network/networkd-dhcp4.h +++ b/src/network/networkd-dhcp4.h @@ -14,14 +14,12 @@ typedef enum DHCPClientIdentifier { * https://github.com/systemd/systemd/issues/7828 */ DHCP_CLIENT_ID_DUID_ONLY, _DHCP_CLIENT_ID_MAX, - _DHCP_CLIENT_ID_INVALID = -1, + _DHCP_CLIENT_ID_INVALID = -EINVAL, } DHCPClientIdentifier; int dhcp4_configure(Link *link); int dhcp4_update_mac(Link *link); -int link_deserialize_dhcp4(Link *link, const char *dhcp4_address); - CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_max_attempts); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index d4d4182ee..72bb46b18 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -11,9 +11,9 @@ #include "escape.h" #include "hashmap.h" +#include "hostname-setup.h" #include "hostname-util.h" #include "missing_network.h" -#include "network-internal.h" #include "networkd-address.h" #include "networkd-dhcp6.h" #include "networkd-link.h" @@ -137,7 +137,7 @@ static int dhcp6_pd_remove_old(Link *link, bool force) { assert(link); assert(link->manager); - if (!force && (link->dhcp6_pd_address_messages != 0 || link->dhcp6_pd_route_configured != 0)) + if (!force && (link->dhcp6_pd_address_messages != 0 || link->dhcp6_pd_route_messages != 0)) return 0; if (set_isempty(link->dhcp6_pd_addresses_old) && set_isempty(link->dhcp6_pd_routes_old)) @@ -161,8 +161,6 @@ static int dhcp6_pd_remove_old(Link *link, bool force) { log_link_debug(link, "Removing old DHCPv6 Prefix Delegation addresses and routes."); - link_dirty(link); - SET_FOREACH(route, link->dhcp6_pd_routes_old) { k = route_remove(route, NULL, link, NULL); if (k < 0) @@ -205,8 +203,6 @@ int dhcp6_pd_remove(Link *link) { log_link_debug(link, "Removing DHCPv6 Prefix Delegation addresses and routes."); - link_dirty(link); - SET_FOREACH(route, link->dhcp6_pd_routes) { k = route_remove(route, NULL, link, NULL); if (k < 0) @@ -280,10 +276,13 @@ static int dhcp6_set_pd_route(Link *link, const union in_addr_union *prefix, con route->family = AF_INET6; route->dst = *prefix; route->dst_prefixlen = 64; + route->protocol = RTPROT_DHCP; r = route_configure(route, link, dhcp6_pd_route_handler, &ret); if (r < 0) return log_link_error_errno(link, r, "Failed to set DHCPv6 prefix route: %m"); + if (r > 0) + link->dhcp6_pd_route_configured = false; link->dhcp6_pd_route_messages++; @@ -309,11 +308,9 @@ static int dhcp6_set_pd_route(Link *link, const union in_addr_union *prefix, con .link = link_ref(link), }; - r = hashmap_ensure_allocated(&link->manager->dhcp6_prefixes, &in6_addr_hash_ops); - if (r < 0) + r = hashmap_ensure_put(&link->manager->dhcp6_prefixes, &in6_addr_hash_ops, &pd->prefix, pd); + if (r == -ENOMEM) return log_oom(); - - r = hashmap_put(link->manager->dhcp6_prefixes, &pd->prefix, pd); if (r < 0) return log_link_error_errno(link, r, "Failed to store DHCPv6 prefix route at manager: %m"); @@ -354,22 +351,16 @@ static int dhcp6_pd_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin link_enter_failed(link); return 1; } - - r = link_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; - } } return 1; } -static int dhcp6_set_pd_address(Link *link, - const union in_addr_union *prefix, - uint8_t prefix_len, - uint32_t lifetime_preferred, - uint32_t lifetime_valid) { +static int dhcp6_set_pd_address( + Link *link, + const union in_addr_union *prefix, + uint32_t lifetime_preferred, + uint32_t lifetime_valid) { _cleanup_(address_freep) Address *address = NULL; Address *ret; @@ -388,7 +379,7 @@ static int dhcp6_set_pd_address(Link *link, address->in_addr = *prefix; - if (!in_addr_is_null(AF_INET6, &link->network->dhcp6_pd_token)) + if (in_addr_is_set(AF_INET6, &link->network->dhcp6_pd_token)) memcpy(address->in_addr.in6.s6_addr + 8, link->network->dhcp6_pd_token.in6.s6_addr + 8, 8); else { r = generate_ipv6_eui_64_address(link, &address->in_addr.in6); @@ -396,14 +387,17 @@ static int dhcp6_set_pd_address(Link *link, return log_link_warning_errno(link, r, "Failed to generate EUI64 address for acquired DHCPv6 delegated prefix: %m"); } - address->prefixlen = prefix_len; + address->prefixlen = 64; address->family = AF_INET6; address->cinfo.ifa_prefered = lifetime_preferred; address->cinfo.ifa_valid = lifetime_valid; + SET_FLAG(address->flags, IFA_F_MANAGETEMPADDR, link->network->dhcp6_pd_manage_temporary_address); - r = address_configure(address, link, dhcp6_pd_address_handler, true, &ret); + r = address_configure(address, link, dhcp6_pd_address_handler, &ret); if (r < 0) return log_link_error_errno(link, r, "Failed to set DHCPv6 delegated prefix address: %m"); + if (r > 0) + link->dhcp6_pd_address_configured = false; link->dhcp6_pd_address_messages++; @@ -416,8 +410,13 @@ static int dhcp6_set_pd_address(Link *link, return 0; } -static int dhcp6_pd_assign_prefix(Link *link, const union in_addr_union *prefix, const union in_addr_union *pd_prefix, - uint8_t prefix_len, uint32_t lifetime_preferred, uint32_t lifetime_valid) { +static int dhcp6_pd_assign_prefix( + Link *link, + const union in_addr_union *prefix, + const union in_addr_union *pd_prefix, + uint32_t lifetime_preferred, + uint32_t lifetime_valid) { + int r; assert(link); @@ -425,7 +424,7 @@ static int dhcp6_pd_assign_prefix(Link *link, const union in_addr_union *prefix, assert(prefix); if (link->network->dhcp6_pd_announce) { - r = radv_add_prefix(link, &prefix->in6, prefix_len, lifetime_preferred, lifetime_valid); + r = radv_add_prefix(link, &prefix->in6, 64, lifetime_preferred, lifetime_valid); if (r < 0) return r; } @@ -434,7 +433,7 @@ static int dhcp6_pd_assign_prefix(Link *link, const union in_addr_union *prefix, if (r < 0) return r; - r = dhcp6_set_pd_address(link, prefix, prefix_len, lifetime_preferred, lifetime_valid); + r = dhcp6_set_pd_address(link, prefix, lifetime_preferred, lifetime_valid); if (r < 0) return r; @@ -559,7 +558,7 @@ static void dhcp6_pd_prefix_distribute(Link *dhcp6_link, } (void) in_addr_to_string(AF_INET6, &assigned_prefix, &assigned_buf); - r = dhcp6_pd_assign_prefix(link, &assigned_prefix, masked_pd_prefix, 64, + r = dhcp6_pd_assign_prefix(link, &assigned_prefix, masked_pd_prefix, lifetime_preferred, lifetime_valid); if (r < 0) { log_link_error_errno(link, r, "Unable to assign/update prefix %s/64: %m", @@ -581,10 +580,6 @@ static int dhcp6_pd_prepare(Link *link) { if (!link_dhcp6_pd_is_enabled(link)) return 0; - link_dirty(link); - - link->dhcp6_pd_address_configured = false; - link->dhcp6_pd_route_configured = false; link->dhcp6_pd_prefixes_assigned = true; while ((address = set_steal_first(link->dhcp6_pd_addresses))) { @@ -614,14 +609,8 @@ static int dhcp6_pd_finalize(Link *link) { if (link->dhcp6_pd_address_messages == 0) { if (link->dhcp6_pd_prefixes_assigned) link->dhcp6_pd_address_configured = true; - } else { + } else log_link_debug(link, "Setting DHCPv6 PD addresses"); - /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are - * called, the related flags must be cleared. Otherwise, the link becomes configured - * state before routes are configured. */ - link->static_routes_configured = false; - link->static_nexthops_configured = false; - } if (link->dhcp6_pd_route_messages == 0) { if (link->dhcp6_pd_prefixes_assigned) @@ -704,8 +693,6 @@ static int dhcp6_remove_old(Link *link, bool force) { log_link_debug(link, "Removing old DHCPv6 addresses and routes."); - link_dirty(link); - SET_FOREACH(route, link->dhcp6_routes_old) { k = route_remove(route, NULL, link, NULL); if (k < 0) @@ -740,8 +727,6 @@ static int dhcp6_remove(Link *link) { log_link_debug(link, "Removing DHCPv6 addresses and routes."); - link_dirty(link); - SET_FOREACH(route, link->dhcp6_routes) { k = route_remove(route, NULL, link, NULL); if (k < 0) @@ -800,23 +785,21 @@ static int dhcp6_set_unreachable_route(Link *link, const union in_addr_union *ad assert(link); assert(addr); - (void) in_addr_to_string(AF_INET6, addr, &buf); + (void) in_addr_prefix_to_string(AF_INET6, addr, prefixlen, &buf); if (prefixlen > 64) { - log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s/%u", - strna(buf), prefixlen); + log_link_debug(link, "PD Prefix length > 64, ignoring prefix %s", strna(buf)); return 0; } if (prefixlen == 64) { - log_link_debug(link, "Not adding a blocking route for DHCPv6 delegated subnet %s/64 since distributed prefix is 64", + log_link_debug(link, "Not adding a blocking route for DHCPv6 delegated subnet %s since distributed prefix is 64", strna(buf)); return 1; } if (prefixlen < 48) - log_link_warning(link, "PD Prefix length < 48, looks unusual %s/%u", - strna(buf), prefixlen); + log_link_warning(link, "PD Prefix length < 48, looks unusual: %s", strna(buf)); r = route_new(&route); if (r < 0) @@ -827,18 +810,21 @@ static int dhcp6_set_unreachable_route(Link *link, const union in_addr_union *ad route->dst_prefixlen = prefixlen; route->table = link_get_dhcp_route_table(link); route->type = RTN_UNREACHABLE; + route->protocol = RTPROT_DHCP; r = route_configure(route, link, dhcp6_route_handler, &ret); if (r < 0) - return log_link_error_errno(link, r, "Failed to set unreachable route for DHCPv6 delegated subnet %s/%u: %m", - strna(buf), prefixlen); + return log_link_error_errno(link, r, "Failed to set unreachable route for DHCPv6 delegated subnet %s: %m", + strna(buf)); + if (r > 0) + link->dhcp6_route_configured = false; link->dhcp6_route_messages++; r = set_ensure_put(&link->dhcp6_routes, &route_hash_ops, ret); if (r < 0) - return log_link_error_errno(link, r, "Failed to store unreachable route for DHCPv6 delegated subnet %s/%u: %m", - strna(buf), prefixlen); + return log_link_error_errno(link, r, "Failed to store unreachable route for DHCPv6 delegated subnet %s: %m", + strna(buf)); (void) set_remove(link->dhcp6_routes_old, ret); @@ -897,9 +883,9 @@ static int dhcp6_pd_prefix_acquired(Link *dhcp6_link) { uint64_t n_prefixes = UINT64_C(1) << (64 - pd_prefix_len); _cleanup_free_ char *buf = NULL; - (void) in_addr_to_string(AF_INET6, &prefix, &buf); - log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s/%u", - n_prefixes, strna(buf), pd_prefix_len); + (void) in_addr_prefix_to_string(AF_INET6, &prefix, pd_prefix_len, &buf); + log_link_debug(dhcp6_link, "Assigning up to %" PRIu64 " prefixes from %s", + n_prefixes, strna(buf)); } dhcp6_pd_prefix_distribute(dhcp6_link, @@ -957,17 +943,75 @@ static int dhcp6_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * link_enter_failed(link); return 1; } - - r = link_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; - } } return 1; } +static void log_dhcp6_address(Link *link, const Address *address, char **ret) { + char valid_buf[FORMAT_TIMESPAN_MAX], preferred_buf[FORMAT_TIMESPAN_MAX]; + const char *valid_str = NULL, *preferred_str = NULL; + _cleanup_free_ char *buffer = NULL; + bool by_ndisc = false; + Address *existing; + NDiscAddress *na; + int log_level, r; + + assert(link); + assert(address); + + (void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buffer); + if (address->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME) + valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX, + address->cinfo.ifa_valid * USEC_PER_SEC, + USEC_PER_SEC); + if (address->cinfo.ifa_prefered != CACHE_INFO_INFINITY_LIFE_TIME) + preferred_str = format_timespan(preferred_buf, FORMAT_TIMESPAN_MAX, + address->cinfo.ifa_prefered * USEC_PER_SEC, + USEC_PER_SEC); + + r = address_get(link, address, &existing); + if (r < 0) { + /* New address. */ + log_level = LOG_INFO; + goto simple_log; + } else + log_level = LOG_DEBUG; + + if (set_contains(link->dhcp6_addresses, address)) + /* Already warned. */ + goto simple_log; + + if (address->prefixlen == existing->prefixlen) + /* Currently, only conflict in prefix length is reported. */ + goto simple_log; + + SET_FOREACH(na, link->ndisc_addresses) + if (address_compare_func(na->address, existing)) { + by_ndisc = true; + break; + } + + log_link_warning(link, "DHCPv6 address %s (valid %s%s, preferred %s%s) conflicts the existing address %s %s.", + strna(buffer), + valid_str ? "for " : "forever", strempty(valid_str), + preferred_str ? "for " : "forever", strempty(preferred_str), + strna(buffer), + by_ndisc ? "assigned by NDISC. Please try to use or update IPv6Token= setting " + "to change the address generated by NDISC, or disable UseAutonomousPrefix=" : ""); + goto finalize; + +simple_log: + log_link_full(link, log_level, "DHCPv6 address %s (valid %s%s, preferred %s%s)", + strna(buffer), + valid_str ? "for " : "forever", strempty(valid_str), + preferred_str ? "for " : "forever", strempty(preferred_str)); + +finalize: + if (ret) + *ret = TAKE_PTR(buffer); +} + static int dhcp6_update_address( Link *link, const struct in6_addr *ip6_addr, @@ -990,22 +1034,19 @@ static int dhcp6_update_address( addr->cinfo.ifa_prefered = lifetime_preferred; addr->cinfo.ifa_valid = lifetime_valid; - (void) in_addr_to_string(addr->family, &addr->in_addr, &buffer); - log_link_full(link, set_contains(link->dhcp6_addresses, addr) ? LOG_DEBUG : LOG_INFO, - "DHCPv6 address %s/%u timeout preferred %d valid %d", - strna(buffer), addr->prefixlen, lifetime_preferred, lifetime_valid); + log_dhcp6_address(link, addr, &buffer); - r = address_configure(addr, link, dhcp6_address_handler, true, &ret); + r = address_configure(addr, link, dhcp6_address_handler, &ret); if (r < 0) - return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s/%u: %m", - strna(buffer), addr->prefixlen); + return log_link_error_errno(link, r, "Failed to set DHCPv6 address %s: %m", strna(buffer)); + if (r > 0) + link->dhcp6_address_configured = false; link->dhcp6_address_messages++; r = set_ensure_put(&link->dhcp6_addresses, &address_hash_ops, ret); if (r < 0) - return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s/%u: %m", - strna(buffer), addr->prefixlen); + return log_link_error_errno(link, r, "Failed to store DHCPv6 address %s: %m", strna(buffer)); (void) set_remove(link->dhcp6_addresses_old, ret); @@ -1016,8 +1057,12 @@ static int dhcp6_address_acquired(Link *link) { int r; assert(link); + assert(link->network); assert(link->dhcp6_lease); + if (!link->network->dhcp6_use_address) + return 0; + for (sd_dhcp6_lease_reset_address_iter(link->dhcp6_lease);;) { uint32_t lifetime_preferred, lifetime_valid; struct in6_addr ip6_addr; @@ -1031,6 +1076,26 @@ static int dhcp6_address_acquired(Link *link) { return r; } + if (link->network->dhcp6_use_hostname) { + const char *dhcpname = NULL; + _cleanup_free_ char *hostname = NULL; + + (void) sd_dhcp6_lease_get_fqdn(link->dhcp6_lease, &dhcpname); + + if (dhcpname) { + r = shorten_overlong(dhcpname, &hostname); + if (r < 0) + log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname); + if (r == 1) + log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname); + } + if (hostname) { + r = manager_set_hostname(link->manager, hostname); + if (r < 0) + log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname); + } + } + return 0; } @@ -1041,11 +1106,6 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { Route *rt; int r; - link->dhcp6_address_configured = false; - link->dhcp6_route_configured = false; - - link_dirty(link); - while ((a = set_steal_first(link->dhcp6_addresses))) { r = set_ensure_put(&link->dhcp6_addresses_old, &address_hash_ops, a); if (r < 0) @@ -1079,14 +1139,8 @@ static int dhcp6_lease_ip_acquired(sd_dhcp6_client *client, Link *link) { if (link->dhcp6_address_messages == 0) link->dhcp6_address_configured = true; - else { + else log_link_debug(link, "Setting DHCPv6 addresses"); - /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are - * called, the related flags must be cleared. Otherwise, the link becomes configured - * state before routes are configured. */ - link->static_routes_configured = false; - link->static_nexthops_configured = false; - } if (link->dhcp6_route_messages == 0) link->dhcp6_route_configured = true; @@ -1178,7 +1232,7 @@ int dhcp6_request_address(Link *link, int ir) { assert(link); assert(link->dhcp6_client); assert(link->network); - assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0); + assert(in6_addr_is_link_local(&link->ipv6ll_address)); r = sd_dhcp6_client_is_running(link->dhcp6_client); if (r < 0) @@ -1556,6 +1610,8 @@ int config_parse_dhcp6_pd_hint( void *userdata) { Network *network = data; + union in_addr_union u; + unsigned char prefixlen; int r; assert(filename); @@ -1563,18 +1619,22 @@ int config_parse_dhcp6_pd_hint( assert(rvalue); assert(data); - r = in_addr_prefix_from_string(rvalue, AF_INET6, (union in_addr_union *) &network->dhcp6_pd_address, &network->dhcp6_pd_length); + r = in_addr_prefix_from_string(rvalue, AF_INET6, &u, &prefixlen); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse PrefixDelegationHint=%s, ignoring assignment", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=%s, ignoring assignment.", lvalue, rvalue); return 0; } - if (network->dhcp6_pd_length < 1 || network->dhcp6_pd_length > 128) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid prefix length='%d', ignoring assignment", network->dhcp6_pd_length); - network->dhcp6_pd_length = 0; + if (prefixlen < 1 || prefixlen > 128) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid prefix length in %s=%s, ignoring assignment.", lvalue, rvalue); return 0; } + network->dhcp6_pd_address = u.in6; + network->dhcp6_pd_length = prefixlen; + return 0; } diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h index 65b35fd1e..f74476d57 100644 --- a/src/network/networkd-dhcp6.h +++ b/src/network/networkd-dhcp6.h @@ -11,7 +11,7 @@ typedef enum DHCP6ClientStartMode { DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST, DHCP6_CLIENT_START_MODE_SOLICIT, _DHCP6_CLIENT_START_MODE_MAX, - _DHCP6_CLIENT_START_MODE_INVALID = -1, + _DHCP6_CLIENT_START_MODE_INVALID = -EINVAL, } DHCP6ClientStartMode; typedef struct Link Link; diff --git a/src/network/networkd-fdb.c b/src/network/networkd-fdb.c index 283dece04..e4e727038 100644 --- a/src/network/networkd-fdb.c +++ b/src/network/networkd-fdb.c @@ -79,11 +79,7 @@ static int fdb_entry_new_static( .fdb_ntf_flags = NEIGHBOR_CACHE_ENTRY_FLAGS_SELF, }; - r = hashmap_ensure_allocated(&network->fdb_entries_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->fdb_entries_by_section, fdb_entry->section, fdb_entry); + r = hashmap_ensure_put(&network->fdb_entries_by_section, &network_config_hash_ops, fdb_entry->section, fdb_entry); if (r < 0) return r; @@ -146,7 +142,7 @@ static int fdb_entry_configure(Link *link, FdbEntry *fdb_entry) { return log_link_error_errno(link, r, "Could not append NDA_VLAN attribute: %m"); } - if (!in_addr_is_null(fdb_entry->family, &fdb_entry->destination_addr)) { + if (in_addr_is_set(fdb_entry->family, &fdb_entry->destination_addr)) { r = netlink_message_append_in_addr_union(req, NDA_DST, fdb_entry->family, &fdb_entry->destination_addr); if (r < 0) return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m"); @@ -381,7 +377,6 @@ int config_parse_fdb_ntf_flags( _cleanup_(fdb_entry_free_or_set_invalidp) FdbEntry *fdb_entry = NULL; Network *network = userdata; - NeighborCacheEntryFlags f; int r; assert(filename); @@ -394,9 +389,9 @@ int config_parse_fdb_ntf_flags( if (r < 0) return log_oom(); - f = fdb_ntf_flags_from_string(rvalue); + NeighborCacheEntryFlags f = fdb_ntf_flags_from_string(rvalue); if (f < 0) { - log_syntax(unit, LOG_WARNING, filename, line, SYNTHETIC_ERRNO(EINVAL), + log_syntax(unit, LOG_WARNING, filename, line, f, "FDB failed to parse AssociatedWith=, ignoring assignment: %s", rvalue); return 0; diff --git a/src/network/networkd-fdb.h b/src/network/networkd-fdb.h index 48f4e40b3..dc85a70f8 100644 --- a/src/network/networkd-fdb.h +++ b/src/network/networkd-fdb.h @@ -22,7 +22,7 @@ typedef enum NeighborCacheEntryFlags { NEIGHBOR_CACHE_ENTRY_FLAGS_MASTER = NTF_MASTER, NEIGHBOR_CACHE_ENTRY_FLAGS_ROUTER = NTF_ROUTER, _NEIGHBOR_CACHE_ENTRY_FLAGS_MAX, - _NEIGHBOR_CACHE_ENTRY_FLAGS_INVALID = -1, + _NEIGHBOR_CACHE_ENTRY_FLAGS_INVALID = -EINVAL, } NeighborCacheEntryFlags; typedef struct FdbEntry { diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index aaabb3d1b..b2a2f5579 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -6,6 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "conf-parser.h" #include "networkd-conf.h" #include "networkd-manager.h" +#include "networkd-route.h" %} struct ConfigPerfItem; %null_strings @@ -21,5 +23,6 @@ struct ConfigPerfItem; Network.SpeedMeter, config_parse_bool, 0, offsetof(Manager, use_speed_meter) Network.SpeedMeterIntervalSec, config_parse_sec, 0, offsetof(Manager, speed_meter_interval_usec) Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes) +Network.RouteTable, config_parse_route_table_names, 0, 0 DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid) DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid) diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c index 295abe866..65266633e 100644 --- a/src/network/networkd-ipv4ll.c +++ b/src/network/networkd-ipv4ll.c @@ -92,7 +92,7 @@ static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htobe32(0xfffffffflu >> ll_addr->prefixlen); ll_addr->scope = RT_SCOPE_LINK; - r = address_configure(ll_addr, link, ipv4ll_address_handler, false, NULL); + r = address_configure(ll_addr, link, ipv4ll_address_handler, NULL); if (r < 0) return r; @@ -142,37 +142,24 @@ static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata) { } } -static int ipv4ll_init(Link *link) { - int r; - - assert(link); - - if (link->ipv4ll) - return 0; - - r = sd_ipv4ll_new(&link->ipv4ll); - if (r < 0) - return r; - - r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0); - if (r < 0) - return r; - - return 0; -} - int ipv4ll_configure(Link *link) { uint64_t seed; int r; assert(link); - if (!link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) + if (!link_ipv4ll_enabled(link)) return 0; - r = ipv4ll_init(link); - if (r < 0) - return r; + if (!link->ipv4ll) { + r = sd_ipv4ll_new(&link->ipv4ll); + if (r < 0) + return r; + + r = sd_ipv4ll_attach_event(link->ipv4ll, link->manager->event, 0); + if (r < 0) + return r; + } if (link->sd_device && net_get_unique_predictable_data(link->sd_device, true, &seed) >= 0) { @@ -224,52 +211,6 @@ int ipv4ll_update_mac(Link *link) { return 0; } -int link_serialize_ipv4ll(Link *link, FILE *f) { - struct in_addr address; - int r; - - assert(link); - - if (!link->ipv4ll) - return 0; - - r = sd_ipv4ll_get_address(link->ipv4ll, &address); - if (r == -ENOENT) - return 0; - if (r < 0) - return r; - - fputs("IPV4LL_ADDRESS=", f); - serialize_in_addrs(f, &address, 1, false, NULL); - fputc('\n', f); - - return 0; -} - -int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address) { - union in_addr_union address; - int r; - - assert(link); - - if (isempty(ipv4ll_address)) - return 0; - - r = in_addr_from_string(AF_INET, ipv4ll_address, &address); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to parse IPv4LL address: %s", ipv4ll_address); - - r = ipv4ll_init(link); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to initialize IPv4LL client: %m"); - - r = sd_ipv4ll_set_address(link->ipv4ll, &address.in); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to set initial IPv4LL address %s: %m", ipv4ll_address); - - return 0; -} - int config_parse_ipv4ll( const char* unit, const char *filename, diff --git a/src/network/networkd-ipv4ll.h b/src/network/networkd-ipv4ll.h index fae48cd92..82acc2ec7 100644 --- a/src/network/networkd-ipv4ll.h +++ b/src/network/networkd-ipv4ll.h @@ -9,7 +9,5 @@ typedef struct Link Link; int ipv4ll_configure(Link *link); int ipv4ll_update_mac(Link *link); -int link_serialize_ipv4ll(Link *link, FILE *f); -int link_deserialize_ipv4ll(Link *link, const char *ipv4ll_address); CONFIG_PARSER_PROTOTYPE(config_parse_ipv4ll); diff --git a/src/network/networkd-ipv6-proxy-ndp.c b/src/network/networkd-ipv6-proxy-ndp.c index 7a370e931..57b3fb011 100644 --- a/src/network/networkd-ipv6-proxy-ndp.c +++ b/src/network/networkd-ipv6-proxy-ndp.c @@ -18,7 +18,7 @@ static int set_ipv6_proxy_ndp_address_handler(sd_netlink *rtnl, sd_netlink_messa assert(link); r = sd_netlink_message_get_errno(m); - if (r < 0 && r != -EEXIST) + if (r < 0) log_link_message_warning_errno(link, m, r, "Could not add IPv6 proxy ndp address entry, ignoring"); return 1; diff --git a/src/network/networkd-link-bus.c b/src/network/networkd-link-bus.c index 4df31df4a..f57828b57 100644 --- a/src/network/networkd-link-bus.c +++ b/src/network/networkd-link-bus.c @@ -13,6 +13,7 @@ #include "networkd-link-bus.h" #include "networkd-link.h" #include "networkd-manager.h" +#include "networkd-state-file.h" #include "parse-util.h" #include "resolve-util.h" #include "socket-netlink.h" @@ -146,7 +147,7 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi goto finalize; } - if (l->n_dns != (unsigned) -1) + if (l->n_dns != UINT_MAX) for (unsigned i = 0; i < l->n_dns; i++) in_addr_full_free(l->dns[i]); @@ -686,21 +687,81 @@ const sd_bus_vtable link_vtable[] = { SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0), - SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDNSEx", "a(iayqs)", NULL, bus_link_method_set_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Renew", NULL, NULL, bus_link_method_renew, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ForceRenew", NULL, NULL, bus_link_method_force_renew, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Reconfigure", NULL, NULL, bus_link_method_reconfigure, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetNTP", + SD_BUS_ARGS("as", servers), + SD_BUS_NO_RESULT, + bus_link_method_set_ntp_servers, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDNS", + SD_BUS_ARGS("a(iay)", addresses), + SD_BUS_NO_RESULT, + bus_link_method_set_dns_servers, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDNSEx", + SD_BUS_ARGS("a(iayqs)", addresses), + SD_BUS_NO_RESULT, + bus_link_method_set_dns_servers_ex, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDomains", + SD_BUS_ARGS("a(sb)", domains), + SD_BUS_NO_RESULT, + bus_link_method_set_domains, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute", + SD_BUS_ARGS("b", enable), + SD_BUS_NO_RESULT, + bus_link_method_set_default_route, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLLMNR", + SD_BUS_ARGS("s", mode), + SD_BUS_NO_RESULT, + bus_link_method_set_llmnr, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS", + SD_BUS_ARGS("s", mode), + SD_BUS_NO_RESULT, + bus_link_method_set_mdns, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS", + SD_BUS_ARGS("s", mode), + SD_BUS_NO_RESULT, + bus_link_method_set_dns_over_tls, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDNSSEC", + SD_BUS_ARGS("s", mode), + SD_BUS_NO_RESULT, + bus_link_method_set_dnssec, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors", + SD_BUS_ARGS("as", names), + SD_BUS_NO_RESULT, + bus_link_method_set_dnssec_negative_trust_anchors, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RevertNTP", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_link_method_revert_ntp, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RevertDNS", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_link_method_revert_dns, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Renew", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_link_method_renew, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ForceRenew", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_link_method_force_renew, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Reconfigure", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_link_method_reconfigure, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 812034361..6868a7ccb 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -7,15 +7,19 @@ #include #include "alloc-util.h" +#include "batadv.h" #include "bond.h" #include "bridge.h" #include "bus-util.h" +#include "device-private.h" +#include "device-util.h" #include "dhcp-identifier.h" #include "dhcp-lease-internal.h" #include "env-file.h" #include "ethtool-util.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "ipvlan.h" #include "missing_network.h" #include "netlink-util.h" @@ -28,7 +32,6 @@ #include "networkd-dhcp6.h" #include "networkd-fdb.h" #include "networkd-ipv4ll.h" -#include "networkd-ipv6-proxy-ndp.h" #include "networkd-link-bus.h" #include "networkd-link.h" #include "networkd-lldp-tx.h" @@ -41,6 +44,7 @@ #include "networkd-sysctl.h" #include "networkd-radv.h" #include "networkd-routing-policy-rule.h" +#include "networkd-state-file.h" #include "networkd-wifi.h" #include "set.h" #include "socket-util.h" @@ -55,9 +59,8 @@ #include "util.h" #include "vrf.h" -bool link_ipv4ll_enabled(Link *link, AddressFamily mask) { +bool link_ipv4ll_enabled(Link *link) { assert(link); - assert((mask & ~(ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_FALLBACK_IPV4)) == 0); if (link->flags & IFF_LOOPBACK) return false; @@ -80,7 +83,7 @@ bool link_ipv4ll_enabled(Link *link, AddressFamily mask) { if (link->network->bond) return false; - return link->network->link_local & mask; + return link->network->link_local & ADDRESS_FAMILY_IPV4; } bool link_ipv6ll_enabled(Link *link) { @@ -266,6 +269,7 @@ void link_update_operstate(Link *link, bool also_update_master) { link_dirty(link); if (also_update_master && link->network) { + link_update_master_operstate(link, link->network->batadv); link_update_master_operstate(link, link->network->bond); link_update_master_operstate(link, link->network->bridge); } @@ -399,7 +403,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { .ifindex = ifindex, .iftype = iftype, - .n_dns = (unsigned) -1, + .n_dns = UINT_MAX, .dns_default_route = -1, .llmnr = _RESOLVE_SUPPORT_INVALID, .mdns = _RESOLVE_SUPPORT_INVALID, @@ -450,11 +454,7 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) { if (asprintf(&link->lldp_file, "/run/systemd/netif/lldp/%d", link->ifindex) < 0) return -ENOMEM; - r = hashmap_ensure_allocated(&manager->links, NULL); - if (r < 0) - return r; - - r = hashmap_put(manager->links, INT_TO_PTR(link->ifindex), link); + r = hashmap_ensure_put(&manager->links, NULL, INT_TO_PTR(link->ifindex), link); if (r < 0) return r; @@ -472,11 +472,11 @@ void link_ntp_settings_clear(Link *link) { } void link_dns_settings_clear(Link *link) { - if (link->n_dns != (unsigned) -1) + if (link->n_dns != UINT_MAX) for (unsigned i = 0; i < link->n_dns; i++) in_addr_full_free(link->dns[i]); link->dns = mfree(link->dns); - link->n_dns = (unsigned) -1; + link->n_dns = UINT_MAX; link->search_domains = ordered_set_free_free(link->search_domains); link->route_domains = ordered_set_free_free(link->route_domains); @@ -546,8 +546,6 @@ static Link *link_free(Link *link) { link->ndisc_addresses = set_free(link->ndisc_addresses); link_free_engines(link); - free(link->lease_file); - free(link->lldp_file); free(link->ifname); strv_free(link->alternative_names); @@ -555,8 +553,9 @@ static Link *link_free(Link *link) { free(link->ssid); free(link->driver); - (void) unlink(link->state_file); - free(link->state_file); + unlink_and_free(link->lease_file); + unlink_and_free(link->lldp_file); + unlink_and_free(link->state_file); sd_device_unref(link->sd_device); @@ -601,14 +600,13 @@ void link_set_state(Link *link, LinkState state) { link->state = state; link_send_changed(link, "AdministrativeState", NULL); + link_dirty(link); } static void link_enter_unmanaged(Link *link) { assert(link); link_set_state(link, LINK_STATE_UNMANAGED); - - link_dirty(link); } int link_stop_engines(Link *link, bool may_keep_dhcp) { @@ -680,8 +678,6 @@ void link_enter_failed(Link *link) { link_set_state(link, LINK_STATE_FAILED); (void) link_stop_engines(link, false); - - link_dirty(link); } static int link_join_netdevs_after_configured(Link *link) { @@ -722,8 +718,6 @@ static void link_enter_configured(Link *link) { link_set_state(link, LINK_STATE_CONFIGURED); (void) link_join_netdevs_after_configured(link); - - link_dirty(link); } void link_check_ready(Link *link) { @@ -734,77 +728,50 @@ void link_check_ready(Link *link) { if (link->state == LINK_STATE_CONFIGURED) return; - if (link->state != LINK_STATE_CONFIGURING) { - log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state)); - return; - } + if (link->state != LINK_STATE_CONFIGURING) + return (void) log_link_debug(link, "%s(): link is in %s state.", __func__, link_state_to_string(link->state)); if (!link->network) return; - if (!link->addresses_configured) { - log_link_debug(link, "%s(): static addresses are not configured.", __func__); - return; - } + if (!link->addresses_configured) + return (void) log_link_debug(link, "%s(): static addresses are not configured.", __func__); - if (!link->neighbors_configured) { - log_link_debug(link, "%s(): static neighbors are not configured.", __func__); - return; - } + if (!link->neighbors_configured) + return (void) log_link_debug(link, "%s(): static neighbors are not configured.", __func__); SET_FOREACH(a, link->addresses) if (!address_is_ready(a)) { _cleanup_free_ char *str = NULL; - (void) in_addr_to_string(a->family, &a->in_addr, &str); - log_link_debug(link, "%s(): an address %s/%d is not ready.", __func__, strnull(str), a->prefixlen); - return; + (void) in_addr_prefix_to_string(a->family, &a->in_addr, a->prefixlen, &str); + return (void) log_link_debug(link, "%s(): an address %s is not ready.", __func__, strna(str)); } - if (!link->static_routes_configured) { - log_link_debug(link, "%s(): static routes are not configured.", __func__); - return; - } + if (!link->static_routes_configured) + return (void) log_link_debug(link, "%s(): static routes are not configured.", __func__); - if (!link->static_nexthops_configured) { - log_link_debug(link, "%s(): static nexthops are not configured.", __func__); - return; - } + if (!link->static_nexthops_configured) + return (void) log_link_debug(link, "%s(): static nexthops are not configured.", __func__); - if (!link->routing_policy_rules_configured) { - log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__); - return; - } + if (!link->routing_policy_rules_configured) + return (void) log_link_debug(link, "%s(): static routing policy rules are not configured.", __func__); - if (!link->tc_configured) { - log_link_debug(link, "%s(): traffic controls are not configured.", __func__); - return; - } + if (!link->tc_configured) + return (void) log_link_debug(link, "%s(): traffic controls are not configured.", __func__); - if (!link->sr_iov_configured) { - log_link_debug(link, "%s(): SR-IOV is not configured.", __func__); - return; - } + if (!link->sr_iov_configured) + return (void) log_link_debug(link, "%s(): SR-IOV is not configured.", __func__); - if (!link->bridge_mdb_configured) { - log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__); - return; - } + if (!link->bridge_mdb_configured) + return (void) log_link_debug(link, "%s(): Bridge MDB is not configured.", __func__); if (link_has_carrier(link) || !link->network->configure_without_carrier) { bool has_ndisc_address = false; NDiscAddress *n; - if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) { - log_link_debug(link, "%s(): IPv4LL is not configured.", __func__); - return; - } - - if (link_ipv6ll_enabled(link) && - in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) { - log_link_debug(link, "%s(): IPv6LL is not configured.", __func__); - return; - } + if (link_ipv6ll_enabled(link) && !in6_addr_is_set(&link->ipv6ll_address)) + return (void) log_link_debug(link, "%s(): IPv6LL is not configured yet.", __func__); SET_FOREACH(n, link->ndisc_addresses) if (!n->marked) { @@ -812,28 +779,26 @@ void link_check_ready(Link *link) { break; } - if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && + if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_ipv4ll_enabled(link)) && !link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address && - !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) { - log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__); - return; - } + !link->ipv4ll_address_configured) + /* When DHCP[46] or IPv4LL is enabled, at least one address is acquired by them. */ + return (void) log_link_debug(link, "%s(): DHCP4, DHCP6 or IPv4LL is enabled but no dynamic address is assigned yet.", __func__); - if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || link_ipv6_accept_ra_enabled(link)) { + if (link_dhcp4_enabled(link) || link_dhcp6_enabled(link) || link_dhcp6_pd_is_enabled(link) || + link_ipv6_accept_ra_enabled(link) || link_ipv4ll_enabled(link)) { if (!link->dhcp4_configured && !(link->dhcp6_address_configured && link->dhcp6_route_configured) && !(link->dhcp6_pd_address_configured && link->dhcp6_pd_route_configured) && !(link->ndisc_addresses_configured && link->ndisc_routes_configured) && - !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) { - /* When DHCP or RA is enabled, at least one protocol must provide an address, or - * an IPv4ll fallback address must be configured. */ - log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__); - return; - } + !link->ipv4ll_address_configured) + /* When DHCP[46], NDisc, or IPv4LL is enabled, at least one protocol must be finished. */ + return (void) log_link_debug(link, "%s(): dynamic addresses or routes are not configured.", __func__); - log_link_debug(link, "%s(): dhcp4:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s", + log_link_debug(link, "%s(): dhcp4:%s ipv4ll:%s dhcp6_addresses:%s dhcp_routes:%s dhcp_pd_addresses:%s dhcp_pd_routes:%s ndisc_addresses:%s ndisc_routes:%s", __func__, yes_no(link->dhcp4_configured), + yes_no(link->ipv4ll_address_configured), yes_no(link->dhcp6_address_configured), yes_no(link->dhcp6_route_configured), yes_no(link->dhcp6_pd_address_configured), @@ -844,8 +809,6 @@ void link_check_ready(Link *link) { } link_enter_configured(link); - - return; } static int link_set_static_configs(Link *link) { @@ -970,7 +933,7 @@ static int link_set_nomaster(Link *link) { assert(link->manager->rtnl); /* set it free if not enslaved with networkd */ - if (link->network->bridge || link->network->bond || link->network->vrf) + if (link->network->batadv || link->network->bridge || link->network->bond || link->network->vrf) return 0; log_link_debug(link, "Setting nomaster"); @@ -1139,7 +1102,8 @@ static int link_set_flags(Link *link) { if (!link->network) return 0; - if (link->network->arp < 0 && link->network->multicast < 0 && link->network->allmulticast < 0) + if (link->network->arp < 0 && link->network->multicast < 0 && link->network->allmulticast < 0 && + link->network->promiscuous < 0) return 0; r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_SETLINK, link->ifindex); @@ -1161,6 +1125,11 @@ static int link_set_flags(Link *link) { SET_FLAG(ifi_flags, IFF_ALLMULTI, link->network->allmulticast); } + if (link->network->promiscuous >= 0) { + ifi_change |= IFF_PROMISC; + SET_FLAG(ifi_flags, IFF_PROMISC, link->network->promiscuous); + } + r = sd_rtnl_message_link_set_flags(req, ifi_flags, ifi_change); if (r < 0) return log_link_error_errno(link, r, "Could not set link flags: %m"); @@ -1190,7 +1159,7 @@ static int link_acquire_ipv6_conf(Link *link) { if (link->radv) { assert(link->radv); - assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); + assert(in6_addr_is_link_local(&link->ipv6ll_address)); log_link_debug(link, "Starting IPv6 Router Advertisements"); @@ -1207,7 +1176,7 @@ static int link_acquire_ipv6_conf(Link *link) { DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST, DHCP6_CLIENT_START_MODE_SOLICIT)) { assert(link->dhcp6_client); - assert(in_addr_is_link_local(AF_INET6, (const union in_addr_union*)&link->ipv6ll_address) > 0); + assert(in6_addr_is_link_local(&link->ipv6ll_address)); r = dhcp6_request_address(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); if (r < 0 && r != -EBUSY) @@ -1230,22 +1199,19 @@ static int link_acquire_ipv4_conf(Link *link) { assert(link->manager); assert(link->manager->event); - if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4)) { - assert(link->ipv4ll); - - log_link_debug(link, "Acquiring IPv4 link-local address"); - - r = sd_ipv4ll_start(link->ipv4ll); - if (r < 0) - return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); - } - if (link->dhcp_client) { log_link_debug(link, "Acquiring DHCPv4 lease"); r = sd_dhcp_client_start(link->dhcp_client); if (r < 0) return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); + + } else if (link->ipv4ll) { + log_link_debug(link, "Acquiring IPv4 link-local address"); + + r = sd_ipv4ll_start(link->ipv4ll); + if (r < 0) + return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m"); } return 0; @@ -1260,7 +1226,7 @@ static int link_acquire_conf(Link *link) { if (r < 0) return r; - if (!in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address)) { + if (in6_addr_is_set(&link->ipv6ll_address)) { r = link_acquire_ipv6_conf(link); if (r < 0) return r; @@ -1578,13 +1544,11 @@ static int link_put_carrier(Link *link, Link *carrier, Hashmap **h) { if (hashmap_get(*h, INT_TO_PTR(carrier->ifindex))) return 0; - r = hashmap_ensure_allocated(h, NULL); + r = hashmap_ensure_put(h, NULL, INT_TO_PTR(carrier->ifindex), carrier); if (r < 0) return r; - r = hashmap_put(*h, INT_TO_PTR(carrier->ifindex), carrier); - if (r < 0) - return r; + link_dirty(link); return 0; } @@ -1593,7 +1557,6 @@ static int link_new_bound_by_list(Link *link) { Manager *m; Link *carrier; int r; - bool list_updated = false; assert(link); assert(link->manager); @@ -1611,20 +1574,13 @@ static int link_new_bound_by_list(Link *link) { r = link_put_carrier(link, carrier, &link->bound_by_links); if (r < 0) return r; - - list_updated = true; } } - if (list_updated) - link_dirty(link); - HASHMAP_FOREACH(carrier, link->bound_by_links) { r = link_put_carrier(carrier, link, &carrier->bound_to_links); if (r < 0) return r; - - link_dirty(carrier); } return 0; @@ -1634,7 +1590,6 @@ static int link_new_bound_to_list(Link *link) { Manager *m; Link *carrier; int r; - bool list_updated = false; assert(link); assert(link->manager); @@ -1652,20 +1607,13 @@ static int link_new_bound_to_list(Link *link) { r = link_put_carrier(link, carrier, &link->bound_to_links); if (r < 0) return r; - - list_updated = true; } } - if (list_updated) - link_dirty(link); - HASHMAP_FOREACH (carrier, link->bound_to_links) { r = link_put_carrier(carrier, link, &carrier->bound_by_links); if (r < 0) return r; - - link_dirty(carrier); } return 0; @@ -1694,23 +1642,32 @@ static int link_new_carrier_maps(Link *link) { } static void link_free_bound_to_list(Link *link) { + bool updated = false; Link *bound_to; - HASHMAP_FOREACH (bound_to, link->bound_to_links) { - hashmap_remove(link->bound_to_links, INT_TO_PTR(bound_to->ifindex)); + assert(link); + + while ((bound_to = hashmap_steal_first(link->bound_to_links))) { + updated = true; if (hashmap_remove(bound_to->bound_by_links, INT_TO_PTR(link->ifindex))) link_dirty(bound_to); } + if (updated) + link_dirty(link); + return; } static void link_free_bound_by_list(Link *link) { + bool updated = false; Link *bound_by; - HASHMAP_FOREACH (bound_by, link->bound_by_links) { - hashmap_remove(link->bound_by_links, INT_TO_PTR(bound_by->ifindex)); + assert(link); + + while ((bound_by = hashmap_steal_first(link->bound_by_links))) { + updated = true; if (hashmap_remove(bound_by->bound_to_links, INT_TO_PTR(link->ifindex))) { link_dirty(bound_by); @@ -1718,26 +1675,17 @@ static void link_free_bound_by_list(Link *link) { } } + if (updated) + link_dirty(link); + return; } static void link_free_carrier_maps(Link *link) { - bool list_updated = false; - assert(link); - if (!hashmap_isempty(link->bound_to_links)) { - link_free_bound_to_list(link); - list_updated = true; - } - - if (!hashmap_isempty(link->bound_by_links)) { - link_free_bound_by_list(link); - list_updated = true; - } - - if (list_updated) - link_dirty(link); + link_free_bound_to_list(link); + link_free_bound_by_list(link); return; } @@ -1787,7 +1735,7 @@ static void link_detach_from_manager(Link *link) { link_unref(link); } -void link_drop(Link *link) { +static void link_drop(Link *link) { if (!link || link->state == LINK_STATE_LINGER) return; @@ -1796,6 +1744,7 @@ void link_drop(Link *link) { link_free_carrier_maps(link); if (link->network) { + link_drop_from_master(link, link->network->batadv); link_drop_from_master(link, link->network->bridge); link_drop_from_master(link, link->network->bond); } @@ -1812,17 +1761,38 @@ static int link_joined(Link *link) { assert(link); assert(link->network); - if (!hashmap_isempty(link->bound_to_links)) { + switch (link->network->activation_policy) { + case ACTIVATION_POLICY_BOUND: r = link_handle_bound_to_list(link); if (r < 0) return r; - } else if (!(link->flags & IFF_UP)) { + break; + case ACTIVATION_POLICY_UP: + if (link->activated) + break; + _fallthrough_; + case ACTIVATION_POLICY_ALWAYS_UP: r = link_up(link); if (r < 0) { link_enter_failed(link); return r; } + break; + case ACTIVATION_POLICY_DOWN: + if (link->activated) + break; + _fallthrough_; + case ACTIVATION_POLICY_ALWAYS_DOWN: + r = link_down(link, NULL); + if (r < 0) { + link_enter_failed(link); + return r; + } + break; + default: + break; } + link->activated = true; if (link->network->bridge) { r = link_set_bridge(link); @@ -1903,7 +1873,6 @@ static int link_enter_join_netdev(Link *link) { link_set_state(link, LINK_STATE_CONFIGURING); - link_dirty(link); link->enslaving = 0; if (link->network->bond) { @@ -1929,6 +1898,25 @@ static int link_enter_join_netdev(Link *link) { } } + if (link->network->batadv) { + log_struct(LOG_DEBUG, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->batadv), + LOG_LINK_MESSAGE(link, "Enslaving by '%s'", link->network->batadv->ifname)); + + link->enslaving++; + + r = netdev_join(link->network->batadv, link, netdev_join_handler); + if (r < 0) { + log_struct_errno(LOG_WARNING, r, + LOG_LINK_INTERFACE(link), + LOG_NETDEV_INTERFACE(link->network->batadv), + LOG_LINK_MESSAGE(link, "Could not join netdev '%s': %m", link->network->batadv->ifname)); + link_enter_failed(link); + return r; + } + } + if (link->network->bridge) { log_struct(LOG_DEBUG, LOG_LINK_INTERFACE(link), @@ -2001,37 +1989,59 @@ static int link_enter_join_netdev(Link *link) { } static int link_drop_foreign_config(Link *link) { - int r; + int k, r; + + assert(link); + assert(link->manager); r = link_drop_foreign_addresses(link); - if (r < 0) - return r; - r = link_drop_foreign_neighbors(link); - if (r < 0) - return r; + k = link_drop_foreign_neighbors(link); + if (k < 0 && r >= 0) + r = k; - return link_drop_foreign_routes(link); + k = link_drop_foreign_routes(link); + if (k < 0 && r >= 0) + r = k; + + k = link_drop_foreign_nexthops(link); + if (k < 0 && r >= 0) + r = k; + + k = manager_drop_foreign_routing_policy_rules(link->manager); + if (k < 0 && r >= 0) + r = k; + + return r; } static int link_drop_config(Link *link) { - int r; + int k, r; + + assert(link); + assert(link->manager); r = link_drop_addresses(link); - if (r < 0) - return r; - r = link_drop_neighbors(link); - if (r < 0) - return r; + k = link_drop_neighbors(link); + if (k < 0 && r >= 0) + r = k; - r = link_drop_routes(link); - if (r < 0) - return r; + k = link_drop_routes(link); + if (k < 0 && r >= 0) + r = k; + + k = link_drop_nexthops(link); + if (k < 0 && r >= 0) + r = k; + + k = manager_drop_routing_policy_rules(link->manager, link); + if (k < 0 && r >= 0) + r = k; ndisc_flush(link); - return 0; + return r; } int link_configure(Link *link) { @@ -2056,10 +2066,6 @@ int link_configure(Link *link) { if (r < 0) return r; - r = link_set_ipv6_proxy_ndp_addresses(link); - if (r < 0) - return r; - r = link_set_mac(link); if (r < 0) return r; @@ -2205,18 +2211,18 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for link_free_carrier_maps(link); link_free_engines(link); link->network = network_unref(link->network); + link_unref(set_remove(link->manager->links_requesting_uuid, link)); /* Then, apply new .network file */ - r = network_apply(network, link); - if (r < 0) - return r; + link->network = network_ref(network); + link_dirty(link); r = link_new_carrier_maps(link); if (r < 0) return r; link_set_state(link, LINK_STATE_INITIALIZED); - link_dirty(link); + link->activated = false; /* link_configure_duid() returns 0 if it requests product UUID. In that case, * link_configure() is called later asynchronously. */ @@ -2256,10 +2262,10 @@ int link_reconfigure(Link *link, bool force) { int r; /* When link in pending or initialized state, then link_configure() will be called. To prevent - * the function be called multiple times simultaneously, refuse to reconfigure the interface in - * these case. */ + * the function from being called multiple times simultaneously, refuse to reconfigure the + * interface in these cases. */ if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER)) - return 0; /* o means no-op. */ + return 0; /* 0 means no-op. */ r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex); @@ -2330,9 +2336,8 @@ static int link_initialized_and_synced(Link *link) { log_link_debug(link, "Ignoring DHCP server for loopback link"); } - r = network_apply(network, link); - if (r < 0) - return r; + link->network = network_ref(network); + link_dirty(link); } r = link_new_bound_to_list(link); @@ -2377,7 +2382,7 @@ static int link_initialized_handler(sd_netlink *rtnl, sd_netlink_message *m, Lin return 1; } -int link_initialized(Link *link, sd_device *device) { +static int link_initialized(Link *link, sd_device *device) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -2417,70 +2422,7 @@ int link_initialized(Link *link, sd_device *device) { return 0; } -static int link_load(Link *link) { - _cleanup_free_ char *network_file = NULL, - *addresses = NULL, - *routes = NULL, - *dhcp4_address = NULL, - *ipv4ll_address = NULL; - int r; - - assert(link); - - r = parse_env_file(NULL, link->state_file, - "NETWORK_FILE", &network_file, - "ADDRESSES", &addresses, - "ROUTES", &routes, - "DHCP4_ADDRESS", &dhcp4_address, - "IPV4LL_ADDRESS", &ipv4ll_address); - if (r < 0 && r != -ENOENT) - return log_link_error_errno(link, r, "Failed to read %s: %m", link->state_file); - - if (network_file) { - Network *network; - char *suffix; - - /* drop suffix */ - suffix = strrchr(network_file, '.'); - if (!suffix) { - log_link_debug(link, "Failed to get network name from %s", network_file); - goto network_file_fail; - } - *suffix = '\0'; - - r = network_get_by_name(link->manager, basename(network_file), &network); - if (r < 0) { - log_link_debug_errno(link, r, "Failed to get network %s: %m", basename(network_file)); - goto network_file_fail; - } - - r = network_apply(network, link); - if (r < 0) - return log_link_error_errno(link, r, "Failed to apply network %s: %m", basename(network_file)); - } - -network_file_fail: - - r = link_deserialize_addresses(link, addresses); - if (r < 0) - log_link_warning_errno(link, r, "Failed to load addresses from %s, ignoring: %m", link->state_file); - - r = link_deserialize_routes(link, routes); - if (r < 0) - log_link_warning_errno(link, r, "Failed to load routes from %s, ignoring: %m", link->state_file); - - r = link_deserialize_dhcp4(link, dhcp4_address); - if (r < 0) - log_link_warning_errno(link, r, "Failed to load DHCPv4 address from %s, ignoring: %m", link->state_file); - - r = link_deserialize_ipv4ll(link, ipv4ll_address); - if (r < 0) - log_link_warning_errno(link, r, "Failed to load IPv4LL address from %s, ignoring: %m", link->state_file); - - return 0; -} - -int link_add(Manager *m, sd_netlink_message *message, Link **ret) { +static int link_add(Manager *m, sd_netlink_message *message, Link **ret) { _cleanup_(sd_device_unrefp) sd_device *device = NULL; char ifindex_str[2 + DECIMAL_STR_MAX(int)]; Link *link; @@ -2499,10 +2441,6 @@ int link_add(Manager *m, sd_netlink_message *message, Link **ret) { log_link_debug(link, "Link %d added", link->ifindex); - r = link_load(link); - if (r < 0) - return r; - if (path_is_read_only_fs("/sys") <= 0) { /* udev should be around */ sprintf(ifindex_str, "n%d", link->ifindex); @@ -2569,6 +2507,57 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address) { return 0; } +int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) { + sd_device_action_t action; + Manager *m = userdata; + Link *link = NULL; + int r, ifindex; + + assert(m); + assert(device); + + r = sd_device_get_action(device, &action); + if (r < 0) { + log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m"); + return 0; + } + + /* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents + * are "positive" events in some form, i.e. inform us about a changed or new network interface, that + * still exists — and we are interested in that. */ + if (action == SD_DEVICE_REMOVE) + return 0; + + r = sd_device_get_ifindex(device, &ifindex); + if (r < 0) { + log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m", + device_action_to_string(action)); + return 0; + } + + r = device_is_renaming(device); + if (r < 0) { + log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m", + device_action_to_string(action)); + return 0; + } + if (r > 0) { + log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed."); + return 0; + } + + r = link_get(m, ifindex, &link); + if (r < 0) { + if (r != -ENODEV) + log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex); + return 0; + } + + (void) link_initialized(link, device); + + return 0; +} + static int link_carrier_gained(Link *link) { int r; @@ -2682,11 +2671,22 @@ int link_carrier_reset(Link *link) { return 0; } -/* This is called every time an interface admin state changes to up; - * specifically, when IFF_UP flag changes from unset to set */ static int link_admin_state_up(Link *link) { int r; + assert(link); + + /* This is called every time an interface admin state changes to up; + * specifically, when IFF_UP flag changes from unset to set. */ + + if (!link->network) + return 0; + + if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_DOWN) { + log_link_info(link, "ActivationPolicy is \"always-off\", forcing link down"); + return link_down(link, NULL); + } + /* We set the ipv6 mtu after the device mtu, but the kernel resets * ipv6 mtu on NETDEV_UP, so we need to reset it. The check for * ipv6_mtu_set prevents this from trying to set it too early before @@ -2701,7 +2701,21 @@ static int link_admin_state_up(Link *link) { return 0; } -int link_update(Link *link, sd_netlink_message *m) { +static int link_admin_state_down(Link *link) { + assert(link); + + if (!link->network) + return 0; + + if (link->network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) { + log_link_info(link, "ActivationPolicy is \"always-on\", forcing link up"); + return link_up(link); + } + + return 0; +} + +static int link_update(Link *link, sd_netlink_message *m) { _cleanup_strv_free_ char **s = NULL; hw_addr_data hw_addr; const char *ifname; @@ -2813,9 +2827,14 @@ int link_update(Link *link, sd_netlink_message *m) { r = link_admin_state_up(link); if (r < 0) return r; - } else if (link_was_admin_up && !(link->flags & IFF_UP)) + } else if (link_was_admin_up && !(link->flags & IFF_UP)) { log_link_info(link, "Link DOWN"); + r = link_admin_state_down(link); + if (r < 0) + return r; + } + r = link_update_lldp(link); if (r < 0) return r; @@ -2840,402 +2859,91 @@ int link_update(Link *link, sd_netlink_message *m) { return 0; } -static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { - bool space = false; - Link *link; +int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { + Link *link = NULL; + NetDev *netdev = NULL; + uint16_t type; + const char *name; + int r, ifindex; - assert(f); - assert(prefix); + assert(rtnl); + assert(message); + assert(m); - if (hashmap_isempty(h)) - return; + if (sd_netlink_message_is_error(message)) { + r = sd_netlink_message_get_errno(message); + if (r < 0) + log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring"); - fputs(prefix, f); - HASHMAP_FOREACH(link, h) { - if (space) - fputc(' ', f); - - fprintf(f, "%i", link->ifindex); - space = true; - } - - fputc('\n', f); -} - -static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) { - for (unsigned j = 0; j < n_dns; j++) { - const char *str; - - if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex) - continue; - - str = in_addr_full_to_string(dns[j]); - if (!str) - continue; - - if (*space) - fputc(' ', f); - fputs(str, f); - *space = true; - } -} - -static void serialize_addresses( - FILE *f, - const char *lvalue, - bool *space, - char **addresses, - sd_dhcp_lease *lease, - bool conditional, - sd_dhcp_lease_server_type what, - sd_dhcp6_lease *lease6, - bool conditional6, - int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**), - int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) { - int r; - - bool _space = false; - if (!space) - space = &_space; - - if (lvalue) - fprintf(f, "%s=", lvalue); - fputstrv(f, addresses, NULL, space); - - if (lease && conditional) { - const struct in_addr *lease_addresses; - - r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses); - if (r > 0) - serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local); - } - - if (lease6 && conditional6 && lease6_get_addr) { - const struct in6_addr *in6_addrs; - - r = lease6_get_addr(lease6, &in6_addrs); - if (r > 0) - serialize_in6_addrs(f, in6_addrs, r, space); - } - - if (lease6 && conditional6 && lease6_get_fqdn) { - char **in6_hosts; - - r = lease6_get_fqdn(lease6, &in6_hosts); - if (r > 0) - fputstrv(f, in6_hosts, NULL, space); - } - - if (lvalue) - fputc('\n', f); -} - -int link_save(Link *link) { - const char *admin_state, *oper_state, *carrier_state, *address_state; - _cleanup_free_ char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - int r; - - assert(link); - assert(link->state_file); - assert(link->lease_file); - assert(link->manager); - - if (link->state == LINK_STATE_LINGER) { - (void) unlink(link->state_file); return 0; } - link_lldp_save(link); + r = sd_netlink_message_get_type(message, &type); + if (r < 0) { + log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m"); + return 0; + } else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) { + log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type); + return 0; + } - admin_state = link_state_to_string(link->state); - assert(admin_state); + r = sd_rtnl_message_link_get_ifindex(message, &ifindex); + if (r < 0) { + log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m"); + return 0; + } else if (ifindex <= 0) { + log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex); + return 0; + } - oper_state = link_operstate_to_string(link->operstate); - assert(oper_state); + r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name); + if (r < 0) { + log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m"); + return 0; + } - carrier_state = link_carrier_state_to_string(link->carrier_state); - assert(carrier_state); + (void) link_get(m, ifindex, &link); + (void) netdev_get(m, name, &netdev); - address_state = link_address_state_to_string(link->address_state); - assert(address_state); - - r = fopen_temporary(link->state_file, &f, &temp_path); - if (r < 0) - goto fail; - - (void) fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "ADMIN_STATE=%s\n" - "OPER_STATE=%s\n" - "CARRIER_STATE=%s\n" - "ADDRESS_STATE=%s\n", - admin_state, oper_state, carrier_state, address_state); - - if (link->network) { - char **dhcp6_domains = NULL, **dhcp_domains = NULL; - const char *dhcp_domainname = NULL, *p; - bool space; - - fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", - yes_no(link->network->required_for_online)); - - LinkOperationalStateRange st = link->network->required_operstate_for_online; - fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n", - strempty(link_operstate_to_string(st.min)), - st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "", - st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : ""); - - fprintf(f, "NETWORK_FILE=%s\n", link->network->filename); - - /************************************************************/ - - fputs("DNS=", f); - space = false; - if (link->n_dns != (unsigned) -1) - link_save_dns(link, f, link->dns, link->n_dns, &space); - else - link_save_dns(link, f, link->network->dns, link->network->n_dns, &space); - - serialize_addresses(f, NULL, &space, - NULL, - link->dhcp_lease, - link->network->dhcp_use_dns, - SD_DHCP_LEASE_DNS, - link->dhcp6_lease, - link->network->dhcp6_use_dns, - sd_dhcp6_lease_get_dns, - NULL); - - /* Make sure to flush out old entries before we use the NDisc data */ - ndisc_vacuum(link); - - if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) { - NDiscRDNSS *dd; - - SET_FOREACH(dd, link->ndisc_rdnss) - serialize_in6_addrs(f, &dd->address, 1, &space); - } - - fputc('\n', f); - - /************************************************************/ - - serialize_addresses(f, "NTP", NULL, - link->ntp ?: link->network->ntp, - link->dhcp_lease, - link->network->dhcp_use_ntp, - SD_DHCP_LEASE_NTP, - link->dhcp6_lease, - link->network->dhcp6_use_ntp, - sd_dhcp6_lease_get_ntp_addrs, - sd_dhcp6_lease_get_ntp_fqdn); - - serialize_addresses(f, "SIP", NULL, - NULL, - link->dhcp_lease, - link->network->dhcp_use_sip, - SD_DHCP_LEASE_SIP, - NULL, false, NULL, NULL); - - /************************************************************/ - - if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { - if (link->dhcp_lease) { - (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname); - (void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains); + switch (type) { + case RTM_NEWLINK: + if (!link) { + /* link is new, so add it */ + r = link_add(m, message, &link); + if (r < 0) { + log_warning_errno(r, "Could not process new link message, ignoring: %m"); + return 0; } - if (link->dhcp6_lease) - (void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains); } - fputs("DOMAINS=", f); - space = false; - ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains) - fputs_with_space(f, p, NULL, &space); - - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) { - if (dhcp_domainname) - fputs_with_space(f, dhcp_domainname, NULL, &space); - if (dhcp_domains) - fputstrv(f, dhcp_domains, NULL, &space); - if (dhcp6_domains) - fputstrv(f, dhcp6_domains, NULL, &space); + if (netdev) { + /* netdev exists, so make sure the ifindex matches */ + r = netdev_set_ifindex(netdev, message); + if (r < 0) { + log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m"); + return 0; + } } - if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) { - NDiscDNSSL *dd; - - SET_FOREACH(dd, link->ndisc_dnssl) - fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + r = link_update(link, message); + if (r < 0) { + log_warning_errno(r, "Could not process link message, ignoring: %m"); + return 0; } - fputc('\n', f); + break; - /************************************************************/ + case RTM_DELLINK: + link_drop(link); + netdev_drop(netdev); - fputs("ROUTE_DOMAINS=", f); - space = false; - ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains) - fputs_with_space(f, p, NULL, &space); + break; - if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) { - if (dhcp_domainname) - fputs_with_space(f, dhcp_domainname, NULL, &space); - if (dhcp_domains) - fputstrv(f, dhcp_domains, NULL, &space); - if (dhcp6_domains) - fputstrv(f, dhcp6_domains, NULL, &space); - } - - if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) { - NDiscDNSSL *dd; - - SET_FOREACH(dd, link->ndisc_dnssl) - fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); - } - - fputc('\n', f); - - /************************************************************/ - - fprintf(f, "LLMNR=%s\n", - resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr)); - - /************************************************************/ - - fprintf(f, "MDNS=%s\n", - resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns)); - - /************************************************************/ - - int dns_default_route = - link->dns_default_route >= 0 ? link->dns_default_route : - link->network->dns_default_route; - if (dns_default_route >= 0) - fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route)); - - /************************************************************/ - - DnsOverTlsMode dns_over_tls_mode = - link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode : - link->network->dns_over_tls_mode; - if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID) - fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode)); - - /************************************************************/ - - DnssecMode dnssec_mode = - link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode : - link->network->dnssec_mode; - if (dnssec_mode != _DNSSEC_MODE_INVALID) - fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode)); - - /************************************************************/ - - Set *nta_anchors = link->dnssec_negative_trust_anchors; - if (set_isempty(nta_anchors)) - nta_anchors = link->network->dnssec_negative_trust_anchors; - - if (!set_isempty(nta_anchors)) { - const char *n; - - fputs("DNSSEC_NTA=", f); - space = false; - SET_FOREACH(n, nta_anchors) - fputs_with_space(f, n, NULL, &space); - fputc('\n', f); - } - - /************************************************************/ - - r = link_serialize_addresses(link, f); - if (r < 0) - goto fail; - - /************************************************************/ - - r = link_serialize_routes(link, f); - if (r < 0) - goto fail; + default: + assert_not_reached("Received link message with invalid RTNL message type."); } - print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links); - print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); - - if (link->dhcp_lease) { - r = dhcp_lease_save(link->dhcp_lease, link->lease_file); - if (r < 0) - goto fail; - - fprintf(f, - "DHCP_LEASE=%s\n", - link->lease_file); - } else - (void) unlink(link->lease_file); - - r = link_serialize_ipv4ll(link, f); - if (r < 0) - goto fail; - - r = link_serialize_dhcp6_client(link, f); - if (r < 0) - goto fail; - - r = fflush_and_check(f); - if (r < 0) - goto fail; - - if (rename(temp_path, link->state_file) < 0) { - r = -errno; - goto fail; - } - - return 0; - -fail: - (void) unlink(link->state_file); - if (temp_path) - (void) unlink(temp_path); - - return log_link_error_errno(link, r, "Failed to save link data to %s: %m", link->state_file); -} - -/* The serialized state in /run is no longer up-to-date. */ -void link_dirty(Link *link) { - int r; - - assert(link); - - /* mark manager dirty as link is dirty */ - manager_dirty(link->manager); - - r = set_ensure_put(&link->manager->dirty_links, NULL, link); - if (r <= 0) - /* Ignore allocation errors and don't take another ref if the link was already dirty */ - return; - link_ref(link); -} - -/* The serialized state in /run is up-to-date */ -void link_clean(Link *link) { - assert(link); - assert(link->manager); - - link_unref(set_remove(link->manager->dirty_links, link)); -} - -int link_save_and_clean(Link *link) { - int r; - - r = link_save(link); - if (r < 0) - return r; - - link_clean(link); - return 0; + return 1; } static const char* const link_state_table[_LINK_STATE_MAX] = { diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index cd541920c..d3353a1c4 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -33,7 +33,7 @@ typedef enum LinkState { LINK_STATE_FAILED, /* at least one configuration process failed */ LINK_STATE_LINGER, /* RTM_DELLINK for the link has been received */ _LINK_STATE_MAX, - _LINK_STATE_INVALID = -1 + _LINK_STATE_INVALID = -EINVAL, } LinkState; typedef struct Manager Manager; @@ -83,7 +83,6 @@ typedef struct Link { unsigned route_messages; unsigned nexthop_messages; unsigned routing_policy_rule_messages; - unsigned routing_policy_rule_remove_messages; unsigned tc_messages; unsigned sr_iov_messages; unsigned enslaving; @@ -130,6 +129,7 @@ typedef struct Link { bool setting_genmode:1; bool ipv6_mtu_set:1; bool bridge_mdb_configured:1; + bool activated:1; sd_dhcp_server *dhcp_server; @@ -203,24 +203,15 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref); DEFINE_TRIVIAL_DESTRUCTOR(link_netlink_destroy_callback, Link, link_unref); int link_get(Manager *m, int ifindex, Link **ret); -int link_add(Manager *manager, sd_netlink_message *message, Link **ret); -void link_drop(Link *link); int link_down(Link *link, link_netlink_message_handler_t callback); void link_enter_failed(Link *link); -int link_initialized(Link *link, sd_device *device); void link_set_state(Link *link, LinkState state); void link_check_ready(Link *link); void link_update_operstate(Link *link, bool also_update_bond_master); -int link_update(Link *link, sd_netlink_message *message); - -void link_dirty(Link *link); -void link_clean(Link *link); -int link_save(Link *link); -int link_save_and_clean(Link *link); int link_carrier_reset(Link *link); bool link_has_carrier(Link *link); @@ -231,7 +222,7 @@ int link_ipv6ll_gained(Link *link, const struct in6_addr *address); int link_set_mtu(Link *link, uint32_t mtu); -bool link_ipv4ll_enabled(Link *link, AddressFamily mask); +bool link_ipv4ll_enabled(Link *link); int link_stop_engines(Link *link, bool may_keep_dhcp); @@ -241,6 +232,9 @@ LinkState link_state_from_string(const char *s) _pure_; int link_configure(Link *link); int link_reconfigure(Link *link, bool force); +int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata); +int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); + int log_link_message_full_errno(Link *link, sd_netlink_message *m, int level, int err, const char *msg); #define log_link_message_error_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_ERR, err, msg) #define log_link_message_warning_errno(link, m, err, msg) log_link_message_full_errno(link, m, LOG_WARNING, err, msg) diff --git a/src/network/networkd-lldp-rx.c b/src/network/networkd-lldp-rx.c index c22852ff5..bf1dd045b 100644 --- a/src/network/networkd-lldp-rx.c +++ b/src/network/networkd-lldp-rx.c @@ -6,6 +6,7 @@ #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "networkd-link.h" #include "networkd-lldp-rx.h" #include "networkd-lldp-tx.h" @@ -47,7 +48,7 @@ static bool link_lldp_rx_enabled(Link *link) { return link->network->lldp_mode != LLDP_MODE_NO; } -static void lldp_handler(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata) { +static void lldp_handler(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, void *userdata) { Link *link = userdata; int r; @@ -134,7 +135,7 @@ int link_update_lldp(Link *link) { } int link_lldp_save(Link *link) { - _cleanup_free_ char *temp_path = NULL; + _cleanup_(unlink_and_freep) char *temp_path = NULL; _cleanup_fclose_ FILE *f = NULL; sd_lldp_neighbor **l = NULL; int n = 0, r, i; @@ -149,10 +150,10 @@ int link_lldp_save(Link *link) { r = sd_lldp_get_neighbors(link->lldp, &l); if (r < 0) - goto finish; + return r; if (r == 0) { (void) unlink(link->lldp_file); - goto finish; + return 0; } n = r; @@ -181,19 +182,13 @@ int link_lldp_save(Link *link) { if (r < 0) goto finish; - if (rename(temp_path, link->lldp_file) < 0) { - r = -errno; + r = conservative_rename(temp_path, link->lldp_file); + if (r < 0) goto finish; - } finish: - if (r < 0) { - (void) unlink(link->lldp_file); - if (temp_path) - (void) unlink(temp_path); - + if (r < 0) log_link_error_errno(link, r, "Failed to save LLDP data to %s: %m", link->lldp_file); - } if (l) { for (i = 0; i < n; i++) diff --git a/src/network/networkd-lldp-rx.h b/src/network/networkd-lldp-rx.h index 78c522893..49306eafd 100644 --- a/src/network/networkd-lldp-rx.h +++ b/src/network/networkd-lldp-rx.h @@ -10,7 +10,7 @@ typedef enum LLDPMode { LLDP_MODE_YES = 1, LLDP_MODE_ROUTERS_ONLY = 2, _LLDP_MODE_MAX, - _LLDP_MODE_INVALID = -1, + _LLDP_MODE_INVALID = -EINVAL, } LLDPMode; int link_lldp_rx_configure(Link *link); diff --git a/src/network/networkd-lldp-tx.c b/src/network/networkd-lldp-tx.c index b03d948bd..1b97e6584 100644 --- a/src/network/networkd-lldp-tx.c +++ b/src/network/networkd-lldp-tx.c @@ -17,6 +17,7 @@ #include "parse-util.h" #include "random-util.h" #include "socket-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "unaligned.h" @@ -415,46 +416,6 @@ void link_lldp_emit_stop(Link *link) { link->lldp_emit_event_source = sd_event_source_unref(link->lldp_emit_event_source); } -int config_parse_lldp_emit( - 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) { - - LLDPEmit *emit = data; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - - if (isempty(rvalue)) - *emit = LLDP_EMIT_NO; - else if (streq(rvalue, "nearest-bridge")) - *emit = LLDP_EMIT_NEAREST_BRIDGE; - else if (streq(rvalue, "non-tpmr-bridge")) - *emit = LLDP_EMIT_NON_TPMR_BRIDGE; - else if (streq(rvalue, "customer-bridge")) - *emit = LLDP_EMIT_CUSTOMER_BRIDGE; - else { - r = parse_boolean(rvalue); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse LLDP emission setting, ignoring: %s", rvalue); - return 0; - } - - *emit = r ? LLDP_EMIT_NEAREST_BRIDGE : LLDP_EMIT_NO; - } - - return 0; -} - int config_parse_lldp_mud( const char *unit, const char *filename, @@ -491,3 +452,13 @@ int config_parse_lldp_mud( return free_and_replace(n->lldp_mud, unescaped); } + +static const char * const lldp_emit_table[_LLDP_EMIT_MAX] = { + [LLDP_EMIT_NO] = "no", + [LLDP_EMIT_NEAREST_BRIDGE] = "nearest-bridge", + [LLDP_EMIT_NON_TPMR_BRIDGE] = "non-tpmr-bridge", + [LLDP_EMIT_CUSTOMER_BRIDGE] = "customer-bridge", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(lldp_emit, LLDPEmit, LLDP_EMIT_NEAREST_BRIDGE); +DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_lldp_emit, lldp_emit, LLDPEmit, LLDP_EMIT_NO, "Failed to parse LLDP emission setting"); diff --git a/src/network/networkd-lldp-tx.h b/src/network/networkd-lldp-tx.h index aae30cba0..b8917f9de 100644 --- a/src/network/networkd-lldp-tx.h +++ b/src/network/networkd-lldp-tx.h @@ -13,6 +13,7 @@ typedef enum LLDPEmit { LLDP_EMIT_NON_TPMR_BRIDGE, LLDP_EMIT_CUSTOMER_BRIDGE, _LLDP_EMIT_MAX, + _LLDP_EMIT_INVALID = -EINVAL, } LLDPEmit; bool link_lldp_emit_enabled(Link *link); diff --git a/src/network/networkd-manager-bus.c b/src/network/networkd-manager-bus.c index a0ac8b51f..fce10a7e7 100644 --- a/src/network/networkd-manager-bus.c +++ b/src/network/networkd-manager-bus.c @@ -236,25 +236,101 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Manager, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Manager, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), - SD_BUS_METHOD("ListLinks", NULL, "a(iso)", method_list_links, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetLinkByName", "s", "io", method_get_link_by_name, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetLinkByIndex", "i", "so", method_get_link_by_index, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkNTP", "ias", NULL, bus_method_set_link_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDNSEx", "ia(iayqs)", NULL, bus_method_set_link_dns_servers_ex, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RenewLink", "i", NULL, bus_method_renew_link, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ForceRenewLink", "i", NULL, bus_method_force_renew_link, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ReconfigureLink", "i", NULL, bus_method_reconfigure_link, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Reload", NULL, NULL, bus_method_reload, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ListLinks", + SD_BUS_NO_ARGS, + SD_BUS_RESULT("a(iso)", links), + method_list_links, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetLinkByName", + SD_BUS_ARGS("s", name), + SD_BUS_RESULT("i", ifindex, "o", path), + method_get_link_by_name, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetLinkByIndex", + SD_BUS_ARGS("i", ifindex), + SD_BUS_RESULT("s", name, "o", path), + method_get_link_by_index, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkNTP", + SD_BUS_ARGS("i", ifindex, "as", servers), + SD_BUS_NO_RESULT, + bus_method_set_link_ntp_servers, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDNS", + SD_BUS_ARGS("i", ifindex, "a(iay)", addresses), + SD_BUS_NO_RESULT, + bus_method_set_link_dns_servers, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDNSEx", + SD_BUS_ARGS("i", ifindex, "a(iayqs)", addresses), + SD_BUS_NO_RESULT, + bus_method_set_link_dns_servers_ex, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDomains", + SD_BUS_ARGS("i", ifindex, "a(sb)", domains), + SD_BUS_NO_RESULT, + bus_method_set_link_domains, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDefaultRoute", + SD_BUS_ARGS("i", ifindex, "b", enable), + SD_BUS_NO_RESULT, + bus_method_set_link_default_route, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkLLMNR", + SD_BUS_ARGS("i", ifindex, "s", mode), + SD_BUS_NO_RESULT, + bus_method_set_link_llmnr, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkMulticastDNS", + SD_BUS_ARGS("i", ifindex, "s", mode), + SD_BUS_NO_RESULT, + bus_method_set_link_mdns, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDNSOverTLS", + SD_BUS_ARGS("i", ifindex, "s", mode), + SD_BUS_NO_RESULT, + bus_method_set_link_dns_over_tls, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSEC", + SD_BUS_ARGS("i", ifindex, "s", mode), + SD_BUS_NO_RESULT, + bus_method_set_link_dnssec, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSECNegativeTrustAnchors", + SD_BUS_ARGS("i", ifindex, "as", names), + SD_BUS_NO_RESULT, + bus_method_set_link_dnssec_negative_trust_anchors, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RevertLinkNTP", + SD_BUS_ARGS("i", ifindex), + SD_BUS_NO_RESULT, + bus_method_revert_link_ntp, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RevertLinkDNS", + SD_BUS_ARGS("i", ifindex), + SD_BUS_NO_RESULT, + bus_method_revert_link_dns, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RenewLink", + SD_BUS_ARGS("i", ifindex), + SD_BUS_NO_RESULT, + bus_method_renew_link, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ForceRenewLink", + SD_BUS_ARGS("i", ifindex), + SD_BUS_NO_RESULT, + bus_method_force_renew_link, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ReconfigureLink", + SD_BUS_ARGS("i", ifindex), + SD_BUS_NO_RESULT, + bus_method_reconfigure_link, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Reload", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_method_reload, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 19c3cc6f7..bfdb1f8c9 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -11,16 +11,17 @@ #include "sd-netlink.h" #include "alloc-util.h" +#include "bus-error.h" #include "bus-log-control-api.h" #include "bus-polkit.h" #include "bus-util.h" #include "conf-parser.h" #include "def.h" -#include "device-private.h" -#include "device-util.h" #include "dns-domain.h" #include "fd-util.h" #include "fileio.h" +#include "firewall-util.h" +#include "fs-util.h" #include "local-addresses.h" #include "netlink-util.h" #include "network-internal.h" @@ -35,6 +36,7 @@ #include "networkd-nexthop.h" #include "networkd-routing-policy-rule.h" #include "networkd-speed-meter.h" +#include "networkd-state-file.h" #include "ordered-set.h" #include "path-lookup.h" #include "path-util.h" @@ -45,7 +47,6 @@ #include "strv.h" #include "sysctl-util.h" #include "tmpfile-util.h" -#include "udev-util.h" /* use 128 MB for receive socket kernel queue. */ #define RCVBUF_SIZE (128*1024*1024) @@ -178,57 +179,6 @@ int manager_connect_bus(Manager *m) { return 0; } -static int manager_udev_process_link(sd_device_monitor *monitor, sd_device *device, void *userdata) { - Manager *m = userdata; - DeviceAction action; - Link *link = NULL; - int r, ifindex; - - assert(m); - assert(device); - - r = device_get_action(device, &action); - if (r < 0) { - log_device_debug_errno(device, r, "Failed to get udev action, ignoring device: %m"); - return 0; - } - - /* Ignore the "remove" uevent — let's remove a device only if rtnetlink says so. All other uevents - * are "positive" events in some form, i.e. inform us about a changed or new network interface, that - * still exists — and we are interested in that. */ - if (action == DEVICE_ACTION_REMOVE) - return 0; - - r = sd_device_get_ifindex(device, &ifindex); - if (r < 0) { - log_device_debug_errno(device, r, "Ignoring udev %s event for device without ifindex or with invalid ifindex: %m", - device_action_to_string(action)); - return 0; - } - - r = device_is_renaming(device); - if (r < 0) { - log_device_error_errno(device, r, "Failed to determine the device is renamed or not, ignoring '%s' uevent: %m", - device_action_to_string(action)); - return 0; - } - if (r > 0) { - log_device_debug(device, "Interface is under renaming, wait for the interface to be renamed."); - return 0; - } - - r = link_get(m, ifindex, &link); - if (r < 0) { - if (r != -ENODEV) - log_debug_errno(r, "Failed to get link from ifindex %i, ignoring: %m", ifindex); - return 0; - } - - (void) link_initialized(link, device); - - return 0; -} - static int manager_connect_udev(Manager *m) { int r; @@ -260,93 +210,6 @@ static int manager_connect_udev(Manager *m) { return 0; } -static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { - Link *link = NULL; - NetDev *netdev = NULL; - uint16_t type; - const char *name; - int r, ifindex; - - assert(rtnl); - assert(message); - assert(m); - - if (sd_netlink_message_is_error(message)) { - r = sd_netlink_message_get_errno(message); - if (r < 0) - log_message_warning_errno(message, r, "rtnl: Could not receive link message, ignoring"); - - return 0; - } - - r = sd_netlink_message_get_type(message, &type); - if (r < 0) { - log_warning_errno(r, "rtnl: Could not get message type, ignoring: %m"); - return 0; - } else if (!IN_SET(type, RTM_NEWLINK, RTM_DELLINK)) { - log_warning("rtnl: Received unexpected message type %u when processing link, ignoring.", type); - return 0; - } - - r = sd_rtnl_message_link_get_ifindex(message, &ifindex); - if (r < 0) { - log_warning_errno(r, "rtnl: Could not get ifindex from link message, ignoring: %m"); - return 0; - } else if (ifindex <= 0) { - log_warning("rtnl: received link message with invalid ifindex %d, ignoring.", ifindex); - return 0; - } - - r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name); - if (r < 0) { - log_warning_errno(r, "rtnl: Received link message without ifname, ignoring: %m"); - return 0; - } - - (void) link_get(m, ifindex, &link); - (void) netdev_get(m, name, &netdev); - - switch (type) { - case RTM_NEWLINK: - if (!link) { - /* link is new, so add it */ - r = link_add(m, message, &link); - if (r < 0) { - log_warning_errno(r, "Could not process new link message, ignoring: %m"); - return 0; - } - } - - if (netdev) { - /* netdev exists, so make sure the ifindex matches */ - r = netdev_set_ifindex(netdev, message); - if (r < 0) { - log_warning_errno(r, "Could not process new link message for netdev, ignoring: %m"); - return 0; - } - } - - r = link_update(link, message); - if (r < 0) { - log_warning_errno(r, "Could not process link message, ignoring: %m"); - return 0; - } - - break; - - case RTM_DELLINK: - link_drop(link); - netdev_drop(netdev); - - break; - - default: - assert_not_reached("Received link message with invalid RTNL message type."); - } - - return 1; -} - static int systemd_netlink_fd(void) { int n, fd, rtnl_fd = -EINVAL; @@ -354,14 +217,13 @@ static int systemd_netlink_fd(void) { if (n <= 0) return -EINVAL; - for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) { + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) { if (rtnl_fd >= 0) return -EINVAL; rtnl_fd = fd; } - } return rtnl_fd; } @@ -463,307 +325,24 @@ static int manager_connect_rtnl(Manager *m) { return 0; } -static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) { - const char *p; - int r; - - assert(s); - assert(dns); - - if (dns->ifindex != 0 && dns->ifindex != ifindex) - return 0; - - p = in_addr_full_to_string(dns); - if (!p) - return 0; - - r = ordered_set_put_strdup(s, p); - if (r == -EEXIST) - return 0; - - return r; -} - -static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) { - int r, c = 0; - unsigned i; - - assert(s); - assert(dns || n == 0); - - for (i = 0; i < n; i++) { - r = ordered_set_put_dns_server(s, ifindex, dns[i]); - if (r < 0) - return r; - - c += r; - } - - return c; -} - -static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) { - char *p; - int r; - - assert(s); - assert(address); - - r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); - if (r < 0) - return r; - - r = ordered_set_consume(s, p); - if (r == -EEXIST) - return 0; - - return r; -} - -static int ordered_set_put_in4_addrv(OrderedSet *s, - const struct in_addr *addresses, - size_t n, - bool (*predicate)(const struct in_addr *addr)) { - int r, c = 0; - size_t i; - - assert(s); - assert(n == 0 || addresses); - - for (i = 0; i < n; i++) { - if (predicate && !predicate(&addresses[i])) - continue; - r = ordered_set_put_in4_addr(s, addresses+i); - if (r < 0) - return r; - - c += r; - } - - return c; -} - -static int manager_save(Manager *m) { - _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL; - const char *operstate_str, *carrier_state_str, *address_state_str; - LinkOperationalState operstate = LINK_OPERSTATE_OFF; - LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF; - LinkAddressState address_state = LINK_ADDRESS_STATE_OFF; - _cleanup_free_ char *temp_path = NULL; - _cleanup_strv_free_ char **p = NULL; - _cleanup_fclose_ FILE *f = NULL; - Link *link; - int r; - - assert(m); - assert(m->state_file); - - /* We add all NTP and DNS server to a set, to filter out duplicates */ - dns = ordered_set_new(&string_hash_ops); - if (!dns) - return -ENOMEM; - - ntp = ordered_set_new(&string_hash_ops); - if (!ntp) - return -ENOMEM; - - sip = ordered_set_new(&string_hash_ops); - if (!sip) - return -ENOMEM; - - search_domains = ordered_set_new(&dns_name_hash_ops); - if (!search_domains) - return -ENOMEM; - - route_domains = ordered_set_new(&dns_name_hash_ops); - if (!route_domains) - return -ENOMEM; - - HASHMAP_FOREACH(link, m->links) { - const struct in_addr *addresses; - - if (link->flags & IFF_LOOPBACK) - continue; - - if (link->operstate > operstate) - operstate = link->operstate; - - if (link->carrier_state > carrier_state) - carrier_state = link->carrier_state; - - if (link->address_state > address_state) - address_state = link->address_state; - - if (!link->network) - continue; - - /* First add the static configured entries */ - if (link->n_dns != (unsigned) -1) - r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns); - else - r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns); - if (r < 0) - return r; - - r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp); - if (r < 0) - return r; - - r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains); - if (r < 0) - return r; - - r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains); - if (r < 0) - return r; - - if (!link->dhcp_lease) - continue; - - /* Secondly, add the entries acquired via DHCP */ - if (link->network->dhcp_use_dns) { - r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); - if (r > 0) { - r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_use_ntp) { - r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); - if (r > 0) { - r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_use_sip) { - r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses); - if (r > 0) { - r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local); - if (r < 0) - return r; - } else if (r < 0 && r != -ENODATA) - return r; - } - - if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { - const char *domainname; - char **domains = NULL; - - OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains; - r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); - if (r >= 0) { - r = ordered_set_put_strdup(target_domains, domainname); - if (r < 0) - return r; - } else if (r != -ENODATA) - return r; - - r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains); - if (r >= 0) { - r = ordered_set_put_strdupv(target_domains, domains); - if (r < 0) - return r; - } else if (r != -ENODATA) - return r; - } - } - - if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED) - carrier_state = LINK_CARRIER_STATE_CARRIER; - - operstate_str = link_operstate_to_string(operstate); - assert(operstate_str); - - carrier_state_str = link_carrier_state_to_string(carrier_state); - assert(carrier_state_str); - - address_state_str = link_address_state_to_string(address_state); - assert(address_state_str); - - r = fopen_temporary(m->state_file, &f, &temp_path); - if (r < 0) - return r; - - (void) fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n" - "OPER_STATE=%s\n" - "CARRIER_STATE=%s\n" - "ADDRESS_STATE=%s\n", - operstate_str, carrier_state_str, address_state_str); - - ordered_set_print(f, "DNS=", dns); - ordered_set_print(f, "NTP=", ntp); - ordered_set_print(f, "SIP=", sip); - ordered_set_print(f, "DOMAINS=", search_domains); - ordered_set_print(f, "ROUTE_DOMAINS=", route_domains); - - r = routing_policy_serialize_rules(m->rules, f); - if (r < 0) - goto fail; - - r = fflush_and_check(f); - if (r < 0) - goto fail; - - if (rename(temp_path, m->state_file) < 0) { - r = -errno; - goto fail; - } - - if (m->operational_state != operstate) { - m->operational_state = operstate; - if (strv_extend(&p, "OperationalState") < 0) - log_oom(); - } - - if (m->carrier_state != carrier_state) { - m->carrier_state = carrier_state; - if (strv_extend(&p, "CarrierState") < 0) - log_oom(); - } - - if (m->address_state != address_state) { - m->address_state = address_state; - if (strv_extend(&p, "AddressState") < 0) - log_oom(); - } - - if (p) { - r = manager_send_changed_strv(m, p); - if (r < 0) - log_error_errno(r, "Could not emit changed properties: %m"); - } - - m->dirty = false; - - return 0; - -fail: - (void) unlink(m->state_file); - (void) unlink(temp_path); - - return log_error_errno(r, "Failed to save network state to %s: %m", m->state_file); -} - static int manager_dirty_handler(sd_event_source *s, void *userdata) { Manager *m = userdata; Link *link; + int r; assert(m); - if (m->dirty) - manager_save(m); + if (m->dirty) { + r = manager_save(m); + if (r < 0) + log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); + } - SET_FOREACH(link, m->dirty_links) - (void) link_save_and_clean(link); + SET_FOREACH(link, m->dirty_links) { + r = link_save_and_clean(link); + if (r < 0) + log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); + } return 1; } @@ -849,18 +428,16 @@ int manager_new(Manager **ret) { m->duid.type = DUID_TYPE_EN; - (void) routing_policy_load_rules(m->state_file, &m->rules_saved); - *ret = TAKE_PTR(m); return 0; } -void manager_free(Manager *m) { +Manager* manager_free(Manager *m) { Link *link; if (!m) - return; + return NULL; free(m->state_file); @@ -881,11 +458,13 @@ void manager_free(Manager *m) { ordered_set_free_free(m->address_pools); + hashmap_free(m->route_table_names_by_number); + hashmap_free(m->route_table_numbers_by_name); + /* routing_policy_rule_free() access m->rules and m->rules_foreign. * So, it is necessary to set NULL after the sets are freed. */ m->rules = set_free(m->rules); m->rules_foreign = set_free(m->rules_foreign); - set_free(m->rules_saved); sd_netlink_unref(m->rtnl); sd_netlink_unref(m->genl); @@ -898,6 +477,10 @@ void manager_free(Manager *m) { m->routes = set_free(m->routes); m->routes_foreign = set_free(m->routes_foreign); + m->nexthops = set_free(m->nexthops); + m->nexthops_foreign = set_free(m->nexthops_foreign); + m->nexthops_by_id = hashmap_free(m->nexthops_by_id); + sd_event_source_unref(m->speed_meter_event_source); sd_event_unref(m->event); @@ -911,7 +494,9 @@ void manager_free(Manager *m) { safe_close(m->ethtool_fd); - free(m); + m->fw_ctx = fw_ctx_free(m->fw_ctx); + + return mfree(m); } int manager_start(Manager *m) { @@ -927,10 +512,15 @@ int manager_start(Manager *m) { /* The dirty handler will deal with future serialization, but the first one must be done explicitly. */ - manager_save(m); + r = manager_save(m); + if (r < 0) + log_warning_errno(r, "Failed to update state file %s, ignoring: %m", m->state_file); - HASHMAP_FOREACH(link, m->links) - (void) link_save(link); + HASHMAP_FOREACH(link, m->links) { + r = link_save(link); + if (r < 0) + log_link_warning_errno(link, r, "Failed to update link state file %s, ignoring: %m", link->state_file); + } return 0; } @@ -1101,6 +691,10 @@ int manager_enumerate(Manager *m) { if (r < 0) return log_error_errno(r, "Could not enumerate neighbors: %m"); + r = manager_enumerate_nexthop(m); + if (r < 0) + return log_error_errno(r, "Could not enumerate nexthop rules: %m"); + r = manager_enumerate_routes(m); if (r < 0) return log_error_errno(r, "Could not enumerate routes: %m"); @@ -1109,16 +703,12 @@ int manager_enumerate(Manager *m) { if (r < 0) return log_error_errno(r, "Could not enumerate routing policy rules: %m"); - r = manager_enumerate_nexthop(m); - if (r < 0) - return log_error_errno(r, "Could not enumerate nexthop rules: %m"); - return 0; } Link* manager_find_uplink(Manager *m, Link *exclude) { _cleanup_free_ struct local_address *gateways = NULL; - int n, i; + int n; assert(m); @@ -1132,7 +722,7 @@ Link* manager_find_uplink(Manager *m, Link *exclude) { return NULL; } - for (i = 0; i < n; i++) { + for (int i = 0; i < n; i++) { Link *link; link = hashmap_get(m->links, INT_TO_PTR(gateways[i].ifindex)); @@ -1153,23 +743,17 @@ Link* manager_find_uplink(Manager *m, Link *exclude) { return NULL; } -void manager_dirty(Manager *manager) { - assert(manager); - - /* the serialized state in /run is no longer up-to-date */ - manager->dirty = true; -} - static int set_hostname_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { - _unused_ Manager *manager = userdata; const sd_bus_error *e; + int r; assert(m); - assert(manager); e = sd_bus_message_get_error(m); - if (e) - log_warning_errno(sd_bus_error_get_errno(e), "Could not set hostname: %s", e->message); + if (e) { + r = sd_bus_error_get_errno(e); + log_warning_errno(r, "Could not set hostname: %s", bus_error_message(e, r)); + } return 1; } @@ -1179,8 +763,9 @@ int manager_set_hostname(Manager *m, const char *hostname) { log_debug("Setting transient hostname: '%s'", strna(hostname)); - if (free_and_strdup(&m->dynamic_hostname, hostname) < 0) - return log_oom(); + r = free_and_strdup_warn(&m->dynamic_hostname, hostname); + if (r < 0) + return r; if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { log_debug("Not connected to system bus, setting hostname later."); @@ -1207,15 +792,16 @@ int manager_set_hostname(Manager *m, const char *hostname) { } static int set_timezone_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { - _unused_ Manager *manager = userdata; const sd_bus_error *e; + int r; assert(m); - assert(manager); e = sd_bus_message_get_error(m); - if (e) - log_warning_errno(sd_bus_error_get_errno(e), "Could not set timezone: %s", e->message); + if (e) { + r = sd_bus_error_get_errno(e); + log_warning_errno(r, "Could not set timezone: %s", bus_error_message(e, r)); + } return 1; } @@ -1227,8 +813,9 @@ int manager_set_timezone(Manager *m, const char *tz) { assert(tz); log_debug("Setting system timezone: '%s'", tz); - if (free_and_strdup(&m->dynamic_timezone, tz) < 0) - return log_oom(); + r = free_and_strdup_warn(&m->dynamic_timezone, tz); + if (r < 0) + return r; if (!m->bus || sd_bus_is_ready(m->bus) <= 0) { log_debug("Not connected to system bus, setting timezone later."); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index b67116be5..929855daa 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -9,6 +9,7 @@ #include "sd-resolve.h" #include "dhcp-identifier.h" +#include "firewall-util.h" #include "hashmap.h" #include "networkd-link.h" #include "networkd-network.h" @@ -59,12 +60,22 @@ struct Manager { Set *rules; Set *rules_foreign; - Set *rules_saved; + + /* Manage nexthops by id. */ + Hashmap *nexthops_by_id; + + /* Manager stores nexthops without RTA_OIF attribute. */ + Set *nexthops; + Set *nexthops_foreign; /* Manager stores routes without RTA_OIF attribute. */ Set *routes; Set *routes_foreign; + /* Route table name */ + Hashmap *route_table_numbers_by_name; + Hashmap *route_table_names_by_number; + /* For link speed meter*/ bool use_speed_meter; sd_event_source *speed_meter_event_source; @@ -74,10 +85,12 @@ struct Manager { bool dhcp4_prefix_root_cannot_set_table:1; bool bridge_mdb_on_master_not_supported:1; + + FirewallContext *fw_ctx; }; int manager_new(Manager **ret); -void manager_free(Manager *m); +Manager* manager_free(Manager *m); int manager_connect_bus(Manager *m); int manager_start(Manager *m); @@ -87,8 +100,6 @@ bool manager_should_reload(Manager *m); int manager_enumerate(Manager *m); -void manager_dirty(Manager *m); - Link* manager_find_uplink(Manager *m, Link *exclude); int manager_set_hostname(Manager *m, const char *hostname); diff --git a/src/network/networkd-mdb.c b/src/network/networkd-mdb.c index 0300dced6..f5aff7224 100644 --- a/src/network/networkd-mdb.c +++ b/src/network/networkd-mdb.c @@ -70,11 +70,7 @@ static int mdb_entry_new_static( .section = TAKE_PTR(n), }; - r = hashmap_ensure_allocated(&network->mdb_entries_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->mdb_entries_by_section, mdb_entry->section, mdb_entry); + r = hashmap_ensure_put(&network->mdb_entries_by_section, &network_config_hash_ops, mdb_entry->section, mdb_entry); if (r < 0) return r; @@ -199,6 +195,11 @@ int link_set_bridge_mdb(Link *link) { assert(link); assert(link->manager); + if (link->bridge_mdb_messages != 0) { + log_link_debug(link, "MDB entries are configuring."); + return 0; + } + link->bridge_mdb_configured = false; if (!link->network) @@ -321,8 +322,7 @@ int config_parse_mdb_vlan_id( if (r < 0) return r; - mdb_entry = NULL; - + TAKE_PTR(mdb_entry); return 0; } @@ -359,7 +359,6 @@ int config_parse_mdb_group_address( return 0; } - mdb_entry = NULL; - + TAKE_PTR(mdb_entry); return 0; } diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index d2aa3db17..035e80dab 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -15,6 +15,7 @@ #include "networkd-dhcp6.h" #include "networkd-manager.h" #include "networkd-ndisc.h" +#include "networkd-state-file.h" #include "string-table.h" #include "string-util.h" #include "strv.h" @@ -69,6 +70,15 @@ void network_adjust_ipv6_accept_ra(Network *network) { if (network->ipv6_accept_ra < 0) /* default to accept RA if ip_forward is disabled and ignore RA if ip_forward is enabled */ network->ipv6_accept_ra = !FLAGS_SET(network->ip_forward, ADDRESS_FAMILY_IPV6); + + /* When RouterAllowList=, PrefixAllowList= or RouteAllowList= are specified, then + * RouterDenyList=, PrefixDenyList= or RouteDenyList= are ignored, respectively. */ + if (!set_isempty(network->ndisc_allow_listed_router)) + network->ndisc_deny_listed_router = set_free_free(network->ndisc_deny_listed_router); + if (!set_isempty(network->ndisc_allow_listed_prefix)) + network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix); + if (!set_isempty(network->ndisc_allow_listed_route_prefix)) + network->ndisc_deny_listed_route_prefix = set_free_free(network->ndisc_deny_listed_route_prefix); } static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force); @@ -86,12 +96,12 @@ static int ndisc_address_callback(Address *address) { break; } - if (IN6_IS_ADDR_UNSPECIFIED(&router)) { + if (in6_addr_is_null(&router)) { _cleanup_free_ char *buf = NULL; - (void) in_addr_to_string(address->family, &address->in_addr, &buf); - log_link_debug(address->link, "%s is called for %s/%u, but it is already removed, ignoring.", - __func__, strna(buf), address->prefixlen); + (void) in_addr_prefix_to_string(address->family, &address->in_addr, address->prefixlen, &buf); + log_link_debug(address->link, "%s is called for %s, but it is already removed, ignoring.", + __func__, strna(buf)); return 0; } @@ -109,6 +119,7 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool NDiscDNSSL *dnssl; NDiscRDNSS *rdnss; int k, r = 0; + bool updated = false; assert(link); assert(router); @@ -140,7 +151,7 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool if (DEBUG_LOGGING) { _cleanup_free_ char *buf = NULL; - (void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf); + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) router, &buf); log_link_debug(link, "No SLAAC address obtained from %s is ready. " "The old NDisc information will be removed later.", strna(buf)); @@ -152,12 +163,10 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool if (DEBUG_LOGGING) { _cleanup_free_ char *buf = NULL; - (void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf); + (void) in_addr_to_string(AF_INET6, (const union in_addr_union*) router, &buf); log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf)); } - link_dirty(link); - SET_FOREACH(na, link->ndisc_addresses) if (na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) { k = address_remove(na->address, link, NULL); @@ -173,12 +182,19 @@ static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool } SET_FOREACH(rdnss, link->ndisc_rdnss) - if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router)) + if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router)) { free(set_remove(link->ndisc_rdnss, rdnss)); + updated = true; + } SET_FOREACH(dnssl, link->ndisc_dnssl) - if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router)) + if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router)) { free(set_remove(link->ndisc_dnssl, dnssl)); + updated = true; + } + + if (updated) + link_dirty(link); return r; } @@ -328,6 +344,8 @@ static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt) r = route_configure(route, link, ndisc_route_handler, &ret); if (r < 0) return log_link_error_errno(link, r, "Failed to set NDisc route: %m"); + if (r > 0) + link->ndisc_routes_configured = false; link->ndisc_routes_messages++; @@ -403,12 +421,6 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link * link_enter_failed(link); return 1; } - - r = link_set_routes(link); - if (r < 0) { - link_enter_failed(link); - return 1; - } } return 1; @@ -425,9 +437,11 @@ static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router assert(link); assert(rt); - r = address_configure(address, link, ndisc_address_handler, true, &ret); + r = address_configure(address, link, ndisc_address_handler, &ret); if (r < 0) return log_link_error_errno(link, r, "Failed to set NDisc SLAAC address: %m"); + if (r > 0) + link->ndisc_addresses_configured = false; link->ndisc_addresses_messages++; @@ -483,7 +497,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m"); - if (address_exists(link, AF_INET6, &gateway)) { + if (link_has_ipv6_address(link, &gateway.in6) > 0) { if (DEBUG_LOGGING) { _cleanup_free_ char *buffer = NULL; @@ -521,7 +535,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { route->pref = preference; route->gw_family = AF_INET6; route->gw = gateway; - route->lifetime = time_now + lifetime * USEC_PER_SEC; + route->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC); route->mtu = mtu; r = ndisc_route_configure(route, link, rt); @@ -545,7 +559,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) { route_gw->protocol = RTPROT_RA; if (!route_gw->pref_set) route->pref = preference; - route_gw->lifetime = time_now + lifetime * USEC_PER_SEC; + route_gw->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC); if (route_gw->mtu == 0) route_gw->mtu = mtu; @@ -636,12 +650,11 @@ static int ndisc_router_generate_addresses(Link *link, struct in6_addr *address, _cleanup_free_ struct in6_addr *new_address = NULL; if (j->address_generation_type == IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE - && (IN6_IS_ADDR_UNSPECIFIED(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) { + && (in6_addr_is_null(&j->prefix) || IN6_ARE_ADDR_EQUAL(&j->prefix, address))) { /* While this loop uses dad_counter and a retry limit as specified in RFC 7217, the loop - does not actually attempt Duplicate Address Detection; the counter will be incremented - only when the address generation algorithm produces an invalid address, and the loop - may exit with an address which ends up being unusable due to duplication on the link. - */ + * does not actually attempt Duplicate Address Detection; the counter will be incremented + * only when the address generation algorithm produces an invalid address, and the loop + * may exit with an address which ends up being unusable due to duplication on the link. */ for (; j->dad_counter < DAD_CONFLICTS_IDGEN_RETRIES_RFC7217; j->dad_counter++) { r = make_stableprivate_address(link, address, prefixlen, j->dad_counter, &new_address); if (r < 0) @@ -805,7 +818,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { route->protocol = RTPROT_RA; route->flags = RTM_F_PREFIX; route->dst_prefixlen = prefixlen; - route->lifetime = time_now + lifetime * USEC_PER_SEC; + route->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC); r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6); if (r < 0) @@ -820,7 +833,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { _cleanup_(route_freep) Route *route = NULL; - struct in6_addr gateway; + union in_addr_union gateway, dst; uint32_t lifetime; unsigned preference, prefixlen; usec_t time_now; @@ -835,10 +848,39 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { if (lifetime == 0) return 0; - r = sd_ndisc_router_get_address(rt, &gateway); + r = sd_ndisc_router_route_get_address(rt, &dst.in6); + if (r < 0) + return log_link_error_errno(link, r, "Failed to get route address: %m"); + + if ((!set_isempty(link->network->ndisc_allow_listed_route_prefix) && + !set_contains(link->network->ndisc_allow_listed_route_prefix, &dst.in6)) || + set_contains(link->network->ndisc_deny_listed_route_prefix, &dst.in6)) { + if (DEBUG_LOGGING) { + _cleanup_free_ char *buf = NULL; + + (void) in_addr_to_string(AF_INET6, &dst, &buf); + if (!set_isempty(link->network->ndisc_allow_listed_route_prefix)) + log_link_debug(link, "Route prefix '%s' is not in allow list, ignoring", strnull(buf)); + else + log_link_debug(link, "Route prefix '%s' is in deny list, ignoring", strnull(buf)); + } + return 0; + } + + r = sd_ndisc_router_get_address(rt, &gateway.in6); if (r < 0) return log_link_error_errno(link, r, "Failed to get gateway address from RA: %m"); + if (link_has_ipv6_address(link, &gateway.in6) > 0) { + if (DEBUG_LOGGING) { + _cleanup_free_ char *buf = NULL; + + (void) in_addr_to_string(AF_INET6, &gateway, &buf); + log_link_debug(link, "Advertised route gateway, %s, is local to the link, ignoring route", strnull(buf)); + } + return 0; + } + r = sd_ndisc_router_route_get_prefixlen(rt, &prefixlen); if (r < 0) return log_link_error_errno(link, r, "Failed to get route prefix length: %m"); @@ -860,14 +902,11 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) { route->priority = link->network->dhcp6_route_metric; route->protocol = RTPROT_RA; route->pref = preference; - route->gw.in6 = gateway; + route->gw = gateway; route->gw_family = AF_INET6; + route->dst = dst; route->dst_prefixlen = prefixlen; - route->lifetime = time_now + lifetime * USEC_PER_SEC; - - r = sd_ndisc_router_route_get_address(rt, &route->dst.in6); - if (r < 0) - return log_link_error_errno(link, r, "Failed to get route address: %m"); + route->lifetime = usec_add(time_now, lifetime * USEC_PER_SEC); r = ndisc_route_configure(route, link, rt); if (r < 0) @@ -897,6 +936,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { struct in6_addr router; NDiscRDNSS *rdnss; usec_t time_now; + bool updated = false; int n, r; assert(link); @@ -958,8 +998,13 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_oom(); assert(r > 0); + + updated = true; } + if (updated) + link_dirty(link); + return 0; } @@ -984,6 +1029,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { uint32_t lifetime; usec_t time_now; NDiscDNSSL *dnssl; + bool updated = false; char **j; int r; @@ -1043,8 +1089,13 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_oom(); assert(r > 0); + + updated = true; } + if (updated) + link_dirty(link); + return 0; } @@ -1075,12 +1126,17 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { if (r < 0) return log_link_error_errno(link, r, "Failed to get prefix address: %m"); - if (set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) { + if ((!set_isempty(link->network->ndisc_allow_listed_prefix) && + !set_contains(link->network->ndisc_allow_listed_prefix, &a.in6)) || + set_contains(link->network->ndisc_deny_listed_prefix, &a.in6)) { if (DEBUG_LOGGING) { _cleanup_free_ char *b = NULL; (void) in_addr_to_string(AF_INET6, &a, &b); - log_link_debug(link, "Prefix '%s' is deny-listed, ignoring", strna(b)); + if (!set_isempty(link->network->ndisc_allow_listed_prefix)) + log_link_debug(link, "Prefix '%s' is not in allow list, ignoring", strna(b)); + else + log_link_debug(link, "Prefix '%s' is in deny list, ignoring", strna(b)); } break; } @@ -1131,7 +1187,7 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) { } static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { - struct in6_addr router; + union in_addr_union router; uint64_t flags; NDiscAddress *na; NDiscRoute *nr; @@ -1142,21 +1198,31 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { assert(link->manager); assert(rt); - link->ndisc_addresses_configured = false; - link->ndisc_routes_configured = false; - - link_dirty(link); - - r = sd_ndisc_router_get_address(rt, &router); + r = sd_ndisc_router_get_address(rt, &router.in6); if (r < 0) return log_link_error_errno(link, r, "Failed to get router address from RA: %m"); + if ((!set_isempty(link->network->ndisc_allow_listed_router) && + !set_contains(link->network->ndisc_allow_listed_router, &router.in6)) || + set_contains(link->network->ndisc_deny_listed_router, &router.in6)) { + if (DEBUG_LOGGING) { + _cleanup_free_ char *buf = NULL; + + (void) in_addr_to_string(AF_INET6, &router, &buf); + if (!set_isempty(link->network->ndisc_allow_listed_router)) + log_link_debug(link, "Router '%s' is not in allow list, ignoring", strna(buf)); + else + log_link_debug(link, "Router '%s' is in deny list, ignoring", strna(buf)); + } + return 0; + } + SET_FOREACH(na, link->ndisc_addresses) - if (IN6_ARE_ADDR_EQUAL(&na->router, &router)) + if (IN6_ARE_ADDR_EQUAL(&na->router, &router.in6)) na->marked = true; SET_FOREACH(nr, link->ndisc_routes) - if (IN6_ARE_ADDR_EQUAL(&nr->router, &router)) + if (IN6_ARE_ADDR_EQUAL(&nr->router, &router.in6)) nr->marked = true; r = sd_ndisc_router_get_flags(rt, &flags); @@ -1189,16 +1255,9 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { if (link->ndisc_addresses_messages == 0) link->ndisc_addresses_configured = true; - else { + else log_link_debug(link, "Setting SLAAC addresses."); - /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are - * called, the related flags must be cleared. Otherwise, the link becomes configured - * state before routes are configured. */ - link->static_routes_configured = false; - link->static_nexthops_configured = false; - } - if (link->ndisc_routes_messages == 0) link->ndisc_routes_configured = true; else @@ -1216,7 +1275,7 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { return 0; } -static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata) { +static void ndisc_handler(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata) { Link *link = userdata; int r; @@ -1285,7 +1344,6 @@ void ndisc_vacuum(Link *link) { NDiscRDNSS *r; NDiscDNSSL *d; usec_t time_now; - bool updated = false; assert(link); @@ -1294,19 +1352,12 @@ void ndisc_vacuum(Link *link) { time_now = now(clock_boottime_or_monotonic()); SET_FOREACH(r, link->ndisc_rdnss) - if (r->valid_until < time_now) { + if (r->valid_until < time_now) free(set_remove(link->ndisc_rdnss, r)); - updated = true; - } SET_FOREACH(d, link->ndisc_dnssl) - if (d->valid_until < time_now) { + if (d->valid_until < time_now) free(set_remove(link->ndisc_dnssl, d)); - updated = true; - } - - if (updated) - link_dirty(link); } void ndisc_flush(Link *link) { @@ -1356,7 +1407,7 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( ipv6_token_compare_func, free); -int config_parse_ndisc_deny_listed_prefix( +int config_parse_ndisc_address_filter( const char *unit, const char *filename, unsigned line, @@ -1368,8 +1419,7 @@ int config_parse_ndisc_deny_listed_prefix( void *data, void *userdata) { - Network *network = data; - const char *p; + Set **list = data; int r; assert(filename); @@ -1378,11 +1428,11 @@ int config_parse_ndisc_deny_listed_prefix( assert(data); if (isempty(rvalue)) { - network->ndisc_deny_listed_prefix = set_free_free(network->ndisc_deny_listed_prefix); + *list = set_free_free(*list); return 0; } - for (p = rvalue;;) { + for (const char *p = rvalue;;) { _cleanup_free_ char *n = NULL; _cleanup_free_ struct in6_addr *a = NULL; union in_addr_union ip; @@ -1392,8 +1442,8 @@ int config_parse_ndisc_deny_listed_prefix( return log_oom(); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse NDisc deny-listed prefix, ignoring assignment: %s", - rvalue); + "Failed to parse NDisc %s=, ignoring assignment: %s", + lvalue, rvalue); return 0; } if (r == 0) @@ -1402,20 +1452,22 @@ int config_parse_ndisc_deny_listed_prefix( r = in_addr_from_string(AF_INET6, n, &ip); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, - "NDisc deny-listed prefix is invalid, ignoring assignment: %s", n); + "NDisc %s= entry is invalid, ignoring assignment: %s", + lvalue, n); continue; } - if (set_contains(network->ndisc_deny_listed_prefix, &ip.in6)) - continue; - a = newdup(struct in6_addr, &ip.in6, 1); if (!a) return log_oom(); - r = set_ensure_consume(&network->ndisc_deny_listed_prefix, &in6_addr_hash_ops, TAKE_PTR(a)); + r = set_ensure_consume(list, &in6_addr_hash_ops, TAKE_PTR(a)); if (r < 0) return log_oom(); + if (r == 0) + log_syntax(unit, LOG_WARNING, filename, line, 0, + "NDisc %s= entry is duplicated, ignoring assignment: %s", + lvalue, n); } } @@ -1488,11 +1540,9 @@ int config_parse_address_generation_type( token->prefix = buffer.in6; } - r = ordered_set_ensure_allocated(&network->ipv6_tokens, &ipv6_token_hash_ops); - if (r < 0) + r = ordered_set_ensure_put(&network->ipv6_tokens, &ipv6_token_hash_ops, token); + if (r == -ENOMEM) return log_oom(); - - r = ordered_set_put(network->ipv6_tokens, token); if (r == -EEXIST) log_syntax(unit, LOG_DEBUG, filename, line, r, "IPv6 token '%s' is duplicated, ignoring: %m", rvalue); diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h index 156241122..8984d8861 100644 --- a/src/network/networkd-ndisc.h +++ b/src/network/networkd-ndisc.h @@ -14,7 +14,7 @@ typedef enum IPv6TokenAddressGeneration { IPV6_TOKEN_ADDRESS_GENERATION_STATIC, IPV6_TOKEN_ADDRESS_GENERATION_PREFIXSTABLE, _IPV6_TOKEN_ADDRESS_GENERATION_MAX, - _IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -1, + _IPV6_TOKEN_ADDRESS_GENERATION_INVALID = -EINVAL, } IPv6TokenAddressGeneration; typedef enum IPv6AcceptRAStartDHCP6Client { @@ -22,7 +22,7 @@ typedef enum IPv6AcceptRAStartDHCP6Client { IPV6_ACCEPT_RA_START_DHCP6_CLIENT_ALWAYS, IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES, _IPV6_ACCEPT_RA_START_DHCP6_CLIENT_MAX, - _IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -1, + _IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -EINVAL, } IPv6AcceptRAStartDHCP6Client; typedef struct NDiscAddress { @@ -63,7 +63,6 @@ struct IPv6Token { }; int ipv6token_new(IPv6Token **ret); -DEFINE_TRIVIAL_CLEANUP_FUNC(IPv6Token *, freep); static inline char* NDISC_DNSSL_DOMAIN(const NDiscDNSSL *n) { return ((char*) n) + ALIGN(sizeof(NDiscDNSSL)); @@ -77,7 +76,7 @@ int ndisc_configure(Link *link); void ndisc_vacuum(Link *link); void ndisc_flush(Link *link); -CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_deny_listed_prefix); +CONFIG_PARSER_PROTOTYPE(config_parse_ndisc_address_filter); CONFIG_PARSER_PROTOTYPE(config_parse_address_generation_type); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_accept_ra_start_dhcp6_client); diff --git a/src/network/networkd-neighbor.c b/src/network/networkd-neighbor.c index c805d52cf..f54a2f9c9 100644 --- a/src/network/networkd-neighbor.c +++ b/src/network/networkd-neighbor.c @@ -60,11 +60,7 @@ static int neighbor_new_static(Network *network, const char *filename, unsigned .section = TAKE_PTR(n), }; - r = hashmap_ensure_allocated(&network->neighbors_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->neighbors_by_section, neighbor->section, neighbor); + r = hashmap_ensure_put(&network->neighbors_by_section, &network_config_hash_ops, neighbor->section, neighbor); if (r < 0) return r; @@ -174,6 +170,7 @@ static int neighbor_add_internal(Link *link, Set **neighbors, const Neighbor *in } static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) { + bool is_new = false; Neighbor *neighbor; int r; @@ -183,6 +180,7 @@ static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) { r = neighbor_add_internal(link, &link->neighbors, in, &neighbor); if (r < 0) return r; + is_new = true; } else if (r == 0) { /* Neighbor is foreign, claim it as recognized */ r = set_ensure_put(&link->neighbors, &neighbor_hash_ops, neighbor); @@ -192,12 +190,13 @@ static int neighbor_add(Link *link, const Neighbor *in, Neighbor **ret) { set_remove(link->neighbors_foreign, neighbor); } else if (r == 1) { /* Neighbor already exists */ + ; } else return r; if (ret) *ret = neighbor; - return 0; + return is_new; } static int neighbor_add_foreign(Link *link, const Neighbor *in, Neighbor **ret) { @@ -283,7 +282,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not add neighbor: %m"); - return 0; + return r; } int link_set_neighbors(Link *link) { @@ -294,6 +293,11 @@ int link_set_neighbors(Link *link) { assert(link->network); assert(link->state != _LINK_STATE_INVALID); + if (link->neighbor_messages != 0) { + log_link_debug(link, "Neighbors are configuring."); + return 0; + } + link->neighbors_configured = false; HASHMAP_FOREACH(neighbor, link->network->neighbors_by_section) { diff --git a/src/network/networkd-network-bus.c b/src/network/networkd-network-bus.c index 0e5f1488d..8c52faf18 100644 --- a/src/network/networkd-network-bus.c +++ b/src/network/networkd-network-bus.c @@ -45,11 +45,11 @@ const sd_bus_vtable network_vtable[] = { SD_BUS_PROPERTY("Description", "s", NULL, offsetof(Network, description), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Network, filename), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match_mac), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match_path), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match_driver), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match_type), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("MatchName", "as", NULL, offsetof(Network, match_name), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchMAC", "as", property_get_ether_addrs, offsetof(Network, match.mac), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchPath", "as", NULL, offsetof(Network, match.path), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchDriver", "as", NULL, offsetof(Network, match.driver), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchType", "as", NULL, offsetof(Network, match.iftype), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("MatchName", "as", NULL, offsetof(Network, match.ifname), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 5cc9e3e8f..a61113406 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -5,7 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include #include "conf-parser.h" #include "netem.h" -#include "network-internal.h" +#include "net-condition.h" #include "networkd-address-label.h" #include "networkd-address.h" #include "networkd-can.h" @@ -41,16 +42,16 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_mac) -Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(Network, match_permanent_mac) -Match.Path, config_parse_match_strv, 0, offsetof(Network, match_path) -Match.Driver, config_parse_match_strv, 0, offsetof(Network, match_driver) -Match.Type, config_parse_match_strv, 0, offsetof(Network, match_type) -Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match_wlan_iftype) -Match.SSID, config_parse_match_strv, 0, offsetof(Network, match_ssid) -Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match_bssid) -Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match_name) -Match.Property, config_parse_match_property, 0, offsetof(Network, match_property) +Match.MACAddress, config_parse_hwaddrs, 0, offsetof(Network, match.mac) +Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(Network, match.permanent_mac) +Match.Path, config_parse_match_strv, 0, offsetof(Network, match.path) +Match.Driver, config_parse_match_strv, 0, offsetof(Network, match.driver) +Match.Type, config_parse_match_strv, 0, offsetof(Network, match.iftype) +Match.WLANInterfaceType, config_parse_match_strv, 0, offsetof(Network, match.wifi_iftype) +Match.SSID, config_parse_match_strv, 0, offsetof(Network, match.ssid) +Match.BSSID, config_parse_hwaddrs, 0, offsetof(Network, match.bssid) +Match.Name, config_parse_match_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(Network, match.ifname) +Match.Property, config_parse_match_property, 0, offsetof(Network, match.property) Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(Network, conditions) Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(Network, conditions) Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(Network, conditions) @@ -62,7 +63,9 @@ Link.Group, config_parse_uint32, Link.ARP, config_parse_tristate, 0, offsetof(Network, arp) Link.Multicast, config_parse_tristate, 0, offsetof(Network, multicast) Link.AllMulticast, config_parse_tristate, 0, offsetof(Network, allmulticast) +Link.Promiscuous, config_parse_tristate, 0, offsetof(Network, promiscuous) Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged) +Link.ActivationPolicy, config_parse_activation_policy, 0, offsetof(Network, activation_policy) Link.RequiredForOnline, config_parse_required_for_online, 0, 0 SR-IOV.VirtualFunction, config_parse_sr_iov_uint32, 0, 0 SR-IOV.VLANId, config_parse_sr_iov_uint32, 0, 0 @@ -74,6 +77,7 @@ SR-IOV.Trust, config_parse_sr_iov_boolean, SR-IOV.LinkState, config_parse_sr_iov_link_state, 0, 0 SR-IOV.MACAddress, config_parse_sr_iov_mac, 0, 0 Network.Description, config_parse_string, 0, offsetof(Network, description) +Network.BatmanAdvanced, config_parse_ifname, 0, offsetof(Network, batadv_name) Network.Bridge, config_parse_ifname, 0, offsetof(Network, bridge_name) Network.Bond, config_parse_ifname, 0, offsetof(Network, bond_name) Network.VLAN, config_parse_stacked_netdev, NETDEV_KIND_VLAN, offsetof(Network, stacked_netdev_names) @@ -108,7 +112,7 @@ Network.DNSSEC, config_parse_dnssec_mode, Network.DNSSECNegativeTrustAnchors, config_parse_dnssec_negative_trust_anchors, 0, 0 Network.NTP, config_parse_ntp, 0, offsetof(Network, ntp) Network.IPForward, config_parse_address_family_with_kernel, 0, offsetof(Network, ip_forward) -Network.IPMasquerade, config_parse_bool, 0, offsetof(Network, ip_masquerade) +Network.IPMasquerade, config_parse_ip_masquerade, 0, offsetof(Network, ip_masquerade) Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Network, ipv6_privacy_extensions) Network.IPv6AcceptRA, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra) @@ -117,6 +121,7 @@ Network.IPv6HopLimit, config_parse_int, Network.IPv6ProxyNDP, config_parse_tristate, 0, offsetof(Network, ipv6_proxy_ndp) Network.IPv6MTUBytes, config_parse_mtu, AF_INET6, offsetof(Network, ipv6_mtu) Network.IPv4AcceptLocal, config_parse_tristate, 0, offsetof(Network, ipv4_accept_local) +Network.IPv4RouteLocalnet, config_parse_tristate, 0, offsetof(Network, ipv4_route_localnet) Network.ActiveSlave, config_parse_bool, 0, offsetof(Network, active_slave) Network.PrimarySlave, config_parse_bool, 0, offsetof(Network, primary_slave) Network.IPv4ProxyARP, config_parse_tristate, 0, offsetof(Network, proxy_arp) @@ -160,6 +165,7 @@ RoutingPolicyRule.InvertRule, config_parse_routing_policy_rule_in RoutingPolicyRule.Family, config_parse_routing_policy_rule_family, 0, 0 RoutingPolicyRule.User, config_parse_routing_policy_rule_uid_range, 0, 0 RoutingPolicyRule.SuppressPrefixLength, config_parse_routing_policy_rule_suppress_prefixlen, 0, 0 +RoutingPolicyRule.Type, config_parse_routing_policy_rule_type, 0, 0 Route.Gateway, config_parse_gateway, 0, 0 Route.Destination, config_parse_destination, 0, 0 Route.Source, config_parse_destination, 0, 0 @@ -175,12 +181,17 @@ Route.Protocol, config_parse_route_protocol, Route.Type, config_parse_route_type, 0, 0 Route.InitialCongestionWindow, config_parse_tcp_window, 0, 0 Route.InitialAdvertisedReceiveWindow, config_parse_tcp_window, 0, 0 +Route.TCPAdvertisedMaximumSegmentSize, config_parse_tcp_advmss, 0, 0 Route.QuickAck, config_parse_route_boolean, 0, 0 Route.FastOpenNoCookie, config_parse_route_boolean, 0, 0 Route.TTLPropagate, config_parse_route_boolean, 0, 0 Route.MultiPathRoute, config_parse_multipath_route, 0, 0 +Route.NextHop, config_parse_route_nexthop, 0, 0 NextHop.Id, config_parse_nexthop_id, 0, 0 NextHop.Gateway, config_parse_nexthop_gateway, 0, 0 +NextHop.Family, config_parse_nexthop_family, 0, 0 +NextHop.OnLink, config_parse_nexthop_onlink, 0, 0 +NextHop.Blackhole, config_parse_nexthop_blackhole, 0, 0 DHCPv4.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier) DHCPv4.UseDNS, config_parse_dhcp_use_dns, 0, 0 DHCPv4.RoutesToDNS, config_parse_bool, 0, offsetof(Network, dhcp_routes_to_dns) @@ -199,7 +210,7 @@ DHCPv4.RequestBroadcast, config_parse_bool, DHCPv4.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0 DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0 -DHCPv4.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class) +DHCPv4.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCPv4.RouteMetric, config_parse_dhcp_route_metric, 0, 0 @@ -216,13 +227,15 @@ DHCPv4.SendOption, config_parse_dhcp_send_option, DHCPv4.SendVendorOption, config_parse_dhcp_send_option, 0, offsetof(Network, dhcp_client_send_vendor_options) DHCPv4.RouteMTUBytes, config_parse_mtu, AF_INET, offsetof(Network, dhcp_route_mtu) DHCPv4.FallbackLeaseLifetimeSec, config_parse_dhcp_fallback_lease_lifetime, 0, 0 +DHCPv6.UseAddress, config_parse_bool, 0, offsetof(Network, dhcp6_use_address) DHCPv6.UseDNS, config_parse_dhcp_use_dns, 0, 0 +DHCPv6.UseHostname, config_parse_bool, 0, offsetof(Network, dhcp6_use_hostname) DHCPv6.UseNTP, config_parse_dhcp_use_ntp, 0, 0 DHCPv6.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit) DHCPv6.MUDURL, config_parse_dhcp6_mud_url, 0, 0 DHCPv6.RequestOptions, config_parse_dhcp_request_options, AF_INET6, 0 -DHCPv6.UserClass, config_parse_dhcp_user_class, AF_INET6, offsetof(Network, dhcp6_user_class) -DHCPv6.VendorClass, config_parse_dhcp_vendor_class, 0, offsetof(Network, dhcp6_vendor_class) +DHCPv6.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_user_class) +DHCPv6.VendorClass, config_parse_dhcp_user_or_vendor_class, AF_INET6, offsetof(Network, dhcp6_vendor_class) DHCPv6.SendVendorOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_vendor_options) DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0 @@ -235,8 +248,12 @@ IPv6AcceptRA.UseDNS, config_parse_bool, IPv6AcceptRA.UseDomains, config_parse_dhcp_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains) IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client) IPv6AcceptRA.RouteTable, config_parse_section_route_table, 0, 0 -IPv6AcceptRA.DenyList, config_parse_ndisc_deny_listed_prefix, 0, 0 -IPv6AcceptRA.BlackList, config_parse_ndisc_deny_listed_prefix, 0, 0 +IPv6AcceptRA.RouterAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_router) +IPv6AcceptRA.RouterDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_router) +IPv6AcceptRA.PrefixAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_prefix) +IPv6AcceptRA.PrefixDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix) +IPv6AcceptRA.RouteAllowList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_allow_listed_route_prefix) +IPv6AcceptRA.RouteDenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_route_prefix) DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec) DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec) DHCPServer.EmitDNS, config_parse_bool, 0, offsetof(Network, dhcp_server_emit[SD_DHCP_LEASE_DNS].emit) @@ -285,6 +302,7 @@ BridgeVLAN.EgressUntagged, config_parse_brvlan_untagged, DHCPv6PrefixDelegation.SubnetId, config_parse_dhcp6_pd_subnet_id, 0, offsetof(Network, dhcp6_pd_subnet_id) DHCPv6PrefixDelegation.Announce, config_parse_bool, 0, offsetof(Network, dhcp6_pd_announce) DHCPv6PrefixDelegation.Assign, config_parse_bool, 0, offsetof(Network, dhcp6_pd_assign) +DHCPv6PrefixDelegation.ManageTemporaryAddress, config_parse_bool, 0, offsetof(Network, dhcp6_pd_manage_temporary_address) DHCPv6PrefixDelegation.Token, config_parse_dhcp6_pd_token, 0, offsetof(Network, dhcp6_pd_token) IPv6SendRA.RouterLifetimeSec, config_parse_sec, 0, offsetof(Network, router_lifetime_usec) IPv6SendRA.Managed, config_parse_bool, 0, offsetof(Network, router_managed) @@ -312,6 +330,7 @@ CAN.FDMode, config_parse_tristate, CAN.FDNonISO, config_parse_tristate, 0, offsetof(Network, can_non_iso) CAN.RestartSec, config_parse_sec, 0, offsetof(Network, can_restart_us) CAN.TripleSampling, config_parse_tristate, 0, offsetof(Network, can_triple_sampling) +CAN.BusErrorReporting, config_parse_tristate, 0, offsetof(Network, can_berr_reporting) CAN.Termination, config_parse_tristate, 0, offsetof(Network, can_termination) CAN.ListenOnly, config_parse_tristate, 0, offsetof(Network, can_listen_only) QDisc.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 @@ -456,7 +475,7 @@ DHCP.Hostname, config_parse_hostname, DHCP.RequestBroadcast, config_parse_bool, 0, offsetof(Network, dhcp_broadcast) DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) -DHCP.UserClass, config_parse_dhcp_user_class, AF_INET, offsetof(Network, dhcp_user_class) +DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) DHCP.RouteMetric, config_parse_dhcp_route_metric, 0, 0 @@ -468,6 +487,8 @@ DHCP.RapidCommit, config_parse_bool, DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) DHCPv4.UseDomainName, config_parse_dhcp_use_domains, 0, offsetof(Network, dhcp_use_domains) DHCPv4.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) +IPv6AcceptRA.DenyList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix) +IPv6AcceptRA.BlackList, config_parse_ndisc_address_filter, 0, offsetof(Network, ndisc_deny_listed_prefix) TrafficControlQueueingDiscipline.Parent, config_parse_qdisc_parent, _QDISC_KIND_INVALID, 0 TrafficControlQueueingDiscipline.NetworkEmulatorDelaySec, config_parse_network_emulator_delay, 0, 0 TrafficControlQueueingDiscipline.NetworkEmulatorDelayJitterSec, config_parse_network_emulator_delay, 0, 0 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 325464146..e5ffd35b6 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -12,11 +12,11 @@ #include "fd-util.h" #include "hostname-util.h" #include "in-addr-util.h" -#include "networkd-dhcp-server.h" -#include "network-internal.h" +#include "net-condition.h" #include "networkd-address-label.h" #include "networkd-address.h" #include "networkd-dhcp-common.h" +#include "networkd-dhcp-server.h" #include "networkd-fdb.h" #include "networkd-manager.h" #include "networkd-mdb.h" @@ -142,11 +142,9 @@ static int network_resolve_stacked_netdevs(Network *network) { if (r <= 0) continue; - r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops); - if (r < 0) + r = hashmap_ensure_put(&network->stacked_netdevs, &string_hash_ops, netdev->ifname, netdev); + if (r == -ENOMEM) return log_oom(); - - r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev); if (r < 0) return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m", network->filename, (const char *) name); @@ -161,11 +159,7 @@ int network_verify(Network *network) { assert(network); assert(network->filename); - if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) && - strv_isempty(network->match_path) && strv_isempty(network->match_driver) && - strv_isempty(network->match_type) && strv_isempty(network->match_name) && - strv_isempty(network->match_property) && strv_isempty(network->match_wlan_iftype) && - strv_isempty(network->match_ssid) && !network->conditions) + if (net_match_is_empty(&network->match) && !network->conditions) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: No valid settings found in the [Match] section, ignoring file. " "To match all interfaces, add Name=* in the [Match] section.", @@ -177,12 +171,14 @@ int network_verify(Network *network) { "%s: Conditions in the file do not match the system environment, skipping.", network->filename); + (void) network_resolve_netdev_one(network, network->batadv_name, NETDEV_KIND_BATADV, &network->batadv); (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond); (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge); (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf); (void) network_resolve_stacked_netdevs(network); /* Free unnecessary entries. */ + network->batadv_name = mfree(network->batadv_name); network->bond_name = mfree(network->bond_name); network->bridge_name = mfree(network->bridge_name); network->vrf_name = mfree(network->vrf_name); @@ -214,16 +210,8 @@ int network_verify(Network *network) { if (network->link_local < 0) network->link_local = network->bridge ? ADDRESS_FAMILY_NO : ADDRESS_FAMILY_IPV6; - if (FLAGS_SET(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4) && - !FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) { - log_warning("%s: fallback assignment of IPv4 link local address is enabled but DHCPv4 is disabled. " - "Disabling the fallback assignment.", network->filename); - SET_FLAG(network->link_local, ADDRESS_FAMILY_FALLBACK_IPV4, false); - } - - /* IPMasquerade=yes implies IPForward=yes */ - if (network->ip_masquerade) - network->ip_forward |= ADDRESS_FAMILY_IPV4; + /* IPMasquerade implies IPForward */ + network->ip_forward |= network->ip_masquerade; network_adjust_ipv6_accept_ra(network); network_adjust_dhcp(network); @@ -238,9 +226,6 @@ int network_verify(Network *network) { if (network->dhcp_use_gateway < 0) network->dhcp_use_gateway = network->dhcp_use_routes; - if (network->ignore_carrier_loss < 0) - network->ignore_carrier_loss = network->configure_without_carrier; - if (network->dhcp_critical >= 0) { if (network->keep_configuration >= 0) log_warning("%s: Both KeepConfiguration= and deprecated CriticalConnection= are set. " @@ -252,6 +237,30 @@ int network_verify(Network *network) { network->keep_configuration = KEEP_CONFIGURATION_NO; } + if (!strv_isempty(network->bind_carrier)) { + if (!IN_SET(network->activation_policy, _ACTIVATION_POLICY_INVALID, ACTIVATION_POLICY_BOUND)) + log_warning("%s: ActivationPolicy=bound is required with BindCarrier=. " + "Setting ActivationPolicy=bound.", network->filename); + network->activation_policy = ACTIVATION_POLICY_BOUND; + } else if (network->activation_policy == ACTIVATION_POLICY_BOUND) { + log_warning("%s: ActivationPolicy=bound requires BindCarrier=. " + "Ignoring ActivationPolicy=bound.", network->filename); + network->activation_policy = ACTIVATION_POLICY_UP; + } + + if (network->activation_policy == _ACTIVATION_POLICY_INVALID) + network->activation_policy = ACTIVATION_POLICY_UP; + + if (network->activation_policy == ACTIVATION_POLICY_ALWAYS_UP) { + if (network->ignore_carrier_loss == false) + log_warning("%s: IgnoreCarrierLoss=false conflicts with ActivationPolicy=always-up. " + "Setting IgnoreCarrierLoss=true.", network->filename); + network->ignore_carrier_loss = true; + } + + if (network->ignore_carrier_loss < 0) + network->ignore_carrier_loss = network->configure_without_carrier; + if (network->keep_configuration < 0) network->keep_configuration = KEEP_CONFIGURATION_NO; @@ -279,7 +288,6 @@ int network_verify(Network *network) { int network_load_one(Manager *manager, OrderedHashmap **networks, const char *filename) { _cleanup_free_ char *fname = NULL, *name = NULL; _cleanup_(network_unrefp) Network *network = NULL; - _cleanup_fclose_ FILE *file = NULL; const char *dropin_dirname; char *d; int r; @@ -287,15 +295,12 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi assert(manager); assert(filename); - file = fopen(filename, "re"); - if (!file) { - if (errno == ENOENT) - return 0; - - return -errno; - } - - if (null_or_empty_fd(fileno(file))) { + r = null_or_empty_path(filename); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + if (r > 0) { log_debug("Skipping empty file: %s", filename); return 0; } @@ -329,9 +334,11 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .required_for_online = true, .required_operstate_for_online = LINK_OPERSTATE_RANGE_DEFAULT, + .activation_policy = _ACTIVATION_POLICY_INVALID, .arp = -1, .multicast = -1, .allmulticast = -1, + .promiscuous = -1, .configure_without_carrier = false, .ignore_carrier_loss = -1, @@ -362,14 +369,17 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .dhcp_use_timezone = false, .dhcp_ip_service_type = -1, + .dhcp6_use_address = true, + .dhcp6_use_dns = true, + .dhcp6_use_hostname = true, + .dhcp6_use_ntp = true, .dhcp6_rapid_commit = true, .dhcp6_route_metric = DHCP_ROUTE_METRIC, - .dhcp6_use_ntp = true, - .dhcp6_use_dns = true, .dhcp6_pd = -1, .dhcp6_pd_announce = true, .dhcp6_pd_assign = true, + .dhcp6_pd_manage_temporary_address = true, .dhcp6_pd_subnet_id = -1, .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true, @@ -410,6 +420,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ipv6ll_address_gen_mode = _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID, .ipv4_accept_local = -1, + .ipv4_route_localnet = -1, .ipv6_privacy_extensions = IPV6_PRIVACY_EXTENSIONS_NO, .ipv6_accept_ra = -1, .ipv6_dad_transmits = -1, @@ -425,6 +436,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ipv6_accept_ra_start_dhcp6_client = IPV6_ACCEPT_RA_START_DHCP6_CLIENT_YES, .can_triple_sampling = -1, + .can_berr_reporting = -1, .can_termination = -1, .can_listen_only = -1, .can_fd_mode = -1, @@ -432,7 +444,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi }; r = config_parse_many( - filename, NETWORK_DIRS, dropin_dirname, + STRV_MAKE_CONST(filename), NETWORK_DIRS, dropin_dirname, "Match\0" "Link\0" "SR-IOV\0" @@ -508,15 +520,11 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi /* Ignore .network files that do not match the conditions. */ return 0; - r = ordered_hashmap_ensure_allocated(networks, &string_hash_ops); + r = ordered_hashmap_ensure_put(networks, &string_hash_ops, network->name, network); if (r < 0) return r; - r = ordered_hashmap_put(*networks, network->name, network); - if (r < 0) - return r; - - network = NULL; + TAKE_PTR(network); return 0; } @@ -589,16 +597,7 @@ static Network *network_free(Network *network) { free(network->filename); - set_free_free(network->match_mac); - set_free_free(network->match_permanent_mac); - strv_free(network->match_path); - strv_free(network->match_driver); - strv_free(network->match_type); - strv_free(network->match_name); - strv_free(network->match_property); - strv_free(network->match_wlan_iftype); - strv_free(network->match_ssid); - set_free_free(network->match_bssid); + net_match_clear(&network->match); condition_free_list(network->conditions); free(network->description); @@ -625,8 +624,14 @@ static Network *network_free(Network *network) { ordered_set_free(network->router_search_domains); free(network->router_dns); + set_free_free(network->ndisc_deny_listed_router); + set_free_free(network->ndisc_allow_listed_router); set_free_free(network->ndisc_deny_listed_prefix); + set_free_free(network->ndisc_allow_listed_prefix); + set_free_free(network->ndisc_deny_listed_route_prefix); + set_free_free(network->ndisc_allow_listed_route_prefix); + free(network->batadv_name); free(network->bridge_name); free(network->bond_name); free(network->vrf_name); @@ -658,7 +663,7 @@ static Network *network_free(Network *network) { free(network->dhcp_server_timezone); - for (sd_dhcp_lease_server_type t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++) + for (sd_dhcp_lease_server_type_t t = 0; t < _SD_DHCP_LEASE_SERVER_TYPE_MAX; t++) free(network->dhcp_server_emit[t].addresses); set_free_free(network->dnssec_negative_trust_anchors); @@ -705,13 +710,9 @@ int network_get(Manager *manager, unsigned short iftype, sd_device *device, assert(ret); ORDERED_HASHMAP_FOREACH(network, manager->networks) - if (net_match_config(network->match_mac, network->match_permanent_mac, - network->match_path, network->match_driver, - network->match_type, network->match_name, network->match_property, - network->match_wlan_iftype, network->match_ssid, network->match_bssid, - device, mac, permanent_mac, driver, iftype, + if (net_match_config(&network->match, device, mac, permanent_mac, driver, iftype, ifname, alternative_names, wlan_iftype, ssid, bssid)) { - if (network->match_name && device) { + if (network->match.ifname && device) { const char *attr; uint8_t name_assign_type = NET_NAME_UNKNOWN; @@ -735,21 +736,6 @@ int network_get(Manager *manager, unsigned short iftype, sd_device *device, return -ENOENT; } -int network_apply(Network *network, Link *link) { - assert(network); - assert(link); - - link->network = network_ref(network); - - if (network->n_dns > 0 || - !strv_isempty(network->ntp) || - !ordered_set_isempty(network->search_domains) || - !ordered_set_isempty(network->route_domains)) - link_dirty(link); - - return 0; -} - bool network_has_static_ipv6_configurations(Network *network) { Address *address; Route *route; @@ -826,11 +812,9 @@ int config_parse_stacked_netdev(const char *unit, if (!name) return log_oom(); - r = hashmap_ensure_allocated(h, &string_hash_ops); - if (r < 0) + r = hashmap_ensure_put(h, &string_hash_ops, name, INT_TO_PTR(kind)); + if (r == -ENOMEM) return log_oom(); - - r = hashmap_put(*h, name, INT_TO_PTR(kind)); if (r < 0) log_syntax(unit, LOG_WARNING, filename, line, r, "Cannot add NetDev '%s' to network, ignoring assignment: %m", name); @@ -838,7 +822,7 @@ int config_parse_stacked_netdev(const char *unit, log_syntax(unit, LOG_DEBUG, filename, line, r, "NetDev '%s' specified twice, ignoring.", name); else - name = NULL; + TAKE_PTR(name); return 0; } @@ -946,7 +930,7 @@ int config_parse_hostname( if (r < 0) return r; - if (!hostname_is_valid(hn, false)) { + if (!hostname_is_valid(hn, 0)) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Hostname is not valid, ignoring assignment: %s", rvalue); return 0; @@ -1236,3 +1220,15 @@ static const char* const ipv6_link_local_address_gen_mode_table[_IPV6_LINK_LOCAL DEFINE_STRING_TABLE_LOOKUP(ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode); DEFINE_CONFIG_PARSE_ENUM(config_parse_ipv6_link_local_address_gen_mode, ipv6_link_local_address_gen_mode, IPv6LinkLocalAddressGenMode, "Failed to parse IPv6 link local address generation mode"); + +static const char* const activation_policy_table[_ACTIVATION_POLICY_MAX] = { + [ACTIVATION_POLICY_UP] = "up", + [ACTIVATION_POLICY_ALWAYS_UP] = "always-up", + [ACTIVATION_POLICY_MANUAL] = "manual", + [ACTIVATION_POLICY_ALWAYS_DOWN] = "always-down", + [ACTIVATION_POLICY_DOWN] = "down", + [ACTIVATION_POLICY_BOUND] = "bound", +}; + +DEFINE_STRING_TABLE_LOOKUP(activation_policy, ActivationPolicy); +DEFINE_CONFIG_PARSE_ENUM(config_parse_activation_policy, activation_policy, ActivationPolicy, "Failed to parse activation policy"); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index fd0fe056b..e859b590c 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -10,6 +10,7 @@ #include "condition.h" #include "conf-parser.h" #include "hashmap.h" +#include "net-condition.h" #include "netdev.h" #include "networkd-brvlan.h" #include "networkd-dhcp-common.h" @@ -34,7 +35,7 @@ typedef enum KeepConfiguration { KEEP_CONFIGURATION_STATIC = 1 << 2, KEEP_CONFIGURATION_YES = KEEP_CONFIGURATION_DHCP | KEEP_CONFIGURATION_STATIC, _KEEP_CONFIGURATION_MAX, - _KEEP_CONFIGURATION_INVALID = -1, + _KEEP_CONFIGURATION_INVALID = -EINVAL, } KeepConfiguration; typedef enum IPv6LinkLocalAddressGenMode { @@ -43,9 +44,20 @@ typedef enum IPv6LinkLocalAddressGenMode { IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_STABLE_PRIVACY = IN6_ADDR_GEN_MODE_STABLE_PRIVACY, IPV6_LINK_LOCAL_ADDRESSS_GEN_MODE_RANDOM = IN6_ADDR_GEN_MODE_RANDOM, _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_MAX, - _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID = -1 + _IPV6_LINK_LOCAL_ADDRESS_GEN_MODE_INVALID = -EINVAL, } IPv6LinkLocalAddressGenMode; +typedef enum ActivationPolicy { + ACTIVATION_POLICY_UP, + ACTIVATION_POLICY_ALWAYS_UP, + ACTIVATION_POLICY_MANUAL, + ACTIVATION_POLICY_ALWAYS_DOWN, + ACTIVATION_POLICY_DOWN, + ACTIVATION_POLICY_BOUND, + _ACTIVATION_POLICY_MAX, + _ACTIVATION_POLICY_INVALID = -EINVAL, +} ActivationPolicy; + typedef struct Manager Manager; typedef struct NetworkDHCPServerEmitAddress { @@ -65,24 +77,17 @@ struct Network { char *description; /* [Match] section */ - Set *match_mac; - Set *match_permanent_mac; - char **match_path; - char **match_driver; - char **match_type; - char **match_name; - char **match_property; - char **match_wlan_iftype; - char **match_ssid; - Set *match_bssid; + NetMatch match; LIST_HEAD(Condition, conditions); /* Master or stacked netdevs */ + NetDev *batadv; NetDev *bridge; NetDev *bond; NetDev *vrf; NetDev *xfrm; Hashmap *stacked_netdevs; + char *batadv_name; char *bridge_name; char *bond_name; char *vrf_name; @@ -95,9 +100,11 @@ struct Network { int arp; int multicast; int allmulticast; + int promiscuous; bool unmanaged; bool required_for_online; /* Is this network required to be considered online? */ LinkOperationalStateRange required_operstate_for_online; + ActivationPolicy activation_policy; /* misc settings */ bool configure_without_carrier; @@ -105,7 +112,7 @@ struct Network { KeepConfiguration keep_configuration; char **bind_carrier; bool default_route_on_device; - bool ip_masquerade; + AddressFamily ip_masquerade; /* DHCP Client Support */ AddressFamily dhcp; @@ -151,8 +158,10 @@ struct Network { OrderedHashmap *dhcp_client_send_vendor_options; /* DHCPv6 Client support*/ + bool dhcp6_use_address; bool dhcp6_use_dns; bool dhcp6_use_dns_set; + bool dhcp6_use_hostname; bool dhcp6_use_ntp; bool dhcp6_use_ntp_set; bool dhcp6_rapid_commit; @@ -204,6 +213,7 @@ struct Network { int dhcp6_pd; bool dhcp6_pd_announce; bool dhcp6_pd_assign; + bool dhcp6_pd_manage_temporary_address; int64_t dhcp6_pd_subnet_id; union in_addr_union dhcp6_pd_token; @@ -236,6 +246,7 @@ struct Network { unsigned can_data_sample_point; usec_t can_restart_us; int can_triple_sampling; + int can_berr_reporting; int can_termination; int can_listen_only; int can_fd_mode; @@ -244,6 +255,7 @@ struct Network { /* sysctl settings */ AddressFamily ip_forward; int ipv4_accept_local; + int ipv4_route_localnet; int ipv6_dad_transmits; int ipv6_hop_limit; int proxy_arp; @@ -263,7 +275,12 @@ struct Network { DHCPUseDomains ipv6_accept_ra_use_domains; IPv6AcceptRAStartDHCP6Client ipv6_accept_ra_start_dhcp6_client; uint32_t ipv6_accept_ra_route_table; + Set *ndisc_deny_listed_router; + Set *ndisc_allow_listed_router; Set *ndisc_deny_listed_prefix; + Set *ndisc_allow_listed_prefix; + Set *ndisc_deny_listed_route_prefix; + Set *ndisc_allow_listed_route_prefix; OrderedSet *ipv6_tokens; /* LLDP support */ @@ -314,7 +331,6 @@ int network_get(Manager *manager, unsigned short iftype, sd_device *device, const struct ether_addr *mac, const struct ether_addr *permanent_mac, enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid, Network **ret); -int network_apply(Network *network, Link *link); void network_apply_anonymize_if_set(Network *network); bool network_has_static_ipv6_configurations(Network *network); @@ -330,6 +346,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ntp); CONFIG_PARSER_PROTOTYPE(config_parse_required_for_online); CONFIG_PARSER_PROTOTYPE(config_parse_keep_configuration); CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_link_local_address_gen_mode); +CONFIG_PARSER_PROTOTYPE(config_parse_activation_policy); const struct ConfigPerfItem* network_network_gperf_lookup(const char *key, GPERF_LEN_TYPE length); @@ -338,3 +355,6 @@ KeepConfiguration keep_configuration_from_string(const char *s) _pure_; const char* ipv6_link_local_address_gen_mode_to_string(IPv6LinkLocalAddressGenMode s) _const_; IPv6LinkLocalAddressGenMode ipv6_link_local_address_gen_mode_from_string(const char *s) _pure_; + +const char* activation_policy_to_string(ActivationPolicy i) _const_; +ActivationPolicy activation_policy_from_string(const char *s) _pure_; diff --git a/src/network/networkd-nexthop.c b/src/network/networkd-nexthop.c index 4a09b4c91..470095c89 100644 --- a/src/network/networkd-nexthop.c +++ b/src/network/networkd-nexthop.c @@ -28,6 +28,17 @@ NextHop *nexthop_free(NextHop *nexthop) { if (nexthop->link) { set_remove(nexthop->link->nexthops, nexthop); set_remove(nexthop->link->nexthops_foreign, nexthop); + + if (nexthop->link->manager && nexthop->id > 0) + hashmap_remove(nexthop->link->manager->nexthops_by_id, UINT32_TO_PTR(nexthop->id)); + } + + if (nexthop->manager) { + set_remove(nexthop->manager->nexthops, nexthop); + set_remove(nexthop->manager->nexthops_foreign, nexthop); + + if (nexthop->id > 0) + hashmap_remove(nexthop->manager->nexthops_by_id, UINT32_TO_PTR(nexthop->id)); } return mfree(nexthop); @@ -44,6 +55,7 @@ static int nexthop_new(NextHop **ret) { *nexthop = (NextHop) { .family = AF_UNSPEC, + .onlink = -1, }; *ret = TAKE_PTR(nexthop); @@ -79,11 +91,7 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s nexthop->network = network; nexthop->section = TAKE_PTR(n); - r = hashmap_ensure_allocated(&network->nexthops_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->nexthops_by_section, nexthop->section, nexthop); + r = hashmap_ensure_put(&network->nexthops_by_section, &network_config_hash_ops, nexthop->section, nexthop); if (r < 0) return r; @@ -94,7 +102,9 @@ static int nexthop_new_static(Network *network, const char *filename, unsigned s static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) { assert(nexthop); + siphash24_compress(&nexthop->protocol, sizeof(nexthop->protocol), state); siphash24_compress(&nexthop->id, sizeof(nexthop->id), state); + siphash24_compress(&nexthop->blackhole, sizeof(nexthop->blackhole), state); siphash24_compress(&nexthop->family, sizeof(nexthop->family), state); switch (nexthop->family) { @@ -112,10 +122,18 @@ static void nexthop_hash_func(const NextHop *nexthop, struct siphash *state) { static int nexthop_compare_func(const NextHop *a, const NextHop *b) { int r; + r = CMP(a->protocol, b->protocol); + if (r != 0) + return r; + r = CMP(a->id, b->id); if (r != 0) return r; + r = CMP(a->blackhole, b->blackhole); + if (r != 0) + return r; + r = CMP(a->family, b->family); if (r != 0) return r; @@ -133,20 +151,60 @@ DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR( nexthop_compare_func, nexthop_free); -static int nexthop_get(Link *link, NextHop *in, NextHop **ret) { +static bool nexthop_equal(const NextHop *a, const NextHop *b) { + if (a == b) + return true; + + if (!a || !b) + return false; + + return nexthop_compare_func(a, b) == 0; +} + +static void nexthop_copy(NextHop *dest, const NextHop *src) { + assert(dest); + assert(src); + + /* This only copies entries used in the above hash and compare functions. */ + + dest->protocol = src->protocol; + dest->id = src->id; + dest->blackhole = src->blackhole; + dest->family = src->family; + dest->gw = src->gw; +} + +int manager_get_nexthop_by_id(Manager *manager, uint32_t id, NextHop **ret) { + NextHop *nh; + + assert(manager); + + if (id == 0) + return -EINVAL; + + nh = hashmap_get(manager->nexthops_by_id, UINT32_TO_PTR(id)); + if (!nh) + return -ENOENT; + + if (ret) + *ret = nh; + return 0; +} + +static int nexthop_get(Manager *manager, Link *link, const NextHop *in, NextHop **ret) { NextHop *existing; - assert(link); + assert(manager || link); assert(in); - existing = set_get(link->nexthops, in); + existing = set_get(link ? link->nexthops : manager->nexthops, in); if (existing) { if (ret) *ret = existing; return 1; } - existing = set_get(link->nexthops_foreign, in); + existing = set_get(link ? link->nexthops_foreign : manager->nexthops_foreign, in); if (existing) { if (ret) *ret = existing; @@ -156,11 +214,11 @@ static int nexthop_get(Link *link, NextHop *in, NextHop **ret) { return -ENOENT; } -static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop **ret) { +static int nexthop_add_internal(Manager *manager, Link *link, Set **nexthops, const NextHop *in, NextHop **ret) { _cleanup_(nexthop_freep) NextHop *nexthop = NULL; int r; - assert(link); + assert(manager || link); assert(nexthops); assert(in); @@ -168,9 +226,7 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop if (r < 0) return r; - nexthop->id = in->id; - nexthop->family = in->family; - nexthop->gw = in->gw; + nexthop_copy(nexthop, in); r = set_ensure_put(nexthops, &nexthop_hash_ops, nexthop); if (r < 0) @@ -179,36 +235,49 @@ static int nexthop_add_internal(Link *link, Set **nexthops, NextHop *in, NextHop return -EEXIST; nexthop->link = link; + nexthop->manager = manager; if (ret) *ret = nexthop; - nexthop = NULL; - + TAKE_PTR(nexthop); return 0; } -static int nexthop_add_foreign(Link *link, NextHop *in, NextHop **ret) { - return nexthop_add_internal(link, &link->nexthops_foreign, in, ret); +static int nexthop_add_foreign(Manager *manager, Link *link, const NextHop *in, NextHop **ret) { + assert(manager || link); + return nexthop_add_internal(manager, link, link ? &link->nexthops_foreign : &manager->nexthops_foreign, in, ret); } -static int nexthop_add(Link *link, NextHop *in, NextHop **ret) { +static int nexthop_add(Link *link, const NextHop *in, NextHop **ret) { + bool is_new = false; NextHop *nexthop; int r; - r = nexthop_get(link, in, &nexthop); + assert(link); + assert(in); + + if (in->blackhole) + r = nexthop_get(link->manager, NULL, in, &nexthop); + else + r = nexthop_get(NULL, link, in, &nexthop); if (r == -ENOENT) { /* NextHop does not exist, create a new one */ - r = nexthop_add_internal(link, &link->nexthops, in, &nexthop); + r = nexthop_add_internal(link->manager, + in->blackhole ? NULL : link, + in->blackhole ? &link->manager->nexthops : &link->nexthops, + in, &nexthop); if (r < 0) return r; + is_new = true; } else if (r == 0) { /* Take over a foreign nexthop */ - r = set_ensure_put(&link->nexthops, &nexthop_hash_ops, nexthop); + r = set_ensure_put(in->blackhole ? &link->manager->nexthops : &link->nexthops, + &nexthop_hash_ops, nexthop); if (r < 0) return r; - set_remove(link->nexthops_foreign, nexthop); + set_remove(in->blackhole ? link->manager->nexthops_foreign : link->nexthops_foreign, nexthop); } else if (r == 1) { /* NextHop exists, do nothing */ ; @@ -217,6 +286,121 @@ static int nexthop_add(Link *link, NextHop *in, NextHop **ret) { if (ret) *ret = nexthop; + return is_new; +} + +static int nexthop_update(Manager *manager, Link *link, NextHop *nexthop, const NextHop *in) { + Set *nexthops; + int r; + + /* link may be NULL. */ + + assert(manager); + assert(nexthop); + assert(in); + assert(in->id > 0); + + /* This updates nexthop ID if necessary, and register the nexthop to Manager. */ + + if (nexthop->id > 0) { + if (nexthop->id == in->id) + goto set_manager; + return -EINVAL; + } + + nexthops = link ? link->nexthops : manager->nexthops; + + nexthop = set_remove(nexthops, nexthop); + if (!nexthop) + return -ENOENT; + + nexthop->id = in->id; + + r = set_put(nexthops, nexthop); + if (r <= 0) { + int k; + + /* On failure, revert the change. */ + nexthop->id = 0; + k = set_put(nexthops, nexthop); + if (k <= 0) { + nexthop_free(nexthop); + return k < 0 ? k : -EEXIST; + } + + return r < 0 ? r : -EEXIST; + } + +set_manager: + return hashmap_ensure_put(&manager->nexthops_by_id, NULL, UINT32_TO_PTR(nexthop->id), nexthop); +} + +static void log_nexthop_debug(const NextHop *nexthop, uint32_t id, const char *str, const Link *link) { + assert(nexthop); + assert(str); + + /* link may be NULL. */ + + if (DEBUG_LOGGING) { + _cleanup_free_ char *gw = NULL; + + (void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw); + + if (nexthop->id == id) + log_link_debug(link, "%s nexthop: id: %"PRIu32", gw: %s, blackhole: %s", + str, nexthop->id, strna(gw), yes_no(nexthop->blackhole)); + else + log_link_debug(link, "%s nexthop: id: %"PRIu32"→%"PRIu32", gw: %s, blackhole: %s", + str, nexthop->id, id, strna(gw), yes_no(nexthop->blackhole)); + } +} + +static int nexthop_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; + + assert(m); + + /* Note that link may be NULL. */ + if (link && IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -ENOENT) + log_link_message_warning_errno(link, m, r, "Could not drop nexthop, ignoring"); + + return 1; +} + +static int nexthop_remove(const NextHop *nexthop, Manager *manager, Link *link) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; + int r; + + assert(nexthop); + assert(manager); + + /* link may be NULL. */ + + if (nexthop->id == 0) { + log_link_debug(link, "Cannot remove nexthop without valid ID, ignoring."); + return 0; + } + + log_nexthop_debug(nexthop, nexthop->id, "Removing", link); + + r = sd_rtnl_message_new_nexthop(manager->rtnl, &req, RTM_DELNEXTHOP, AF_UNSPEC, RTPROT_UNSPEC); + if (r < 0) + return log_link_error_errno(link, r, "Could not create RTM_DELNEXTHOP message: %m"); + + r = sd_netlink_message_append_u32(req, NHA_ID, nexthop->id); + if (r < 0) + return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m"); + + r = netlink_call_async(manager->rtnl, NULL, req, nexthop_remove_handler, + link_netlink_destroy_callback, link); + if (r < 0) + return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); + + link_ref(link); /* link may be NULL, link_ref() is OK with that */ return 0; } @@ -240,15 +424,18 @@ static int nexthop_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) } if (link->nexthop_messages == 0) { - log_link_debug(link, "Nexthop set"); + log_link_debug(link, "Nexthops set"); link->static_nexthops_configured = true; - link_check_ready(link); + /* Now all nexthops are configured. Let's configure remaining routes. */ + r = link_set_routes_with_gateway(link); + if (r < 0) + link_enter_failed(link); } return 1; } -static int nexthop_configure(NextHop *nexthop, Link *link) { +static int nexthop_configure(const NextHop *nexthop, Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; int r; @@ -258,14 +445,7 @@ static int nexthop_configure(NextHop *nexthop, Link *link) { assert(link->ifindex > 0); assert(IN_SET(nexthop->family, AF_INET, AF_INET6)); - if (DEBUG_LOGGING) { - _cleanup_free_ char *gw = NULL; - - if (!in_addr_is_null(nexthop->family, &nexthop->gw)) - (void) in_addr_to_string(nexthop->family, &nexthop->gw, &gw); - - log_link_debug(link, "Configuring nexthop: gw: %s", strna(gw)); - } + log_nexthop_debug(nexthop, nexthop->id, "Configuring", link); r = sd_rtnl_message_new_nexthop(link->manager->rtnl, &req, RTM_NEWNEXTHOP, nexthop->family, @@ -273,22 +453,32 @@ static int nexthop_configure(NextHop *nexthop, Link *link) { if (r < 0) return log_link_error_errno(link, r, "Could not create RTM_NEWNEXTHOP message: %m"); - r = sd_netlink_message_append_u32(req, NHA_ID, nexthop->id); - if (r < 0) - return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m"); - - r = sd_netlink_message_append_u32(req, NHA_OIF, link->ifindex); - if (r < 0) - return log_link_error_errno(link, r, "Could not append NHA_OIF attribute: %m"); - - if (in_addr_is_null(nexthop->family, &nexthop->gw) == 0) { - r = netlink_message_append_in_addr_union(req, NHA_GATEWAY, nexthop->family, &nexthop->gw); + if (nexthop->id > 0) { + r = sd_netlink_message_append_u32(req, NHA_ID, nexthop->id); if (r < 0) - return log_link_error_errno(link, r, "Could not append NHA_GATEWAY attribute: %m"); + return log_link_error_errno(link, r, "Could not append NHA_ID attribute: %m"); + } - r = sd_rtnl_message_nexthop_set_family(req, nexthop->family); + if (nexthop->blackhole) { + r = sd_netlink_message_append_flag(req, NHA_BLACKHOLE); if (r < 0) - return log_link_error_errno(link, r, "Could not set nexthop family: %m"); + return log_link_error_errno(link, r, "Could not append NHA_BLACKHOLE attribute: %m"); + } else { + r = sd_netlink_message_append_u32(req, NHA_OIF, link->ifindex); + if (r < 0) + return log_link_error_errno(link, r, "Could not append NHA_OIF attribute: %m"); + + if (in_addr_is_set(nexthop->family, &nexthop->gw)) { + r = netlink_message_append_in_addr_union(req, NHA_GATEWAY, nexthop->family, &nexthop->gw); + if (r < 0) + return log_link_error_errno(link, r, "Could not append NHA_GATEWAY attribute: %m"); + + if (nexthop->onlink > 0) { + r = sd_rtnl_message_nexthop_set_flags(req, RTNH_F_ONLINK); + if (r < 0) + return log_link_error_errno(link, r, "Failed to set RTNH_F_ONLINK flag: %m"); + } + } } r = netlink_call_async(link->manager->rtnl, NULL, req, nexthop_handler, @@ -298,48 +488,180 @@ static int nexthop_configure(NextHop *nexthop, Link *link) { link_ref(link); - r = nexthop_add(link, nexthop, &nexthop); + r = nexthop_add(link, nexthop, NULL); if (r < 0) return log_link_error_errno(link, r, "Could not add nexthop: %m"); - return 1; + return r; } -int link_set_nexthop(Link *link) { +int link_set_nexthops(Link *link) { + enum { + PHASE_ID, /* First phase: Nexthops with ID */ + PHASE_WITHOUT_ID, /* Second phase: Nexthops without ID */ + _PHASE_MAX, + } phase; NextHop *nh; int r; assert(link); assert(link->network); + if (link->nexthop_messages != 0) { + log_link_debug(link, "Nexthops are configuring."); + return 0; + } + link->static_nexthops_configured = false; - HASHMAP_FOREACH(nh, link->network->nexthops_by_section) { - r = nexthop_configure(nh, link); - if (r < 0) - return log_link_warning_errno(link, r, "Could not set nexthop: %m"); + for (phase = PHASE_ID; phase < _PHASE_MAX; phase++) + HASHMAP_FOREACH(nh, link->network->nexthops_by_section) { + if ((nh->id > 0) != (phase == PHASE_ID)) + continue; - link->nexthop_messages++; - } + r = nexthop_configure(nh, link); + if (r < 0) + return log_link_warning_errno(link, r, "Could not set nexthop: %m"); + + link->nexthop_messages++; + } if (link->nexthop_messages == 0) { link->static_nexthops_configured = true; - link_check_ready(link); - } else { - log_link_debug(link, "Setting nexthop"); - link_set_state(link, LINK_STATE_CONFIGURING); + /* Finally, configure routes with gateways. */ + return link_set_routes_with_gateway(link); } - return 1; + log_link_debug(link, "Setting nexthops"); + link_set_state(link, LINK_STATE_CONFIGURING); + + return 0; +} + +static bool link_has_nexthop(const Link *link, const NextHop *nexthop) { + NextHop *net_nexthop; + + assert(link); + assert(nexthop); + + if (!link->network) + return false; + + HASHMAP_FOREACH(net_nexthop, link->network->nexthops_by_section) + if (nexthop_equal(net_nexthop, nexthop)) + return true; + + return false; +} + +static bool links_have_nexthop(const Manager *manager, const NextHop *nexthop, const Link *except) { + Link *link; + + assert(manager); + + HASHMAP_FOREACH(link, manager->links) { + if (link == except) + continue; + + if (link_has_nexthop(link, nexthop)) + return true; + } + + return false; +} + +static int manager_drop_nexthops_internal(Manager *manager, bool foreign, const Link *except) { + NextHop *nexthop; + Set *nexthops; + int k, r = 0; + + assert(manager); + + nexthops = foreign ? manager->nexthops_foreign : manager->nexthops; + SET_FOREACH(nexthop, nexthops) { + /* do not touch nexthop created by the kernel */ + if (nexthop->protocol == RTPROT_KERNEL) + continue; + + /* The nexthop will be configured later, or already configured by a link. */ + if (links_have_nexthop(manager, nexthop, except)) + continue; + + /* The existing links do not have the nexthop. Let's drop this now. It may be + * re-configured later. */ + k = nexthop_remove(nexthop, manager, NULL); + if (k < 0 && r >= 0) + r = k; + } + + return r; +} + +static int manager_drop_foreign_nexthops(Manager *manager) { + return manager_drop_nexthops_internal(manager, true, NULL); +} + +static int manager_drop_nexthops(Manager *manager, const Link *except) { + return manager_drop_nexthops_internal(manager, false, except); +} + +int link_drop_foreign_nexthops(Link *link) { + NextHop *nexthop; + int k, r = 0; + + assert(link); + assert(link->manager); + + SET_FOREACH(nexthop, link->nexthops_foreign) { + /* do not touch nexthop created by the kernel */ + if (nexthop->protocol == RTPROT_KERNEL) + continue; + + if (link_has_nexthop(link, nexthop)) + k = nexthop_add(link, nexthop, NULL); + else + k = nexthop_remove(nexthop, link->manager, link); + if (k < 0 && r >= 0) + r = k; + } + + k = manager_drop_foreign_nexthops(link->manager); + if (k < 0 && r >= 0) + r = k; + + return r; +} + +int link_drop_nexthops(Link *link) { + NextHop *nexthop; + int k, r = 0; + + assert(link); + assert(link->manager); + + SET_FOREACH(nexthop, link->nexthops) { + /* do not touch nexthop created by the kernel */ + if (nexthop->protocol == RTPROT_KERNEL) + continue; + + k = nexthop_remove(nexthop, link->manager, link); + if (k < 0 && r >= 0) + r = k; + } + + k = manager_drop_nexthops(link->manager, link); + if (k < 0 && r >= 0) + r = k; + + return r; } int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { _cleanup_(nexthop_freep) NextHop *tmp = NULL; - _cleanup_free_ char *gateway = NULL; NextHop *nexthop = NULL; uint32_t ifindex; uint16_t type; - Link *link; + Link *link = NULL; int r; assert(rtnl); @@ -364,22 +686,21 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, } r = sd_netlink_message_read_u32(message, NHA_OIF, &ifindex); - if (r == -ENODATA) { - log_warning_errno(r, "rtnl: received nexthop message without NHA_OIF attribute, ignoring: %m"); - return 0; - } else if (r < 0) { + if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get NHA_OIF attribute, ignoring: %m"); return 0; - } else if (ifindex <= 0) { - log_warning("rtnl: received nexthop message with invalid ifindex %"PRIu32", ignoring.", ifindex); - return 0; - } + } else if (r >= 0) { + if (ifindex <= 0) { + log_warning("rtnl: received nexthop message with invalid ifindex %"PRIu32", ignoring.", ifindex); + return 0; + } - r = link_get(m, ifindex, &link); - if (r < 0 || !link) { - if (!m->enumerating) - log_warning("rtnl: received nexthop message for link (%"PRIu32") we do not know about, ignoring", ifindex); - return 0; + r = link_get(m, ifindex, &link); + if (r < 0 || !link) { + if (!m->enumerating) + log_warning("rtnl: received nexthop message for link (%"PRIu32") we do not know about, ignoring", ifindex); + return 0; + } } r = nexthop_new(&tmp); @@ -393,43 +714,78 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) return log_link_debug(link, "rtnl: received nexthop message with invalid family %d, ignoring.", tmp->family); + r = sd_rtnl_message_nexthop_get_protocol(message, &tmp->protocol); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: could not get nexthop protocol, ignoring: %m"); + return 0; + } + r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, tmp->family, &tmp->gw); if (r < 0 && r != -ENODATA) { log_link_warning_errno(link, r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m"); return 0; } + r = sd_netlink_message_has_flag(message, NHA_BLACKHOLE); + if (r < 0) { + log_link_warning_errno(link, r, "rtnl: could not get NHA_BLACKHOLE attribute, ignoring: %m"); + return 0; + } + tmp->blackhole = r; + r = sd_netlink_message_read_u32(message, NHA_ID, &tmp->id); - if (r < 0 && r != -ENODATA) { + if (r == -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received nexthop message without NHA_ID attribute, ignoring: %m"); + return 0; + } else if (r < 0) { log_link_warning_errno(link, r, "rtnl: could not get NHA_ID attribute, ignoring: %m"); return 0; + } else if (tmp->id == 0) { + log_link_warning(link, "rtnl: received nexthop message with invalid nexthop ID, ignoring: %m"); + return 0; } - (void) nexthop_get(link, tmp, &nexthop); + /* All blackhole nexthops are managed by Manager. Note that the linux kernel does not set + * NHA_OID attribute when NHA_BLACKHOLE is set. Just for safety. */ + if (tmp->blackhole) + link = NULL; - if (DEBUG_LOGGING) - (void) in_addr_to_string(tmp->family, &tmp->gw, &gateway); + r = nexthop_get(m, link, tmp, &nexthop); + if (r < 0) { + uint32_t id; + + /* The nexthop may be created without setting NHA_ID. */ + + id = tmp->id; + tmp->id = 0; + + (void) nexthop_get(m, link, tmp, &nexthop); + + tmp->id = id; + } switch (type) { case RTM_NEWNEXTHOP: if (nexthop) - log_link_debug(link, "Received remembered nexthop: %s, id: %d", strna(gateway), tmp->id); + log_nexthop_debug(nexthop, tmp->id, "Received remembered", link); else { - log_link_debug(link, "Remembering foreign nexthop: %s, id: %d", strna(gateway), tmp->id); - r = nexthop_add_foreign(link, tmp, &nexthop); + log_nexthop_debug(tmp, tmp->id, "Remembering foreign", link); + r = nexthop_add_foreign(m, link, tmp, &nexthop); if (r < 0) { log_link_warning_errno(link, r, "Could not remember foreign nexthop, ignoring: %m"); return 0; } } + + r = nexthop_update(m, link, nexthop, tmp); + if (r < 0) { + log_link_warning_errno(link, r, "Could not update nexthop, ignoring: %m"); + return 0; + } break; case RTM_DELNEXTHOP: - if (nexthop) { - log_link_debug(link, "Forgetting nexthop: %s, id: %d", strna(gateway), tmp->id); - nexthop_free(nexthop); - } else - log_link_debug(link, "Kernel removed a nexthop we don't remember: %s, id: %d, ignoring.", - strna(gateway), tmp->id); + log_nexthop_debug(tmp, tmp->id, nexthop ? "Forgetting" : "Kernel removed unknown", link); + nexthop_free(nexthop); break; default: @@ -443,8 +799,25 @@ static int nexthop_section_verify(NextHop *nh) { if (section_is_invalid(nh->section)) return -EINVAL; - if (in_addr_is_null(nh->family, &nh->gw) < 0) - return -EINVAL; + if (nh->family == AF_UNSPEC) + /* When no Gateway= is specified, assume IPv4. */ + nh->family = AF_INET; + + if (nh->blackhole && in_addr_is_set(nh->family, &nh->gw)) + return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: blackhole nexthop cannot have gateway address. " + "Ignoring [NextHop] section from line %u.", + nh->section->filename, nh->section->line); + + if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw) && + ordered_hashmap_isempty(nh->network->addresses_by_section)) { + /* If no address is configured, in most cases the gateway cannot be reachable. + * TODO: we may need to improve the condition above. */ + log_warning("%s: Gateway= without static address configured. " + "Enabling OnLink= option.", + nh->section->filename); + nh->onlink = true; + } return 0; } @@ -473,6 +846,7 @@ int config_parse_nexthop_id( _cleanup_(nexthop_free_or_set_invalidp) NextHop *n = NULL; Network *network = userdata; + uint32_t id; int r; assert(filename); @@ -485,13 +859,25 @@ int config_parse_nexthop_id( if (r < 0) return log_oom(); - r = safe_atou32(rvalue, &n->id); + if (isempty(rvalue)) { + n->id = 0; + TAKE_PTR(n); + return 0; + } + + r = safe_atou32(rvalue, &id); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse nexthop id \"%s\", ignoring assignment: %m", rvalue); return 0; } + if (id == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid nexthop id \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + n->id = id; TAKE_PTR(n); return 0; } @@ -522,6 +908,14 @@ int config_parse_nexthop_gateway( if (r < 0) return log_oom(); + if (isempty(rvalue)) { + n->family = AF_UNSPEC; + n->gw = IN_ADDR_NULL; + + TAKE_PTR(n); + return 0; + } + r = in_addr_from_string_auto(rvalue, &n->family, &n->gw); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, @@ -532,3 +926,153 @@ int config_parse_nexthop_gateway( TAKE_PTR(n); return 0; } + +int config_parse_nexthop_family( + 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_(nexthop_free_or_set_invalidp) NextHop *n = NULL; + Network *network = userdata; + AddressFamily a; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = nexthop_new_static(network, filename, section_line, &n); + if (r < 0) + return log_oom(); + + if (isempty(rvalue) && + !in_addr_is_set(n->family, &n->gw)) { + /* Accept an empty string only when Gateway= is null or not specified. */ + n->family = AF_UNSPEC; + TAKE_PTR(n); + return 0; + } + + a = nexthop_address_family_from_string(rvalue); + if (a < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue); + return 0; + } + + if (in_addr_is_set(n->family, &n->gw) && + ((a == ADDRESS_FAMILY_IPV4 && n->family == AF_INET6) || + (a == ADDRESS_FAMILY_IPV6 && n->family == AF_INET))) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Specified family '%s' conflicts with the family of the previously specified Gateway=, " + "ignoring assignment.", rvalue); + return 0; + } + + switch(a) { + case ADDRESS_FAMILY_IPV4: + n->family = AF_INET; + break; + case ADDRESS_FAMILY_IPV6: + n->family = AF_INET6; + break; + default: + assert_not_reached("Invalid family."); + } + + TAKE_PTR(n); + return 0; +} + +int config_parse_nexthop_onlink( + 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_(nexthop_free_or_set_invalidp) NextHop *n = NULL; + Network *network = userdata; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = nexthop_new_static(network, filename, section_line, &n); + if (r < 0) + return log_oom(); + + if (isempty(rvalue)) { + n->onlink = -1; + TAKE_PTR(n); + return 0; + } + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + n->onlink = r; + + TAKE_PTR(n); + return 0; +} + +int config_parse_nexthop_blackhole( + 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_(nexthop_free_or_set_invalidp) NextHop *n = NULL; + Network *network = userdata; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = nexthop_new_static(network, filename, section_line, &n); + if (r < 0) + return log_oom(); + + r = parse_boolean(rvalue); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + n->blackhole = r; + + TAKE_PTR(n); + return 0; +} diff --git a/src/network/networkd-nexthop.h b/src/network/networkd-nexthop.h index 75714e7ef..cf06b7e86 100644 --- a/src/network/networkd-nexthop.h +++ b/src/network/networkd-nexthop.h @@ -20,22 +20,31 @@ typedef struct NextHop { Network *network; NetworkConfigSection *section; + Manager *manager; Link *link; - unsigned char protocol; + uint8_t protocol; uint32_t id; + bool blackhole; int family; union in_addr_union gw; + int onlink; } NextHop; NextHop *nexthop_free(NextHop *nexthop); void network_drop_invalid_nexthops(Network *network); -int link_set_nexthop(Link *link); +int link_set_nexthops(Link *link); +int link_drop_nexthops(Link *link); +int link_drop_foreign_nexthops(Link *link); +int manager_get_nexthop_by_id(Manager *manager, uint32_t id, NextHop **ret); int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id); CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway); +CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_family); +CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_onlink); +CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_blackhole); diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index a8e1b2b48..8d8c21c0d 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -75,11 +75,7 @@ static int prefix_new_static(Network *network, const char *filename, unsigned se prefix->network = network; prefix->section = TAKE_PTR(n); - r = hashmap_ensure_allocated(&network->prefixes_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->prefixes_by_section, prefix->section, prefix); + r = hashmap_ensure_put(&network->prefixes_by_section, &network_config_hash_ops, prefix->section, prefix); if (r < 0) return r; @@ -147,11 +143,7 @@ static int route_prefix_new_static(Network *network, const char *filename, unsig prefix->network = network; prefix->section = TAKE_PTR(n); - r = hashmap_ensure_allocated(&network->route_prefixes_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->route_prefixes_by_section, prefix->section, prefix); + r = hashmap_ensure_put(&network->route_prefixes_by_section, &network_config_hash_ops, prefix->section, prefix); if (r < 0) return r; @@ -533,8 +525,8 @@ static int radv_set_dns(Link *link, Link *uplink) { p = dns; for (size_t i = 0; i < link->network->n_router_dns; i++) - if (IN6_IS_ADDR_UNSPECIFIED(&link->network->router_dns[i])) { - if (!IN6_IS_ADDR_UNSPECIFIED(&link->ipv6ll_address)) + if (in6_addr_is_null(&link->network->router_dns[i])) { + if (in6_addr_is_set(&link->ipv6ll_address)) *(p++) = link->ipv6ll_address; } else *(p++) = link->network->router_dns[i]; @@ -956,7 +948,7 @@ int config_parse_router_prefix_delegation( /* For backward compatibility */ val = radv_prefix_delegation_from_string(rvalue); if (val < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, val, "Invalid %s= setting, ignoring assignment: %s", lvalue, rvalue); return 0; } diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h index 4dfbefef9..73d2f2454 100644 --- a/src/network/networkd-radv.h +++ b/src/network/networkd-radv.h @@ -23,7 +23,7 @@ typedef enum RADVPrefixDelegation { RADV_PREFIX_DELEGATION_DHCP6 = 1 << 1, RADV_PREFIX_DELEGATION_BOTH = RADV_PREFIX_DELEGATION_STATIC | RADV_PREFIX_DELEGATION_DHCP6, _RADV_PREFIX_DELEGATION_MAX, - _RADV_PREFIX_DELEGATION_INVALID = -1, + _RADV_PREFIX_DELEGATION_INVALID = -EINVAL, } RADVPrefixDelegation; typedef struct Prefix { diff --git a/src/network/networkd-route.c b/src/network/networkd-route.c index 0ed89584e..a74541a6c 100644 --- a/src/network/networkd-route.c +++ b/src/network/networkd-route.c @@ -65,21 +65,8 @@ static const char * const route_scope_table[] = { [RT_SCOPE_NOWHERE] = "nowhere", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_scope, int); - -#define ROUTE_SCOPE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("nowhere") + 1) -static const char *format_route_scope(int scope, char *buf, size_t size) { - const char *s; - char *p = buf; - - s = route_scope_to_string(scope); - if (s) - strpcpy(&p, size, s); - else - strpcpyf(&p, size, "%d", scope); - - return buf; -} +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_scope, int); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_scope, int, UINT8_MAX); static const char * const route_table_table[] = { [RT_TABLE_DEFAULT] = "default", @@ -89,18 +76,66 @@ static const char * const route_table_table[] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP(route_table, int); -#define ROUTE_TABLE_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("default") + 1) -static const char *format_route_table(int table, char *buf, size_t size) { +int manager_get_route_table_from_string(const Manager *m, const char *s, uint32_t *ret) { + uint32_t t; + int r; + + assert(m); + assert(s); + assert(ret); + + r = route_table_from_string(s); + if (r >= 0) { + *ret = (uint32_t) r; + return 0; + } + + t = PTR_TO_UINT32(hashmap_get(m->route_table_numbers_by_name, s)); + if (t != 0) { + *ret = t; + return 0; + } + + r = safe_atou32(s, &t); + if (r < 0) + return r; + + if (t == 0) + return -ERANGE; + + *ret = t; + return 0; +} + +int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret) { + _cleanup_free_ char *str = NULL; const char *s; - char *p = buf; + + assert(m); + assert(ret); + + if (table == 0) + return -EINVAL; s = route_table_to_string(table); - if (s) - strpcpy(&p, size, s); - else - strpcpyf(&p, size, "%d", table); + if (!s) + s = hashmap_get(m->route_table_names_by_number, UINT32_TO_PTR(table)); - return buf; + if (s) { + /* Currently, this is only used in debugging logs. To not confuse any bug + * reports, let's include the table number. */ + if (asprintf(&str, "%s(%" PRIu32 ")", s, table) < 0) + return -ENOMEM; + + *ret = TAKE_PTR(str); + return 0; + } + + if (asprintf(&str, "%" PRIu32, table) < 0) + return -ENOMEM; + + *ret = TAKE_PTR(str); + return 0; } static const char * const route_protocol_table[] = { @@ -109,7 +144,7 @@ static const char * const route_protocol_table[] = { [RTPROT_STATIC] = "static", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(route_protocol, int); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_FALLBACK(route_protocol, int, UINT8_MAX); static const char * const route_protocol_full_table[] = { [RTPROT_REDIRECT] = "redirect", @@ -134,43 +169,23 @@ static const char * const route_protocol_full_table[] = { [RTPROT_EIGRP] = "eigrp", }; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(route_protocol_full, int); - -#define ROUTE_PROTOCOL_STR_MAX CONST_MAX(DECIMAL_STR_MAX(int), STRLEN("redirect") + 1) -static const char *format_route_protocol(int protocol, char *buf, size_t size) { - const char *s; - char *p = buf; - - s = route_protocol_full_to_string(protocol); - if (s) - strpcpy(&p, size, s); - else - strpcpyf(&p, size, "%d", protocol); - - return buf; -} +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING_FALLBACK(route_protocol_full, int, UINT8_MAX); static unsigned routes_max(void) { static thread_local unsigned cached = 0; - _cleanup_free_ char *s4 = NULL, *s6 = NULL; unsigned val4 = ROUTES_DEFAULT_MAX_PER_FAMILY, val6 = ROUTES_DEFAULT_MAX_PER_FAMILY; if (cached > 0) return cached; - if (sysctl_read("net/ipv4/route/max_size", &s4) >= 0) { - truncate_nl(s4); - if (safe_atou(s4, &val4) >= 0 && - val4 == 2147483647U) + if (sysctl_read_ip_property(AF_INET, NULL, "route/max_size", &s4) >= 0) + if (safe_atou(s4, &val4) >= 0 && val4 == 2147483647U) /* This is the default "no limit" value in the kernel */ val4 = ROUTES_DEFAULT_MAX_PER_FAMILY; - } - if (sysctl_read("net/ipv6/route/max_size", &s6) >= 0) { - truncate_nl(s6); + if (sysctl_read_ip_property(AF_INET6, NULL, "route/max_size", &s6) >= 0) (void) safe_atou(s6, &val6); - } cached = MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val4) + MAX(ROUTES_DEFAULT_MAX_PER_FAMILY, val6); @@ -233,11 +248,7 @@ static int route_new_static(Network *network, const char *filename, unsigned sec route->network = network; route->section = TAKE_PTR(n); - r = hashmap_ensure_allocated(&network->routes_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->routes_by_section, route->section, route); + r = hashmap_ensure_put(&network->routes_by_section, &network_config_hash_ops, route->section, route); if (r < 0) return r; @@ -316,6 +327,9 @@ void route_hash_func(const Route *route, struct siphash *state) { siphash24_compress(&route->initcwnd, sizeof(route->initcwnd), state); siphash24_compress(&route->initrwnd, sizeof(route->initrwnd), state); + siphash24_compress(&route->advmss, sizeof(route->advmss), state); + siphash24_compress(&route->nexthop_id, sizeof(route->nexthop_id), state); + break; default: /* treat any other address family as AF_UNSPEC */ @@ -399,6 +413,14 @@ int route_compare_func(const Route *a, const Route *b) { if (r != 0) return r; + r = CMP(a->advmss, b->advmss); + if (r != 0) + return r; + + r = CMP(a->nexthop_id, b->nexthop_id); + if (r != 0) + return r; + return 0; default: /* treat any other address family as AF_UNSPEC */ @@ -429,43 +451,29 @@ static int route_get(const Manager *manager, const Link *link, const Route *in, assert(manager || link); assert(in); - if (link) { - existing = set_get(link->routes, in); - if (existing) { - if (ret) - *ret = existing; - return 1; - } + existing = set_get(link ? link->routes : manager->routes, in); + if (existing) { + if (ret) + *ret = existing; + return 1; + } - existing = set_get(link->routes_foreign, in); - if (existing) { - if (ret) - *ret = existing; - return 0; - } - } else { - existing = set_get(manager->routes, in); - if (existing) { - if (ret) - *ret = existing; - return 1; - } - - existing = set_get(manager->routes_foreign, in); - if (existing) { - if (ret) - *ret = existing; - return 0; - } + existing = set_get(link ? link->routes_foreign : manager->routes_foreign, in); + if (existing) { + if (ret) + *ret = existing; + return 0; } return -ENOENT; } -static void route_copy(Route *dest, const Route *src, const MultipathRoute *m) { +static void route_copy(Route *dest, const Route *src, const MultipathRoute *m, const NextHop *nh) { assert(dest); assert(src); + /* This only copies entries used by the above hash and compare functions. */ + dest->family = src->family; dest->src = src->src; dest->src_prefixlen = src->src_prefixlen; @@ -474,15 +482,24 @@ static void route_copy(Route *dest, const Route *src, const MultipathRoute *m) { dest->prefsrc = src->prefsrc; dest->scope = src->scope; dest->protocol = src->protocol; - dest->type = src->type; + if (nh && nh->blackhole) + dest->type = RTN_BLACKHOLE; + else + dest->type = src->type; dest->tos = src->tos; dest->priority = src->priority; dest->table = src->table; dest->initcwnd = src->initcwnd; dest->initrwnd = src->initrwnd; dest->lifetime = src->lifetime; + dest->advmss = src->advmss; + dest->nexthop_id = src->nexthop_id; - if (m) { + if (nh) { + dest->gw_family = nh->family; + dest->gw = nh->gw; + dest->gw_weight = src->gw_weight; + } else if (m) { dest->gw_family = m->gateway.family; dest->gw = m->gateway.address; dest->gw_weight = m->weight; @@ -505,7 +522,7 @@ static int route_add_internal(Manager *manager, Link *link, Set **routes, const if (r < 0) return r; - route_copy(route, in, NULL); + route_copy(route, in, NULL, NULL); r = set_ensure_put(routes, &route_hash_ops, route); if (r < 0) @@ -529,22 +546,30 @@ static int route_add_foreign(Manager *manager, Link *link, const Route *in, Rout return route_add_internal(manager, link, link ? &link->routes_foreign : &manager->routes_foreign, in, ret); } -static int route_add(Manager *manager, Link *link, const Route *in, const MultipathRoute *m, Route **ret) { +static int route_add(Manager *manager, Link *link, const Route *in, const MultipathRoute *m, const NextHop *nh, Route **ret) { _cleanup_(route_freep) Route *tmp = NULL; + bool is_new = false; Route *route; int r; assert(manager || link); assert(in); - if (m) { + if (nh) { + r = route_new(&tmp); + if (r < 0) + return r; + + route_copy(tmp, in, NULL, nh); + in = tmp; + } else if (m) { assert(link && (m->ifindex == 0 || m->ifindex == link->ifindex)); r = route_new(&tmp); if (r < 0) return r; - route_copy(tmp, in, m); + route_copy(tmp, in, m, NULL); in = tmp; } @@ -554,21 +579,14 @@ static int route_add(Manager *manager, Link *link, const Route *in, const Multip r = route_add_internal(manager, link, link ? &link->routes : &manager->routes, in, &route); if (r < 0) return r; + is_new = true; } else if (r == 0) { /* Take over a foreign route */ - if (link) { - r = set_ensure_put(&link->routes, &route_hash_ops, route); - if (r < 0) - return r; + r = set_ensure_put(link ? &link->routes : &manager->routes, &route_hash_ops, route); + if (r < 0) + return r; - set_remove(link->routes_foreign, route); - } else { - r = set_ensure_put(&manager->routes, &route_hash_ops, route); - if (r < 0) - return r; - - set_remove(manager->routes_foreign, route); - } + set_remove(link ? link->routes_foreign : manager->routes_foreign, route); } else if (r == 1) { /* Route exists, do nothing */ ; @@ -577,8 +595,45 @@ static int route_add(Manager *manager, Link *link, const Route *in, const Multip if (ret) *ret = route; + return is_new; +} - return 0; +static bool route_type_is_reject(const Route *route) { + assert(route); + + return IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW); +} + +static void log_route_debug(const Route *route, const char *str, const Link *link, const Manager *m) { + assert(route); + assert(str); + assert(m); + + /* link may be NULL. */ + + if (DEBUG_LOGGING) { + _cleanup_free_ char *dst = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL, + *table = NULL, *scope = NULL, *proto = NULL; + + if (in_addr_is_set(route->family, &route->dst)) + (void) in_addr_prefix_to_string(route->family, &route->dst, route->dst_prefixlen, &dst); + if (in_addr_is_set(route->family, &route->src)) + (void) in_addr_to_string(route->family, &route->src, &src); + if (in_addr_is_set(route->gw_family, &route->gw)) + (void) in_addr_to_string(route->gw_family, &route->gw, &gw); + if (in_addr_is_set(route->family, &route->prefsrc)) + (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); + (void) route_scope_to_string_alloc(route->scope, &scope); + (void) manager_get_route_table_to_string(m, route->table, &table); + (void) route_protocol_full_to_string_alloc(route->protocol, &proto); + + log_link_debug(link, + "%s route: dst: %s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s, nexthop: %"PRIu32, + str, strna(dst), strna(src), strna(gw), strna(prefsrc), + strna(scope), strna(table), strna(proto), + strna(route_type_to_string(route->type)), + route->nexthop_id); + } } static int route_set_netlink_message(const Route *route, sd_netlink_message *req, Link *link) { @@ -590,7 +645,7 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req /* link may be NULL */ - if (in_addr_is_null(route->gw_family, &route->gw) == 0) { + if (in_addr_is_set(route->gw_family, &route->gw)) { if (route->gw_family == route->family) { r = netlink_message_append_in_addr_union(req, RTA_GATEWAY, route->gw_family, &route->gw); if (r < 0) @@ -627,7 +682,7 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req return log_link_error_errno(link, r, "Could not set source prefix length: %m"); } - if (in_addr_is_null(route->family, &route->prefsrc) == 0) { + if (in_addr_is_set(route->family, &route->prefsrc)) { r = netlink_message_append_in_addr_union(req, RTA_PREFSRC, route->family, &route->prefsrc); if (r < 0) return log_link_error_errno(link, r, "Could not append RTA_PREFSRC attribute: %m"); @@ -666,7 +721,7 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req if (r < 0) return log_link_error_errno(link, r, "Could not set route type: %m"); - if (!IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) { + if (!route_type_is_reject(route) && route->nexthop_id == 0) { assert(link); /* Those routes must be attached to a specific link */ r = sd_netlink_message_append_u32(req, RTA_OIF, link->ifindex); @@ -674,6 +729,12 @@ static int route_set_netlink_message(const Route *route, sd_netlink_message *req return log_link_error_errno(link, r, "Could not append RTA_OIF attribute: %m"); } + if (route->nexthop_id > 0) { + r = sd_netlink_message_append_u32(req, RTA_NH_ID, route->nexthop_id); + if (r < 0) + return log_link_error_errno(link, r, "Could not append RTA_NH_ID attribute: %m"); + } + r = sd_netlink_message_append_u8(req, RTA_PREF, route->pref); if (r < 0) return log_link_error_errno(link, r, "Could not append RTA_PREF attribute: %m"); @@ -717,35 +778,14 @@ int route_remove( manager = link->manager; /* link may be NULL! */ + log_route_debug(route, "Removing", link, manager); + r = sd_rtnl_message_new_route(manager->rtnl, &req, RTM_DELROUTE, route->family, route->protocol); if (r < 0) return log_link_error_errno(link, r, "Could not create RTM_DELROUTE message: %m"); - if (DEBUG_LOGGING) { - _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL; - char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX]; - - if (!in_addr_is_null(route->family, &route->dst)) { - (void) in_addr_to_string(route->family, &route->dst, &dst); - (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen); - } - if (!in_addr_is_null(route->family, &route->src)) - (void) in_addr_to_string(route->family, &route->src, &src); - if (!in_addr_is_null(route->gw_family, &route->gw)) - (void) in_addr_to_string(route->gw_family, &route->gw, &gw); - if (!in_addr_is_null(route->family, &route->prefsrc)) - (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); - - log_link_debug(link, "Removing route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s", - strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc), - format_route_scope(route->scope, scope, sizeof(scope)), - format_route_table(route->table, table, sizeof(table)), - format_route_protocol(route->protocol, protocol, sizeof(protocol)), - strna(route_type_to_string(route->type))); - } - r = route_set_netlink_message(route, req, link); if (r < 0) return r; @@ -777,7 +817,7 @@ static bool link_has_route(const Link *link, const Route *route) { return false; } -static bool links_have_route(Manager *manager, const Route *route, const Link *except) { +static bool links_have_route(const Manager *manager, const Route *route, const Link *except) { Link *link; assert(manager); @@ -793,22 +833,24 @@ static bool links_have_route(Manager *manager, const Route *route, const Link *e return false; } -static int manager_drop_foreign_routes(Manager *manager) { +static int manager_drop_routes_internal(Manager *manager, bool foreign, const Link *except) { Route *route; int k, r = 0; + Set *routes; assert(manager); - SET_FOREACH(route, manager->routes_foreign) { - /* do not touch routes managed by the kernel */ + routes = foreign ? manager->routes_foreign : manager->routes; + SET_FOREACH(route, routes) { + /* Do not touch routes managed by the kernel. */ if (route->protocol == RTPROT_KERNEL) continue; - if (links_have_route(manager, route, NULL)) - /* The route will be configured later. */ + /* The route will be configured later, or already configured by a link. */ + if (links_have_route(manager, route, except)) continue; - /* The existing links do not have the route. Let's drop this now. It may by + /* The existing links do not have the route. Let's drop this now. It may be * re-configured later. */ k = route_remove(route, manager, NULL, NULL); if (k < 0 && r >= 0) @@ -818,29 +860,12 @@ static int manager_drop_foreign_routes(Manager *manager) { return r; } -static int manager_drop_routes(Manager *manager, Link *except) { - Route *route; - int k, r = 0; +static int manager_drop_foreign_routes(Manager *manager) { + return manager_drop_routes_internal(manager, true, NULL); +} - assert(manager); - - SET_FOREACH(route, manager->routes) { - /* do not touch routes managed by the kernel */ - if (route->protocol == RTPROT_KERNEL) - continue; - - if (links_have_route(manager, route, except)) - /* The route will be configured later. */ - continue; - - /* The existing links do not have the route. Let's drop this now. It may by - * re-configured later. */ - k = route_remove(route, manager, NULL, NULL); - if (k < 0 && r >= 0) - r = k; - } - - return r; +static int manager_drop_routes(Manager *manager, const Link *except) { + return manager_drop_routes_internal(manager, false, except); } int link_drop_foreign_routes(Link *link) { @@ -873,7 +898,7 @@ int link_drop_foreign_routes(Link *link) { continue; if (link_has_route(link, route)) - k = route_add(NULL, link, route, NULL, NULL); + k = route_add(NULL, link, route, NULL, NULL, NULL); else k = route_remove(route, NULL, link, NULL); if (k < 0 && r >= 0) @@ -927,16 +952,20 @@ static int route_expire_handler(sd_event_source *s, uint64_t usec, void *userdat static int route_add_and_setup_timer(Link *link, const Route *route, const MultipathRoute *m, Route **ret) { _cleanup_(sd_event_source_unrefp) sd_event_source *expire = NULL; + NextHop *nh = NULL; Route *nr; - int r; + int r, k; assert(link); + assert(link->manager); assert(route); - if (IN_SET(route->type, RTN_UNREACHABLE, RTN_PROHIBIT, RTN_BLACKHOLE, RTN_THROW)) - r = route_add(link->manager, NULL, route, NULL, &nr); + (void) manager_get_nexthop_by_id(link->manager, route->nexthop_id, &nh); + + if (route_type_is_reject(route) || (nh && nh->blackhole)) + k = route_add(link->manager, NULL, route, NULL, nh, &nr); else if (!m || m->ifindex == 0 || m->ifindex == link->ifindex) - r = route_add(NULL, link, route, m, &nr); + k = route_add(NULL, link, route, m, nh, &nr); else { Link *link_gw; @@ -944,10 +973,10 @@ static int route_add_and_setup_timer(Link *link, const Route *route, const Multi if (r < 0) return log_link_error_errno(link, r, "Failed to get link with ifindex %d: %m", m->ifindex); - r = route_add(NULL, link_gw, route, m, &nr); + k = route_add(NULL, link_gw, route, m, NULL, &nr); } - if (r < 0) - return log_link_error_errno(link, r, "Could not add route: %m"); + if (k < 0) + return log_link_error_errno(link, k, "Could not add route: %m"); /* TODO: drop expiration handling once it can be pushed into the kernel */ if (nr->lifetime != USEC_INFINITY && !kernel_route_expiration_supported()) { @@ -963,7 +992,7 @@ static int route_add_and_setup_timer(Link *link, const Route *route, const Multi if (ret) *ret = nr; - return 0; + return k; } static int append_nexthop_one(const Route *route, const MultipathRoute *m, struct rtattr **rta, size_t offset) { @@ -1054,7 +1083,8 @@ int route_configure( Route **ret) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; - int r; + int r, k = 0; + Route *nr; assert(link); assert(link->manager); @@ -1068,28 +1098,7 @@ int route_configure( return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG), "Too many routes are configured, refusing: %m"); - if (DEBUG_LOGGING) { - _cleanup_free_ char *dst = NULL, *dst_prefixlen = NULL, *src = NULL, *gw = NULL, *prefsrc = NULL; - char scope[ROUTE_SCOPE_STR_MAX], table[ROUTE_TABLE_STR_MAX], protocol[ROUTE_PROTOCOL_STR_MAX]; - - if (!in_addr_is_null(route->family, &route->dst)) { - (void) in_addr_to_string(route->family, &route->dst, &dst); - (void) asprintf(&dst_prefixlen, "/%u", route->dst_prefixlen); - } - if (!in_addr_is_null(route->family, &route->src)) - (void) in_addr_to_string(route->family, &route->src, &src); - if (!in_addr_is_null(route->gw_family, &route->gw)) - (void) in_addr_to_string(route->gw_family, &route->gw, &gw); - if (!in_addr_is_null(route->family, &route->prefsrc)) - (void) in_addr_to_string(route->family, &route->prefsrc, &prefsrc); - - log_link_debug(link, "Configuring route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s", - strna(dst), strempty(dst_prefixlen), strna(src), strna(gw), strna(prefsrc), - format_route_scope(route->scope, scope, sizeof(scope)), - format_route_table(route->table, table, sizeof(table)), - format_route_protocol(route->protocol, protocol, sizeof(protocol)), - strna(route_type_to_string(route->type))); - } + log_route_debug(route, "Configuring", link, link->manager); r = sd_rtnl_message_new_route(link->manager->rtnl, &req, RTM_NEWROUTE, route->family, @@ -1148,6 +1157,12 @@ int route_configure( return log_link_error_errno(link, r, "Could not append RTAX_FASTOPEN_NO_COOKIE attribute: %m"); } + if (route->advmss > 0) { + r = sd_netlink_message_append_u32(req, RTAX_ADVMSS, route->advmss); + if (r < 0) + return log_link_error_errno(link, r, "Could not append RTAX_ADVMSS attribute: %m"); + } + r = sd_netlink_message_close_container(req); if (r < 0) return log_link_error_errno(link, r, "Could not append RTA_METRICS attribute: %m"); @@ -1157,14 +1172,9 @@ int route_configure( return log_link_error_errno(link, r, "Could not append RTA_MULTIPATH attribute: %m"); if (ordered_set_isempty(route->multipath_routes)) { - Route *nr; - - r = route_add_and_setup_timer(link, route, NULL, &nr); - if (r < 0) - return r; - - if (ret) - *ret = nr; + k = route_add_and_setup_timer(link, route, NULL, &nr); + if (k < 0) + return k; } else { MultipathRoute *m; @@ -1174,6 +1184,8 @@ int route_configure( r = route_add_and_setup_timer(link, route, m, NULL); if (r < 0) return r; + if (r > 0) + k = 1; } } @@ -1184,10 +1196,13 @@ int route_configure( link_ref(link); - return 0; + if (ret) + *ret = nr; + + return k; } -static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int route_handler_with_gateway(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { int r; assert(link); @@ -1200,29 +1215,118 @@ static int route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { r = sd_netlink_message_get_errno(m); if (r < 0 && r != -EEXIST) { - log_link_message_warning_errno(link, m, r, "Could not set route"); + log_link_message_warning_errno(link, m, r, "Could not set route with gateway"); link_enter_failed(link); return 1; } if (link->route_messages == 0) { - log_link_debug(link, "Routes set"); + log_link_debug(link, "Routes with gateway set"); link->static_routes_configured = true; - link_set_nexthop(link); + link_check_ready(link); } return 1; } -int link_set_routes(Link *link) { - enum { - PHASE_NON_GATEWAY, /* First phase: Routes without a gateway */ - PHASE_GATEWAY, /* Second phase: Routes with a gateway */ - _PHASE_MAX - } phase; +static int route_handler_without_gateway(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { + int r; + + assert(link); + assert(link->route_messages > 0); + + link->route_messages--; + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return 1; + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_link_message_warning_errno(link, m, r, "Could not set route without gateway"); + link_enter_failed(link); + return 1; + } + + if (link->route_messages == 0) { + log_link_debug(link, "Routes set without gateway"); + /* Now, we can talk to gateways, let's configure nexthops. */ + r = link_set_nexthops(link); + if (r < 0) + link_enter_failed(link); + } + + return 1; +} + +static bool route_has_gateway(const Route *route) { + assert(route); + + if (in_addr_is_set(route->gw_family, &route->gw)) + return true; + + if (!ordered_set_isempty(route->multipath_routes)) + return true; + + if (route->nexthop_id > 0) + return true; + + return false; +} + +static int link_set_routes_internal(Link *link, bool with_gateway) { Route *rt; int r; + assert(link); + assert(link->network); + + HASHMAP_FOREACH(rt, link->network->routes_by_section) { + if (rt->gateway_from_dhcp_or_ra) + continue; + + if (route_has_gateway(rt) != with_gateway) + continue; + + r = route_configure(rt, link, with_gateway ? route_handler_with_gateway : route_handler_without_gateway, NULL); + if (r < 0) + return log_link_warning_errno(link, r, "Could not set routes: %m"); + + link->route_messages++; + } + + return 0; +} + +int link_set_routes_with_gateway(Link *link) { + int r; + + assert(link); + assert(link->network); + + if (!link_has_carrier(link) && !link->network->configure_without_carrier) + /* During configuring addresses, the link lost its carrier. As networkd is dropping + * the addresses now, let's not configure the routes either. */ + return 0; + + /* Finally, add routes that needs a gateway. */ + r = link_set_routes_internal(link, true); + if (r < 0) + return r; + + if (link->route_messages == 0) { + link->static_routes_configured = true; + link_check_ready(link); + } else { + log_link_debug(link, "Setting routes with gateway"); + link_set_state(link, LINK_STATE_CONFIGURING); + } + + return 0; +} + +int link_set_routes(Link *link) { + int r; + assert(link); assert(link->network); assert(link->state != _LINK_STATE_INVALID); @@ -1237,33 +1341,26 @@ int link_set_routes(Link *link) { * the addresses now, let's not configure the routes either. */ return 0; + if (link->route_messages != 0) { + log_link_debug(link, "Static routes are configuring."); + return 0; + } + r = link_set_routing_policy_rules(link); if (r < 0) return r; - /* First add the routes that enable us to talk to gateways, then add in the others that need a gateway. */ - for (phase = 0; phase < _PHASE_MAX; phase++) - HASHMAP_FOREACH(rt, link->network->routes_by_section) { - if (rt->gateway_from_dhcp_or_ra) - continue; + /* First, add the routes that enable us to talk to gateways. */ + r = link_set_routes_internal(link, false); + if (r < 0) + return r; - if ((in_addr_is_null(rt->gw_family, &rt->gw) && ordered_set_isempty(rt->multipath_routes)) != (phase == PHASE_NON_GATEWAY)) - continue; + if (link->route_messages == 0) + /* If no route is configured, then configure nexthops. */ + return link_set_nexthops(link); - r = route_configure(rt, link, route_handler, NULL); - if (r < 0) - return log_link_warning_errno(link, r, "Could not set routes: %m"); - - link->route_messages++; - } - - if (link->route_messages == 0) { - link->static_routes_configured = true; - link_set_nexthop(link); - } else { - log_link_debug(link, "Setting routes"); - link_set_state(link, LINK_STATE_CONFIGURING); - } + log_link_debug(link, "Setting routes without gateway"); + link_set_state(link, LINK_STATE_CONFIGURING); return 0; } @@ -1271,13 +1368,30 @@ int link_set_routes(Link *link) { static int process_route_one(Manager *manager, Link *link, uint16_t type, const Route *tmp, const MultipathRoute *m) { _cleanup_(route_freep) Route *nr = NULL; Route *route = NULL; + NextHop *nh = NULL; int r; assert(manager); assert(tmp); assert(IN_SET(type, RTM_NEWROUTE, RTM_DELROUTE)); - if (m) { + (void) manager_get_nexthop_by_id(manager, tmp->nexthop_id, &nh); + + if (nh) { + if (link && link != nh->link) + return log_link_warning_errno(link, SYNTHETIC_ERRNO(EINVAL), + "rtnl: received RTA_OIF and ifindex of nexthop corresponding to RTA_NH_ID do not match, ignoring."); + + link = nh->link; + + r = route_new(&nr); + if (r < 0) + return log_oom(); + + route_copy(nr, tmp, NULL, nh); + + tmp = nr; + } else if (m) { if (link) return log_link_warning_errno(link, SYNTHETIC_ERRNO(EINVAL), "rtnl: received route contains both RTA_OIF and RTA_MULTIPATH, ignoring."); @@ -1296,57 +1410,37 @@ static int process_route_one(Manager *manager, Link *link, uint16_t type, const if (r < 0) return log_oom(); - route_copy(nr, tmp, m); + route_copy(nr, tmp, m, NULL); tmp = nr; } (void) route_get(manager, link, tmp, &route); - if (DEBUG_LOGGING) { - _cleanup_free_ char *buf_dst = NULL, *buf_dst_prefixlen = NULL, - *buf_src = NULL, *buf_gw = NULL, *buf_prefsrc = NULL; - char buf_scope[ROUTE_SCOPE_STR_MAX], buf_table[ROUTE_TABLE_STR_MAX], - buf_protocol[ROUTE_PROTOCOL_STR_MAX]; - - if (!in_addr_is_null(tmp->family, &tmp->dst)) { - (void) in_addr_to_string(tmp->family, &tmp->dst, &buf_dst); - (void) asprintf(&buf_dst_prefixlen, "/%u", tmp->dst_prefixlen); - } - if (!in_addr_is_null(tmp->family, &tmp->src)) - (void) in_addr_to_string(tmp->family, &tmp->src, &buf_src); - if (!in_addr_is_null(tmp->gw_family, &tmp->gw)) - (void) in_addr_to_string(tmp->gw_family, &tmp->gw, &buf_gw); - if (!in_addr_is_null(tmp->family, &tmp->prefsrc)) - (void) in_addr_to_string(tmp->family, &tmp->prefsrc, &buf_prefsrc); - - log_link_debug(link, - "%s route: dst: %s%s, src: %s, gw: %s, prefsrc: %s, scope: %s, table: %s, proto: %s, type: %s", - (!route && !manager->manage_foreign_routes) ? "Ignoring received foreign" : - type == RTM_DELROUTE ? "Forgetting" : - route ? "Received remembered" : "Remembering", - strna(buf_dst), strempty(buf_dst_prefixlen), - strna(buf_src), strna(buf_gw), strna(buf_prefsrc), - format_route_scope(tmp->scope, buf_scope, sizeof buf_scope), - format_route_table(tmp->table, buf_table, sizeof buf_table), - format_route_protocol(tmp->protocol, buf_protocol, sizeof buf_protocol), - strna(route_type_to_string(tmp->type))); - } - switch (type) { case RTM_NEWROUTE: - if (!route && manager->manage_foreign_routes) { - /* A route appeared that we did not request */ - r = route_add_foreign(manager, link, tmp, NULL); - if (r < 0) { - log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m"); - return 0; + if (!route) { + if (!manager->manage_foreign_routes) + log_route_debug(tmp, "Ignoring received foreign", link, manager); + else { + /* A route appeared that we did not request */ + log_route_debug(tmp, "Remembering foreign", link, manager); + r = route_add_foreign(manager, link, tmp, NULL); + if (r < 0) { + log_link_warning_errno(link, r, "Failed to remember foreign route, ignoring: %m"); + return 0; + } } - } + } else + log_route_debug(tmp, "Received remembered", link, manager); break; case RTM_DELROUTE: + log_route_debug(tmp, + route ? "Forgetting" : + manager->manage_foreign_routes ? "Kernel removed unknown" : "Ignoring received foreign", + link, manager); route_free(route); break; @@ -1365,7 +1459,6 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma uint32_t ifindex; uint16_t type; unsigned char table; - RouteVia via; size_t rta_len; int r; @@ -1429,20 +1522,20 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma return 0; } - switch (tmp->family) { - case AF_INET: - r = sd_netlink_message_read_in_addr(message, RTA_DST, &tmp->dst.in); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m"); - return 0; - } + r = netlink_message_read_in_addr_union(message, RTA_DST, tmp->family, &tmp->dst); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m"); + return 0; + } - r = sd_netlink_message_read_in_addr(message, RTA_GATEWAY, &tmp->gw.in); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m"); - return 0; - } else if (r >= 0) - tmp->gw_family = AF_INET; + r = netlink_message_read_in_addr_union(message, RTA_GATEWAY, tmp->family, &tmp->gw); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m"); + return 0; + } else if (r >= 0) + tmp->gw_family = tmp->family; + else if (tmp->family == AF_INET) { + RouteVia via; r = sd_netlink_message_read(message, RTA_VIA, sizeof(via), &via); if (r < 0 && r != -ENODATA) { @@ -1452,51 +1545,17 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma tmp->gw_family = via.family; tmp->gw = via.address; } + } - r = sd_netlink_message_read_in_addr(message, RTA_SRC, &tmp->src.in); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m"); - return 0; - } + r = netlink_message_read_in_addr_union(message, RTA_SRC, tmp->family, &tmp->src); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m"); + return 0; + } - r = sd_netlink_message_read_in_addr(message, RTA_PREFSRC, &tmp->prefsrc.in); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m"); - return 0; - } - - break; - - case AF_INET6: - r = sd_netlink_message_read_in6_addr(message, RTA_DST, &tmp->dst.in6); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid destination, ignoring: %m"); - return 0; - } - - r = sd_netlink_message_read_in6_addr(message, RTA_GATEWAY, &tmp->gw.in6); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid gateway, ignoring: %m"); - return 0; - } else if (r >= 0) - tmp->gw_family = AF_INET6; - - r = sd_netlink_message_read_in6_addr(message, RTA_SRC, &tmp->src.in6); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid source, ignoring: %m"); - return 0; - } - - r = sd_netlink_message_read_in6_addr(message, RTA_PREFSRC, &tmp->prefsrc.in6); - if (r < 0 && r != -ENODATA) { - log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m"); - return 0; - } - - break; - - default: - assert_not_reached("Received route message with unsupported address family"); + r = netlink_message_read_in_addr_union(message, RTA_PREFSRC, tmp->family, &tmp->prefsrc); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route message without valid preferred source, ignoring: %m"); return 0; } @@ -1543,6 +1602,12 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma return 0; } + r = sd_netlink_message_read_u32(message, RTA_NH_ID, &tmp->nexthop_id); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route message with invalid nexthop id, ignoring: %m"); + return 0; + } + r = sd_netlink_message_enter_container(message, RTA_METRICS); if (r < 0 && r != -ENODATA) { log_link_error_errno(link, r, "rtnl: Could not enter RTA_METRICS container: %m"); @@ -1561,6 +1626,12 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma return 0; } + r = sd_netlink_message_read_u32(message, RTAX_ADVMSS, &tmp->advmss); + if (r < 0 && r != -ENODATA) { + log_link_warning_errno(link, r, "rtnl: received route message with invalid advmss, ignoring: %m"); + return 0; + } + r = sd_netlink_message_exit_container(message); if (r < 0) { log_link_error_errno(link, r, "rtnl: Could not exit from RTA_METRICS container: %m"); @@ -1580,6 +1651,12 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma } } + /* IPv6 routes with reject type are always assigned to the loopback interface. See kernel's + * fib6_nh_init() in net/ipv6/route.c. However, we'd like to manage them by Manager. Hence, set + * link to NULL here. */ + if (route_type_is_reject(tmp)) + link = NULL; + if (ordered_set_isempty(multipath_routes)) (void) process_route_one(m, link, type, tmp, NULL); else { @@ -1595,84 +1672,6 @@ int manager_rtnl_process_route(sd_netlink *rtnl, sd_netlink_message *message, Ma return 1; } -int link_serialize_routes(const Link *link, FILE *f) { - bool space = false; - Route *route; - - assert(link); - assert(link->network); - assert(f); - - fputs("ROUTES=", f); - SET_FOREACH(route, link->routes) { - _cleanup_free_ char *route_str = NULL; - - if (in_addr_to_string(route->family, &route->dst, &route_str) < 0) - continue; - - fprintf(f, "%s%s/%hhu/%hhu/%"PRIu32"/%"PRIu32"/"USEC_FMT, - space ? " " : "", route_str, - route->dst_prefixlen, route->tos, route->priority, route->table, route->lifetime); - space = true; - } - fputc('\n', f); - - return 0; -} - -int link_deserialize_routes(Link *link, const char *routes) { - int r; - - assert(link); - - for (const char *p = routes;; ) { - _cleanup_(route_freep) Route *tmp = NULL; - _cleanup_free_ char *route_str = NULL; - char *prefixlen_str; - - r = extract_first_word(&p, &route_str, NULL, 0); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to parse ROUTES=: %m"); - if (r == 0) - return 0; - - prefixlen_str = strchr(route_str, '/'); - if (!prefixlen_str) { - log_link_debug(link, "Failed to parse route, ignoring: %s", route_str); - continue; - } - *prefixlen_str++ = '\0'; - - r = route_new(&tmp); - if (r < 0) - return log_oom(); - - r = sscanf(prefixlen_str, - "%hhu/%hhu/%"SCNu32"/%"PRIu32"/"USEC_FMT, - &tmp->dst_prefixlen, - &tmp->tos, - &tmp->priority, - &tmp->table, - &tmp->lifetime); - if (r != 5) { - log_link_debug(link, - "Failed to parse destination prefix length, tos, priority, table or expiration: %s", - prefixlen_str); - continue; - } - - r = in_addr_from_string_auto(route_str, &tmp->family, &tmp->dst); - if (r < 0) { - log_link_debug_errno(link, r, "Failed to parse route destination %s: %m", route_str); - continue; - } - - r = route_add_and_setup_timer(link, tmp, NULL, NULL); - if (r < 0) - return log_link_debug_errno(link, r, "Failed to add route: %m"); - } -} - int network_add_ipv4ll_route(Network *network) { _cleanup_(route_free_or_set_invalidp) Route *n = NULL; unsigned section_line; @@ -1992,7 +1991,7 @@ int config_parse_route_scope( r = route_scope_from_string(rvalue); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown route scope: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Unknown route scope: %s", rvalue); return 0; } @@ -2002,6 +2001,59 @@ int config_parse_route_scope( return 0; } +int config_parse_route_nexthop( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + Network *network = userdata; + _cleanup_(route_free_or_set_invalidp) Route *n = NULL; + uint32_t id; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &n); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (isempty(rvalue)) { + n->nexthop_id = 0; + TAKE_PTR(n); + return 0; + } + + r = safe_atou32(rvalue, &id); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse nexthop ID, ignoring assignment: %s", rvalue); + return 0; + } + if (id == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid nexthop ID, ignoring assignment: %s", rvalue); + return 0; + } + + n->nexthop_id = id; + TAKE_PTR(n); + return 0; +} + int config_parse_route_table( const char *unit, const char *filename, @@ -2033,16 +2085,11 @@ int config_parse_route_table( return 0; } - r = route_table_from_string(rvalue); - if (r >= 0) - n->table = r; - else { - r = safe_atou32(rvalue, &n->table); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue); - return 0; - } + r = manager_get_route_table_from_string(network->manager, rvalue, &n->table); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse route table number \"%s\", ignoring assignment: %m", rvalue); + return 0; } n->table_set = true; @@ -2170,17 +2217,14 @@ int config_parse_route_protocol( } r = route_protocol_from_string(rvalue); - if (r >= 0) - n->protocol = r; - else { - r = safe_atou8(rvalue , &n->protocol); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Could not parse route protocol \"%s\", ignoring assignment: %m", rvalue); - return 0; - } + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse route protocol \"%s\", ignoring assignment: %m", rvalue); + return 0; } + n->protocol = r; + TAKE_PTR(n); return 0; } @@ -2212,7 +2256,7 @@ int config_parse_route_type( t = route_type_from_string(rvalue); if (t < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, r, "Could not parse route type \"%s\", ignoring assignment: %m", rvalue); return 0; } @@ -2223,6 +2267,63 @@ int config_parse_route_type( return 0; } +int config_parse_tcp_advmss( + 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_(route_free_or_set_invalidp) Route *n = NULL; + Network *network = userdata; + uint64_t u; + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = route_new_static(network, filename, section_line, &n); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to allocate route, ignoring assignment: %m"); + return 0; + } + + if (isempty(rvalue)) { + n->advmss = 0; + TAKE_PTR(n); + return 0; + } + + r = parse_size(rvalue, 1024, &u); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + + if (u == 0 || u > UINT32_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid TCPAdvertisedMaximumSegmentSize= \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + + n->advmss = u; + + TAKE_PTR(n); + return 0; +} + int config_parse_tcp_window( const char *unit, const char *filename, @@ -2266,6 +2367,11 @@ int config_parse_tcp_window( "Specified TCP %s \"%s\" is too large, ignoring assignment: %m", lvalue, rvalue); return 0; } + if (k == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid TCP %s \"%s\", ignoring assignment: %m", lvalue, rvalue); + return 0; + } if (streq(lvalue, "InitialCongestionWindow")) n->initcwnd = k; @@ -2414,11 +2520,9 @@ int config_parse_multipath_route( } } - r = ordered_set_ensure_allocated(&n->multipath_routes, NULL); - if (r < 0) + r = ordered_set_ensure_put(&n->multipath_routes, NULL, m); + if (r == -ENOMEM) return log_oom(); - - r = ordered_set_put(n->multipath_routes, m); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to store multipath route, ignoring assignment: %m"); @@ -2430,6 +2534,112 @@ int config_parse_multipath_route( return 0; } +int config_parse_route_table_names( + 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) { + + Manager *m = userdata; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(userdata); + + if (isempty(rvalue)) { + m->route_table_names_by_number = hashmap_free(m->route_table_names_by_number); + m->route_table_numbers_by_name = hashmap_free(m->route_table_numbers_by_name); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *name = NULL; + uint32_t table; + char *num; + + r = extract_first_word(&p, &name, NULL, 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid RouteTable=, ignoring assignment: %s", rvalue); + return 0; + } + if (r == 0) + return 0; + + num = strchr(name, ':'); + if (!num) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid route table name and number pair, ignoring assignment: %s", name); + continue; + } + + *num++ = '\0'; + + if (STR_IN_SET(name, "default", "main", "local")) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Route table name %s already predefined. Ignoring assignment: %s:%s", name, name, num); + continue; + } + + r = safe_atou32(num, &table); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse route table number '%s', ignoring assignment: %s:%s", num, name, num); + continue; + } + if (table == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid route table number, ignoring assignment: %s:%s", name, num); + continue; + } + + r = hashmap_ensure_put(&m->route_table_numbers_by_name, &string_hash_ops_free, name, UINT32_TO_PTR(table)); + if (r == -ENOMEM) + return log_oom(); + if (r == -EEXIST) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name, num); + continue; + } + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to store route table name and number pair, ignoring assignment: %s:%s", name, num); + continue; + } + if (r == 0) + /* The entry is duplicated. It should not be added to route_table_names_by_number hashmap. */ + continue; + + r = hashmap_ensure_put(&m->route_table_names_by_number, NULL, UINT32_TO_PTR(table), name); + if (r < 0) { + hashmap_remove(m->route_table_numbers_by_name, name); + + if (r == -ENOMEM) + return log_oom(); + if (r == -EEXIST) + log_syntax(unit, LOG_WARNING, filename, line, r, + "Specified route table name and number pair conflicts with others, ignoring assignment: %s:%s", name, num); + else + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to store route table name and number pair, ignoring assignment: %s:%s", name, num); + continue; + } + assert(r > 0); + + TAKE_PTR(name); + } +} + static int route_section_verify(Route *route, Network *network) { if (section_is_invalid(route->section)) return -EINVAL; @@ -2514,15 +2724,35 @@ static int route_section_verify(Route *route, Network *network) { if (route->family == AF_INET6 && route->priority == 0) route->priority = IP6_RT_PRIO_USER; - if (ordered_hashmap_isempty(network->addresses_by_section) && - in_addr_is_null(route->gw_family, &route->gw) == 0 && - route->gateway_onlink < 0) { + if (route->gateway_onlink < 0 && in_addr_is_set(route->gw_family, &route->gw) && + ordered_hashmap_isempty(network->addresses_by_section)) { + /* If no address is configured, in most cases the gateway cannot be reachable. + * TODO: we may need to improve the condition above. */ log_warning("%s: Gateway= without static address configured. " "Enabling GatewayOnLink= option.", network->filename); route->gateway_onlink = true; } + if (route->family == AF_INET6) { + MultipathRoute *m; + + ORDERED_SET_FOREACH(m, route->multipath_routes) + if (m->gateway.family == AF_INET) + return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: IPv4 multipath route is specified for IPv6 route. " + "Ignoring [Route] section from line %u.", + route->section->filename, route->section->line); + } + + if (route->nexthop_id > 0 && + (in_addr_is_set(route->gw_family, &route->gw) || + !ordered_set_isempty(route->multipath_routes))) + return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: NextHopId= cannot be specified with Gateway= or MultiPathRoute=. " + "Ignoring [Route] section from line %u.", + route->section->filename, route->section->line); + return 0; } diff --git a/src/network/networkd-route.h b/src/network/networkd-route.h index f59369392..331f1f9ea 100644 --- a/src/network/networkd-route.h +++ b/src/network/networkd-route.h @@ -40,9 +40,11 @@ typedef struct Route { uint32_t mtu; uint32_t initcwnd; uint32_t initrwnd; + uint32_t advmss; unsigned char pref; unsigned flags; int gateway_onlink; + uint32_t nexthop_id; bool scope_set:1; bool table_set:1; @@ -73,10 +75,9 @@ int route_configure(const Route *route, Link *link, link_netlink_message_handler int route_remove(const Route *route, Manager *manager, Link *link, link_netlink_message_handler_t callback); int link_set_routes(Link *link); +int link_set_routes_with_gateway(Link *link); int link_drop_routes(Link *link); int link_drop_foreign_routes(Link *link); -int link_serialize_routes(const Link *link, FILE *f); -int link_deserialize_routes(Link *link, const char *routes); uint32_t link_get_dhcp_route_table(const Link *link); uint32_t link_get_ipv6_accept_ra_route_table(const Link *link); @@ -87,6 +88,9 @@ int network_add_ipv4ll_route(Network *network); int network_add_default_route_on_device(Network *network); void network_drop_invalid_routes(Network *network); +int manager_get_route_table_from_string(const Manager *m, const char *table, uint32_t *ret); +int manager_get_route_table_to_string(const Manager *m, uint32_t table, char **ret); + CONFIG_PARSER_PROTOTYPE(config_parse_gateway); CONFIG_PARSER_PROTOTYPE(config_parse_preferred_src); CONFIG_PARSER_PROTOTYPE(config_parse_destination); @@ -100,3 +104,6 @@ CONFIG_PARSER_PROTOTYPE(config_parse_route_type); CONFIG_PARSER_PROTOTYPE(config_parse_tcp_window); CONFIG_PARSER_PROTOTYPE(config_parse_route_mtu); CONFIG_PARSER_PROTOTYPE(config_parse_multipath_route); +CONFIG_PARSER_PROTOTYPE(config_parse_tcp_advmss); +CONFIG_PARSER_PROTOTYPE(config_parse_route_table_names); +CONFIG_PARSER_PROTOTYPE(config_parse_route_nexthop); diff --git a/src/network/networkd-routing-policy-rule.c b/src/network/networkd-routing-policy-rule.c index e44ecb485..a7fddfd58 100644 --- a/src/network/networkd-routing-policy-rule.c +++ b/src/network/networkd-routing-policy-rule.c @@ -8,6 +8,7 @@ #include "conf-parser.h" #include "fileio.h" #include "format-util.h" +#include "hashmap.h" #include "ip-protocol-list.h" #include "netlink-util.h" #include "networkd-manager.h" @@ -15,10 +16,20 @@ #include "networkd-util.h" #include "parse-util.h" #include "socket-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "user-util.h" +static const char *const fr_act_type_table[__FR_ACT_MAX] = { + [FR_ACT_BLACKHOLE] = "blackhole", + [FR_ACT_UNREACHABLE] = "unreachable", + [FR_ACT_PROHIBIT] = "prohibit", +}; + +assert_cc(__FR_ACT_MAX <= UINT8_MAX); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(fr_act_type, int); + RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) { if (!rule) return NULL; @@ -29,10 +40,8 @@ RoutingPolicyRule *routing_policy_rule_free(RoutingPolicyRule *rule) { } if (rule->manager) { - if (set_get(rule->manager->rules, rule) == rule) - set_remove(rule->manager->rules, rule); - if (set_get(rule->manager->rules_foreign, rule) == rule) - set_remove(rule->manager->rules_foreign, rule); + set_remove(rule->manager->rules, rule); + set_remove(rule->manager->rules_foreign, rule); } network_config_section_free(rule->section); @@ -56,6 +65,8 @@ static int routing_policy_rule_new(RoutingPolicyRule **ret) { .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, + .protocol = RTPROT_UNSPEC, + .type = FR_ACT_TO_TBL, }; *ret = rule; @@ -88,12 +99,9 @@ static int routing_policy_rule_new_static(Network *network, const char *filename rule->network = network; rule->section = TAKE_PTR(n); + rule->protocol = RTPROT_STATIC; - r = hashmap_ensure_allocated(&network->rules_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(network->rules_by_section, rule->section, rule); + r = hashmap_ensure_put(&network->rules_by_section, &network_config_hash_ops, rule->section, rule); if (r < 0) return r; @@ -101,7 +109,7 @@ static int routing_policy_rule_new_static(Network *network, const char *filename return 0; } -static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule *src) { +static int routing_policy_rule_copy(RoutingPolicyRule *dest, const RoutingPolicyRule *src) { _cleanup_free_ char *iif = NULL, *oif = NULL; assert(dest); @@ -126,12 +134,14 @@ static int routing_policy_rule_copy(RoutingPolicyRule *dest, RoutingPolicyRule * dest->to_prefixlen = src->to_prefixlen; dest->invert_rule = src->invert_rule; dest->tos = src->tos; + dest->type = src->type; dest->fwmark = src->fwmark; dest->fwmask = src->fwmask; dest->priority = src->priority; dest->table = src->table; dest->iif = TAKE_PTR(iif); dest->oif = TAKE_PTR(oif); + dest->ipproto = src->ipproto; dest->protocol = src->protocol; dest->sport = src->sport; dest->dport = src->dport; @@ -158,12 +168,14 @@ static void routing_policy_rule_hash_func(const RoutingPolicyRule *rule, struct siphash24_compress_boolean(rule->invert_rule, state); siphash24_compress(&rule->tos, sizeof(rule->tos), state); + siphash24_compress(&rule->type, sizeof(rule->type), state); siphash24_compress(&rule->fwmark, sizeof(rule->fwmark), state); siphash24_compress(&rule->fwmask, sizeof(rule->fwmask), state); siphash24_compress(&rule->priority, sizeof(rule->priority), state); siphash24_compress(&rule->table, sizeof(rule->table), state); siphash24_compress(&rule->suppress_prefixlen, sizeof(rule->suppress_prefixlen), state); + siphash24_compress(&rule->ipproto, sizeof(rule->ipproto), state); siphash24_compress(&rule->protocol, sizeof(rule->protocol), state); siphash24_compress(&rule->sport, sizeof(rule->sport), state); siphash24_compress(&rule->dport, sizeof(rule->dport), state); @@ -213,6 +225,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro if (r != 0) return r; + r = CMP(a->type, b->type); + if (r != 0) + return r; + r = CMP(a->fwmark, b->fwmark); if (r != 0) return r; @@ -233,6 +249,10 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro if (r != 0) return r; + r = CMP(a->ipproto, b->ipproto); + if (r != 0) + return r; + r = CMP(a->protocol, b->protocol); if (r != 0) return r; @@ -264,6 +284,16 @@ static int routing_policy_rule_compare_func(const RoutingPolicyRule *a, const Ro } } +static bool routing_policy_rule_equal(const RoutingPolicyRule *rule1, const RoutingPolicyRule *rule2) { + if (rule1 == rule2) + return true; + + if (!rule1 || !rule2) + return false; + + return routing_policy_rule_compare_func(rule1, rule2) == 0; +} + DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( routing_policy_rule_hash_ops, RoutingPolicyRule, @@ -271,8 +301,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR( routing_policy_rule_compare_func, routing_policy_rule_free); -static int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) { - +static int routing_policy_rule_get(Manager *m, const RoutingPolicyRule *rule, RoutingPolicyRule **ret) { RoutingPolicyRule *existing; assert(m); @@ -294,12 +323,13 @@ static int routing_policy_rule_get(Manager *m, RoutingPolicyRule *rule, RoutingP return -ENOENT; } -static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) { +static int routing_policy_rule_add(Manager *m, const RoutingPolicyRule *in, int family, RoutingPolicyRule **ret) { _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL; + RoutingPolicyRule *existing; + bool is_new = false; int r; assert(m); - assert(rules); assert(in); assert(IN_SET(family, AF_INET, AF_INET6)); assert(in->family == AF_UNSPEC || in->family == family); @@ -314,52 +344,98 @@ static int routing_policy_rule_add_internal(Manager *m, Set **rules, RoutingPoli rule->family = family; - r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule); - if (r < 0) + r = routing_policy_rule_get(m, rule, &existing); + if (r == -ENOENT) { + /* Rule does not exist, use a new one. */ + r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, rule); + if (r < 0) + return r; + assert(r > 0); + + rule->manager = m; + existing = TAKE_PTR(rule); + is_new = true; + } else if (r == 0) { + /* Take over a foreign rule. */ + r = set_ensure_put(&m->rules, &routing_policy_rule_hash_ops, existing); + if (r < 0) + return r; + assert(r > 0); + + set_remove(m->rules_foreign, existing); + } else if (r == 1) { + /* Already exists, do nothing. */ + ; + } else + return r; + + if (ret) + *ret = existing; + return is_new; +} + +static int routing_policy_rule_consume_foreign(Manager *m, RoutingPolicyRule *rule) { + int r; + + assert(m); + assert(rule); + assert(IN_SET(rule->family, AF_INET, AF_INET6)); + + r = set_ensure_consume(&m->rules_foreign, &routing_policy_rule_hash_ops, rule); + if (r <= 0) return r; - if (r == 0) - return -EEXIST; rule->manager = m; - if (ret) - *ret = rule; - - TAKE_PTR(rule); - return 0; + return 1; } -static int routing_policy_rule_add(Manager *m, RoutingPolicyRule *rule, int family, RoutingPolicyRule **ret) { - return routing_policy_rule_add_internal(m, &m->rules, rule, family, ret); +static void log_routing_policy_rule_debug(const RoutingPolicyRule *rule, int family, const char *str, const Link *link, const Manager *m) { + assert(rule); + assert(IN_SET(family, AF_INET, AF_INET6)); + assert(str); + assert(m); + + /* link may be NULL. */ + + if (DEBUG_LOGGING) { + _cleanup_free_ char *from = NULL, *to = NULL, *table = NULL; + + (void) in_addr_prefix_to_string(family, &rule->from, rule->from_prefixlen, &from); + (void) in_addr_prefix_to_string(family, &rule->to, rule->to_prefixlen, &to); + (void) manager_get_route_table_to_string(m, rule->table, &table); + + log_link_debug(link, + "%s routing policy rule: priority: %"PRIu32", %s -> %s, iif: %s, oif: %s, table: %s", + str, rule->priority, strna(from), strna(to), + strna(rule->iif), strna(rule->oif), strna(table)); + } } -static int routing_policy_rule_add_foreign(Manager *m, RoutingPolicyRule *rule, RoutingPolicyRule **ret) { - return routing_policy_rule_add_internal(m, &m->rules_foreign, rule, rule->family, ret); -} - -static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_netlink_message *m, Link *link) { +static int routing_policy_rule_set_netlink_message(const RoutingPolicyRule *rule, sd_netlink_message *m, Link *link) { int r; assert(rule); assert(m); - assert(link); - if (in_addr_is_null(rule->family, &rule->from) == 0) { + /* link may be NULL. */ + + if (in_addr_is_set(rule->family, &rule->from)) { r = netlink_message_append_in_addr_union(m, FRA_SRC, rule->family, &rule->from); if (r < 0) return log_link_error_errno(link, r, "Could not append FRA_SRC attribute: %m"); - r = sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(m, rule->from_prefixlen); + r = sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(m, rule->from_prefixlen); if (r < 0) return log_link_error_errno(link, r, "Could not set source prefix length: %m"); } - if (in_addr_is_null(rule->family, &rule->to) == 0) { + if (in_addr_is_set(rule->family, &rule->to)) { r = netlink_message_append_in_addr_union(m, FRA_DST, rule->family, &rule->to); if (r < 0) return log_link_error_errno(link, r, "Could not append FRA_DST attribute: %m"); - r = sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(m, rule->to_prefixlen); + r = sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(m, rule->to_prefixlen); if (r < 0) return log_link_error_errno(link, r, "Could not set destination prefix length: %m"); } @@ -410,10 +486,14 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n return log_link_error_errno(link, r, "Could not append FRA_OIFNAME attribute: %m"); } - r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->protocol); + r = sd_netlink_message_append_u8(m, FRA_IP_PROTO, rule->ipproto); if (r < 0) return log_link_error_errno(link, r, "Could not append FRA_IP_PROTO attribute: %m"); + r = sd_netlink_message_append_u8(m, FRA_PROTOCOL, rule->protocol); + if (r < 0) + return log_link_error_errno(link, r, "Could not append FRA_PROTOCOL attribute: %m"); + if (rule->sport.start != 0 || rule->sport.end != 0) { r = sd_netlink_message_append_data(m, FRA_SPORT_RANGE, &rule->sport, sizeof(rule->sport)); if (r < 0) @@ -444,65 +524,51 @@ static int routing_policy_rule_set_netlink_message(RoutingPolicyRule *rule, sd_n return log_link_error_errno(link, r, "Could not append FRA_SUPPRESS_PREFIXLEN attribute: %m"); } + if (rule->type != FR_ACT_TO_TBL) { + r = sd_rtnl_message_routing_policy_rule_set_fib_type(m, rule->type); + if (r < 0) + return log_link_error_errno(link, r, "Could not append FIB rule type attribute: %m"); + } + return 0; } -static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { +static int routing_policy_rule_remove_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { int r; assert(m); - assert(link); - assert(link->ifname); - - link->routing_policy_rule_remove_messages--; - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return 1; r = sd_netlink_message_get_errno(m); if (r < 0) - log_link_message_warning_errno(link, m, r, "Could not drop routing policy rule"); + log_message_warning_errno(m, r, "Could not drop routing policy rule"); return 1; } -static int routing_policy_rule_remove(RoutingPolicyRule *rule, Link *link) { +static int routing_policy_rule_remove(const RoutingPolicyRule *rule, Manager *manager) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; assert(rule); - assert(link); - assert(link->manager); - assert(link->manager->rtnl); - assert(link->ifindex > 0); + assert(manager); + assert(manager->rtnl); assert(IN_SET(rule->family, AF_INET, AF_INET6)); - if (DEBUG_LOGGING) { - _cleanup_free_ char *from = NULL, *to = NULL; + log_routing_policy_rule_debug(rule, rule->family, "Removing", NULL, manager); - (void) in_addr_to_string(rule->family, &rule->from, &from); - (void) in_addr_to_string(rule->family, &rule->to, &to); - - log_link_debug(link, - "Removing routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32, - rule->priority, strna(from), rule->from_prefixlen, strna(to), rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table); - } - - r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_DELRULE, rule->family); + r = sd_rtnl_message_new_routing_policy_rule(manager->rtnl, &m, RTM_DELRULE, rule->family); if (r < 0) - return log_link_error_errno(link, r, "Could not allocate RTM_DELRULE message: %m"); + return log_error_errno(r, "Could not allocate RTM_DELRULE message: %m"); - r = routing_policy_rule_set_netlink_message(rule, m, link); + r = routing_policy_rule_set_netlink_message(rule, m, NULL); if (r < 0) return r; - r = netlink_call_async(link->manager->rtnl, NULL, m, - routing_policy_rule_remove_handler, - link_netlink_destroy_callback, link); + r = sd_netlink_call_async(manager->rtnl, NULL, m, + routing_policy_rule_remove_handler, + NULL, NULL, 0, __func__); if (r < 0) - return log_link_error_errno(link, r, "Could not send rtnetlink message: %m"); - - link_ref(link); + return log_error_errno(r, "Could not send rtnetlink message: %m"); return 0; } @@ -537,7 +603,7 @@ static int routing_policy_rule_handler(sd_netlink *rtnl, sd_netlink_message *m, return 1; } -static int routing_policy_rule_configure_internal(RoutingPolicyRule *rule, int family, Link *link) { +static int routing_policy_rule_configure_internal(const RoutingPolicyRule *rule, int family, Link *link) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -547,16 +613,7 @@ static int routing_policy_rule_configure_internal(RoutingPolicyRule *rule, int f assert(link->manager); assert(link->manager->rtnl); - if (DEBUG_LOGGING) { - _cleanup_free_ char *from = NULL, *to = NULL; - - (void) in_addr_to_string(family, &rule->from, &from); - (void) in_addr_to_string(family, &rule->to, &to); - - log_link_debug(link, - "Configuring routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32, - rule->priority, strna(from), rule->from_prefixlen, strna(to), rule->to_prefixlen, strna(rule->iif), strna(rule->oif), rule->table); - } + log_routing_policy_rule_debug(rule, family, "Configuring", link, link->manager); r = sd_rtnl_message_new_routing_policy_rule(link->manager->rtnl, &m, RTM_NEWRULE, family); if (r < 0) @@ -579,10 +636,10 @@ static int routing_policy_rule_configure_internal(RoutingPolicyRule *rule, int f if (r < 0) return log_link_error_errno(link, r, "Could not add rule: %m"); - return 1; + return r; } -static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link) { +static int routing_policy_rule_configure(const RoutingPolicyRule *rule, Link *link) { int r; if (IN_SET(rule->family, AF_INET, AF_INET6)) @@ -603,8 +660,9 @@ static int routing_policy_rule_configure(RoutingPolicyRule *rule, Link *link) { return 0; } -static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule *rule) { +static int links_have_routing_policy_rule(const Manager *m, const RoutingPolicyRule *rule, const Link *except) { Link *link; + int r; assert(m); assert(rule); @@ -612,48 +670,68 @@ static bool manager_links_have_routing_policy_rule(Manager *m, RoutingPolicyRule HASHMAP_FOREACH(link, m->links) { RoutingPolicyRule *link_rule; + if (link == except) + continue; + if (!link->network) continue; HASHMAP_FOREACH(link_rule, link->network->rules_by_section) - if (routing_policy_rule_compare_func(link_rule, rule) == 0) - return true; + if (IN_SET(link_rule->family, AF_INET, AF_INET6)) { + if (routing_policy_rule_equal(link_rule, rule)) + return true; + } else { + /* The case Family=both. */ + _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL; + + r = routing_policy_rule_new(&tmp); + if (r < 0) + return r; + + r = routing_policy_rule_copy(tmp, link_rule); + if (r < 0) + return r; + + tmp->family = AF_INET; + if (routing_policy_rule_equal(tmp, rule)) + return true; + + tmp->family = AF_INET6; + if (routing_policy_rule_equal(tmp, rule)) + return true; + } } return false; } -static void routing_policy_rule_purge(Manager *m, Link *link) { +int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except) { RoutingPolicyRule *rule; - int r; + int k, r = 0; + Set *rules; assert(m); - assert(link); - SET_FOREACH(rule, m->rules_saved) { - RoutingPolicyRule *existing; + rules = foreign ? m->rules_foreign : m->rules; + SET_FOREACH(rule, rules) { + /* Do not touch rules managed by kernel. */ + if (rule->protocol == RTPROT_KERNEL) + continue; - existing = set_get(m->rules_foreign, rule); - if (!existing) - continue; /* Saved rule does not exist anymore. */ - - if (manager_links_have_routing_policy_rule(m, existing)) - continue; /* Existing links have the saved rule. */ - - /* Existing links do not have the saved rule. Let's drop the rule now, and re-configure it - * later when it is requested. */ - - r = routing_policy_rule_remove(existing, link); - if (r < 0) { - log_warning_errno(r, "Could not remove routing policy rules: %m"); + /* The rule will be configured later, or already configured by a link. */ + k = links_have_routing_policy_rule(m, rule, except); + if (k != 0) { + if (k < 0 && r >= 0) + r = k; continue; } - link->routing_policy_rule_remove_messages++; - - assert_se(set_remove(m->rules_foreign, existing) == existing); - routing_policy_rule_free(existing); + k = routing_policy_rule_remove(rule, m); + if (k < 0 && r >= 0) + r = k; } + + return r; } int link_set_routing_policy_rules(Link *link) { @@ -663,29 +741,19 @@ int link_set_routing_policy_rules(Link *link) { assert(link); assert(link->network); + if (link->routing_policy_rule_messages != 0) { + log_link_debug(link, "Routing policy rules are configuring."); + return 0; + } + link->routing_policy_rules_configured = false; HASHMAP_FOREACH(rule, link->network->rules_by_section) { - RoutingPolicyRule *existing; - - r = routing_policy_rule_get(link->manager, rule, &existing); - if (r > 0) - continue; - if (r == 0) { - r = set_ensure_put(&link->manager->rules, &routing_policy_rule_hash_ops, existing); - if (r < 0) - return log_link_warning_errno(link, r, "Could not store existing routing policy rule: %m"); - - set_remove(link->manager->rules_foreign, existing); - continue; - } - r = routing_policy_rule_configure(rule, link); if (r < 0) return log_link_warning_errno(link, r, "Could not set routing policy rule: %m"); } - routing_policy_rule_purge(link->manager, link); if (link->routing_policy_rule_messages == 0) link->routing_policy_rules_configured = true; else { @@ -696,11 +764,34 @@ int link_set_routing_policy_rules(Link *link) { return 0; } +static const RoutingPolicyRule kernel_rules[] = { + { .family = AF_INET, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET, .priority = 32767, .table = RT_TABLE_DEFAULT, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET6, .priority = 0, .table = RT_TABLE_LOCAL, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, + { .family = AF_INET6, .priority = 32766, .table = RT_TABLE_MAIN, .type = FR_ACT_TO_TBL, .uid_range.start = UID_INVALID, .uid_range.end = UID_INVALID, .suppress_prefixlen = -1, }, +}; + +static bool routing_policy_rule_is_created_by_kernel(const RoutingPolicyRule *rule) { + assert(rule); + + if (rule->l3mdev > 0) + /* Currently, [RoutingPolicyRule] does not explicitly set FRA_L3MDEV. So, if the flag + * is set, it is safe to treat the rule as created by kernel. */ + return true; + + for (size_t i = 0; i < ELEMENTSOF(kernel_rules); i++) + if (routing_policy_rule_equal(rule, &kernel_rules[i])) + return true; + + return false; +} + int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) { _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *tmp = NULL; - _cleanup_free_ char *from = NULL, *to = NULL; RoutingPolicyRule *rule = NULL; const char *iif = NULL, *oif = NULL; + bool adjust_protocol = false; uint32_t suppress_prefixlen; unsigned flags; uint16_t type; @@ -741,63 +832,28 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man return 0; } - switch (tmp->family) { - case AF_INET: - r = sd_netlink_message_read_in_addr(message, FRA_SRC, &tmp->from.in); - if (r < 0 && r != -ENODATA) { - log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m"); + r = netlink_message_read_in_addr_union(message, FRA_SRC, tmp->family, &tmp->from); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m"); + return 0; + } else if (r >= 0) { + r = sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(message, &tmp->from_prefixlen); + if (r < 0) { + log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m"); return 0; - } else if (r >= 0) { - r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen); - if (r < 0) { - log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m"); - return 0; - } } + } - r = sd_netlink_message_read_in_addr(message, FRA_DST, &tmp->to.in); - if (r < 0 && r != -ENODATA) { - log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m"); + r = netlink_message_read_in_addr_union(message, FRA_DST, tmp->family, &tmp->to); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m"); + return 0; + } else if (r >= 0) { + r = sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(message, &tmp->to_prefixlen); + if (r < 0) { + log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m"); return 0; - } else if (r >= 0) { - r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen); - if (r < 0) { - log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m"); - return 0; - } } - - break; - - case AF_INET6: - r = sd_netlink_message_read_in6_addr(message, FRA_SRC, &tmp->from.in6); - if (r < 0 && r != -ENODATA) { - log_warning_errno(r, "rtnl: could not get FRA_SRC attribute, ignoring: %m"); - return 0; - } else if (r >= 0) { - r = sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(message, &tmp->from_prefixlen); - if (r < 0) { - log_warning_errno(r, "rtnl: received rule message without valid source prefix length, ignoring: %m"); - return 0; - } - } - - r = sd_netlink_message_read_in6_addr(message, FRA_DST, &tmp->to.in6); - if (r < 0 && r != -ENODATA) { - log_warning_errno(r, "rtnl: could not get FRA_DST attribute, ignoring: %m"); - return 0; - } else if (r >= 0) { - r = sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(message, &tmp->to_prefixlen); - if (r < 0) { - log_warning_errno(r, "rtnl: received rule message without valid destination prefix length, ignoring: %m"); - return 0; - } - } - - break; - - default: - assert_not_reached("Received rule message with unsupported address family"); } r = sd_rtnl_message_routing_policy_rule_get_flags(message, &flags); @@ -833,7 +889,13 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man r = sd_rtnl_message_routing_policy_rule_get_tos(message, &tmp->tos); if (r < 0 && r != -ENODATA) { - log_warning_errno(r, "rtnl: could not get ip rule TOS, ignoring: %m"); + log_warning_errno(r, "rtnl: could not get FIB rule TOS, ignoring: %m"); + return 0; + } + + r = sd_rtnl_message_routing_policy_rule_get_fib_type(message, &tmp->type); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FIB rule type, ignoring: %m"); return 0; } @@ -855,12 +917,29 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man if (r < 0) return log_oom(); - r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->protocol); + r = sd_netlink_message_read_u8(message, FRA_IP_PROTO, &tmp->ipproto); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_IP_PROTO attribute, ignoring: %m"); return 0; } + r = sd_netlink_message_read_u8(message, FRA_PROTOCOL, &tmp->protocol); + if (r == -ENODATA) + /* If FRA_PROTOCOL is supported by kernel, then the attribute is always appended. + * When the received message does not have FRA_PROTOCOL, then we need to adjust the + * protocol of the rule later. */ + adjust_protocol = true; + else if (r < 0) { + log_warning_errno(r, "rtnl: could not get FRA_PROTOCOL attribute, ignoring: %m"); + return 0; + } + + r = sd_netlink_message_read_u8(message, FRA_L3MDEV, &tmp->l3mdev); + if (r < 0 && r != -ENODATA) { + log_warning_errno(r, "rtnl: could not get FRA_L3MDEV attribute, ignoring: %m"); + return 0; + } + r = sd_netlink_message_read(message, FRA_SPORT_RANGE, sizeof(tmp->sport), &tmp->sport); if (r < 0 && r != -ENODATA) { log_warning_errno(r, "rtnl: could not get FRA_SPORT_RANGE attribute, ignoring: %m"); @@ -887,36 +966,30 @@ int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Man if (r >= 0) tmp->suppress_prefixlen = (int) suppress_prefixlen; - (void) routing_policy_rule_get(m, tmp, &rule); + if (adjust_protocol) + /* As .network files does not have setting to specify protocol, we can assume the + * protocol of the received rule is RTPROT_KERNEL or RTPROT_STATIC. */ + tmp->protocol = routing_policy_rule_is_created_by_kernel(tmp) ? RTPROT_KERNEL : RTPROT_STATIC; - if (DEBUG_LOGGING) { - (void) in_addr_to_string(tmp->family, &tmp->from, &from); - (void) in_addr_to_string(tmp->family, &tmp->to, &to); - } + (void) routing_policy_rule_get(m, tmp, &rule); switch (type) { case RTM_NEWRULE: if (rule) - log_debug("Received remembered routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32, - tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table); + log_routing_policy_rule_debug(tmp, tmp->family, "Received remembered", NULL, m); else { - log_debug("Remembering foreign routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32, - tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table); - r = routing_policy_rule_add_foreign(m, tmp, &rule); - if (r < 0) { + log_routing_policy_rule_debug(tmp, tmp->family, "Remembering foreign", NULL, m); + r = routing_policy_rule_consume_foreign(m, TAKE_PTR(tmp)); + if (r < 0) log_warning_errno(r, "Could not remember foreign rule, ignoring: %m"); - return 0; - } } break; case RTM_DELRULE: if (rule) { - log_debug("Forgetting routing policy rule: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32, - tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table); + log_routing_policy_rule_debug(tmp, tmp->family, "Forgetting", NULL, m); routing_policy_rule_free(rule); } else - log_debug("Kernel removed a routing policy rule we don't remember: priority: %"PRIu32", %s/%u -> %s/%u, iif: %s, oif: %s, table: %"PRIu32", ignoring.", - tmp->priority, strna(from), tmp->from_prefixlen, strna(to), tmp->to_prefixlen, strna(tmp->iif), strna(tmp->oif), tmp->table); + log_routing_policy_rule_debug(tmp, tmp->family, "Kernel removed unknown", NULL, m); break; default: @@ -994,8 +1067,7 @@ int config_parse_routing_policy_rule_tos( return 0; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1031,8 +1103,7 @@ int config_parse_routing_policy_rule_priority( return 0; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1062,14 +1133,14 @@ int config_parse_routing_policy_rule_table( if (r < 0) return log_oom(); - r = safe_atou32(rvalue, &n->table); + r = manager_get_route_table_from_string(network->manager, rvalue, &n->table); if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse RPDB rule table, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, + "Could not parse RPDB rule route table number \"%s\", ignoring assignment: %m", rvalue); return 0; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1105,8 +1176,7 @@ int config_parse_routing_policy_rule_fwmark_mask( return 0; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1155,8 +1225,7 @@ int config_parse_routing_policy_rule_prefix( return 0; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1201,8 +1270,7 @@ int config_parse_routing_policy_rule_device( return log_oom(); } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1246,8 +1314,7 @@ int config_parse_routing_policy_rule_port_range( n->dport.end = high; } - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1283,10 +1350,9 @@ int config_parse_routing_policy_rule_ip_protocol( return 0; } - n->protocol = r; - - n = NULL; + n->ipproto = r; + TAKE_PTR(n); return 0; } @@ -1324,8 +1390,7 @@ int config_parse_routing_policy_rule_invert( n->invert_rule = r; - n = NULL; - + TAKE_PTR(n); return 0; } @@ -1358,14 +1423,14 @@ int config_parse_routing_policy_rule_family( a = routing_policy_rule_address_family_from_string(rvalue); if (a < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, a, "Invalid address family '%s', ignoring.", rvalue); return 0; } n->address_family = a; - n = NULL; + TAKE_PTR(n); return 0; } @@ -1410,8 +1475,8 @@ int config_parse_routing_policy_rule_uid_range( n->uid_range.start = start; n->uid_range.end = end; - n = NULL; + TAKE_PTR(n); return 0; } @@ -1451,8 +1516,46 @@ int config_parse_routing_policy_rule_suppress_prefixlen( return 0; } - n = NULL; + TAKE_PTR(n); + return 0; +} +int config_parse_routing_policy_rule_type( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + _cleanup_(routing_policy_rule_free_or_set_invalidp) RoutingPolicyRule *n = NULL; + Network *network = userdata; + int r, t; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + assert(data); + + r = routing_policy_rule_new_static(network, filename, section_line, &n); + if (r < 0) + return log_oom(); + + t = fr_act_type_from_string(rvalue); + if (t < 0) { + log_syntax(unit, LOG_WARNING, filename, line, t, + "Could not parse FIB rule type \"%s\", ignoring assignment: %m", rvalue); + return 0; + } + + n->type = (uint8_t) t; + + TAKE_PTR(n); return 0; } @@ -1467,8 +1570,19 @@ static int routing_policy_rule_section_verify(RoutingPolicyRule *rule) { "specified by To= or From=. Ignoring [RoutingPolicyRule] section from line %u.", rule->section->filename, rule->section->line); - if (rule->family == AF_UNSPEC && rule->address_family == ADDRESS_FAMILY_NO) - rule->family = AF_INET; + if (rule->family == AF_UNSPEC) { + if (IN_SET(rule->address_family, ADDRESS_FAMILY_IPV4, ADDRESS_FAMILY_NO)) + rule->family = AF_INET; + else if (rule->address_family == ADDRESS_FAMILY_IPV6) + rule->family = AF_INET6; + /* rule->family can be AF_UNSPEC only when Family=both. */ + } + + /* Currently, [RoutingPolicyRule] does not have a setting to set FRA_L3MDEV flag. Please also + * update routing_policy_rule_is_created_by_kernel() when a new setting which sets the flag is + * added in the future. */ + if (rule->l3mdev > 0) + assert_not_reached("FRA_L3MDEV flag should not be configured."); return 0; } @@ -1482,329 +1596,3 @@ void network_drop_invalid_routing_policy_rules(Network *network) { if (routing_policy_rule_section_verify(rule) < 0) routing_policy_rule_free(rule); } - -int routing_policy_serialize_rules(Set *rules, FILE *f) { - RoutingPolicyRule *rule; - int r; - - assert(f); - - SET_FOREACH(rule, rules) { - const char *family_str; - bool space = false; - - fputs("RULE=", f); - - family_str = af_to_name(rule->family); - if (family_str) { - fprintf(f, "family=%s", - family_str); - space = true; - } - - if (!in_addr_is_null(rule->family, &rule->from)) { - _cleanup_free_ char *str = NULL; - - r = in_addr_to_string(rule->family, &rule->from, &str); - if (r < 0) - return r; - - fprintf(f, "%sfrom=%s/%hhu", - space ? " " : "", - str, rule->from_prefixlen); - space = true; - } - - if (!in_addr_is_null(rule->family, &rule->to)) { - _cleanup_free_ char *str = NULL; - - r = in_addr_to_string(rule->family, &rule->to, &str); - if (r < 0) - return r; - - fprintf(f, "%sto=%s/%hhu", - space ? " " : "", - str, rule->to_prefixlen); - space = true; - } - - if (rule->tos != 0) { - fprintf(f, "%stos=%hhu", - space ? " " : "", - rule->tos); - space = true; - } - - if (rule->priority != 0) { - fprintf(f, "%spriority=%"PRIu32, - space ? " " : "", - rule->priority); - space = true; - } - - if (rule->fwmark != 0) { - fprintf(f, "%sfwmark=%"PRIu32, - space ? " " : "", - rule->fwmark); - if (rule->fwmask != UINT32_MAX) - fprintf(f, "/%"PRIu32, rule->fwmask); - space = true; - } - - if (rule->iif) { - fprintf(f, "%siif=%s", - space ? " " : "", - rule->iif); - space = true; - } - - if (rule->oif) { - fprintf(f, "%soif=%s", - space ? " " : "", - rule->oif); - space = true; - } - - if (rule->protocol != 0) { - fprintf(f, "%sprotocol=%hhu", - space ? " " : "", - rule->protocol); - space = true; - } - - if (rule->sport.start != 0 || rule->sport.end != 0) { - fprintf(f, "%ssourcesport=%"PRIu16"-%"PRIu16, - space ? " " : "", - rule->sport.start, rule->sport.end); - space = true; - } - - if (rule->dport.start != 0 || rule->dport.end != 0) { - fprintf(f, "%sdestinationport=%"PRIu16"-%"PRIu16, - space ? " " : "", - rule->dport.start, rule->dport.end); - space = true; - } - - if (rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID) { - assert_cc(sizeof(uid_t) == sizeof(uint32_t)); - fprintf(f, "%suidrange="UID_FMT"-"UID_FMT, - space ? " " : "", - rule->uid_range.start, rule->uid_range.end); - space = true; - } - - if (rule->suppress_prefixlen >= 0) { - fprintf(f, "%ssuppress_prefixlen=%d", - space ? " " : "", - rule->suppress_prefixlen); - space = true; - } - - fprintf(f, "%sinvert_rule=%s table=%"PRIu32"\n", - space ? " " : "", - yes_no(rule->invert_rule), - rule->table); - } - - return 0; -} - -static int routing_policy_rule_read_full_file(const char *state_file, char ***ret) { - _cleanup_strv_free_ char **lines = NULL; - _cleanup_free_ char *s = NULL; - int r; - - assert(state_file); - - r = read_full_file(state_file, &s, NULL); - if (r == -ENOENT) { - *ret = NULL; - return 0; - } - if (r < 0) - return r; - - lines = strv_split_newlines(s); - if (!lines) - return -ENOMEM; - - *ret = TAKE_PTR(lines); - return 0; -} - -int routing_policy_load_rules(const char *state_file, Set **rules) { - _cleanup_strv_free_ char **data = NULL; - char **i; - int r; - - assert(state_file); - assert(rules); - - r = routing_policy_rule_read_full_file(state_file, &data); - if (r < 0) - return log_warning_errno(r, "Failed to read %s, ignoring: %m", state_file); - - STRV_FOREACH(i, data) { - _cleanup_(routing_policy_rule_freep) RoutingPolicyRule *rule = NULL; - const char *p; - - p = startswith(*i, "RULE="); - if (!p) - continue; - - r = routing_policy_rule_new(&rule); - if (r < 0) - return log_oom(); - - for (;;) { - _cleanup_free_ char *a = NULL; - char *b; - - r = extract_first_word(&p, &a, NULL, 0); - if (r < 0) - return log_oom(); - if (r == 0) - break; - - b = strchr(a, '='); - if (!b) { - log_warning_errno(r, "Failed to parse RPDB rule, ignoring: %s", a); - continue; - } - *b++ = '\0'; - - if (streq(a, "family")) { - r = af_from_name(b); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule family, ignoring: %s", b); - continue; - } - if (rule->family != AF_UNSPEC && rule->family != r) { - log_warning("RPDB rule family is already specified, ignoring assignment: %s", b); - continue; - } - rule->family = r; - } else if (STR_IN_SET(a, "from", "to")) { - union in_addr_union *buffer; - uint8_t *prefixlen; - - if (streq(a, "to")) { - buffer = &rule->to; - prefixlen = &rule->to_prefixlen; - } else { - buffer = &rule->from; - prefixlen = &rule->from_prefixlen; - } - - if (rule->family == AF_UNSPEC) - r = in_addr_prefix_from_string_auto(b, &rule->family, buffer, prefixlen); - else - r = in_addr_prefix_from_string(b, rule->family, buffer, prefixlen); - if (r < 0) { - log_warning_errno(r, "RPDB rule prefix is invalid, ignoring assignment: %s", b); - continue; - } - } else if (streq(a, "tos")) { - r = safe_atou8(b, &rule->tos); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule TOS, ignoring: %s", b); - continue; - } - } else if (streq(a, "table")) { - r = safe_atou32(b, &rule->table); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule table, ignoring: %s", b); - continue; - } - } else if (streq(a, "priority")) { - r = safe_atou32(b, &rule->priority); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule priority, ignoring: %s", b); - continue; - } - } else if (streq(a, "fwmark")) { - r = parse_fwmark_fwmask(b, &rule->fwmark, &rule->fwmask); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule firewall mark or mask, ignoring: %s", a); - continue; - } - } else if (streq(a, "iif")) { - if (free_and_strdup(&rule->iif, b) < 0) - return log_oom(); - - } else if (streq(a, "oif")) { - - if (free_and_strdup(&rule->oif, b) < 0) - return log_oom(); - } else if (streq(a, "protocol")) { - r = safe_atou8(b, &rule->protocol); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule protocol, ignoring: %s", b); - continue; - } - } else if (streq(a, "sourceport")) { - uint16_t low, high; - - r = parse_ip_port_range(b, &low, &high); - if (r < 0) { - log_warning_errno(r, "Invalid routing policy rule source port range, ignoring assignment: '%s'", b); - continue; - } - - rule->sport.start = low; - rule->sport.end = high; - } else if (streq(a, "destinationport")) { - uint16_t low, high; - - r = parse_ip_port_range(b, &low, &high); - if (r < 0) { - log_warning_errno(r, "Invalid routing policy rule destination port range, ignoring assignment: '%s'", b); - continue; - } - - rule->dport.start = low; - rule->dport.end = high; - } else if (streq(a, "uidrange")) { - uid_t lower, upper; - - r = parse_uid_range(b, &lower, &upper); - if (r < 0) { - log_warning_errno(r, "Invalid routing policy rule uid range, ignoring assignment: '%s'", b); - continue; - } - - rule->uid_range.start = lower; - rule->uid_range.end = upper; - } else if (streq(a, "suppress_prefixlen")) { - r = parse_ip_prefix_length(b, &rule->suppress_prefixlen); - if (r == -ERANGE) { - log_warning_errno(r, "Prefix length outside of valid range 0-128, ignoring: %s", b); - continue; - } - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule suppress_prefixlen, ignoring: %s", b); - continue; - } - } else if (streq(a, "invert_rule")) { - r = parse_boolean(b); - if (r < 0) { - log_warning_errno(r, "Failed to parse RPDB rule invert_rule, ignoring: %s", b); - continue; - } - rule->invert_rule = r; - } else - log_warning("Unknown RPDB rule, ignoring: %s", a); - } - - r = set_ensure_put(rules, &routing_policy_rule_hash_ops, rule); - if (r < 0) { - log_warning_errno(r, "Failed to add RPDB rule to saved DB, ignoring: %s", *i); - continue; - } - if (r > 0) - rule = NULL; - } - - return 0; -} diff --git a/src/network/networkd-routing-policy-rule.h b/src/network/networkd-routing-policy-rule.h index baf086f25..dbda8c51b 100644 --- a/src/network/networkd-routing-policy-rule.h +++ b/src/network/networkd-routing-policy-rule.h @@ -23,7 +23,12 @@ typedef struct RoutingPolicyRule { bool invert_rule; uint8_t tos; - uint8_t protocol; + uint8_t type; + uint8_t ipproto; /* FRA_IP_PROTO */ + uint8_t protocol; /* FRA_PROTOCOL */ + uint8_t to_prefixlen; + uint8_t from_prefixlen; + uint8_t l3mdev; /* FRA_L3MDEV */ uint32_t table; uint32_t fwmark; @@ -32,8 +37,6 @@ typedef struct RoutingPolicyRule { AddressFamily address_family; /* Specified by Family= */ int family; /* Automatically determined by From= or To= */ - unsigned char to_prefixlen; - unsigned char from_prefixlen; char *iif; char *oif; @@ -55,9 +58,13 @@ void network_drop_invalid_routing_policy_rules(Network *network); int link_set_routing_policy_rules(Link *link); int manager_rtnl_process_rule(sd_netlink *rtnl, sd_netlink_message *message, Manager *m); - -int routing_policy_serialize_rules(Set *rules, FILE *f); -int routing_policy_load_rules(const char *state_file, Set **rules); +int manager_drop_routing_policy_rules_internal(Manager *m, bool foreign, const Link *except); +static inline int manager_drop_foreign_routing_policy_rules(Manager *m) { + return manager_drop_routing_policy_rules_internal(m, true, NULL); +} +static inline int manager_drop_routing_policy_rules(Manager *m, const Link *except) { + return manager_drop_routing_policy_rules_internal(m, false, except); +} CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_tos); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_table); @@ -71,3 +78,4 @@ CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_invert); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_family); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_uid_range); CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_suppress_prefixlen); +CONFIG_PARSER_PROTOTYPE(config_parse_routing_policy_rule_type); diff --git a/src/network/networkd-speed-meter.c b/src/network/networkd-speed-meter.c index e7f0682c3..97204c89e 100644 --- a/src/network/networkd-speed-meter.c +++ b/src/network/networkd-speed-meter.c @@ -44,7 +44,6 @@ static int process_message(Manager *manager, sd_netlink_message *message) { static int speed_meter_handler(sd_event_source *s, uint64_t usec, void *userdata) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; Manager *manager = userdata; - sd_netlink_message *i; usec_t usec_now; Link *link; int r; @@ -84,7 +83,7 @@ static int speed_meter_handler(sd_event_source *s, uint64_t usec, void *userdata return 0; } - for (i = reply; i; i = sd_netlink_message_next(i)) + for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) (void) process_message(manager, i); return 0; diff --git a/src/network/networkd-sriov.c b/src/network/networkd-sriov.c index 68f43b5ce..7a76b61c4 100644 --- a/src/network/networkd-sriov.c +++ b/src/network/networkd-sriov.c @@ -17,7 +17,7 @@ static int sr_iov_new(SRIOV **ret) { return -ENOMEM; *sr_iov = (SRIOV) { - .vf = (uint32_t) -1, + .vf = UINT32_MAX, .vlan_proto = ETH_P_8021Q, .vf_spoof_check_setting = -1, .trust = -1, @@ -58,11 +58,7 @@ static int sr_iov_new_static(Network *network, const char *filename, unsigned se sr_iov->network = network; sr_iov->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_allocated(&network->sr_iov_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(network->sr_iov_by_section, sr_iov->section, sr_iov); + r = ordered_hashmap_ensure_put(&network->sr_iov_by_section, &network_config_hash_ops, sr_iov->section, sr_iov); if (r < 0) return r; @@ -230,8 +226,15 @@ int link_configure_sr_iov(Link *link) { SRIOV *sr_iov; int r; + assert(link); + assert(link->network); + + if (link->sr_iov_messages != 0) { + log_link_debug(link, "SR-IOV is configuring."); + return 0; + } + link->sr_iov_configured = false; - link->sr_iov_messages = 0; ORDERED_HASHMAP_FOREACH(sr_iov, link->network->sr_iov_by_section) { r = sr_iov_configure(link, sr_iov); @@ -253,7 +256,7 @@ static int sr_iov_section_verify(SRIOV *sr_iov) { if (section_is_invalid(sr_iov->section)) return -EINVAL; - if (sr_iov->vf == (uint32_t) -1) + if (sr_iov->vf == UINT32_MAX) return log_warning_errno(SYNTHETIC_ERRNO(EINVAL), "%s: [SRIOV] section without VirtualFunction= field configured. " "Ignoring [SRIOV] section from line %u.", @@ -300,7 +303,7 @@ int config_parse_sr_iov_uint32( if (isempty(rvalue)) { if (streq(lvalue, "VirtualFunction")) - sr_iov->vf = (uint32_t) -1; + sr_iov->vf = UINT32_MAX; else if (streq(lvalue, "VLANId")) sr_iov->vlan = 0; else if (streq(lvalue, "QualityOfService")) diff --git a/src/network/networkd-sriov.h b/src/network/networkd-sriov.h index dae5ff030..950d1f9c5 100644 --- a/src/network/networkd-sriov.h +++ b/src/network/networkd-sriov.h @@ -15,7 +15,7 @@ typedef enum SRIOVLinkState { SR_IOV_LINK_STATE_ENABLE = IFLA_VF_LINK_STATE_ENABLE, SR_IOV_LINK_STATE_DISABLE = IFLA_VF_LINK_STATE_DISABLE, _SR_IOV_LINK_STATE_MAX, - _SR_IOV_LINK_STATE_INVALID = -1, + _SR_IOV_LINK_STATE_INVALID = -EINVAL, } SRIOVLinkState; typedef struct SRIOV { diff --git a/src/network/networkd-state-file.c b/src/network/networkd-state-file.c new file mode 100644 index 000000000..9c5c5047b --- /dev/null +++ b/src/network/networkd-state-file.c @@ -0,0 +1,682 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "alloc-util.h" +#include "dns-domain.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "network-internal.h" +#include "networkd-link.h" +#include "networkd-manager-bus.h" +#include "networkd-manager.h" +#include "networkd-network.h" +#include "networkd-state-file.h" +#include "ordered-set.h" +#include "set.h" +#include "strv.h" +#include "tmpfile-util.h" + +static int ordered_set_put_dns_server(OrderedSet *s, int ifindex, struct in_addr_full *dns) { + const char *p; + int r; + + assert(s); + assert(dns); + + if (dns->ifindex != 0 && dns->ifindex != ifindex) + return 0; + + p = in_addr_full_to_string(dns); + if (!p) + return 0; + + r = ordered_set_put_strdup(s, p); + if (r == -EEXIST) + return 0; + + return r; +} + +static int ordered_set_put_dns_servers(OrderedSet *s, int ifindex, struct in_addr_full **dns, unsigned n) { + int r, c = 0; + + assert(s); + assert(dns || n == 0); + + for (unsigned i = 0; i < n; i++) { + r = ordered_set_put_dns_server(s, ifindex, dns[i]); + if (r < 0) + return r; + + c += r; + } + + return c; +} + +static int ordered_set_put_in4_addr(OrderedSet *s, const struct in_addr *address) { + char *p; + int r; + + assert(s); + assert(address); + + r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p); + if (r < 0) + return r; + + r = ordered_set_consume(s, p); + if (r == -EEXIST) + return 0; + + return r; +} + +static int ordered_set_put_in4_addrv( + OrderedSet *s, + const struct in_addr *addresses, + size_t n, + bool (*predicate)(const struct in_addr *addr)) { + + int r, c = 0; + + assert(s); + assert(n == 0 || addresses); + + for (size_t i = 0; i < n; i++) { + if (predicate && !predicate(&addresses[i])) + continue; + r = ordered_set_put_in4_addr(s, addresses+i); + if (r < 0) + return r; + + c += r; + } + + return c; +} + +int manager_save(Manager *m) { + _cleanup_ordered_set_free_free_ OrderedSet *dns = NULL, *ntp = NULL, *sip = NULL, *search_domains = NULL, *route_domains = NULL; + const char *operstate_str, *carrier_state_str, *address_state_str; + LinkOperationalState operstate = LINK_OPERSTATE_OFF; + LinkCarrierState carrier_state = LINK_CARRIER_STATE_OFF; + LinkAddressState address_state = LINK_ADDRESS_STATE_OFF; + _cleanup_(unlink_and_freep) char *temp_path = NULL; + _cleanup_strv_free_ char **p = NULL; + _cleanup_fclose_ FILE *f = NULL; + Link *link; + int r; + + assert(m); + assert(m->state_file); + + /* We add all NTP and DNS server to a set, to filter out duplicates */ + dns = ordered_set_new(&string_hash_ops); + if (!dns) + return -ENOMEM; + + ntp = ordered_set_new(&string_hash_ops); + if (!ntp) + return -ENOMEM; + + sip = ordered_set_new(&string_hash_ops); + if (!sip) + return -ENOMEM; + + search_domains = ordered_set_new(&dns_name_hash_ops); + if (!search_domains) + return -ENOMEM; + + route_domains = ordered_set_new(&dns_name_hash_ops); + if (!route_domains) + return -ENOMEM; + + HASHMAP_FOREACH(link, m->links) { + const struct in_addr *addresses; + + if (link->flags & IFF_LOOPBACK) + continue; + + if (link->operstate > operstate) + operstate = link->operstate; + + if (link->carrier_state > carrier_state) + carrier_state = link->carrier_state; + + if (link->address_state > address_state) + address_state = link->address_state; + + if (!link->network) + continue; + + /* First add the static configured entries */ + if (link->n_dns != UINT_MAX) + r = ordered_set_put_dns_servers(dns, link->ifindex, link->dns, link->n_dns); + else + r = ordered_set_put_dns_servers(dns, link->ifindex, link->network->dns, link->network->n_dns); + if (r < 0) + return r; + + r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp); + if (r < 0) + return r; + + r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains); + if (r < 0) + return r; + + r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains); + if (r < 0) + return r; + + if (!link->dhcp_lease) + continue; + + /* Secondly, add the entries acquired via DHCP */ + if (link->network->dhcp_use_dns) { + r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses); + if (r > 0) { + r = ordered_set_put_in4_addrv(dns, addresses, r, in4_addr_is_non_local); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_use_ntp) { + r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses); + if (r > 0) { + r = ordered_set_put_in4_addrv(ntp, addresses, r, in4_addr_is_non_local); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_use_sip) { + r = sd_dhcp_lease_get_sip(link->dhcp_lease, &addresses); + if (r > 0) { + r = ordered_set_put_in4_addrv(sip, addresses, r, in4_addr_is_non_local); + if (r < 0) + return r; + } else if (r < 0 && r != -ENODATA) + return r; + } + + if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { + const char *domainname; + char **domains = NULL; + + OrderedSet *target_domains = (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) ? search_domains : route_domains; + r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname); + if (r >= 0) { + r = ordered_set_put_strdup(target_domains, domainname); + if (r < 0) + return r; + } else if (r != -ENODATA) + return r; + + r = sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains); + if (r >= 0) { + r = ordered_set_put_strdupv(target_domains, domains); + if (r < 0) + return r; + } else if (r != -ENODATA) + return r; + } + } + + if (carrier_state >= LINK_CARRIER_STATE_ENSLAVED) + carrier_state = LINK_CARRIER_STATE_CARRIER; + + operstate_str = link_operstate_to_string(operstate); + assert(operstate_str); + + carrier_state_str = link_carrier_state_to_string(carrier_state); + assert(carrier_state_str); + + address_state_str = link_address_state_to_string(address_state); + assert(address_state_str); + + r = fopen_temporary(m->state_file, &f, &temp_path); + if (r < 0) + return r; + + (void) fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "OPER_STATE=%s\n" + "CARRIER_STATE=%s\n" + "ADDRESS_STATE=%s\n", + operstate_str, carrier_state_str, address_state_str); + + ordered_set_print(f, "DNS=", dns); + ordered_set_print(f, "NTP=", ntp); + ordered_set_print(f, "SIP=", sip); + ordered_set_print(f, "DOMAINS=", search_domains); + ordered_set_print(f, "ROUTE_DOMAINS=", route_domains); + + r = fflush_and_check(f); + if (r < 0) + return r; + + r = conservative_rename(temp_path, m->state_file); + if (r < 0) + return r; + + temp_path = mfree(temp_path); + + if (m->operational_state != operstate) { + m->operational_state = operstate; + if (strv_extend(&p, "OperationalState") < 0) + log_oom(); + } + + if (m->carrier_state != carrier_state) { + m->carrier_state = carrier_state; + if (strv_extend(&p, "CarrierState") < 0) + log_oom(); + } + + if (m->address_state != address_state) { + m->address_state = address_state; + if (strv_extend(&p, "AddressState") < 0) + log_oom(); + } + + if (p) { + r = manager_send_changed_strv(m, p); + if (r < 0) + log_warning_errno(r, "Could not emit changed properties, ignoring: %m"); + } + + m->dirty = false; + + return 0; +} + +static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) { + bool space = false; + Link *link; + + assert(f); + assert(prefix); + + if (hashmap_isempty(h)) + return; + + fputs(prefix, f); + HASHMAP_FOREACH(link, h) { + if (space) + fputc(' ', f); + + fprintf(f, "%i", link->ifindex); + space = true; + } + + fputc('\n', f); +} + +static void link_save_dns(Link *link, FILE *f, struct in_addr_full **dns, unsigned n_dns, bool *space) { + for (unsigned j = 0; j < n_dns; j++) { + const char *str; + + if (dns[j]->ifindex != 0 && dns[j]->ifindex != link->ifindex) + continue; + + str = in_addr_full_to_string(dns[j]); + if (!str) + continue; + + if (*space) + fputc(' ', f); + fputs(str, f); + *space = true; + } +} + +static void serialize_addresses( + FILE *f, + const char *lvalue, + bool *space, + char **addresses, + sd_dhcp_lease *lease, + bool conditional, + sd_dhcp_lease_server_type_t what, + sd_dhcp6_lease *lease6, + bool conditional6, + int (*lease6_get_addr)(sd_dhcp6_lease*, const struct in6_addr**), + int (*lease6_get_fqdn)(sd_dhcp6_lease*, char ***)) { + + bool _space = false; + int r; + + if (!space) + space = &_space; + + if (lvalue) + fprintf(f, "%s=", lvalue); + fputstrv(f, addresses, NULL, space); + + if (lease && conditional) { + const struct in_addr *lease_addresses; + + r = sd_dhcp_lease_get_servers(lease, what, &lease_addresses); + if (r > 0) + serialize_in_addrs(f, lease_addresses, r, space, in4_addr_is_non_local); + } + + if (lease6 && conditional6 && lease6_get_addr) { + const struct in6_addr *in6_addrs; + + r = lease6_get_addr(lease6, &in6_addrs); + if (r > 0) + serialize_in6_addrs(f, in6_addrs, r, space); + } + + if (lease6 && conditional6 && lease6_get_fqdn) { + char **in6_hosts; + + r = lease6_get_fqdn(lease6, &in6_hosts); + if (r > 0) + fputstrv(f, in6_hosts, NULL, space); + } + + if (lvalue) + fputc('\n', f); +} + +int link_save(Link *link) { + const char *admin_state, *oper_state, *carrier_state, *address_state; + _cleanup_(unlink_and_freep) char *temp_path = NULL; + _cleanup_fclose_ FILE *f = NULL; + int r; + + assert(link); + assert(link->state_file); + assert(link->lease_file); + assert(link->manager); + + if (link->state == LINK_STATE_LINGER) + return 0; + + link_lldp_save(link); + + admin_state = link_state_to_string(link->state); + assert(admin_state); + + oper_state = link_operstate_to_string(link->operstate); + assert(oper_state); + + carrier_state = link_carrier_state_to_string(link->carrier_state); + assert(carrier_state); + + address_state = link_address_state_to_string(link->address_state); + assert(address_state); + + r = fopen_temporary(link->state_file, &f, &temp_path); + if (r < 0) + return r; + + (void) fchmod(fileno(f), 0644); + + fprintf(f, + "# This is private data. Do not parse.\n" + "ADMIN_STATE=%s\n" + "OPER_STATE=%s\n" + "CARRIER_STATE=%s\n" + "ADDRESS_STATE=%s\n", + admin_state, oper_state, carrier_state, address_state); + + if (link->network) { + char **dhcp6_domains = NULL, **dhcp_domains = NULL; + const char *dhcp_domainname = NULL, *p; + bool space; + + fprintf(f, "REQUIRED_FOR_ONLINE=%s\n", + yes_no(link->network->required_for_online)); + + LinkOperationalStateRange st = link->network->required_operstate_for_online; + fprintf(f, "REQUIRED_OPER_STATE_FOR_ONLINE=%s%s%s\n", + strempty(link_operstate_to_string(st.min)), + st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? ":" : "", + st.max != LINK_OPERSTATE_RANGE_DEFAULT.max ? strempty(link_operstate_to_string(st.max)) : ""); + + fprintf(f, "ACTIVATION_POLICY=%s\n", + activation_policy_to_string(link->network->activation_policy)); + + fprintf(f, "NETWORK_FILE=%s\n", link->network->filename); + + /************************************************************/ + + fputs("DNS=", f); + space = false; + if (link->n_dns != UINT_MAX) + link_save_dns(link, f, link->dns, link->n_dns, &space); + else + link_save_dns(link, f, link->network->dns, link->network->n_dns, &space); + + serialize_addresses(f, NULL, &space, + NULL, + link->dhcp_lease, + link->network->dhcp_use_dns, + SD_DHCP_LEASE_DNS, + link->dhcp6_lease, + link->network->dhcp6_use_dns, + sd_dhcp6_lease_get_dns, + NULL); + + /* Make sure to flush out old entries before we use the NDisc data */ + ndisc_vacuum(link); + + if (link->network->ipv6_accept_ra_use_dns && link->ndisc_rdnss) { + NDiscRDNSS *dd; + + SET_FOREACH(dd, link->ndisc_rdnss) + serialize_in6_addrs(f, &dd->address, 1, &space); + } + + fputc('\n', f); + + /************************************************************/ + + serialize_addresses(f, "NTP", NULL, + link->ntp ?: link->network->ntp, + link->dhcp_lease, + link->network->dhcp_use_ntp, + SD_DHCP_LEASE_NTP, + link->dhcp6_lease, + link->network->dhcp6_use_ntp, + sd_dhcp6_lease_get_ntp_addrs, + sd_dhcp6_lease_get_ntp_fqdn); + + serialize_addresses(f, "SIP", NULL, + NULL, + link->dhcp_lease, + link->network->dhcp_use_sip, + SD_DHCP_LEASE_SIP, + NULL, false, NULL, NULL); + + /************************************************************/ + + if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) { + if (link->dhcp_lease) { + (void) sd_dhcp_lease_get_domainname(link->dhcp_lease, &dhcp_domainname); + (void) sd_dhcp_lease_get_search_domains(link->dhcp_lease, &dhcp_domains); + } + if (link->dhcp6_lease) + (void) sd_dhcp6_lease_get_domains(link->dhcp6_lease, &dhcp6_domains); + } + + fputs("DOMAINS=", f); + space = false; + ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains) + fputs_with_space(f, p, NULL, &space); + + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) { + if (dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + if (dhcp_domains) + fputstrv(f, dhcp_domains, NULL, &space); + if (dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + } + + if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_YES) { + NDiscDNSSL *dd; + + SET_FOREACH(dd, link->ndisc_dnssl) + fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + } + + fputc('\n', f); + + /************************************************************/ + + fputs("ROUTE_DOMAINS=", f); + space = false; + ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains) + fputs_with_space(f, p, NULL, &space); + + if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) { + if (dhcp_domainname) + fputs_with_space(f, dhcp_domainname, NULL, &space); + if (dhcp_domains) + fputstrv(f, dhcp_domains, NULL, &space); + if (dhcp6_domains) + fputstrv(f, dhcp6_domains, NULL, &space); + } + + if (link->network->ipv6_accept_ra_use_domains == DHCP_USE_DOMAINS_ROUTE) { + NDiscDNSSL *dd; + + SET_FOREACH(dd, link->ndisc_dnssl) + fputs_with_space(f, NDISC_DNSSL_DOMAIN(dd), NULL, &space); + } + + fputc('\n', f); + + /************************************************************/ + + fprintf(f, "LLMNR=%s\n", + resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr)); + + /************************************************************/ + + fprintf(f, "MDNS=%s\n", + resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns)); + + /************************************************************/ + + int dns_default_route = + link->dns_default_route >= 0 ? link->dns_default_route : + link->network->dns_default_route; + if (dns_default_route >= 0) + fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(dns_default_route)); + + /************************************************************/ + + DnsOverTlsMode dns_over_tls_mode = + link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID ? link->dns_over_tls_mode : + link->network->dns_over_tls_mode; + if (dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID) + fprintf(f, "DNS_OVER_TLS=%s\n", dns_over_tls_mode_to_string(dns_over_tls_mode)); + + /************************************************************/ + + DnssecMode dnssec_mode = + link->dnssec_mode != _DNSSEC_MODE_INVALID ? link->dnssec_mode : + link->network->dnssec_mode; + if (dnssec_mode != _DNSSEC_MODE_INVALID) + fprintf(f, "DNSSEC=%s\n", dnssec_mode_to_string(dnssec_mode)); + + /************************************************************/ + + Set *nta_anchors = link->dnssec_negative_trust_anchors; + if (set_isempty(nta_anchors)) + nta_anchors = link->network->dnssec_negative_trust_anchors; + + if (!set_isempty(nta_anchors)) { + const char *n; + + fputs("DNSSEC_NTA=", f); + space = false; + SET_FOREACH(n, nta_anchors) + fputs_with_space(f, n, NULL, &space); + fputc('\n', f); + } + } + + print_link_hashmap(f, "CARRIER_BOUND_TO=", link->bound_to_links); + print_link_hashmap(f, "CARRIER_BOUND_BY=", link->bound_by_links); + + if (link->dhcp_lease) { + r = dhcp_lease_save(link->dhcp_lease, link->lease_file); + if (r < 0) + return r; + + fprintf(f, + "DHCP_LEASE=%s\n", + link->lease_file); + } else + (void) unlink(link->lease_file); + + r = link_serialize_dhcp6_client(link, f); + if (r < 0) + return r; + + r = fflush_and_check(f); + if (r < 0) + return r; + + r = conservative_rename(temp_path, link->state_file); + if (r < 0) + return r; + + temp_path = mfree(temp_path); + + return 0; +} + +void link_dirty(Link *link) { + int r; + + assert(link); + assert(link->manager); + + /* The serialized state in /run is no longer up-to-date. */ + + /* Also mark manager dirty as link is dirty */ + link->manager->dirty = true; + + r = set_ensure_put(&link->manager->dirty_links, NULL, link); + if (r <= 0) + /* Ignore allocation errors and don't take another ref if the link was already dirty */ + return; + link_ref(link); +} + +void link_clean(Link *link) { + assert(link); + assert(link->manager); + + /* The serialized state in /run is up-to-date */ + + link_unref(set_remove(link->manager->dirty_links, link)); +} + +int link_save_and_clean(Link *link) { + int r; + + r = link_save(link); + if (r < 0) + return r; + + link_clean(link); + return 0; +} diff --git a/src/network/networkd-state-file.h b/src/network/networkd-state-file.h new file mode 100644 index 000000000..44a109fdf --- /dev/null +++ b/src/network/networkd-state-file.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +typedef struct Link Link; +typedef struct Manager Manager; + +void link_dirty(Link *link); +void link_clean(Link *link); +int link_save(Link *link); +int link_save_and_clean(Link *link); + +int manager_save(Manager *m); diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index bde0cec38..11681286e 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -173,6 +173,18 @@ static int link_set_ipv4_accept_local(Link *link) { return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "accept_local", link->network->ipv4_accept_local > 0); } +static int link_set_ipv4_route_localnet(Link *link) { + assert(link); + + if (link->flags & IFF_LOOPBACK) + return 0; + + if (link->network->ipv4_route_localnet < 0) + return 0; + + return sysctl_write_ip_property_boolean(AF_INET, link->ifname, "route_localnet", link->network->ipv4_route_localnet > 0); +} + int link_set_sysctl(Link *link) { int r; @@ -216,6 +228,19 @@ int link_set_sysctl(Link *link) { if (r < 0) log_link_warning_errno(link, r, "Cannot set IPv4 accept_local flag for interface, ignoring: %m"); + r = link_set_ipv4_route_localnet(link); + if (r < 0) + log_link_warning_errno(link, r, "Cannot set IPv4 route_localnet flag for interface, ignoring: %m"); + + /* If promote_secondaries is not set, DHCP will work only as long as the IP address does not + * changes between leases. The kernel will remove all secondary IP addresses of an interface + * otherwise. The way systemd-networkd works is that the new IP of a lease is added as a + * secondary IP and when the primary one expires it relies on the kernel to promote the + * secondary IP. See also https://github.com/systemd/systemd/issues/7163 */ + r = sysctl_write_ip_property_boolean(AF_INET, link->ifname, "promote_secondaries", true); + if (r < 0) + log_link_warning_errno(link, r, "Cannot enable promote_secondaries for interface, ignoring: %m"); + return 0; } diff --git a/src/network/networkd-sysctl.h b/src/network/networkd-sysctl.h index 3568900a1..cb1db10fe 100644 --- a/src/network/networkd-sysctl.h +++ b/src/network/networkd-sysctl.h @@ -13,7 +13,7 @@ typedef enum IPv6PrivacyExtensions { IPV6_PRIVACY_EXTENSIONS_PREFER_PUBLIC, IPV6_PRIVACY_EXTENSIONS_YES, /* aka prefer-temporary */ _IPV6_PRIVACY_EXTENSIONS_MAX, - _IPV6_PRIVACY_EXTENSIONS_INVALID = -1, + _IPV6_PRIVACY_EXTENSIONS_INVALID = -EINVAL, } IPv6PrivacyExtensions; int link_set_sysctl(Link *link); diff --git a/src/network/networkd-util.c b/src/network/networkd-util.c index 8ddcbb2fc..a9dd6d45e 100644 --- a/src/network/networkd-util.c +++ b/src/network/networkd-util.c @@ -9,32 +9,42 @@ #include "util.h" static const char* const address_family_table[_ADDRESS_FAMILY_MAX] = { - [ADDRESS_FAMILY_NO] = "no", - [ADDRESS_FAMILY_YES] = "yes", - [ADDRESS_FAMILY_IPV4] = "ipv4", - [ADDRESS_FAMILY_IPV6] = "ipv6", -}; - -static const char* const link_local_address_family_table[_ADDRESS_FAMILY_MAX] = { - [ADDRESS_FAMILY_NO] = "no", - [ADDRESS_FAMILY_YES] = "yes", - [ADDRESS_FAMILY_IPV4] = "ipv4", - [ADDRESS_FAMILY_IPV6] = "ipv6", - [ADDRESS_FAMILY_FALLBACK] = "fallback", - [ADDRESS_FAMILY_FALLBACK_IPV4] = "ipv4-fallback", + [ADDRESS_FAMILY_NO] = "no", + [ADDRESS_FAMILY_YES] = "yes", + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", }; static const char* const routing_policy_rule_address_family_table[_ADDRESS_FAMILY_MAX] = { - [ADDRESS_FAMILY_YES] = "both", - [ADDRESS_FAMILY_IPV4] = "ipv4", - [ADDRESS_FAMILY_IPV6] = "ipv6", + [ADDRESS_FAMILY_YES] = "both", + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", +}; + +static const char* const nexthop_address_family_table[_ADDRESS_FAMILY_MAX] = { + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", }; static const char* const duplicate_address_detection_address_family_table[_ADDRESS_FAMILY_MAX] = { - [ADDRESS_FAMILY_NO] = "none", - [ADDRESS_FAMILY_YES] = "both", - [ADDRESS_FAMILY_IPV4] = "ipv4", - [ADDRESS_FAMILY_IPV6] = "ipv6", + [ADDRESS_FAMILY_NO] = "none", + [ADDRESS_FAMILY_YES] = "both", + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", +}; + +static const char* const dhcp_deprecated_address_family_table[_ADDRESS_FAMILY_MAX] = { + [ADDRESS_FAMILY_NO] = "none", + [ADDRESS_FAMILY_YES] = "both", + [ADDRESS_FAMILY_IPV4] = "v4", + [ADDRESS_FAMILY_IPV6] = "v6", +}; + +static const char* const ip_masquerade_address_family_table[_ADDRESS_FAMILY_MAX] = { + [ADDRESS_FAMILY_NO] = "no", + [ADDRESS_FAMILY_YES] = "both", + [ADDRESS_FAMILY_IPV4] = "ipv4", + [ADDRESS_FAMILY_IPV6] = "ipv6", }; static const char* const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE_MAX] = { @@ -47,12 +57,23 @@ static const char* const dhcp_lease_server_type_table[_SD_DHCP_LEASE_SERVER_TYPE }; DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(address_family, AddressFamily, ADDRESS_FAMILY_YES); -DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(link_local_address_family, AddressFamily, ADDRESS_FAMILY_YES); + +AddressFamily link_local_address_family_from_string(const char *s) { + if (streq_ptr(s, "fallback")) /* compat name */ + return ADDRESS_FAMILY_YES; + if (streq_ptr(s, "fallback-ipv4")) /* compat name */ + return ADDRESS_FAMILY_IPV4; + return address_family_from_string(s); +} + DEFINE_STRING_TABLE_LOOKUP(routing_policy_rule_address_family, AddressFamily); +DEFINE_STRING_TABLE_LOOKUP(nexthop_address_family, AddressFamily); DEFINE_STRING_TABLE_LOOKUP(duplicate_address_detection_address_family, AddressFamily); DEFINE_CONFIG_PARSE_ENUM(config_parse_link_local_address_family, link_local_address_family, AddressFamily, "Failed to parse option"); -DEFINE_STRING_TABLE_LOOKUP(dhcp_lease_server_type, sd_dhcp_lease_server_type); +DEFINE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_deprecated_address_family, AddressFamily); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(ip_masquerade_address_family, AddressFamily); +DEFINE_STRING_TABLE_LOOKUP(dhcp_lease_server_type, sd_dhcp_lease_server_type_t); int config_parse_address_family_with_kernel( const char* unit, @@ -96,6 +117,49 @@ int config_parse_address_family_with_kernel( return 0; } +int config_parse_ip_masquerade( + 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) { + + AddressFamily a, *ret = data; + int r; + + if (isempty(rvalue)) { + *ret = ADDRESS_FAMILY_NO; + return 0; + } + + r = parse_boolean(rvalue); + if (r >= 0) { + if (r) + log_syntax(unit, LOG_WARNING, filename, line, 0, + "IPMasquerade=%s is deprecated, and it is handled as \"ipv4\" instead of \"both\". " + "Please use \"ipv4\" or \"both\".", + rvalue); + + *ret = r ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_NO; + return 0; + } + + a = ip_masquerade_address_family_from_string(rvalue); + if (a < 0) { + log_syntax(unit, LOG_WARNING, filename, line, a, + "Failed to parse IPMasquerade= setting, ignoring assignment: %s", rvalue); + return 0; + } + + *ret = a; + return 0; +} + /* Router lifetime can be set with netlink interface since kernel >= 4.5 * so for the supported kernel we don't need to expire routes in userspace */ int kernel_route_expiration_supported(void) { @@ -148,10 +212,6 @@ int network_config_section_new(const char *filename, unsigned line, NetworkConfi return 0; } -void network_config_section_free(NetworkConfigSection *cs) { - free(cs); -} - unsigned hashmap_find_free_section_line(Hashmap *hashmap) { NetworkConfigSection *cs; unsigned n = 0; diff --git a/src/network/networkd-util.h b/src/network/networkd-util.h index 6100a0031..01675e8b5 100644 --- a/src/network/networkd-util.h +++ b/src/network/networkd-util.h @@ -16,10 +16,8 @@ typedef enum AddressFamily { ADDRESS_FAMILY_IPV4 = 1 << 0, ADDRESS_FAMILY_IPV6 = 1 << 1, ADDRESS_FAMILY_YES = ADDRESS_FAMILY_IPV4 | ADDRESS_FAMILY_IPV6, - ADDRESS_FAMILY_FALLBACK_IPV4 = 1 << 2, - ADDRESS_FAMILY_FALLBACK = ADDRESS_FAMILY_FALLBACK_IPV4 | ADDRESS_FAMILY_IPV6, _ADDRESS_FAMILY_MAX, - _ADDRESS_FAMILY_INVALID = -1, + _ADDRESS_FAMILY_INVALID = -EINVAL, } AddressFamily; typedef struct NetworkConfigSection { @@ -30,27 +28,35 @@ typedef struct NetworkConfigSection { CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family); CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel); +CONFIG_PARSER_PROTOTYPE(config_parse_ip_masquerade); const char *address_family_to_string(AddressFamily b) _const_; AddressFamily address_family_from_string(const char *s) _pure_; -const char *link_local_address_family_to_string(AddressFamily b) _const_; AddressFamily link_local_address_family_from_string(const char *s) _pure_; const char *routing_policy_rule_address_family_to_string(AddressFamily b) _const_; AddressFamily routing_policy_rule_address_family_from_string(const char *s) _pure_; +const char *nexthop_address_family_to_string(AddressFamily b) _const_; +AddressFamily nexthop_address_family_from_string(const char *s) _pure_; + const char *duplicate_address_detection_address_family_to_string(AddressFamily b) _const_; AddressFamily duplicate_address_detection_address_family_from_string(const char *s) _pure_; -const char *dhcp_lease_server_type_to_string(sd_dhcp_lease_server_type t) _const_; -sd_dhcp_lease_server_type dhcp_lease_server_type_from_string(const char *s) _pure_; +AddressFamily dhcp_deprecated_address_family_from_string(const char *s) _pure_; + +const char *dhcp_lease_server_type_to_string(sd_dhcp_lease_server_type_t t) _const_; +sd_dhcp_lease_server_type_t dhcp_lease_server_type_from_string(const char *s) _pure_; int kernel_route_expiration_supported(void); -int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s); -void network_config_section_free(NetworkConfigSection *network); +static inline NetworkConfigSection* network_config_section_free(NetworkConfigSection *cs) { + return mfree(cs); +} DEFINE_TRIVIAL_CLEANUP_FUNC(NetworkConfigSection*, network_config_section_free); + +int network_config_section_new(const char *filename, unsigned line, NetworkConfigSection **s); extern const struct hash_ops network_config_hash_ops; unsigned hashmap_find_free_section_line(Hashmap *hashmap); @@ -64,13 +70,14 @@ static inline bool section_is_invalid(NetworkConfigSection *section) { } #define DEFINE_NETWORK_SECTION_FUNCTIONS(type, free_func) \ - static inline void free_func##_or_set_invalid(type *p) { \ + static inline type* free_func##_or_set_invalid(type *p) { \ assert(p); \ \ if (p->section) \ p->section->invalid = true; \ else \ free_func(p); \ + return NULL; \ } \ DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func); \ DEFINE_TRIVIAL_CLEANUP_FUNC(type*, free_func##_or_set_invalid); diff --git a/src/network/networkd-wifi.c b/src/network/networkd-wifi.c index 0f2def7a1..57e8a0e9b 100644 --- a/src/network/networkd-wifi.c +++ b/src/network/networkd-wifi.c @@ -16,6 +16,8 @@ #include "wifi-util.h" int wifi_get_info(Link *link) { + _cleanup_free_ char *ssid = NULL; + enum nl80211_iftype iftype; const char *type; int r, s = 0; @@ -33,16 +35,18 @@ int wifi_get_info(Link *link) { if (!streq(type, "wlan")) return 0; - _cleanup_free_ char *ssid = NULL; - r = wifi_get_interface(link->manager->genl, link->ifindex, &link->wlan_iftype, &ssid); + r = wifi_get_interface(link->manager->genl, link->ifindex, &iftype, &ssid); if (r < 0) return r; - if (r > 0 && streq_ptr(link->ssid, ssid)) + if (r > 0 && link->wlan_iftype == iftype && streq_ptr(link->ssid, ssid)) r = 0; + + link->wlan_iftype = iftype; free_and_replace(link->ssid, ssid); if (link->wlan_iftype == NL80211_IFTYPE_STATION) { struct ether_addr old_bssid = link->bssid; + s = wifi_get_station(link->manager->genl, link->ifindex, &link->bssid); if (s < 0) return s; @@ -56,7 +60,9 @@ int wifi_get_info(Link *link) { if (link->wlan_iftype == NL80211_IFTYPE_STATION && link->ssid) log_link_info(link, "Connected WiFi access point: %s (%s)", link->ssid, ether_addr_to_string(&link->bssid, buf)); - return 1; + + return 1; /* Some information is updated. */ } - return 0; + + return 0; /* No new information. */ } diff --git a/src/network/networkd.c b/src/network/networkd.c index b448d9b01..48f6061b1 100644 --- a/src/network/networkd.c +++ b/src/network/networkd.c @@ -9,6 +9,7 @@ #include "capability-util.h" #include "daemon-util.h" +#include "firewall-util.h" #include "main-func.h" #include "mkdir.h" #include "networkd-conf.h" @@ -21,7 +22,7 @@ static int run(int argc, char *argv[]) { _cleanup_(notify_on_cleanup) const char *notify_message = NULL; int r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/network/networkd.conf b/src/network/networkd.conf index 5339e5e5e..4850ba61f 100644 --- a/src/network/networkd.conf +++ b/src/network/networkd.conf @@ -1,15 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See networkd.conf(5) for details +# See networkd.conf(5) for details. [Network] #SpeedMeter=no diff --git a/src/network/systemd-networkd.pkla b/src/network/systemd-networkd.pkla index 4d1bb4585..c56ea1b54 100644 --- a/src/network/systemd-networkd.pkla +++ b/src/network/systemd-networkd.pkla @@ -1,3 +1,6 @@ +# This file is part of systemd. +# See systemd-networkd.service(8) and polkit(8) for more information. + [Allow systemd-networkd to set timezone and transient hostname] Identity=unix-user:systemd-network Action=org.freedesktop.hostname1.set-hostname;org.freedesktop.hostname1.get-product-uuid;org.freedesktop.timedate1.set-timezone; diff --git a/src/network/systemd-networkd.rules b/src/network/systemd-networkd.rules index b9077c1ea..86cc84990 100644 --- a/src/network/systemd-networkd.rules +++ b/src/network/systemd-networkd.rules @@ -1,3 +1,6 @@ +// This file is part of systemd. +// See systemd-networkd.service(8) and polkit(8) for more information. + // Allow systemd-networkd to set timezone, get product UUID, // and transient hostname polkit.addRule(function(action, subject) { diff --git a/src/network/tc/cake.c b/src/network/tc/cake.c index 76fb718f9..70dd095e9 100644 --- a/src/network/tc/cake.c +++ b/src/network/tc/cake.c @@ -79,7 +79,7 @@ int config_parse_cake_bandwidth( if (isempty(rvalue)) { c->bandwidth = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -92,7 +92,7 @@ int config_parse_cake_bandwidth( } c->bandwidth = k/8; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -133,7 +133,7 @@ int config_parse_cake_overhead( if (isempty(rvalue)) { c->overhead = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -152,7 +152,7 @@ int config_parse_cake_overhead( } c->overhead = v; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/drr.c b/src/network/tc/drr.c index 86b7f4331..ab67b0ad3 100644 --- a/src/network/tc/drr.c +++ b/src/network/tc/drr.c @@ -79,7 +79,7 @@ int config_parse_drr_size( if (isempty(rvalue)) { drr->quantum = 0; - tclass = NULL; + TAKE_PTR(tclass); return 0; } @@ -98,7 +98,7 @@ int config_parse_drr_size( drr->quantum = (uint32_t) u; - tclass = NULL; + TAKE_PTR(tclass); return 0; } diff --git a/src/network/tc/fifo.c b/src/network/tc/fifo.c index 8b1fa6ee4..3aa957373 100644 --- a/src/network/tc/fifo.c +++ b/src/network/tc/fifo.c @@ -87,7 +87,7 @@ int config_parse_pfifo_size( if (isempty(rvalue)) { fifo->limit = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -99,7 +99,7 @@ int config_parse_pfifo_size( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -140,7 +140,7 @@ int config_parse_bfifo_size( if (isempty(rvalue)) { fifo->limit = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -159,7 +159,7 @@ int config_parse_bfifo_size( fifo->limit = (uint32_t) u; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/fq-codel.c b/src/network/tc/fq-codel.c index 958f65a28..bcc734df9 100644 --- a/src/network/tc/fq-codel.c +++ b/src/network/tc/fq-codel.c @@ -138,7 +138,7 @@ int config_parse_fair_queueing_controlled_delay_u32( if (isempty(rvalue)) { *p = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -150,7 +150,7 @@ int config_parse_fair_queueing_controlled_delay_u32( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -204,7 +204,7 @@ int config_parse_fair_queueing_controlled_delay_usec( else *p = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -216,7 +216,7 @@ int config_parse_fair_queueing_controlled_delay_usec( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -257,7 +257,7 @@ int config_parse_fair_queueing_controlled_delay_bool( if (isempty(rvalue)) { fqcd->ecn = -1; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -270,7 +270,7 @@ int config_parse_fair_queueing_controlled_delay_bool( } fqcd->ecn = r; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -323,7 +323,7 @@ int config_parse_fair_queueing_controlled_delay_size( else *p = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -342,7 +342,7 @@ int config_parse_fair_queueing_controlled_delay_size( } *p = sz; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/gred.c b/src/network/tc/gred.c index 46a9eadf8..04fcd59e4 100644 --- a/src/network/tc/gred.c +++ b/src/network/tc/gred.c @@ -111,7 +111,7 @@ int config_parse_generic_random_early_detection_u32( if (isempty(rvalue)) { *p = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -129,7 +129,7 @@ int config_parse_generic_random_early_detection_u32( lvalue, rvalue); *p = v; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -169,7 +169,7 @@ int config_parse_generic_random_early_detection_bool( if (isempty(rvalue)) { gred->grio = -1; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -182,7 +182,7 @@ int config_parse_generic_random_early_detection_bool( } gred->grio = r; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/hhf.c b/src/network/tc/hhf.c index 69c02f481..68a4b4571 100644 --- a/src/network/tc/hhf.c +++ b/src/network/tc/hhf.c @@ -74,7 +74,7 @@ int config_parse_heavy_hitter_filter_packet_limit( if (isempty(rvalue)) { hhf->packet_limit = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -86,7 +86,7 @@ int config_parse_heavy_hitter_filter_packet_limit( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/htb.c b/src/network/tc/htb.c index 0969587c4..17455248a 100644 --- a/src/network/tc/htb.c +++ b/src/network/tc/htb.c @@ -80,7 +80,7 @@ int config_parse_hierarchy_token_bucket_default_class( if (isempty(rvalue)) { htb->default_class = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -92,7 +92,7 @@ int config_parse_hierarchy_token_bucket_default_class( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -133,7 +133,7 @@ int config_parse_hierarchy_token_bucket_u32( if (isempty(rvalue)) { htb->rate_to_quantum = HTB_DEFAULT_RATE_TO_QUANTUM; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -145,7 +145,7 @@ int config_parse_hierarchy_token_bucket_u32( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/netem.c b/src/network/tc/netem.c index 454e556d2..2d86d5312 100644 --- a/src/network/tc/netem.c +++ b/src/network/tc/netem.c @@ -94,7 +94,7 @@ int config_parse_network_emulator_delay( else if (STR_IN_SET(lvalue, "DelayJitterSec", "NetworkEmulatorDelayJitterSec")) ne->jitter = USEC_INFINITY; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -111,7 +111,7 @@ int config_parse_network_emulator_delay( else if (STR_IN_SET(lvalue, "DelayJitterSec", "NetworkEmulatorDelayJitterSec")) ne->jitter = u; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -156,7 +156,7 @@ int config_parse_network_emulator_rate( else if (STR_IN_SET(lvalue, "DuplicateRate", "NetworkEmulatorDuplicateRate")) ne->duplicate = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -173,7 +173,7 @@ int config_parse_network_emulator_rate( else if (STR_IN_SET(lvalue, "DuplicateRate", "NetworkEmulatorDuplicateRate")) ne->duplicate = rate; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -212,8 +212,8 @@ int config_parse_network_emulator_packet_limit( if (isempty(rvalue)) { ne->limit = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -225,7 +225,7 @@ int config_parse_network_emulator_packet_limit( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/pie.c b/src/network/tc/pie.c index 695a38171..4fcfe625b 100644 --- a/src/network/tc/pie.c +++ b/src/network/tc/pie.c @@ -73,7 +73,7 @@ int config_parse_pie_packet_limit( if (isempty(rvalue)) { pie->packet_limit = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -85,7 +85,7 @@ int config_parse_pie_packet_limit( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/qdisc.c b/src/network/tc/qdisc.c index 2add12816..2e0f0a12e 100644 --- a/src/network/tc/qdisc.c +++ b/src/network/tc/qdisc.c @@ -126,11 +126,7 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns qdisc->network = network; qdisc->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_allocated(&network->tc_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(network->tc_by_section, qdisc->section, TC(qdisc)); + r = ordered_hashmap_ensure_put(&network->tc_by_section, &network_config_hash_ops, qdisc->section, TC(qdisc)); if (r < 0) return r; @@ -138,9 +134,9 @@ int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, uns return 0; } -void qdisc_free(QDisc *qdisc) { +QDisc* qdisc_free(QDisc *qdisc) { if (!qdisc) - return; + return NULL; if (qdisc->network && qdisc->section) ordered_hashmap_remove(qdisc->network->tc_by_section, qdisc->section); @@ -148,7 +144,7 @@ void qdisc_free(QDisc *qdisc) { network_config_section_free(qdisc->section); free(qdisc->tca_kind); - free(qdisc); + return mfree(qdisc); } static int qdisc_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { @@ -324,7 +320,7 @@ int config_parse_qdisc_parent( } else qdisc->tca_kind = mfree(qdisc->tca_kind); - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -362,7 +358,7 @@ int config_parse_qdisc_handle( if (isempty(rvalue)) { qdisc->handle = TC_H_UNSPEC; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -375,7 +371,7 @@ int config_parse_qdisc_handle( } qdisc->handle = (uint32_t) n << 16; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/qdisc.h b/src/network/tc/qdisc.h index f9a995486..bf2df146a 100644 --- a/src/network/tc/qdisc.h +++ b/src/network/tc/qdisc.h @@ -31,7 +31,7 @@ typedef enum QDiscKind { QDISC_KIND_TBF, QDISC_KIND_TEQL, _QDISC_KIND_MAX, - _QDISC_KIND_INVALID = -1, + _QDISC_KIND_INVALID = -EINVAL, } QDiscKind; typedef struct QDisc { @@ -74,7 +74,7 @@ extern const QDiscVTable * const qdisc_vtable[_QDISC_KIND_MAX]; /* For casting the various qdisc kinds into a qdisc */ #define QDISC(q) (&(q)->meta) -void qdisc_free(QDisc *qdisc); +QDisc* qdisc_free(QDisc *qdisc); int qdisc_new_static(QDiscKind kind, Network *network, const char *filename, unsigned section_line, QDisc **ret); int qdisc_configure(Link *link, QDisc *qdisc); diff --git a/src/network/tc/qfq.c b/src/network/tc/qfq.c index 320f2c1c5..d2e7b875e 100644 --- a/src/network/tc/qfq.c +++ b/src/network/tc/qfq.c @@ -85,7 +85,7 @@ int config_parse_quick_fair_queueing_weight( if (isempty(rvalue)) { qfq->weight = 0; - tclass = NULL; + TAKE_PTR(tclass); return 0; } @@ -105,7 +105,7 @@ int config_parse_quick_fair_queueing_weight( } qfq->weight = v; - tclass = NULL; + TAKE_PTR(tclass); return 0; } @@ -146,7 +146,7 @@ int config_parse_quick_fair_queueing_max_packet( if (isempty(rvalue)) { qfq->max_packet = 0; - tclass = NULL; + TAKE_PTR(tclass); return 0; } @@ -166,7 +166,7 @@ int config_parse_quick_fair_queueing_max_packet( } qfq->max_packet = (uint32_t) v; - tclass = NULL; + TAKE_PTR(tclass); return 0; } diff --git a/src/network/tc/sfb.c b/src/network/tc/sfb.c index 674fdf6ac..a4ca4884b 100644 --- a/src/network/tc/sfb.c +++ b/src/network/tc/sfb.c @@ -84,7 +84,7 @@ int config_parse_stochastic_fair_blue_u32( if (isempty(rvalue)) { sfb->packet_limit = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -96,7 +96,7 @@ int config_parse_stochastic_fair_blue_u32( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/sfq.c b/src/network/tc/sfq.c index 387be83a9..f67ffc186 100644 --- a/src/network/tc/sfq.c +++ b/src/network/tc/sfq.c @@ -67,7 +67,7 @@ int config_parse_stochastic_fairness_queueing_perturb_period( if (isempty(rvalue)) { sfq->perturb_period = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -79,7 +79,7 @@ int config_parse_stochastic_fairness_queueing_perturb_period( return 0; } - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/tbf.c b/src/network/tc/tbf.c index 2d84c5a83..50d14a535 100644 --- a/src/network/tc/tbf.c +++ b/src/network/tc/tbf.c @@ -156,7 +156,7 @@ int config_parse_token_bucket_filter_size( else assert_not_reached("unknown lvalue"); - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -179,7 +179,7 @@ int config_parse_token_bucket_filter_size( else assert_not_reached("unknown lvalue"); - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -227,7 +227,7 @@ int config_parse_token_bucket_filter_rate( if (isempty(rvalue)) { *p = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/tc/tc-util.c b/src/network/tc/tc-util.c index 3e10b50c9..378118294 100644 --- a/src/network/tc/tc-util.c +++ b/src/network/tc/tc-util.c @@ -5,6 +5,7 @@ #include "extract-word.h" #include "fileio.h" #include "parse-util.h" +#include "percent-util.h" #include "tc-util.h" #include "time-util.h" @@ -57,17 +58,17 @@ int tc_time_to_tick(usec_t t, uint32_t *ret) { return 0; } -int parse_tc_percent(const char *s, uint32_t *percent) { +int parse_tc_percent(const char *s, uint32_t *ret_fraction) { int r; assert(s); - assert(percent); + assert(ret_fraction); - r = parse_permille(s); + r = parse_permyriad(s); if (r < 0) return r; - *percent = (double) r / 1000 * UINT32_MAX; + *ret_fraction = (double) r / 10000 * UINT32_MAX; return 0; } diff --git a/src/network/tc/tc.c b/src/network/tc/tc.c index c32b04091..0cd46cf63 100644 --- a/src/network/tc/tc.c +++ b/src/network/tc/tc.c @@ -39,8 +39,15 @@ int link_configure_traffic_control(Link *link) { TrafficControl *tc; int r; + assert(link); + assert(link->network); + + if (link->tc_messages != 0) { + log_link_debug(link, "Traffic control is configuring."); + return 0; + } + link->tc_configured = false; - link->tc_messages = 0; ORDERED_HASHMAP_FOREACH(tc, link->network->tc_by_section) { r = traffic_control_configure(link, tc); diff --git a/src/network/tc/tc.h b/src/network/tc/tc.h index 7fbd74414..badd5227c 100644 --- a/src/network/tc/tc.h +++ b/src/network/tc/tc.h @@ -8,7 +8,7 @@ typedef enum TrafficControlKind { TC_KIND_TCLASS, TC_KIND_FILTER, _TC_KIND_MAX, - _TC_KIND_INVALID = -1, + _TC_KIND_INVALID = -EINVAL, } TrafficControlKind; typedef struct TrafficControl { diff --git a/src/network/tc/tclass.c b/src/network/tc/tclass.c index 21b26b01a..d8145997f 100644 --- a/src/network/tc/tclass.c +++ b/src/network/tc/tclass.c @@ -82,11 +82,7 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u tclass->network = network; tclass->section = TAKE_PTR(n); - r = ordered_hashmap_ensure_allocated(&network->tc_by_section, &network_config_hash_ops); - if (r < 0) - return r; - - r = ordered_hashmap_put(network->tc_by_section, tclass->section, tclass); + r = ordered_hashmap_ensure_put(&network->tc_by_section, &network_config_hash_ops, tclass->section, tclass); if (r < 0) return r; @@ -94,16 +90,16 @@ int tclass_new_static(TClassKind kind, Network *network, const char *filename, u return 0; } -void tclass_free(TClass *tclass) { +TClass* tclass_free(TClass *tclass) { if (!tclass) - return; + return NULL; if (tclass->network && tclass->section) ordered_hashmap_remove(tclass->network->tc_by_section, tclass->section); network_config_section_free(tclass->section); - free(tclass); + return mfree(tclass); } static int tclass_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { @@ -234,7 +230,7 @@ int config_parse_tclass_parent( } } - tclass = NULL; + TAKE_PTR(tclass); return 0; } @@ -271,7 +267,7 @@ int config_parse_tclass_classid( if (isempty(rvalue)) { tclass->classid = TC_H_UNSPEC; - tclass = NULL; + TAKE_PTR(tclass); return 0; } @@ -283,7 +279,7 @@ int config_parse_tclass_classid( return 0; } - tclass = NULL; + TAKE_PTR(tclass); return 0; } diff --git a/src/network/tc/tclass.h b/src/network/tc/tclass.h index f02a6a734..fc91789f3 100644 --- a/src/network/tc/tclass.h +++ b/src/network/tc/tclass.h @@ -13,7 +13,7 @@ typedef enum TClassKind { TCLASS_KIND_HTB, TCLASS_KIND_QFQ, _TCLASS_KIND_MAX, - _TCLASS_KIND_INVALID = -1, + _TCLASS_KIND_INVALID = -EINVAL, } TClassKind; typedef struct TClass { @@ -53,7 +53,7 @@ extern const TClassVTable * const tclass_vtable[_TCLASS_KIND_MAX]; /* For casting the various tclass kinds into a tclass */ #define TCLASS(t) (&(t)->meta) -void tclass_free(TClass *tclass); +TClass* tclass_free(TClass *tclass); int tclass_new_static(TClassKind kind, Network *network, const char *filename, unsigned section_line, TClass **ret); int tclass_configure(Link *link, TClass *tclass); diff --git a/src/network/tc/teql.c b/src/network/tc/teql.c index 0da2fc357..633a7827b 100644 --- a/src/network/tc/teql.c +++ b/src/network/tc/teql.c @@ -68,7 +68,7 @@ int config_parse_trivial_link_equalizer_id( if (isempty(rvalue)) { teql->id = 0; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } @@ -86,6 +86,6 @@ int config_parse_trivial_link_equalizer_id( teql->id = id; - qdisc = NULL; + TAKE_PTR(qdisc); return 0; } diff --git a/src/network/test-network-tables.c b/src/network/test-network-tables.c index 475cac752..ce3444955 100644 --- a/src/network/test-network-tables.c +++ b/src/network/test-network-tables.c @@ -40,10 +40,16 @@ int main(int argc, char **argv) { test_table(wol, WOL); test_table(lldp_event, SD_LLDP_EVENT); test_table(ndisc_event, SD_NDISC_EVENT); + test_table(dhcp_lease_server_type, SD_DHCP_LEASE_SERVER_TYPE); test_table_sparse(ipvlan_mode, NETDEV_IPVLAN_MODE); test_table_sparse(macvlan_mode, NETDEV_MACVLAN_MODE); test_table_sparse(address_family, ADDRESS_FAMILY); + assert_cc(sizeof(sd_lldp_event_t) == sizeof(int64_t)); + assert_cc(sizeof(sd_ndisc_event_t) == sizeof(int64_t)); + assert_cc(sizeof(sd_dhcp_lease_server_type_t) == sizeof(int64_t)); + assert_cc(sizeof(sd_genl_family_t) == sizeof(int64_t)); + return EXIT_SUCCESS; } diff --git a/src/network/test-network.c b/src/network/test-network.c index 03c94409f..25ff3a33a 100644 --- a/src/network/test-network.c +++ b/src/network/test-network.c @@ -8,10 +8,11 @@ #include "alloc-util.h" #include "dhcp-lease-internal.h" #include "ether-addr-util.h" -#include "hostname-util.h" +#include "hostname-setup.h" #include "network-internal.h" #include "networkd-manager.h" #include "string-util.h" +#include "strv.h" #include "tests.h" static void test_deserialize_in_addr(void) { @@ -33,15 +34,15 @@ static void test_deserialize_in_addr(void) { assert_se((size = deserialize_in_addrs(&addresses, addresses_string)) >= 0); assert_se(size == 3); - assert_se(in_addr_equal(AF_INET, &a, (union in_addr_union *) &addresses[0])); - assert_se(in_addr_equal(AF_INET, &b, (union in_addr_union *) &addresses[1])); - assert_se(in_addr_equal(AF_INET, &c, (union in_addr_union *) &addresses[2])); + assert_se(in4_addr_equal(&a.in, &addresses[0])); + assert_se(in4_addr_equal(&b.in, &addresses[1])); + assert_se(in4_addr_equal(&c.in, &addresses[2])); assert_se((size = deserialize_in6_addrs(&addresses6, addresses_string)) >= 0); assert_se(size == 3); - assert_se(in_addr_equal(AF_INET6, &d, (union in_addr_union *) &addresses6[0])); - assert_se(in_addr_equal(AF_INET6, &e, (union in_addr_union *) &addresses6[1])); - assert_se(in_addr_equal(AF_INET6, &f, (union in_addr_union *) &addresses6[2])); + assert_se(in6_addr_equal(&d.in6, &addresses6[0])); + assert_se(in6_addr_equal(&e.in6, &addresses6[1])); + assert_se(in6_addr_equal(&f.in6, &addresses6[2])); } static void test_deserialize_dhcp_routes(void) { @@ -101,6 +102,53 @@ static void test_deserialize_dhcp_routes(void) { } } +static void test_route_tables_one(Manager *manager, const char *name, uint32_t number) { + _cleanup_free_ char *str = NULL, *expected = NULL, *num_str = NULL; + uint32_t t; + + if (!STR_IN_SET(name, "default", "main", "local")) { + assert_se(streq(hashmap_get(manager->route_table_names_by_number, UINT32_TO_PTR(number)), name)); + assert_se(PTR_TO_UINT32(hashmap_get(manager->route_table_numbers_by_name, name)) == number); + } + + assert_se(asprintf(&expected, "%s(%" PRIu32 ")", name, number) >= 0); + assert_se(manager_get_route_table_to_string(manager, number, &str) >= 0); + assert_se(streq(str, expected)); + + assert_se(manager_get_route_table_from_string(manager, name, &t) >= 0); + assert_se(t == number); + + assert_se(asprintf(&num_str, "%" PRIu32, number) >= 0); + assert_se(manager_get_route_table_from_string(manager, num_str, &t) >= 0); + assert_se(t == number); +} + +static void test_route_tables(Manager *manager) { + assert_se(config_parse_route_table_names("manager", "filename", 1, "section", 1, "RouteTable", 0, "hoge:123 foo:456 aaa:111", manager, manager) >= 0); + assert_se(config_parse_route_table_names("manager", "filename", 1, "section", 1, "RouteTable", 0, "bbb:11111 ccc:22222", manager, manager) >= 0); + assert_se(config_parse_route_table_names("manager", "filename", 1, "section", 1, "RouteTable", 0, "ddd:22222", manager, manager) >= 0); + + test_route_tables_one(manager, "hoge", 123); + test_route_tables_one(manager, "foo", 456); + test_route_tables_one(manager, "aaa", 111); + test_route_tables_one(manager, "bbb", 11111); + test_route_tables_one(manager, "ccc", 22222); + + assert_se(!hashmap_get(manager->route_table_numbers_by_name, "ddd")); + + test_route_tables_one(manager, "default", 253); + test_route_tables_one(manager, "main", 254); + test_route_tables_one(manager, "local", 255); + + assert_se(config_parse_route_table_names("manager", "filename", 1, "section", 1, "RouteTable", 0, "", manager, manager) >= 0); + assert_se(!manager->route_table_names_by_number); + assert_se(!manager->route_table_numbers_by_name); + + test_route_tables_one(manager, "default", 253); + test_route_tables_one(manager, "main", 254); + test_route_tables_one(manager, "local", 255); +} + static int test_load_config(Manager *manager) { int r; /* TODO: should_reload, is false if the config dirs do not exist, so @@ -241,6 +289,8 @@ int main(void) { assert_se(manager_new(&manager) >= 0); + test_route_tables(manager); + r = test_load_config(manager); if (r == -EPERM) return log_tests_skipped("Cannot load configuration"); diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c index c77100743..5156fcc7d 100644 --- a/src/network/test-networkd-conf.c +++ b/src/network/test-networkd-conf.c @@ -1,15 +1,12 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "ether-addr-util.h" #include "hexdecoct.h" #include "log.h" #include "macro.h" -#include "set.h" -#include "string-util.h" - -#include "network-internal.h" +#include "net-condition.h" #include "networkd-conf.h" #include "networkd-network.h" +#include "strv.h" static void test_config_parse_duid_type_one(const char *rvalue, int ret, DUIDType expected, usec_t expected_time) { DUID actual = {}; @@ -70,12 +67,11 @@ static void test_config_parse_hwaddr_one(const char *rvalue, int ret, const stru static void test_config_parse_hwaddrs_one(const char *rvalue, const struct ether_addr* list, size_t n) { _cleanup_set_free_free_ Set *s = NULL; - size_t m; assert_se(config_parse_hwaddrs("network", "filename", 1, "section", 1, "lvalue", 0, rvalue, &s, NULL) == 0); assert_se(set_size(s) == n); - for (m = 0; m < n; m++) { + for (size_t m = 0; m < n; m++) { _cleanup_free_ struct ether_addr *q = NULL; assert_se(q = set_remove(s, &list[m])); @@ -174,7 +170,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign assert_se(network = new0(Network, 1)); network->n_ref = 1; assert_se(network->filename = strdup("hogehoge.network")); - assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0); + assert_se(config_parse_match_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match.ifname, network) == 0); assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0); assert_se(ordered_hashmap_size(network->addresses_by_section) == 1); assert_se(network_verify(network) >= 0); diff --git a/src/network/test-routing-policy-rule.c b/src/network/test-routing-policy-rule.c deleted file mode 100644 index 8d87cdf9c..000000000 --- a/src/network/test-routing-policy-rule.c +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "fd-util.h" -#include "fileio.h" -#include "networkd-routing-policy-rule.h" -#include "string-util.h" -#include "tests.h" -#include "tmpfile-util.h" - -static void test_rule_serialization(const char *title, const char *ruleset, const char *expected) { - char pattern[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX", - pattern2[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX", - pattern3[] = "/tmp/systemd-test-routing-policy-rule.XXXXXX"; - const char *cmd; - int fd, fd2, fd3; - _cleanup_fclose_ FILE *f = NULL, *f2 = NULL, *f3 = NULL; - Set *rules = NULL; - _cleanup_free_ char *buf = NULL; - size_t buf_size; - - log_info("========== %s ==========", title); - log_info("put:\n%s\n", ruleset); - - fd = mkostemp_safe(pattern); - assert_se(fd >= 0); - assert_se(f = fdopen(fd, "a+")); - assert_se(write_string_stream(f, ruleset, 0) == 0); - - assert_se(routing_policy_load_rules(pattern, &rules) == 0); - - fd2 = mkostemp_safe(pattern2); - assert_se(fd2 >= 0); - assert_se(f2 = fdopen(fd2, "a+")); - - assert_se(routing_policy_serialize_rules(rules, f2) == 0); - assert_se(fflush_and_check(f2) == 0); - - assert_se(read_full_file(pattern2, &buf, &buf_size) == 0); - - log_info("got:\n%s", buf); - - fd3 = mkostemp_safe(pattern3); - assert_se(fd3 >= 0); - assert_se(f3 = fdopen(fd3, "w")); - assert_se(write_string_stream(f3, expected ?: ruleset, 0) == 0); - - cmd = strjoina("diff -u ", pattern3, " ", pattern2); - log_info("$ %s", cmd); - assert_se(system(cmd) == 0); - - set_free(rules); -} - -int main(int argc, char **argv) { - _cleanup_free_ char *p = NULL; - - test_setup_logging(LOG_DEBUG); - - test_rule_serialization("basic parsing", - "RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 priority=10 fwmark=1/2 invert_rule=yes table=10", NULL); - - test_rule_serialization("ignored values", - "RULE=something=to=ignore from=1.2.3.4/32 from=1.2.3.4/32" - " \t to=2.3.4.5/24 to=2.3.4.5/32 tos=5 fwmark=2 fwmark=1 table=10 table=20", - "RULE=family=AF_INET from=1.2.3.4/32 to=2.3.4.5/32 tos=5 fwmark=1 invert_rule=no table=20"); - - test_rule_serialization("ipv6", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=yes table=6", NULL); - - assert_se(asprintf(&p, "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=no table=%d", RT_TABLE_MAIN) >= 0); - test_rule_serialization("default table", - "RULE=from=1::2/64 to=2::3/64", p); - - test_rule_serialization("incoming interface", - "RULE=from=1::2/64 to=2::3/64 table=1 iif=lo", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 iif=lo invert_rule=no table=1"); - - test_rule_serialization("outgoing interface", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 oif=eth0 invert_rule=no table=1", NULL); - - test_rule_serialization("freeing interface names", - "RULE=from=1::2/64 to=2::3/64 family=AF_INET6 iif=e0 iif=e1 oif=e0 oif=e1 table=1", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 iif=e1 oif=e1 invert_rule=no table=1"); - - test_rule_serialization("ignoring invalid family", - "RULE=from=1::2/64 to=2::3/64 family=AF_UNSEPC family=AF_INET table=1", - "RULE=family=AF_INET6 from=1::2/64 to=2::3/64 invert_rule=no table=1"); - - return 0; -} diff --git a/src/network/wait-online/link.c b/src/network/wait-online/link.c index 529fc9f22..f2d556f09 100644 --- a/src/network/wait-online/link.c +++ b/src/network/wait-online/link.c @@ -15,14 +15,7 @@ int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) { assert(m); assert(ifindex > 0); - - r = hashmap_ensure_allocated(&m->links, NULL); - if (r < 0) - return r; - - r = hashmap_ensure_allocated(&m->links_by_name, &string_hash_ops); - if (r < 0) - return r; + assert(ifname); n = strdup(ifname); if (!n) @@ -39,11 +32,11 @@ int link_new(Manager *m, Link **ret, int ifindex, const char *ifname) { .required_operstate = LINK_OPERSTATE_RANGE_DEFAULT, }; - r = hashmap_put(m->links_by_name, l->ifname, l); + r = hashmap_ensure_put(&m->links, NULL, INT_TO_PTR(ifindex), l); if (r < 0) return r; - r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); + r = hashmap_ensure_put(&m->links_by_name, &string_hash_ops, l->ifname, l); if (r < 0) return r; @@ -137,8 +130,7 @@ int link_update_monitor(Link *l) { s = link_operstate_from_string(operstate); if (s < 0) - ret = log_link_debug_errno(l, SYNTHETIC_ERRNO(EINVAL), - "Failed to parse operational state, ignoring: %m"); + ret = log_link_debug_errno(l, s, "Failed to parse operational state, ignoring: %m"); else l->operational_state = s; } diff --git a/src/network/wait-online/manager.c b/src/network/wait-online/manager.c index 79994bd49..1438b2744 100644 --- a/src/network/wait-online/manager.c +++ b/src/network/wait-online/manager.c @@ -8,7 +8,6 @@ #include "link.h" #include "manager.h" #include "netlink-util.h" -#include "network-internal.h" #include "strv.h" #include "time-util.h" #include "util.h" @@ -208,7 +207,6 @@ static int on_rtnl_event(sd_netlink *rtnl, sd_netlink_message *mm, void *userdat static int manager_rtnl_listen(Manager *m) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL; - sd_netlink_message *i; int r; assert(m); @@ -243,7 +241,7 @@ static int manager_rtnl_listen(Manager *m) { if (r < 0) return r; - for (i = reply; i; i = sd_netlink_message_next(i)) { + for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i)) { r = manager_process_link(m->rtnl, i, m); if (r < 0) return r; @@ -325,12 +323,8 @@ int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, (void) sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL); if (timeout > 0) { - usec_t usec; - - usec = now(clock_boottime_or_monotonic()) + timeout; - - r = sd_event_add_time(m->event, NULL, clock_boottime_or_monotonic(), usec, 0, NULL, INT_TO_PTR(-ETIMEDOUT)); - if (r < 0) + r = sd_event_add_time_relative(m->event, NULL, clock_boottime_or_monotonic(), timeout, 0, NULL, INT_TO_PTR(-ETIMEDOUT)); + if (r < 0 && r != -EOVERFLOW) return r; } @@ -349,21 +343,18 @@ int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, return 0; } -void manager_free(Manager *m) { +Manager* manager_free(Manager *m) { if (!m) - return; + return NULL; hashmap_free_with_destructor(m->links, link_free); hashmap_free(m->links_by_name); sd_event_source_unref(m->network_monitor_event_source); sd_network_monitor_unref(m->network_monitor); - sd_event_source_unref(m->rtnl_event_source); sd_netlink_unref(m->rtnl); - sd_event_unref(m->event); - free(m); - return; + return mfree(m); } diff --git a/src/network/wait-online/manager.h b/src/network/wait-online/manager.h index f5e83532a..9892a43dc 100644 --- a/src/network/wait-online/manager.h +++ b/src/network/wait-online/manager.h @@ -32,7 +32,7 @@ struct Manager { sd_event *event; }; -void manager_free(Manager *m); +Manager* manager_free(Manager *m); int manager_new(Manager **ret, Hashmap *interfaces, char **ignore, LinkOperationalStateRange required_operstate, bool any, usec_t timeout); diff --git a/src/network/wait-online/wait-online.c b/src/network/wait-online/wait-online.c index c2bdcd490..ca0116e7f 100644 --- a/src/network/wait-online/wait-online.c +++ b/src/network/wait-online/wait-online.c @@ -44,10 +44,9 @@ static int help(void) { " Required operational state\n" " --any Wait until at least one of the interfaces is online\n" " --timeout=SECS Maximum time to wait for network connectivity\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -83,11 +82,9 @@ static int parse_interface_with_operstate_range(const char *str) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid interface name '%s'", ifname); - r = hashmap_ensure_allocated(&arg_interfaces, &string_hash_ops); - if (r < 0) + r = hashmap_ensure_put(&arg_interfaces, &string_hash_ops, ifname, TAKE_PTR(range)); + if (r == -ENOMEM) return log_oom(); - - r = hashmap_put(arg_interfaces, ifname, TAKE_PTR(range)); if (r < 0) return log_error_errno(r, "Failed to store interface name: %m"); if (r == 0) @@ -187,7 +184,7 @@ static int run(int argc, char *argv[]) { _cleanup_(notify_on_cleanup) const char *notify_message = NULL; int r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/notify/notify.c b/src/notify/notify.c index 6a506db3a..40cbc296b 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -48,11 +48,11 @@ static int help(void) { " --status=TEXT Set status text\n" " --booted Check if the system was booted up with systemd\n" " --no-block Do not wait until operation finished\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -241,11 +241,11 @@ static int run(int argc, char* argv[]) { ucred data, and sd_pid_notify() uses the real UID for filling in ucred. */ if (arg_gid != GID_INVALID && - setregid(arg_gid, (gid_t) -1) < 0) + setregid(arg_gid, GID_INVALID) < 0) return log_error_errno(errno, "Failed to change GID: %m"); if (arg_uid != UID_INVALID && - setreuid(arg_uid, (uid_t) -1) < 0) + setreuid(arg_uid, UID_INVALID) < 0) return log_error_errno(errno, "Failed to change UID: %m"); if (arg_pid > 0) diff --git a/src/fuzz/fuzz-nspawn-oci.c b/src/nspawn/fuzz-nspawn-oci.c similarity index 100% rename from src/fuzz/fuzz-nspawn-oci.c rename to src/nspawn/fuzz-nspawn-oci.c diff --git a/src/fuzz/fuzz-nspawn-oci.options b/src/nspawn/fuzz-nspawn-oci.options similarity index 100% rename from src/fuzz/fuzz-nspawn-oci.options rename to src/nspawn/fuzz-nspawn-oci.options diff --git a/src/fuzz/fuzz-nspawn-settings.c b/src/nspawn/fuzz-nspawn-settings.c similarity index 100% rename from src/fuzz/fuzz-nspawn-settings.c rename to src/nspawn/fuzz-nspawn-settings.c diff --git a/src/fuzz/fuzz-nspawn-settings.options b/src/nspawn/fuzz-nspawn-settings.options similarity index 100% rename from src/fuzz/fuzz-nspawn-settings.options rename to src/nspawn/fuzz-nspawn-settings.options diff --git a/src/nspawn/meson.build b/src/nspawn/meson.build index 539ed56c3..172ded43c 100644 --- a/src/nspawn/meson.build +++ b/src/nspawn/meson.build @@ -46,6 +46,8 @@ libnspawn_core = static_library( systemd_nspawn_sources = files('nspawn.c') +############################################################ + tests += [ [['src/nspawn/test-nspawn-tables.c'], [libnspawn_core, @@ -56,5 +58,17 @@ tests += [ [libnspawn_core, libshared], [libacl], - '', 'manual'], + [], '', 'manual'], +] + +fuzzers += [ + [['src/nspawn/fuzz-nspawn-settings.c'], + [libshared, + libnspawn_core], + [libseccomp]], + + [['src/nspawn/fuzz-nspawn-oci.c'], + [libshared, + libnspawn_core], + [libseccomp]], ] diff --git a/src/nspawn/nspawn-expose-ports.c b/src/nspawn/nspawn-expose-ports.c index d8a37a339..9d5051d46 100644 --- a/src/nspawn/nspawn-expose-ports.c +++ b/src/nspawn/nspawn-expose-ports.c @@ -2,6 +2,7 @@ #include "sd-netlink.h" +#include "af-list.h" #include "alloc-util.h" #include "fd-util.h" #include "firewall-util.h" @@ -82,45 +83,43 @@ void expose_port_free_all(ExposePort *p) { } } -int expose_port_flush(ExposePort* l, union in_addr_union *exposed) { +int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_addr_union *exposed) { ExposePort *p; - int r, af = AF_INET; + int r; assert(exposed); if (!l) return 0; - if (in_addr_is_null(af, exposed)) + if (!in_addr_is_set(af, exposed)) return 0; log_debug("Lost IP address."); LIST_FOREACH(ports, p, l) { - r = fw_add_local_dnat(false, + r = fw_add_local_dnat(fw_ctx, + false, af, p->protocol, - NULL, - NULL, 0, - NULL, 0, p->host_port, exposed, p->container_port, NULL); if (r < 0) - log_warning_errno(r, "Failed to modify firewall: %m"); + log_warning_errno(r, "Failed to modify %s firewall: %m", af_to_name(af)); } *exposed = IN_ADDR_NULL; return 0; } -int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *exposed) { +int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *l, int af, union in_addr_union *exposed) { _cleanup_free_ struct local_address *addresses = NULL; union in_addr_union new_exposed; ExposePort *p; bool add; - int af = AF_INET, r; + int r; assert(exposed); @@ -139,7 +138,7 @@ int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *ex addresses[0].scope < RT_SCOPE_LINK; if (!add) - return expose_port_flush(l, exposed); + return expose_port_flush(fw_ctx, l, af, exposed); new_exposed = addresses[0].address; if (in_addr_equal(af, exposed, &new_exposed)) @@ -153,18 +152,16 @@ int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *ex LIST_FOREACH(ports, p, l) { - r = fw_add_local_dnat(true, + r = fw_add_local_dnat(fw_ctx, + true, af, p->protocol, - NULL, - NULL, 0, - NULL, 0, p->host_port, &new_exposed, p->container_port, - in_addr_is_null(af, exposed) ? NULL : exposed); + in_addr_is_set(af, exposed) ? exposed : NULL); if (r < 0) - log_warning_errno(r, "Failed to modify firewall: %m"); + log_warning_errno(r, "Failed to modify %s firewall: %m", af_to_name(af)); } *exposed = new_exposed; @@ -194,7 +191,7 @@ int expose_port_watch_rtnl( sd_event *event, int recv_fd, sd_netlink_message_handler_t handler, - union in_addr_union *exposed, + void *userdata, sd_netlink **ret) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int fd, r; @@ -213,11 +210,11 @@ int expose_port_watch_rtnl( return log_error_errno(r, "Failed to create rtnl object: %m"); } - r = sd_netlink_add_match(rtnl, NULL, RTM_NEWADDR, handler, NULL, exposed, "nspawn-NEWADDR"); + r = sd_netlink_add_match(rtnl, NULL, RTM_NEWADDR, handler, NULL, userdata, "nspawn-NEWADDR"); if (r < 0) return log_error_errno(r, "Failed to subscribe to RTM_NEWADDR messages: %m"); - r = sd_netlink_add_match(rtnl, NULL, RTM_DELADDR, handler, NULL, exposed, "nspawn-DELADDR"); + r = sd_netlink_add_match(rtnl, NULL, RTM_DELADDR, handler, NULL, userdata, "nspawn-DELADDR"); if (r < 0) return log_error_errno(r, "Failed to subscribe to RTM_DELADDR messages: %m"); diff --git a/src/nspawn/nspawn-expose-ports.h b/src/nspawn/nspawn-expose-ports.h index cc834a419..27cfccf01 100644 --- a/src/nspawn/nspawn-expose-ports.h +++ b/src/nspawn/nspawn-expose-ports.h @@ -6,6 +6,7 @@ #include "sd-event.h" #include "sd-netlink.h" +#include "firewall-util.h" #include "in-addr-util.h" #include "list.h" @@ -19,8 +20,8 @@ typedef struct ExposePort { void expose_port_free_all(ExposePort *p); int expose_port_parse(ExposePort **l, const char *s); -int expose_port_watch_rtnl(sd_event *event, int recv_fd, sd_netlink_message_handler_t handler, union in_addr_union *exposed, sd_netlink **ret); +int expose_port_watch_rtnl(sd_event *event, int recv_fd, sd_netlink_message_handler_t handler, void *userdata, sd_netlink **ret); int expose_port_send_rtnl(int send_fd); -int expose_port_execute(sd_netlink *rtnl, ExposePort *l, union in_addr_union *exposed); -int expose_port_flush(ExposePort* l, union in_addr_union *exposed); +int expose_port_execute(sd_netlink *rtnl, FirewallContext **fw_ctx, ExposePort *l, int af, union in_addr_union *exposed); +int expose_port_flush(FirewallContext **fw_ctx, ExposePort* l, int af, union in_addr_union *exposed); diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index 79304d21a..315bf3315 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -25,6 +26,7 @@ Exec.Parameters, config_parse_strv, 0, of Exec.Environment, config_parse_strv, 0, offsetof(Settings, environment) Exec.User, config_parse_string, 0, offsetof(Settings, user) Exec.Capability, config_parse_capability, 0, offsetof(Settings, capability) +Exec.AmbientCapability, config_parse_capability, 0, offsetof(Settings, ambient_capability) Exec.DropCapability, config_parse_capability, 0, offsetof(Settings, drop_capability) Exec.KillSignal, config_parse_signal, 0, offsetof(Settings, kill_signal) Exec.Personality, config_parse_personality, 0, offsetof(Settings, personality) diff --git a/src/nspawn/nspawn-mount.c b/src/nspawn/nspawn-mount.c index 2ea1bed36..dbebc49ae 100644 --- a/src/nspawn/nspawn-mount.c +++ b/src/nspawn/nspawn-mount.c @@ -48,9 +48,7 @@ CustomMount* custom_mount_add(CustomMount **l, size_t *n, CustomMountType t) { } void custom_mount_free_all(CustomMount *l, size_t n) { - size_t i; - - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { CustomMount *m = l + i; free(m->source); @@ -94,7 +92,6 @@ static bool source_path_is_valid(const char *p) { } static char *resolve_source_path(const char *dest, const char *source) { - if (!source) return NULL; @@ -129,7 +126,6 @@ static int allocate_temporary_source(CustomMount *m) { } int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) { - size_t i; int r; /* Prepare all custom mounts. This will make source we know all temporary directories. This is called in the @@ -141,7 +137,7 @@ int custom_mount_prepare_all(const char *dest, CustomMount *l, size_t n) { /* Order the custom mounts, and make sure we have a working directory */ typesafe_qsort(l, n, custom_mount_compare); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { CustomMount *m = l + i; /* /proc we mount in the inner child, i.e. when we acquired CLONE_NEWPID. All other mounts we mount @@ -588,10 +584,9 @@ int mount_all(const char *dest, bool ro = FLAGS_SET(mount_settings, MOUNT_APPLY_APIVFS_RO); bool in_userns = FLAGS_SET(mount_settings, MOUNT_IN_USERNS); bool tmpfs_tmp = FLAGS_SET(mount_settings, MOUNT_APPLY_TMPFS_TMP); - size_t k; int r; - for (k = 0; k < ELEMENTSOF(mount_table); k++) { + for (size_t k = 0; k < ELEMENTSOF(mount_table); k++) { _cleanup_free_ char *where = NULL, *options = NULL, *prefixed = NULL; bool fatal = FLAGS_SET(mount_table[k].mount_settings, MOUNT_FATAL); const char *o; @@ -688,7 +683,6 @@ int mount_all(const char *dest, } static int parse_mount_bind_options(const char *options, unsigned long *mount_flags, char **mount_opts) { - const char *p = options; unsigned long flags = *mount_flags; char *opts = NULL; int r; @@ -698,7 +692,7 @@ static int parse_mount_bind_options(const char *options, unsigned long *mount_fl for (;;) { _cleanup_free_ char *word = NULL; - r = extract_first_word(&p, &word, ",", 0); + r = extract_first_word(&options, &word, ",", 0); if (r < 0) return log_error_errno(r, "Failed to extract mount option: %m"); if (r == 0) @@ -708,11 +702,9 @@ static int parse_mount_bind_options(const char *options, unsigned long *mount_fl flags |= MS_REC; else if (streq(word, "norbind")) flags &= ~MS_REC; - else { + else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid bind mount option: %s", - word); - } + "Invalid bind mount option: %s", word); } *mount_flags = flags; @@ -789,7 +781,6 @@ static int mount_bind(const char *dest, CustomMount *m) { } static int mount_tmpfs(const char *dest, CustomMount *m, uid_t uid_shift, const char *selinux_apifs_context) { - const char *options; _cleanup_free_ char *buf = NULL, *where = NULL; int r; @@ -927,13 +918,11 @@ int mount_custom( uid_t uid_shift, const char *selinux_apifs_context, MountSettingsMask mount_settings) { - - size_t i; int r; assert(dest); - for (i = 0; i < n; i++) { + for (size_t i = 0; i < n; i++) { CustomMount *m = mounts + i; if (FLAGS_SET(mount_settings, MOUNT_IN_USERNS) != m->in_userns) @@ -979,20 +968,14 @@ int mount_custom( } bool has_custom_root_mount(const CustomMount *mounts, size_t n) { - size_t i; - - for (i = 0; i < n; i++) { - const CustomMount *m = mounts + i; - - if (path_equal(m->destination, "/")) + for (size_t i = 0; i < n; i++) + if (path_equal(mounts[i].destination, "/")) return true; - } return false; } static int setup_volatile_state(const char *directory, uid_t uid_shift, const char *selinux_apifs_context) { - _cleanup_free_ char *buf = NULL; const char *p, *options; int r; @@ -1021,7 +1004,6 @@ static int setup_volatile_state(const char *directory, uid_t uid_shift, const ch } static int setup_volatile_yes(const char *directory, uid_t uid_shift, const char *selinux_apifs_context) { - bool tmpfs_mounted = false, bind_mounted = false; char template[] = "/tmp/nspawn-volatile-XXXXXX"; _cleanup_free_ char *buf = NULL, *bindir = NULL; @@ -1109,7 +1091,6 @@ fail: } static int setup_volatile_overlay(const char *directory, uid_t uid_shift, const char *selinux_apifs_context) { - _cleanup_free_ char *buf = NULL, *escaped_directory = NULL, *escaped_upper = NULL, *escaped_work = NULL; char template[] = "/tmp/nspawn-volatile-XXXXXX"; const char *upper, *work, *options; diff --git a/src/nspawn/nspawn-mount.h b/src/nspawn/nspawn-mount.h index e8b75fba6..e19b2cc4e 100644 --- a/src/nspawn/nspawn-mount.h +++ b/src/nspawn/nspawn-mount.h @@ -29,7 +29,7 @@ typedef enum CustomMountType { CUSTOM_MOUNT_INACCESSIBLE, CUSTOM_MOUNT_ARBITRARY, _CUSTOM_MOUNT_TYPE_MAX, - _CUSTOM_MOUNT_TYPE_INVALID = -1 + _CUSTOM_MOUNT_TYPE_INVALID = -EINVAL, } CustomMountType; typedef struct CustomMount { diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c index ca708be75..1db69b451 100644 --- a/src/nspawn/nspawn-oci.c +++ b/src/nspawn/nspawn-oci.c @@ -205,7 +205,7 @@ static int oci_rlimit_type(const char *name, JsonVariant *v, JsonDispatchFlags f t = rlimit_from_string(z); if (t < 0) - return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), + return json_log(v, flags, t, "rlimit name unknown: %s", json_variant_string(v)); *type = t; @@ -308,7 +308,7 @@ static int oci_capability_array(const char *name, JsonVariant *v, JsonDispatchFl m |= UINT64_C(1) << cap; } - if (*mask == (uint64_t) -1) + if (*mask == UINT64_MAX) *mask = m; else *mask |= m; @@ -336,7 +336,7 @@ static int oci_capabilities(const char *name, JsonVariant *v, JsonDispatchFlags if (r < 0) return r; - if (s->full_capabilities.bounding != (uint64_t) -1) { + if (s->full_capabilities.bounding != UINT64_MAX) { s->capability = s->full_capabilities.bounding; s->drop_capability = ~s->full_capabilities.bounding; } @@ -444,6 +444,8 @@ static int oci_process(const char *name, JsonVariant *v, JsonDispatchFlags flags } static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) { + Settings *s = userdata; + int r; static const JsonDispatch table[] = { { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(Settings, root) }, @@ -451,7 +453,21 @@ static int oci_root(const char *name, JsonVariant *v, JsonDispatchFlags flags, v {} }; - return json_dispatch(v, table, oci_unexpected, flags, userdata); + r = json_dispatch(v, table, oci_unexpected, flags, s); + if (r < 0) + return r; + + if (s->root && !path_is_absolute(s->root)) { + char *joined; + + joined = path_join(s->bundle, s->root); + if (!joined) + return log_oom(); + + free_and_replace(s->root, joined); + } + + return 0; } static int oci_hostname(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) { @@ -462,7 +478,7 @@ static int oci_hostname(const char *name, JsonVariant *v, JsonDispatchFlags flag assert_se(n = json_variant_string(v)); - if (!hostname_is_valid(n, false)) + if (!hostname_is_valid(n, 0)) return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), "Hostname string is not a valid hostname: %s", n); @@ -688,7 +704,7 @@ static int oci_uid_gid_range(const char *name, JsonVariant *v, JsonDispatchFlags assert_cc(sizeof(uid_t) == sizeof(gid_t)); /* This is very much like oci_uid_gid(), except the checks are a bit different, as this is a UID range rather - * than a specific UID, and hence (uid_t) -1 has no special significance. OTOH a range of zero makes no + * than a specific UID, and hence UID_INVALID has no special significance. OTOH a range of zero makes no * sense. */ k = json_variant_unsigned(v); @@ -864,8 +880,8 @@ static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags *node = (DeviceNode) { .uid = UID_INVALID, .gid = GID_INVALID, - .major = (unsigned) -1, - .minor = (unsigned) -1, + .major = UINT_MAX, + .minor = UINT_MAX, .mode = 0644, }; @@ -876,7 +892,7 @@ static int oci_devices(const char *name, JsonVariant *v, JsonDispatchFlags flags if (S_ISCHR(node->mode) || S_ISBLK(node->mode)) { _cleanup_free_ char *path = NULL; - if (node->major == (unsigned) -1 || node->minor == (unsigned) -1) { + if (node->major == UINT_MAX || node->minor == UINT_MAX) { r = json_log(e, flags, SYNTHETIC_ERRNO(EINVAL), "Major/minor required when device node is device node"); goto fail_element; @@ -1010,8 +1026,8 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag JSON_VARIANT_ARRAY_FOREACH(e, v) { struct device_data data = { - .major = (unsigned) -1, - .minor = (unsigned) -1, + .major = UINT_MAX, + .minor = UINT_MAX, }, *a; static const JsonDispatch table[] = { @@ -1036,7 +1052,7 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag * is really borked in the spec, with one exception: the entry that's supposed to * drop the kernel's default we ignore silently */ - if (!data.r || !data.w || !data.m || data.type != 0 || data.major != (unsigned) -1 || data.minor != (unsigned) -1) + if (!data.r || !data.w || !data.m || data.type != 0 || data.major != UINT_MAX || data.minor != UINT_MAX) json_log(v, flags|JSON_WARNING, 0, "Devices cgroup allow list with arbitrary 'allow' entries not supported, ignoring."); /* We ignore the 'deny' entry as for us that's implied */ @@ -1048,11 +1064,11 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag continue; } - if (data.minor != (unsigned) -1 && data.major == (unsigned) -1) + if (data.minor != UINT_MAX && data.major == UINT_MAX) return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP), "Device cgroup allow list entries with minors but no majors not supported."); - if (data.major != (unsigned) -1 && data.type == 0) + if (data.major != UINT_MAX && data.type == 0) return json_log(v, flags, SYNTHETIC_ERRNO(EOPNOTSUPP), "Device cgroup allow list entries with majors but no device node type not supported."); @@ -1100,7 +1116,7 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag char access[4]; size_t n = 0; - if (list[i].minor == (unsigned) -1) { + if (list[i].minor == UINT_MAX) { const char *t; if (list[i].type == S_IFBLK) @@ -1110,7 +1126,7 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag t = "char"; } - if (list[i].major == (unsigned) -1) { + if (list[i].major == UINT_MAX) { pattern = strjoin(t, "-*"); if (!pattern) return log_oom(); @@ -1120,7 +1136,7 @@ static int oci_cgroup_devices(const char *name, JsonVariant *v, JsonDispatchFlag } } else { - assert(list[i].major != (unsigned) -1); /* If a minor is specified, then a major also needs to be specified */ + assert(list[i].major != UINT_MAX); /* If a minor is specified, then a major also needs to be specified */ r = device_path_make_major_minor(list[i].type, makedev(list[i].major, list[i].minor), &pattern); if (r < 0) @@ -1400,15 +1416,15 @@ static int oci_cgroup_block_io_weight_device(const char *name, JsonVariant *v, J unsigned minor; uintmax_t weight; } data = { - .major = (unsigned) -1, - .minor = (unsigned) -1, + .major = UINT_MAX, + .minor = UINT_MAX, .weight = UINTMAX_MAX, }; static const JsonDispatch table[] = { { "major", JSON_VARIANT_UNSIGNED, oci_device_major, offsetof(struct device_data, major), JSON_MANDATORY }, { "minor", JSON_VARIANT_UNSIGNED, oci_device_minor, offsetof(struct device_data, minor), JSON_MANDATORY }, - { "weight", JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(struct device_data, weight), 0 }, + { "weight", JSON_VARIANT_UNSIGNED, json_dispatch_uintmax, offsetof(struct device_data, weight), 0 }, { "leafWeight", JSON_VARIANT_INTEGER, oci_unsupported, 0, JSON_PERMISSIVE }, {} }; @@ -1461,14 +1477,14 @@ static int oci_cgroup_block_io_throttle(const char *name, JsonVariant *v, JsonDi unsigned minor; uintmax_t rate; } data = { - .major = (unsigned) -1, - .minor = (unsigned) -1, + .major = UINT_MAX, + .minor = UINT_MAX, }; static const JsonDispatch table[] = { { "major", JSON_VARIANT_UNSIGNED, oci_device_major, offsetof(struct device_data, major), JSON_MANDATORY }, { "minor", JSON_VARIANT_UNSIGNED, oci_device_minor, offsetof(struct device_data, minor), JSON_MANDATORY }, - { "rate", JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(struct device_data, rate), JSON_MANDATORY }, + { "rate", JSON_VARIANT_UNSIGNED, json_dispatch_uintmax, offsetof(struct device_data, rate), JSON_MANDATORY }, {} }; @@ -1874,7 +1890,7 @@ static int oci_seccomp_syscalls(const char *name, JsonVariant *v, JsonDispatchFl { "args", JSON_VARIANT_ARRAY, oci_seccomp_args, 0, 0 }, }; struct syscall_rule rule = { - .action = (uint32_t) -1, + .action = UINT32_MAX, }; char **i; diff --git a/src/nspawn/nspawn-seccomp.c b/src/nspawn/nspawn-seccomp.c index 1da719124..c94512ef3 100644 --- a/src/nspawn/nspawn-seccomp.c +++ b/src/nspawn/nspawn-seccomp.c @@ -126,7 +126,7 @@ static int add_syscall_filters( * @pkey * @swap * - * bpf (NB: bpffs is not namespaced!) + * bpf * fanotify_init * fanotify_mark * kexec_file_load diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 92bb5120a..d4619bead 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -51,10 +51,10 @@ Settings *settings_new(void) { .gid = GID_INVALID, .console_mode = _CONSOLE_MODE_INVALID, - .console_width = (unsigned) -1, - .console_height = (unsigned) -1, + .console_width = UINT_MAX, + .console_height = UINT_MAX, - .clone_ns_flags = (unsigned long) -1, + .clone_ns_flags = ULONG_MAX, .use_cgns = -1, }; @@ -274,7 +274,7 @@ int config_parse_capability( break; if (streq(word, "all")) - u = (uint64_t) -1; + u = UINT64_MAX; else { r = capability_from_name(word); if (r < 0) { @@ -701,15 +701,12 @@ int config_parse_hostname( assert(rvalue); assert(s); - if (!hostname_is_valid(rvalue, false)) { + if (!hostname_is_valid(rvalue, 0)) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid hostname, ignoring: %s", rvalue); return 0; } - if (free_and_strdup(s, empty_to_null(rvalue)) < 0) - return log_oom(); - - return 0; + return free_and_strdup_warn(s, empty_to_null(rvalue)); } int config_parse_oom_score_adjust( diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 4a83e5520..d0c708a8a 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -25,7 +25,7 @@ typedef enum StartMode { START_PID2, /* Use stub init process as PID 1, run parameters as command line as process 2 */ START_BOOT, /* Search for init system, pass arguments as parameters */ _START_MODE_MAX, - _START_MODE_INVALID = -1 + _START_MODE_INVALID = -EINVAL, } StartMode; typedef enum UserNamespaceMode { @@ -33,7 +33,7 @@ typedef enum UserNamespaceMode { USER_NAMESPACE_FIXED, USER_NAMESPACE_PICK, _USER_NAMESPACE_MODE_MAX, - _USER_NAMESPACE_MODE_INVALID = -1, + _USER_NAMESPACE_MODE_INVALID = -EINVAL, } UserNamespaceMode; typedef enum ResolvConfMode { @@ -53,7 +53,7 @@ typedef enum ResolvConfMode { RESOLV_CONF_DELETE, RESOLV_CONF_AUTO, _RESOLV_CONF_MODE_MAX, - _RESOLV_CONF_MODE_INVALID = -1 + _RESOLV_CONF_MODE_INVALID = -EINVAL, } ResolvConfMode; typedef enum LinkJournal { @@ -62,7 +62,7 @@ typedef enum LinkJournal { LINK_HOST, LINK_GUEST, _LINK_JOURNAL_MAX, - _LINK_JOURNAL_INVALID = -1 + _LINK_JOURNAL_INVALID = -EINVAL, } LinkJournal; typedef enum TimezoneMode { @@ -73,7 +73,7 @@ typedef enum TimezoneMode { TIMEZONE_DELETE, TIMEZONE_AUTO, _TIMEZONE_MODE_MAX, - _TIMEZONE_MODE_INVALID = -1 + _TIMEZONE_MODE_INVALID = -EINVAL, } TimezoneMode; typedef enum ConsoleMode { @@ -82,7 +82,7 @@ typedef enum ConsoleMode { CONSOLE_PASSIVE, CONSOLE_PIPE, _CONSOLE_MODE_MAX, - _CONSOLE_MODE_INVALID = -1, + _CONSOLE_MODE_INVALID = -EINVAL, } ConsoleMode; typedef enum SettingsMask { @@ -157,6 +157,7 @@ typedef struct Settings { char *user; uint64_t capability; uint64_t drop_capability; + uint64_t ambient_capability; int kill_signal; unsigned long personality; sd_id128_t machine_id; diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 7515380fc..a4ac8ed2b 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -36,6 +36,7 @@ #include "copy.h" #include "cpu-set-util.h" #include "dev-setup.h" +#include "discover-image.h" #include "dissect-image.h" #include "env-util.h" #include "escape.h" @@ -46,13 +47,13 @@ #include "fs-util.h" #include "gpt.h" #include "hexdecoct.h" +#include "hostname-setup.h" #include "hostname-util.h" #include "id128-util.h" #include "io-util.h" #include "log.h" #include "loop-util.h" #include "loopback-setup.h" -#include "machine-image.h" #include "macro.h" #include "main-func.h" #include "missing_sched.h" @@ -77,6 +78,7 @@ #include "nulstr-util.h" #include "os-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -165,6 +167,7 @@ static uint64_t arg_caps_retain = (1ULL << CAP_SYS_PTRACE) | (1ULL << CAP_SYS_RESOURCE) | (1ULL << CAP_SYS_TTY_CONFIG); +static uint64_t arg_caps_ambient = 0; static CapabilityQuintet arg_full_capabilities = CAPABILITY_QUINTET_NULL; static CustomMount *arg_custom_mounts = NULL; static size_t arg_n_custom_mounts = 0; @@ -214,7 +217,7 @@ static bool arg_oom_score_adjust_set = false; static CPUSet arg_cpu_set = {}; static ResolvConfMode arg_resolv_conf = RESOLV_CONF_AUTO; static TimezoneMode arg_timezone = TIMEZONE_AUTO; -static unsigned arg_console_width = (unsigned) -1, arg_console_height = (unsigned) -1; +static unsigned arg_console_width = UINT_MAX, arg_console_height = UINT_MAX; static DeviceNode* arg_extra_nodes = NULL; static size_t arg_n_extra_nodes = 0; static char **arg_sysctl = NULL; @@ -379,6 +382,9 @@ static int help(void) { " --capability=CAP In addition to the default, retain specified\n" " capability\n" " --drop-capability=CAP Drop the specified capability from the default set\n" + " --ambient-capability=CAP\n" + " Sets the specified capability for the started\n" + " process. Not useful if booting a machine.\n" " --no-new-privileges Set PR_SET_NO_NEW_PRIVS flag for container payload\n" " --system-call-filter=LIST|~LIST\n" " Permit/prohibit specific system calls\n" @@ -424,12 +430,13 @@ static int help(void) { " --load-credential=ID:PATH\n" " Load credential to pass to container from file or\n" " AF_UNIX stream socket.\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - , ansi_underline(), ansi_normal() - , ansi_highlight(), ansi_normal() - ); + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); return 0; } @@ -542,7 +549,7 @@ static int parse_capability_spec(const char *spec, uint64_t *ret_mask) { } if (streq(t, "all")) - mask = (uint64_t) -1; + mask = UINT64_MAX; else { r = capability_from_name(t); if (r < 0) @@ -648,6 +655,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_UUID, ARG_READ_ONLY, ARG_CAPABILITY, + ARG_AMBIENT_CAPABILITY, ARG_DROP_CAPABILITY, ARG_LINK_JOURNAL, ARG_BIND, @@ -709,6 +717,7 @@ static int parse_argv(int argc, char *argv[]) { { "uuid", required_argument, NULL, ARG_UUID }, { "read-only", no_argument, NULL, ARG_READ_ONLY }, { "capability", required_argument, NULL, ARG_CAPABILITY }, + { "ambient-capability", required_argument, NULL, ARG_AMBIENT_CAPABILITY }, { "drop-capability", required_argument, NULL, ARG_DROP_CAPABILITY }, { "no-new-privileges", required_argument, NULL, ARG_NO_NEW_PRIVILEGES }, { "link-journal", required_argument, NULL, ARG_LINK_JOURNAL }, @@ -783,7 +792,7 @@ static int parse_argv(int argc, char *argv[]) { return version(); case 'D': - r = parse_path_argument_and_warn(optarg, false, &arg_directory); + r = parse_path_argument(optarg, false, &arg_directory); if (r < 0) return r; @@ -791,7 +800,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_TEMPLATE: - r = parse_path_argument_and_warn(optarg, false, &arg_template); + r = parse_path_argument(optarg, false, &arg_template); if (r < 0) return r; @@ -799,7 +808,7 @@ static int parse_argv(int argc, char *argv[]) { break; case 'i': - r = parse_path_argument_and_warn(optarg, false, &arg_image); + r = parse_path_argument(optarg, false, &arg_image); if (r < 0) return r; @@ -807,7 +816,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_OCI_BUNDLE: - r = parse_path_argument_and_warn(optarg, false, &arg_oci_bundle); + r = parse_path_argument(optarg, false, &arg_oci_bundle); if (r < 0) return r; @@ -926,7 +935,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NETWORK_NAMESPACE_PATH: - r = parse_path_argument_and_warn(optarg, false, &arg_network_namespace_path); + r = parse_path_argument(optarg, false, &arg_network_namespace_path); if (r < 0) return r; @@ -979,7 +988,7 @@ static int parse_argv(int argc, char *argv[]) { if (isempty(optarg)) arg_machine = mfree(arg_machine); else { - if (!machine_name_is_valid(optarg)) + if (!hostname_is_valid(optarg, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid machine name: %s", optarg); @@ -993,7 +1002,7 @@ static int parse_argv(int argc, char *argv[]) { if (isempty(optarg)) arg_hostname = mfree(arg_hostname); else { - if (!hostname_is_valid(optarg, false)) + if (!hostname_is_valid(optarg, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid hostname: %s", optarg); @@ -1018,6 +1027,15 @@ static int parse_argv(int argc, char *argv[]) { arg_settings_mask |= SETTING_READ_ONLY; break; + case ARG_AMBIENT_CAPABILITY: { + uint64_t m; + r = parse_capability_spec(optarg, &m); + if (r <= 0) + return r; + arg_caps_ambient |= m; + arg_settings_mask |= SETTING_CAPABILITY; + break; + } case ARG_CAPABILITY: case ARG_DROP_CAPABILITY: { uint64_t m; @@ -1092,17 +1110,13 @@ static int parse_argv(int argc, char *argv[]) { break; case 'E': { - char **n; - if (!env_assignment_is_valid(optarg)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Environment variable assignment '%s' is not valid.", optarg); + r = strv_env_replace_strdup(&arg_setenv, optarg); + if (r < 0) + return r; - n = strv_env_set(arg_setenv, optarg); - if (!n) - return log_oom(); - - strv_free_and_replace(arg_setenv, n); arg_settings_mask |= SETTING_ENVIRONMENT; break; } @@ -1263,8 +1277,7 @@ static int parse_argv(int argc, char *argv[]) { arg_kill_signal = signal_from_string(optarg); if (arg_kill_signal < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Cannot parse signal: %s", optarg); + return log_error_errno(arg_kill_signal, "Cannot parse signal: %s", optarg); arg_settings_mask |= SETTING_KILL_SIGNAL; break; @@ -1370,7 +1383,7 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_VERITY_DATA: - r = parse_path_argument_and_warn(optarg, false, &arg_verity_settings.data_path); + r = parse_path_argument(optarg, false, &arg_verity_settings.data_path); if (r < 0) return r; break; @@ -1426,8 +1439,7 @@ static int parse_argv(int argc, char *argv[]) { rl = rlimit_from_string_harder(name); if (rl < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown resource limit: %s", name); + return log_error_errno(rl, "Unknown resource limit: %s", name); if (!arg_rlimit[rl]) { arg_rlimit[rl] = new0(struct rlimit, 1); @@ -1473,7 +1485,7 @@ static int parse_argv(int argc, char *argv[]) { arg_resolv_conf = resolv_conf_mode_from_string(optarg); if (arg_resolv_conf < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + return log_error_errno(arg_resolv_conf, "Failed to parse /etc/resolv.conf mode: %s", optarg); arg_settings_mask |= SETTING_RESOLV_CONF; @@ -1487,7 +1499,7 @@ static int parse_argv(int argc, char *argv[]) { arg_timezone = timezone_mode_from_string(optarg); if (arg_timezone < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + return log_error_errno(arg_timezone, "Failed to parse /etc/localtime mode: %s", optarg); arg_settings_mask |= SETTING_TIMEZONE; @@ -1589,7 +1601,10 @@ static int parse_argv(int argc, char *argv[]) { return log_oom(); } - r = read_full_file_full(AT_FDCWD, j ?: p, flags, NULL, &data, &size); + r = read_full_file_full(AT_FDCWD, j ?: p, UINT64_MAX, SIZE_MAX, + flags, + NULL, + &data, &size); if (r < 0) return log_error_errno(r, "Failed to read credential '%s': %m", j ?: p); @@ -1752,10 +1767,16 @@ static int verify_arguments(void) { if (arg_expose_ports && !arg_private_network) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot use --port= without private networking."); -#if ! HAVE_LIBIPTC - if (arg_expose_ports) - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "--port= is not supported, compiled without libiptc support."); -#endif + if (arg_caps_ambient) { + if (arg_caps_ambient == UINT64_MAX) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= does not support the value all."); + + if ((arg_caps_ambient & arg_caps_retain) != arg_caps_ambient) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= setting is not fully covered by Capability= setting."); + + if (arg_start_mode == START_BOOT) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "AmbientCapability= setting is not useful for boot mode."); + } r = custom_mount_check_all(); if (r < 0) @@ -2445,14 +2466,21 @@ static int setup_kmsg(int kmsg_socket) { return 0; } +struct ExposeArgs { + union in_addr_union address4; + union in_addr_union address6; + struct FirewallContext *fw_ctx; +}; + static int on_address_change(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) { - union in_addr_union *exposed = userdata; + struct ExposeArgs *args = userdata; assert(rtnl); assert(m); - assert(exposed); + assert(args); - expose_port_execute(rtnl, arg_expose_ports, exposed); + expose_port_execute(rtnl, &args->fw_ctx, arg_expose_ports, AF_INET, &args->address4); + expose_port_execute(rtnl, &args->fw_ctx, arg_expose_ports, AF_INET6, &args->address6); return 0; } @@ -2612,20 +2640,20 @@ static int drop_capabilities(uid_t uid) { if (capability_quintet_is_set(&arg_full_capabilities)) { q = arg_full_capabilities; - if (q.bounding == (uint64_t) -1) + if (q.bounding == UINT64_MAX) q.bounding = uid == 0 ? arg_caps_retain : 0; - if (q.effective == (uint64_t) -1) + if (q.effective == UINT64_MAX) q.effective = uid == 0 ? q.bounding : 0; - if (q.inheritable == (uint64_t) -1) - q.inheritable = uid == 0 ? q.bounding : 0; + if (q.inheritable == UINT64_MAX) + q.inheritable = uid == 0 ? q.bounding : arg_caps_ambient; - if (q.permitted == (uint64_t) -1) - q.permitted = uid == 0 ? q.bounding : 0; + if (q.permitted == UINT64_MAX) + q.permitted = uid == 0 ? q.bounding : arg_caps_ambient; - if (q.ambient == (uint64_t) -1 && ambient_capabilities_supported()) - q.ambient = 0; + if (q.ambient == UINT64_MAX && ambient_capabilities_supported()) + q.ambient = arg_caps_ambient; if (capability_quintet_mangle(&q)) return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Cannot set capabilities that are not in the current bounding set."); @@ -2634,9 +2662,9 @@ static int drop_capabilities(uid_t uid) { q = (CapabilityQuintet) { .bounding = arg_caps_retain, .effective = uid == 0 ? arg_caps_retain : 0, - .inheritable = uid == 0 ? arg_caps_retain : 0, - .permitted = uid == 0 ? arg_caps_retain : 0, - .ambient = ambient_capabilities_supported() ? 0 : (uint64_t) -1, + .inheritable = uid == 0 ? arg_caps_retain : arg_caps_ambient, + .permitted = uid == 0 ? arg_caps_retain : arg_caps_ambient, + .ambient = ambient_capabilities_supported() ? arg_caps_ambient : UINT64_MAX, }; /* If we're not using OCI, proceed with mangled capabilities (so we don't error out) @@ -2910,7 +2938,7 @@ static int determine_names(void) { if (arg_machine) { _cleanup_(image_unrefp) Image *i = NULL; - r = image_find(IMAGE_MACHINE, arg_machine, &i); + r = image_find(IMAGE_MACHINE, arg_machine, NULL, &i); if (r == -ENOENT) return log_error_errno(r, "No image for machine '%s'.", arg_machine); if (r < 0) @@ -2955,7 +2983,7 @@ static int determine_names(void) { return log_oom(); hostname_cleanup(arg_machine); - if (!machine_name_is_valid(arg_machine)) + if (!hostname_is_valid(arg_machine, 0)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to determine machine name automatically, please use -M."); if (arg_ephemeral) { @@ -3017,7 +3045,7 @@ static int determine_uid_shift(const char *directory) { arg_uid_range = UINT32_C(0x10000); } - if (arg_uid_shift > (uid_t) -1 - arg_uid_range) + if (arg_uid_shift > UID_INVALID - arg_uid_range) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "UID base too high for UID range."); @@ -4071,6 +4099,7 @@ static int merge_settings(Settings *settings, const char *path) { if ((arg_settings_mask & SETTING_CAPABILITY) == 0) { uint64_t plus, minus; uint64_t network_minus = 0; + uint64_t ambient; /* Note that we copy both the simple plus/minus caps here, and the full quintet from the * Settings structure */ @@ -4102,6 +4131,12 @@ static int merge_settings(Settings *settings, const char *path) { else arg_full_capabilities = settings->full_capabilities; } + + ambient = settings->ambient_capability; + if (!arg_settings_trusted && ambient != 0) + log_warning("Ignoring AmbientCapability= setting, file %s is not trusted.", path); + else + arg_caps_ambient |= ambient; } if ((arg_settings_mask & SETTING_KILL_SIGNAL) == 0 && @@ -4301,7 +4336,7 @@ static int merge_settings(Settings *settings, const char *path) { } if ((arg_settings_mask & SETTING_CLONE_NS_FLAGS) == 0 && - settings->clone_ns_flags != (unsigned long) -1) { + settings->clone_ns_flags != ULONG_MAX) { if (!arg_settings_trusted) log_warning("Ignoring namespace setting, file '%s' is not trusted.", path); @@ -4434,7 +4469,7 @@ static int run_container( bool secondary, FDSet *fds, char veth_name[IFNAMSIZ], bool *veth_created, - union in_addr_union *exposed, + struct ExposeArgs *expose_args, int *master, pid_t *pid, int *ret) { static const struct sigaction sa = { @@ -4528,7 +4563,7 @@ static int run_container( if (child_netns_fd < 0) return log_error_errno(errno, "Cannot open file %s: %m", arg_network_namespace_path); - r = fd_is_network_ns(child_netns_fd); + r = fd_is_ns(child_netns_fd, CLONE_NEWNET); if (r == -EUCLEAN) log_debug_errno(r, "Cannot determine if passed network namespace path '%s' really refers to a network namespace, assuming it does.", arg_network_namespace_path); else if (r < 0) @@ -4815,7 +4850,7 @@ static int run_container( assert_se(sigprocmask(SIG_BLOCK, &mask_chld, NULL) >= 0); /* Reset signal to default */ - r = default_signals(SIGCHLD, -1); + r = default_signals(SIGCHLD); if (r < 0) return log_error_errno(r, "Failed to reset SIGCHLD: %m"); @@ -4863,11 +4898,12 @@ static int run_container( (void) sd_event_add_signal(event, NULL, SIGCHLD, on_sigchld, PID_TO_PTR(*pid)); if (arg_expose_ports) { - r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, exposed, &rtnl); + r = expose_port_watch_rtnl(event, rtnl_socket_pair[0], on_address_change, expose_args, &rtnl); if (r < 0) return r; - (void) expose_port_execute(rtnl, arg_expose_ports, exposed); + (void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET, &expose_args->address4); + (void) expose_port_execute(rtnl, &expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6); } rtnl_socket_pair[0] = safe_close(rtnl_socket_pair[0]); @@ -4895,7 +4931,7 @@ static int run_container( if (r < 0) return log_error_errno(r, "Failed to create PTY forwarder: %m"); - if (arg_console_width != (unsigned) -1 || arg_console_height != (unsigned) -1) + if (arg_console_width != UINT_MAX || arg_console_height != UINT_MAX) (void) pty_forward_set_width_height(forward, arg_console_width, arg_console_height); @@ -4994,7 +5030,8 @@ static int run_container( return 0; /* finito */ } - expose_port_flush(arg_expose_ports, exposed); + expose_port_flush(&expose_args->fw_ctx, arg_expose_ports, AF_INET, &expose_args->address4); + expose_port_flush(&expose_args->fw_ctx, arg_expose_ports, AF_INET6, &expose_args->address6); (void) remove_veth_links(veth_name, arg_network_veth_extra); *veth_created = false; @@ -5123,12 +5160,13 @@ static int run(int argc, char *argv[]) { _cleanup_fdset_free_ FDSet *fds = NULL; int r, n_fd_passed, ret = EXIT_SUCCESS; char veth_name[IFNAMSIZ] = ""; - union in_addr_union exposed = {}; + struct ExposeArgs expose_args = {}; _cleanup_(release_lock_file) LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT; char tmprootdir[] = "/tmp/nspawn-root-XXXXXX"; _cleanup_(loop_device_unrefp) LoopDevice *loop = NULL; _cleanup_(decrypted_image_unrefp) DecryptedImage *decrypted_image = NULL; _cleanup_(dissected_image_unrefp) DissectedImage *dissected_image = NULL; + _cleanup_(fw_ctx_freep) FirewallContext *fw_ctx = NULL; pid_t pid = 0; log_parse_environment(); @@ -5181,7 +5219,7 @@ static int run(int argc, char *argv[]) { /* Ignore SIGPIPE here, because we use splice() on the ptyfwd stuff and that will generate SIGPIPE if * the result is closed. Note that the container payload child will reset signal mask+handler anyway, * so just turning this off here means we only turn it off in nspawn itself, not any children. */ - (void) ignore_signals(SIGPIPE, -1); + (void) ignore_signals(SIGPIPE); n_fd_passed = sd_listen_fds(false); if (n_fd_passed > 0) { @@ -5485,12 +5523,20 @@ static int run(int argc, char *argv[]) { goto finish; } + if (arg_expose_ports) { + r = fw_ctx_new(&fw_ctx); + if (r < 0) { + log_error_errno(r, "Cannot expose configured ports, firewall initialization failed: %m"); + goto finish; + } + expose_args.fw_ctx = fw_ctx; + } for (;;) { r = run_container(dissected_image, secondary, fds, veth_name, &veth_created, - &exposed, &master, + &expose_args, &master, &pid, &ret); if (r <= 0) break; @@ -5506,7 +5552,7 @@ finish: /* Try to flush whatever is still queued in the pty */ if (master >= 0) { - (void) copy_bytes(master, STDOUT_FILENO, (uint64_t) -1, 0); + (void) copy_bytes(master, STDOUT_FILENO, UINT64_MAX, 0); master = safe_close(master); } @@ -5540,7 +5586,8 @@ finish: (void) rm_rf(p, REMOVE_ROOT); } - expose_port_flush(arg_expose_ports, &exposed); + expose_port_flush(&fw_ctx, arg_expose_ports, AF_INET, &expose_args.address4); + expose_port_flush(&fw_ctx, arg_expose_ports, AF_INET6, &expose_args.address6); if (veth_created) (void) remove_veth_links(veth_name, arg_network_veth_extra); diff --git a/src/nss-myhostname/nss-myhostname.c b/src/nss-myhostname/nss-myhostname.c index ffabc60c7..6e37966da 100644 --- a/src/nss-myhostname/nss-myhostname.c +++ b/src/nss-myhostname/nss-myhostname.c @@ -134,7 +134,7 @@ enum nss_status _nss_myhostname_gethostbyname4_r( r_tuple->next = r_tuple_prev; r_tuple->name = r_name; r_tuple->family = a->family; - r_tuple->scopeid = a->family == AF_INET6 && IN6_IS_ADDR_LINKLOCAL(&a->address.in6) ? a->ifindex : 0; + r_tuple->scopeid = a->family == AF_INET6 && in6_addr_is_link_local(&a->address.in6) ? a->ifindex : 0; memcpy(r_tuple->addr, &a->address, 16); idx += ALIGN(sizeof(struct gaih_addrtuple)); diff --git a/src/nss-mymachines/nss-mymachines.c b/src/nss-mymachines/nss-mymachines.c index 53f049211..44715bb3e 100644 --- a/src/nss-mymachines/nss-mymachines.c +++ b/src/nss-mymachines/nss-mymachines.c @@ -2,6 +2,7 @@ #include #include +#include #include "sd-bus.h" #include "sd-login.h" @@ -14,12 +15,27 @@ #include "format-util.h" #include "hostname-util.h" #include "in-addr-util.h" +#include "log.h" #include "macro.h" #include "memory-util.h" #include "nss-util.h" #include "signal-util.h" #include "string-util.h" +static void setup_logging(void) { + /* We need a dummy function because log_parse_environment is a macro. */ + log_parse_environment(); +} + +static void setup_logging_once(void) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + assert_se(pthread_once(&once, setup_logging) == 0); +} + +#define NSS_ENTRYPOINT_BEGIN \ + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \ + setup_logging_once() + NSS_GETHOSTBYNAME_PROTOTYPES(mymachines); NSS_GETPW_PROTOTYPES(mymachines); NSS_GETGR_PROTOTYPES(mymachines); @@ -94,7 +110,7 @@ enum nss_status _nss_mymachines_gethostbyname4_r( int n_ifindices, r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(name); assert(pat); @@ -244,7 +260,7 @@ enum nss_status _nss_mymachines_gethostbyname3_r( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(name); assert(result); diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c index 3fee4f581..dfc0977c8 100644 --- a/src/nss-resolve/nss-resolve.c +++ b/src/nss-resolve/nss-resolve.c @@ -3,10 +3,12 @@ #include #include #include +#include #include #include #include +#include "env-util.h" #include "errno-util.h" #include "in-addr-util.h" #include "macro.h" @@ -17,6 +19,24 @@ #include "strv.h" #include "varlink.h" +static JsonDispatchFlags json_dispatch_flags = 0; + +static void setup_logging(void) { + log_parse_environment(); + + if (DEBUG_LOGGING) + json_dispatch_flags = JSON_LOG; +} + +static void setup_logging_once(void) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + assert_se(pthread_once(&once, setup_logging) == 0); +} + +#define NSS_ENTRYPOINT_BEGIN \ + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \ + setup_logging_once() + NSS_GETHOSTBYNAME_PROTOTYPES(resolve); NSS_GETHOSTBYADDR_PROTOTYPES(resolve); @@ -49,7 +69,7 @@ static int connect_to_resolved(Varlink **ret) { static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) { struct in6_addr in6; - if (family != AF_INET6) + if (family != AF_INET6 || ifindex == 0) return 0; /* Some apps can't deal with the scope ID attached to non-link-local addresses. Hence, let's suppress that. */ @@ -57,7 +77,7 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) { assert(sizeof(in6) == FAMILY_ADDRESS_SIZE(AF_INET6)); memcpy(&in6, a, sizeof(struct in6_addr)); - return IN6_IS_ADDR_LINKLOCAL(&in6) ? ifindex : 0; + return in6_addr_is_link_local(&in6) ? ifindex : 0; } static int json_dispatch_ifindex(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { @@ -71,7 +91,7 @@ static int json_dispatch_ifindex(const char *name, JsonVariant *variant, JsonDis return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name)); t = json_variant_integer(variant); - if (t <= 0 || t > INT_MAX) + if (t > INT_MAX) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is out of bounds for an interface index.", strna(name)); *ifi = (int) t; @@ -165,6 +185,21 @@ static const JsonDispatch address_parameters_dispatch_table[] = { {} }; +static uint64_t query_flags(void) { + uint64_t f = 0; + int r; + + /* Allow callers to turn off validation, when we resolve via nss-resolve */ + + r = getenv_bool_secure("SYSTEMD_NSS_RESOLVE_VALIDATE"); + if (r < 0 && r != -ENXIO) + log_debug_errno(r, "Failed to parse $SYSTEMD_NSS_RESOLVE_VALIDATE value, ignoring."); + else if (r == 0) + f |= SD_RESOLVED_NO_VALIDATE; + + return f; +} + enum nss_status _nss_resolve_gethostbyname4_r( const char *name, struct gaih_addrtuple **pat, @@ -183,7 +218,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(name); assert(pat); @@ -196,7 +231,8 @@ enum nss_status _nss_resolve_gethostbyname4_r( goto fail; r = json_build(&cparams, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("name", JSON_BUILD_STRING(name)))); + JSON_BUILD_PAIR("name", JSON_BUILD_STRING(name)), + JSON_BUILD_PAIR("flags", JSON_BUILD_UNSIGNED(query_flags())))); if (r < 0) goto fail; @@ -214,7 +250,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( goto fail; } - r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, 0, &p); + r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, json_dispatch_flags, &p); if (r < 0) goto fail; if (json_variant_is_blank_object(p.addresses)) @@ -223,7 +259,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) { AddressParameters q = {}; - r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q); + r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q); if (r < 0) goto fail; @@ -260,7 +296,7 @@ enum nss_status _nss_resolve_gethostbyname4_r( JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) { AddressParameters q = {}; - r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q); + r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q); if (r < 0) goto fail; @@ -327,7 +363,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(name); assert(result); @@ -348,7 +384,8 @@ enum nss_status _nss_resolve_gethostbyname3_r( goto fail; r = json_build(&cparams, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("name", JSON_BUILD_STRING(name)), - JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(af)))); + JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(af)), + JSON_BUILD_PAIR("flags", JSON_BUILD_UNSIGNED(query_flags())))); if (r < 0) goto fail; @@ -361,7 +398,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( goto fail; } - r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, 0, &p); + r = json_dispatch(rparams, resolve_hostname_reply_dispatch_table, NULL, json_dispatch_flags, &p); if (r < 0) goto fail; if (json_variant_is_blank_object(p.addresses)) @@ -370,7 +407,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) { AddressParameters q = {}; - r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q); + r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q); if (r < 0) goto fail; @@ -415,7 +452,7 @@ enum nss_status _nss_resolve_gethostbyname3_r( JSON_VARIANT_ARRAY_FOREACH(entry, p.addresses) { AddressParameters q = {}; - r = json_dispatch(entry, address_parameters_dispatch_table, NULL, 0, &q); + r = json_dispatch(entry, address_parameters_dispatch_table, NULL, json_dispatch_flags, &q); if (r < 0) goto fail; @@ -527,7 +564,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(addr); assert(result); @@ -552,7 +589,8 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( goto fail; r = json_build(&cparams, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(addr, len)), - JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(af)))); + JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(af)), + JSON_BUILD_PAIR("flags", JSON_BUILD_UNSIGNED(query_flags())))); if (r < 0) goto fail; @@ -565,7 +603,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( goto fail; } - r = json_dispatch(rparams, resolve_address_reply_dispatch_table, NULL, 0, &p); + r = json_dispatch(rparams, resolve_address_reply_dispatch_table, NULL, json_dispatch_flags, &p); if (r < 0) goto fail; if (json_variant_is_blank_object(p.names)) @@ -574,7 +612,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( JSON_VARIANT_ARRAY_FOREACH(entry, p.names) { _cleanup_(name_parameters_destroy) NameParameters q = {}; - r = json_dispatch(entry, name_parameters_dispatch_table, NULL, 0, &q); + r = json_dispatch(entry, name_parameters_dispatch_table, NULL, json_dispatch_flags, &q); if (r < 0) goto fail; @@ -615,7 +653,7 @@ enum nss_status _nss_resolve_gethostbyaddr2_r( size_t l; char *z; - r = json_dispatch(entry, name_parameters_dispatch_table, NULL, 0, &q); + r = json_dispatch(entry, name_parameters_dispatch_table, NULL, json_dispatch_flags, &q); if (r < 0) goto fail; diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c index 758f3816e..0b716d22d 100644 --- a/src/nss-systemd/nss-systemd.c +++ b/src/nss-systemd/nss-systemd.c @@ -6,6 +6,7 @@ #include "env-util.h" #include "errno-util.h" #include "fd-util.h" +#include "log.h" #include "macro.h" #include "nss-systemd.h" #include "nss-util.h" @@ -72,6 +73,20 @@ static GetentData getgrent_data = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +static void setup_logging(void) { + /* We need a dummy function because log_parse_environment is a macro. */ + log_parse_environment(); +} + +static void setup_logging_once(void) { + static pthread_once_t once = PTHREAD_ONCE_INIT; + assert_se(pthread_once(&once, setup_logging) == 0); +} + +#define NSS_ENTRYPOINT_BEGIN \ + BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); \ + setup_logging_once() + NSS_GETPW_PROTOTYPES(systemd); NSS_GETGR_PROTOTYPES(systemd); NSS_PWENT_PROTOTYPES(systemd); @@ -88,7 +103,7 @@ enum nss_status _nss_systemd_getpwnam_r( int e; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(name); assert(pwd); @@ -139,7 +154,7 @@ enum nss_status _nss_systemd_getpwuid_r( int e; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(pwd); assert(errnop); @@ -188,7 +203,7 @@ enum nss_status _nss_systemd_getgrnam_r( int e; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(name); assert(gr); @@ -236,7 +251,7 @@ enum nss_status _nss_systemd_getgrgid_r( int e; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(gr); assert(errnop); @@ -275,7 +290,7 @@ enum nss_status _nss_systemd_getgrgid_r( static enum nss_status nss_systemd_endent(GetentData *p) { PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(p); @@ -298,7 +313,7 @@ enum nss_status _nss_systemd_endgrent(void) { enum nss_status _nss_systemd_setpwent(int stayopen) { PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; @@ -322,7 +337,7 @@ enum nss_status _nss_systemd_setpwent(int stayopen) { enum nss_status _nss_systemd_setgrent(int stayopen) { PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; if (_nss_systemd_is_blocked()) return NSS_STATUS_NOTFOUND; @@ -349,7 +364,7 @@ enum nss_status _nss_systemd_getpwent_r( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(result); assert(errnop); @@ -396,7 +411,7 @@ enum nss_status _nss_systemd_getgrent_r( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(result); assert(errnop); @@ -525,7 +540,7 @@ enum nss_status _nss_systemd_initgroups_dyn( int r; PROTECT_ERRNO; - BLOCK_SIGNALS(NSS_SIGNALS_BLOCK); + NSS_ENTRYPOINT_BEGIN; assert(user_name); assert(start); diff --git a/src/oom/meson.build b/src/oom/meson.build index 1ea6766d1..4e1c8543c 100644 --- a/src/oom/meson.build +++ b/src/oom/meson.build @@ -15,22 +15,20 @@ oomctl_sources = files(''' '''.split()) if conf.get('ENABLE_OOMD') == 1 - tests += [ - [['src/oom/test-oomd-util.c', - 'src/oom/oomd-util.c', - 'src/oom/oomd-util.h'], - [], - []] - ] - install_data('org.freedesktop.oom1.conf', install_dir : dbuspolicydir) install_data('org.freedesktop.oom1.service', install_dir : dbussystemservicedir) - if install_sysconfdir + if install_sysconfdir_samples install_data('oomd.conf', install_dir : pkgsysconfdir) endif endif + +tests += [ + [['src/oom/test-oomd-util.c', + 'src/oom/oomd-util.c', + 'src/oom/oomd-util.h']], +] diff --git a/src/oom/oomctl.c b/src/oom/oomctl.c index dd393fcac..0d215cf6e 100644 --- a/src/oom/oomctl.c +++ b/src/oom/oomctl.c @@ -30,12 +30,13 @@ static int help(int argc, char *argv[], void *userdata) { " -h --help Show this help\n" " --version Show package version\n" " --no-pager Do not pipe output into a pager\n" - "\nSee the %6$s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , ansi_underline(), ansi_normal() - , link - ); + "\nSee the %6$s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + ansi_underline(), + ansi_normal(), + link); return 0; } @@ -70,7 +71,7 @@ static int dump_state(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); fflush(stdout); - return copy_bytes(fd, STDOUT_FILENO, (uint64_t) -1, 0); + return copy_bytes(fd, STDOUT_FILENO, UINT64_MAX, 0); } static int parse_argv(int argc, char *argv[]) { diff --git a/src/oom/oomd-manager.c b/src/oom/oomd-manager.c index fec96519e..c3e84aadd 100644 --- a/src/oom/oomd-manager.c +++ b/src/oom/oomd-manager.c @@ -6,15 +6,17 @@ #include "cgroup-util.h" #include "fd-util.h" #include "fileio.h" +#include "memory-util.h" #include "oomd-manager-bus.h" #include "oomd-manager.h" #include "path-util.h" +#include "percent-util.h" typedef struct ManagedOOMReply { ManagedOOMMode mode; char *path; char *property; - unsigned limit; + uint32_t limit; } ManagedOOMReply; static void managed_oom_reply_destroy(ManagedOOMReply *reply) { @@ -32,7 +34,7 @@ static int managed_oom_mode(const char *name, JsonVariant *v, JsonDispatchFlags m = managed_oom_mode_from_string(s); if (m < 0) - return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL), "%s is not a valid ManagedOOMMode", s); + return json_log(v, flags, m, "%s is not a valid ManagedOOMMode", s); *mode = m; return 0; @@ -51,10 +53,10 @@ static int process_managed_oom_reply( assert(m); static const JsonDispatch dispatch_table[] = { - { "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMReply, mode), JSON_MANDATORY }, - { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, path), JSON_MANDATORY }, - { "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, property), JSON_MANDATORY }, - { "limit", JSON_VARIANT_UNSIGNED, json_dispatch_unsigned, offsetof(ManagedOOMReply, limit), 0 }, + { "mode", JSON_VARIANT_STRING, managed_oom_mode, offsetof(ManagedOOMReply, mode), JSON_MANDATORY }, + { "path", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, path), JSON_MANDATORY }, + { "property", JSON_VARIANT_STRING, json_dispatch_string, offsetof(ManagedOOMReply, property), JSON_MANDATORY }, + { "limit", JSON_VARIANT_UNSIGNED, json_dispatch_uint32, offsetof(ManagedOOMReply, limit), 0 }, {}, }; @@ -85,27 +87,29 @@ static int process_managed_oom_reply( if (ret == -ENOMEM) { r = ret; goto finish; - } else if (ret < 0) + } + if (ret < 0) continue; monitor_hm = streq(reply.property, "ManagedOOMSwap") ? m->monitored_swap_cgroup_contexts : m->monitored_mem_pressure_cgroup_contexts; if (reply.mode == MANAGED_OOM_AUTO) { - (void) oomd_cgroup_context_free(hashmap_remove(monitor_hm, reply.path)); + (void) oomd_cgroup_context_free(hashmap_remove(monitor_hm, empty_to_root(reply.path))); continue; } limit = m->default_mem_pressure_limit; - if (streq(reply.property, "ManagedOOMMemoryPressure")) { - if (reply.limit > 100) + if (streq(reply.property, "ManagedOOMMemoryPressure") && reply.limit > 0) { + int permyriad = UINT32_SCALE_TO_PERMYRIAD(reply.limit); + + ret = store_loadavg_fixed_point( + (unsigned long) permyriad / 100, + (unsigned long) permyriad % 100, + &limit); + if (ret < 0) continue; - else if (reply.limit != 0) { - ret = store_loadavg_fixed_point((unsigned long) reply.limit, 0, &limit); - if (ret < 0) - continue; - } } ret = oomd_insert_cgroup_context(NULL, monitor_hm, reply.path); @@ -113,10 +117,12 @@ static int process_managed_oom_reply( r = ret; goto finish; } + if (ret < 0 && ret != -EEXIST) + log_debug_errno(ret, "Failed to insert reply, ignoring: %m"); /* Always update the limit in case it was changed. For non-memory pressure detection the value is * ignored so always updating it here is not a problem. */ - ctx = hashmap_get(monitor_hm, reply.path); + ctx = hashmap_get(monitor_hm, empty_to_root(reply.path)); if (ctx) ctx->mem_pressure_limit = limit; } @@ -152,7 +158,11 @@ static int recursively_get_cgroup_context(Hashmap *new_h, const char *path) { return r; else if (r == 0) { /* No subgroups? We're a leaf node */ r = oomd_insert_cgroup_context(NULL, new_h, path); - return (r == -ENOMEM) ? r : 0; + if (r == -ENOMEM) + return r; + if (r < 0) + log_debug_errno(r, "Failed to insert context for %s, ignoring: %m", path); + return 0; } do { @@ -167,8 +177,12 @@ static int recursively_get_cgroup_context(Hashmap *new_h, const char *path) { r = cg_get_attribute_as_bool("memory", cg_path, "memory.oom.group", &oom_group); /* The cgroup might be gone. Skip it as a candidate since we can't get information on it. */ - if (r < 0) - return (r == -ENOMEM) ? r : 0; + if (r == -ENOMEM) + return r; + if (r < 0) { + log_debug_errno(r, "Failed to read memory.oom.group from %s, ignoring: %m", cg_path); + return 0; + } if (oom_group) r = oomd_insert_cgroup_context(NULL, new_h, cg_path); @@ -176,6 +190,8 @@ static int recursively_get_cgroup_context(Hashmap *new_h, const char *path) { r = recursively_get_cgroup_context(new_h, cg_path); if (r == -ENOMEM) return r; + if (r < 0) + log_debug_errno(r, "Failed to insert or recursively get from %s, ignoring: %m", cg_path); } while ((r = cg_read_subgroup(d, &subpath)) > 0); return 0; @@ -197,6 +213,8 @@ static int update_monitored_cgroup_contexts(Hashmap **monitored_cgroups) { r = oomd_insert_cgroup_context(*monitored_cgroups, new_base, ctx->path); if (r == -ENOMEM) return r; + if (r < 0 && !IN_SET(r, -EEXIST, -ENOENT)) + log_debug_errno(r, "Failed to insert context for %s, ignoring: %m", ctx->path); } hashmap_free(*monitored_cgroups); @@ -221,6 +239,8 @@ static int get_monitored_cgroup_contexts_candidates(Hashmap *monitored_cgroups, r = recursively_get_cgroup_context(candidates, ctx->path); if (r == -ENOMEM) return r; + if (r < 0) + log_debug_errno(r, "Failed to recursively get contexts for %s, ignoring: %m", ctx->path); } *ret_candidates = TAKE_PTR(candidates); @@ -228,6 +248,26 @@ static int get_monitored_cgroup_contexts_candidates(Hashmap *monitored_cgroups, return 0; } +static int update_monitored_cgroup_contexts_candidates(Hashmap *monitored_cgroups, Hashmap **candidates) { + _cleanup_hashmap_free_ Hashmap *new_candidates = NULL; + int r; + + assert(monitored_cgroups); + assert(candidates); + assert(*candidates); + + r = get_monitored_cgroup_contexts_candidates(monitored_cgroups, &new_candidates); + if (r < 0) + return log_debug_errno(r, "Failed to get candidate contexts: %m"); + + oomd_update_cgroup_contexts_between_hashmaps(*candidates, new_candidates); + + hashmap_free(*candidates); + *candidates = TAKE_PTR(new_candidates); + + return 0; +} + static int acquire_managed_oom_connect(Manager *m) { _cleanup_(varlink_close_unrefp) Varlink *link = NULL; int r; @@ -271,32 +311,49 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo /* Reset timer */ r = sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &usec_now); if (r < 0) - return log_error_errno(r, "Failed to reset event timer"); + return log_error_errno(r, "Failed to reset event timer: %m"); r = sd_event_source_set_time_relative(s, INTERVAL_USEC); if (r < 0) - return log_error_errno(r, "Failed to set relative time for timer"); + return log_error_errno(r, "Failed to set relative time for timer: %m"); /* Reconnect if our connection dropped */ if (!m->varlink) { r = acquire_managed_oom_connect(m); if (r < 0) - return log_error_errno(r, "Failed to acquire varlink connection"); + return log_error_errno(r, "Failed to acquire varlink connection: %m"); } /* Update the cgroups used for detection/action */ r = update_monitored_cgroup_contexts(&m->monitored_swap_cgroup_contexts); if (r == -ENOMEM) - return log_error_errno(r, "Failed to update monitored swap cgroup contexts"); + return log_oom(); + if (r < 0) + log_debug_errno(r, "Failed to update monitored swap cgroup contexts, ignoring: %m"); r = update_monitored_cgroup_contexts(&m->monitored_mem_pressure_cgroup_contexts); if (r == -ENOMEM) - return log_error_errno(r, "Failed to update monitored memory pressure cgroup contexts"); + return log_oom(); + if (r < 0) + log_debug_errno(r, "Failed to update monitored memory pressure cgroup contexts, ignoring: %m"); + + r = update_monitored_cgroup_contexts_candidates( + m->monitored_mem_pressure_cgroup_contexts, &m->monitored_mem_pressure_cgroup_contexts_candidates); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + log_debug_errno(r, "Failed to update monitored memory pressure candidate cgroup contexts, ignoring: %m"); r = oomd_system_context_acquire("/proc/swaps", &m->system_context); - /* If there aren't units depending on swap actions, the only error we exit on is ENOMEM */ - if (r == -ENOMEM || (r < 0 && !hashmap_isempty(m->monitored_swap_cgroup_contexts))) - return log_error_errno(r, "Failed to acquire system context"); + /* If there aren't units depending on swap actions, the only error we exit on is ENOMEM. + * Allow ENOENT in the event that swap is disabled on the system. */ + if (r == -ENOMEM || (r < 0 && r != -ENOENT && !hashmap_isempty(m->monitored_swap_cgroup_contexts))) + return log_error_errno(r, "Failed to acquire system context: %m"); + else if (r == -ENOENT) + zero(m->system_context); + + if (oomd_memory_reclaim(m->monitored_mem_pressure_cgroup_contexts)) + m->last_reclaim_at = usec_now; /* If we're still recovering from a kill, don't try to kill again yet */ if (m->post_action_delay_start > 0) { @@ -306,58 +363,81 @@ static int monitor_cgroup_contexts_handler(sd_event_source *s, uint64_t usec, vo m->post_action_delay_start = 0; } - r = oomd_pressure_above(m->monitored_mem_pressure_cgroup_contexts, PRESSURE_DURATION_USEC, &targets); + r = oomd_pressure_above(m->monitored_mem_pressure_cgroup_contexts, m->default_mem_pressure_duration_usec, &targets); if (r == -ENOMEM) - return log_error_errno(r, "Failed to check if memory pressure exceeded limits"); + return log_oom(); + if (r < 0) + log_debug_errno(r, "Failed to check if memory pressure exceeded limits, ignoring: %m"); else if (r == 1) { - /* Check if there was reclaim activity in the last interval. The concern is the following case: + /* Check if there was reclaim activity in the given interval. The concern is the following case: * Pressure climbed, a lot of high-frequency pages were reclaimed, and we killed the offending * cgroup. Even after this, well-behaved processes will fault in recently resident pages and * this will cause pressure to remain high. Thus if there isn't any reclaim pressure, no need * to kill something (it won't help anyways). */ - if (oomd_memory_reclaim(m->monitored_mem_pressure_cgroup_contexts)) { - _cleanup_hashmap_free_ Hashmap *candidates = NULL; + if ((usec_now - m->last_reclaim_at) <= RECLAIM_DURATION_USEC) { OomdCGroupContext *t; - r = get_monitored_cgroup_contexts_candidates(m->monitored_mem_pressure_cgroup_contexts, &candidates); - if (r == -ENOMEM) - return log_error_errno(r, "Failed to get monitored memory pressure cgroup candidates"); - SET_FOREACH(t, targets) { - log_notice("Memory pressure for %s is greater than %lu for more than %"PRIu64" seconds and there was reclaim activity", - t->path, LOAD_INT(t->mem_pressure_limit), PRESSURE_DURATION_USEC / USEC_PER_SEC); + _cleanup_free_ char *selected = NULL; + char ts[FORMAT_TIMESPAN_MAX]; - r = oomd_kill_by_pgscan(candidates, t->path, m->dry_run); + log_debug("Memory pressure for %s is %lu.%02lu%% > %lu.%02lu%% for > %s with reclaim activity", + t->path, + LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10), + LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit), + format_timespan(ts, sizeof ts, + m->default_mem_pressure_duration_usec, + USEC_PER_SEC)); + + r = oomd_kill_by_pgscan_rate(m->monitored_mem_pressure_cgroup_contexts_candidates, t->path, m->dry_run, &selected); if (r == -ENOMEM) - return log_error_errno(r, "Failed to kill cgroup processes by pgscan"); + return log_oom(); if (r < 0) - log_info("Failed to kill any cgroup(s) under %s based on pressure", t->path); + log_notice_errno(r, "Failed to kill any cgroup(s) under %s based on pressure: %m", t->path); else { /* Don't act on all the high pressure cgroups at once; return as soon as we kill one */ m->post_action_delay_start = usec_now; + if (selected) + log_notice("Killed %s due to memory pressure for %s being %lu.%02lu%% > %lu.%02lu%%" + " for > %s with reclaim activity", + selected, t->path, + LOAD_INT(t->memory_pressure.avg10), LOAD_FRAC(t->memory_pressure.avg10), + LOAD_INT(t->mem_pressure_limit), LOAD_FRAC(t->mem_pressure_limit), + format_timespan(ts, sizeof ts, + m->default_mem_pressure_duration_usec, + USEC_PER_SEC)); return 0; } } } } - if (oomd_swap_free_below(&m->system_context, (100 - m->swap_used_limit))) { + if (oomd_swap_free_below(&m->system_context, 10000 - m->swap_used_limit_permyriad)) { _cleanup_hashmap_free_ Hashmap *candidates = NULL; + _cleanup_free_ char *selected = NULL; - log_notice("Swap used (%"PRIu64") / total (%"PRIu64") is more than %u%%", - m->system_context.swap_used, m->system_context.swap_total, m->swap_used_limit); + log_debug("Swap used (%"PRIu64") / total (%"PRIu64") is more than " PERMYRIAD_AS_PERCENT_FORMAT_STR, + m->system_context.swap_used, m->system_context.swap_total, + PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad)); r = get_monitored_cgroup_contexts_candidates(m->monitored_swap_cgroup_contexts, &candidates); if (r == -ENOMEM) - return log_error_errno(r, "Failed to get monitored swap cgroup candidates"); - - r = oomd_kill_by_swap_usage(candidates, m->dry_run); - if (r == -ENOMEM) - return log_error_errno(r, "Failed to kill cgroup processes by swap usage"); + return log_oom(); if (r < 0) - log_info("Failed to kill any cgroup(s) based on swap"); + log_debug_errno(r, "Failed to get monitored swap cgroup candidates, ignoring: %m"); + + r = oomd_kill_by_swap_usage(candidates, m->dry_run, &selected); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) + log_notice_errno(r, "Failed to kill any cgroup(s) based on swap: %m"); else { m->post_action_delay_start = usec_now; + if (selected) + log_notice("Killed %s due to swap used (%"PRIu64") / total (%"PRIu64") being more than " + PERMYRIAD_AS_PERCENT_FORMAT_STR, + selected, m->system_context.swap_used, m->system_context.swap_total, + PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad)); return 0; } } @@ -390,7 +470,7 @@ static int monitor_cgroup_contexts(Manager *m) { return 0; } -void manager_free(Manager *m) { +Manager* manager_free(Manager *m) { assert(m); varlink_close_unref(m->varlink); @@ -402,8 +482,9 @@ void manager_free(Manager *m) { hashmap_free(m->monitored_swap_cgroup_contexts); hashmap_free(m->monitored_mem_pressure_cgroup_contexts); + hashmap_free(m->monitored_mem_pressure_cgroup_contexts_candidates); - free(m); + return mfree(m); } int manager_new(Manager **ret) { @@ -438,6 +519,10 @@ int manager_new(Manager **ret) { if (!m->monitored_mem_pressure_cgroup_contexts) return -ENOMEM; + m->monitored_mem_pressure_cgroup_contexts_candidates = hashmap_new(&oomd_cgroup_ctx_hash_ops); + if (!m->monitored_mem_pressure_cgroup_contexts_candidates) + return -ENOMEM; + *ret = TAKE_PTR(m); return 0; } @@ -471,22 +556,38 @@ static int manager_connect_bus(Manager *m) { return 0; } -int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit) { - unsigned long l; +int manager_start( + Manager *m, + bool dry_run, + int swap_used_limit_permyriad, + int mem_pressure_limit_permyriad, + usec_t mem_pressure_usec) { + + unsigned long l, f; int r; assert(m); m->dry_run = dry_run; - m->swap_used_limit = swap_used_limit != -1 ? swap_used_limit : DEFAULT_SWAP_USED_LIMIT; - assert(m->swap_used_limit <= 100); + m->swap_used_limit_permyriad = swap_used_limit_permyriad >= 0 ? swap_used_limit_permyriad : DEFAULT_SWAP_USED_LIMIT_PERCENT * 100; + assert(m->swap_used_limit_permyriad <= 10000); - l = mem_pressure_limit != -1 ? mem_pressure_limit : DEFAULT_MEM_PRESSURE_LIMIT; - r = store_loadavg_fixed_point(l, 0, &m->default_mem_pressure_limit); + if (mem_pressure_limit_permyriad >= 0) { + assert(mem_pressure_limit_permyriad <= 10000); + + l = mem_pressure_limit_permyriad / 100; + f = mem_pressure_limit_permyriad % 100; + } else { + l = DEFAULT_MEM_PRESSURE_LIMIT_PERCENT; + f = 0; + } + r = store_loadavg_fixed_point(l, f, &m->default_mem_pressure_limit); if (r < 0) return r; + m->default_mem_pressure_duration_usec = mem_pressure_usec ?: DEFAULT_MEM_PRESSURE_DURATION_USEC; + r = manager_connect_bus(m); if (r < 0) return r; @@ -505,6 +606,7 @@ int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressur int manager_get_dump_string(Manager *m, char **ret) { _cleanup_free_ char *dump = NULL; _cleanup_fclose_ FILE *f = NULL; + char buf[FORMAT_TIMESPAN_MAX]; OomdCGroupContext *c; size_t size; char *key; @@ -519,12 +621,14 @@ int manager_get_dump_string(Manager *m, char **ret) { fprintf(f, "Dry Run: %s\n" - "Swap Used Limit: %u%%\n" - "Default Memory Pressure Limit: %lu%%\n" + "Swap Used Limit: " PERMYRIAD_AS_PERCENT_FORMAT_STR "\n" + "Default Memory Pressure Limit: %lu.%02lu%%\n" + "Default Memory Pressure Duration: %s\n" "System Context:\n", yes_no(m->dry_run), - m->swap_used_limit, - LOAD_INT(m->default_mem_pressure_limit)); + PERMYRIAD_AS_PERCENT_FORMAT_VAL(m->swap_used_limit_permyriad), + LOAD_INT(m->default_mem_pressure_limit), LOAD_FRAC(m->default_mem_pressure_limit), + format_timespan(buf, sizeof(buf), m->default_mem_pressure_duration_usec, USEC_PER_SEC)); oomd_dump_system_context(&m->system_context, f, "\t"); fprintf(f, "Swap Monitored CGroups:\n"); diff --git a/src/oom/oomd-manager.h b/src/oom/oomd-manager.h index 3f3eb5aa4..9c580c8a2 100644 --- a/src/oom/oomd-manager.h +++ b/src/oom/oomd-manager.h @@ -16,10 +16,11 @@ * percentage of time all tasks were delayed (i.e. unproductive). * Generally 60 or higher might be acceptable for something like system.slice with no memory.high set; processes in * system.slice are assumed to be less latency sensitive. */ -#define PRESSURE_DURATION_USEC (30 * USEC_PER_SEC) -#define DEFAULT_MEM_PRESSURE_LIMIT 60 -#define DEFAULT_SWAP_USED_LIMIT 90 +#define DEFAULT_MEM_PRESSURE_DURATION_USEC (30 * USEC_PER_SEC) +#define DEFAULT_MEM_PRESSURE_LIMIT_PERCENT 60 +#define DEFAULT_SWAP_USED_LIMIT_PERCENT 90 +#define RECLAIM_DURATION_USEC (30 * USEC_PER_SEC) #define POST_ACTION_DELAY_USEC (15 * USEC_PER_SEC) typedef struct Manager Manager; @@ -31,16 +32,19 @@ struct Manager { Hashmap *polkit_registry; bool dry_run; - unsigned swap_used_limit; + int swap_used_limit_permyriad; loadavg_t default_mem_pressure_limit; + usec_t default_mem_pressure_duration_usec; /* k: cgroup paths -> v: OomdCGroupContext * Used to detect when to take action. */ Hashmap *monitored_swap_cgroup_contexts; Hashmap *monitored_mem_pressure_cgroup_contexts; + Hashmap *monitored_mem_pressure_cgroup_contexts_candidates; OomdSystemContext system_context; + usec_t last_reclaim_at; usec_t post_action_delay_start; sd_event_source *cgroup_context_event_source; @@ -48,12 +52,12 @@ struct Manager { Varlink *varlink; }; -void manager_free(Manager *m); +Manager* manager_free(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); int manager_new(Manager **ret); -int manager_start(Manager *m, bool dry_run, int swap_used_limit, int mem_pressure_limit); +int manager_start(Manager *m, bool dry_run, int swap_used_limit_permyriad, int mem_pressure_limit_permyriad, usec_t mem_pressure_usec); int manager_get_dump_string(Manager *m, char **ret); diff --git a/src/oom/oomd-util.c b/src/oom/oomd-util.c index cec656f6f..894d23a83 100644 --- a/src/oom/oomd-util.c +++ b/src/oom/oomd-util.c @@ -3,7 +3,6 @@ #include #include -#include "cgroup-util.h" #include "fd-util.h" #include "format-util.h" #include "oomd-util.h" @@ -135,13 +134,13 @@ bool oomd_memory_reclaim(Hashmap *h) { return pgscan_of > last_pgscan_of; } -bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent) { +bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad) { uint64_t swap_threshold; assert(ctx); - assert(threshold_percent <= 100); + assert(threshold_permyriad <= 10000); - swap_threshold = ctx->swap_total * threshold_percent / ((uint64_t) 100); + swap_threshold = ctx->swap_total * threshold_permyriad / (uint64_t) 10000; return (ctx->swap_total - ctx->swap_used) < swap_threshold; } @@ -159,7 +158,8 @@ int oomd_sort_cgroup_contexts(Hashmap *h, oomd_compare_t compare_func, const cha return -ENOMEM; HASHMAP_FOREACH(item, h) { - if (item->path && prefix && !path_startswith(item->path, prefix)) + /* Skip over cgroups that are not valid candidates or are explicitly marked for omission */ + if ((item->path && prefix && !path_startswith(item->path, prefix)) || item->preference == MANAGED_OOM_PREFERENCE_OMIT) continue; sorted[k++] = item; @@ -201,63 +201,96 @@ int oomd_cgroup_kill(const char *path, bool recurse, bool dry_run) { if (r < 0) return r; - r = increment_oomd_xattr(path, "user.systemd_oomd_kill", set_size(pids_killed)); + r = increment_oomd_xattr(path, "user.oomd_kill", set_size(pids_killed)); if (r < 0) - log_debug_errno(r, "Failed to set user.systemd_oomd_kill on kill: %m"); + log_debug_errno(r, "Failed to set user.oomd_kill on kill: %m"); return set_size(pids_killed) != 0; } -int oomd_kill_by_pgscan(Hashmap *h, const char *prefix, bool dry_run) { +int oomd_kill_by_pgscan_rate(Hashmap *h, const char *prefix, bool dry_run, char **ret_selected) { _cleanup_free_ OomdCGroupContext **sorted = NULL; - int r; + int n, r, ret = 0; assert(h); + assert(ret_selected); - r = oomd_sort_cgroup_contexts(h, compare_pgscan, prefix, &sorted); - if (r < 0) - return r; + n = oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, prefix, &sorted); + if (n < 0) + return n; - for (int i = 0; i < r; i++) { - if (sorted[i]->pgscan == 0) - break; + for (int i = 0; i < n; i++) { + /* Skip cgroups with no reclaim and memory usage; it won't alleviate pressure. + * Continue since there might be "avoid" cgroups at the end. */ + if (sorted[i]->pgscan == 0 && sorted[i]->current_memory_usage == 0) + continue; r = oomd_cgroup_kill(sorted[i]->path, true, dry_run); - if (r > 0 || r == -ENOMEM) - break; + if (r == 0) + continue; /* We didn't find anything to kill */ + if (r == -ENOMEM) + return r; /* Treat oom as a hard error */ + if (r < 0) { + if (ret == 0) + ret = r; + continue; /* Try to find something else to kill */ + } + + char *selected = strdup(sorted[i]->path); + if (!selected) + return -ENOMEM; + *ret_selected = selected; + return 1; } - return r; + return ret; } -int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run) { +int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run, char **ret_selected) { _cleanup_free_ OomdCGroupContext **sorted = NULL; - int r; + int n, r, ret = 0; assert(h); + assert(ret_selected); - r = oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted); - if (r < 0) - return r; + n = oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted); + if (n < 0) + return n; /* Try to kill cgroups with non-zero swap usage until we either succeed in * killing or we get to a cgroup with no swap usage. */ - for (int i = 0; i < r; i++) { + for (int i = 0; i < n; i++) { + /* Skip over cgroups with no resource usage. + * Continue break since there might be "avoid" cgroups at the end. */ if (sorted[i]->swap_usage == 0) - break; + continue; r = oomd_cgroup_kill(sorted[i]->path, true, dry_run); - if (r > 0 || r == -ENOMEM) - break; + if (r == 0) + continue; /* We didn't find anything to kill */ + if (r == -ENOMEM) + return r; /* Treat oom as a hard error */ + if (r < 0) { + if (ret == 0) + ret = r; + continue; /* Try to find something else to kill */ + } + + char *selected = strdup(sorted[i]->path); + if (!selected) + return -ENOMEM; + *ret_selected = selected; + return 1; } - return r; + return ret; } int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret) { _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL; _cleanup_free_ char *p = NULL, *val = NULL; bool is_root; + uid_t uid; int r; assert(path); @@ -268,6 +301,7 @@ int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret) { return -ENOMEM; is_root = empty_or_root(path); + ctx->preference = MANAGED_OOM_PREFERENCE_NONE; r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, path, "memory.pressure", &p); if (r < 0) @@ -277,6 +311,23 @@ int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret) { if (r < 0) return log_debug_errno(r, "Error parsing memory pressure from %s: %m", p); + r = cg_get_owner(SYSTEMD_CGROUP_CONTROLLER, path, &uid); + if (r < 0) + log_debug_errno(r, "Failed to get owner/group from %s: %m", path); + else if (uid == 0) { + /* Ignore most errors when reading the xattr since it is usually unset and cgroup xattrs are only used + * as an optional feature of systemd-oomd (and the system might not even support them). */ + r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, path, "user.oomd_avoid"); + if (r == -ENOMEM) + return r; + ctx->preference = r == 1 ? MANAGED_OOM_PREFERENCE_AVOID : ctx->preference; + + r = cg_get_xattr_bool(SYSTEMD_CGROUP_CONTROLLER, path, "user.oomd_omit"); + if (r == -ENOMEM) + return r; + ctx->preference = r == 1 ? MANAGED_OOM_PREFERENCE_OMIT : ctx->preference; + } + if (is_root) { r = procfs_memory_get_used(&ctx->current_memory_usage); if (r < 0) @@ -361,16 +412,20 @@ int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext * int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path) { _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *curr_ctx = NULL; - OomdCGroupContext *old_ctx, *ctx; + OomdCGroupContext *old_ctx; int r; assert(new_h); assert(path); + path = empty_to_root(path); + r = oomd_cgroup_context_acquire(path, &curr_ctx); if (r < 0) return log_debug_errno(r, "Failed to get OomdCGroupContext for %s: %m", path); + assert_se(streq(path, curr_ctx->path)); + old_ctx = hashmap_get(old_h, path); if (old_ctx) { curr_ctx->last_pgscan = old_ctx->pgscan; @@ -378,14 +433,33 @@ int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path) curr_ctx->last_hit_mem_pressure_limit = old_ctx->last_hit_mem_pressure_limit; } - ctx = TAKE_PTR(curr_ctx); - r = hashmap_put(new_h, ctx->path, ctx); + r = hashmap_put(new_h, curr_ctx->path, curr_ctx); if (r < 0) return r; + TAKE_PTR(curr_ctx); return 0; } +void oomd_update_cgroup_contexts_between_hashmaps(Hashmap *old_h, Hashmap *curr_h) { + OomdCGroupContext *ctx; + + assert(old_h); + assert(curr_h); + + HASHMAP_FOREACH(ctx, curr_h) { + OomdCGroupContext *old_ctx; + + old_ctx = hashmap_get(old_h, ctx->path); + if (!old_ctx) + continue; + + ctx->last_pgscan = old_ctx->pgscan; + ctx->mem_pressure_limit = old_ctx->mem_pressure_limit; + ctx->last_hit_mem_pressure_limit = old_ctx->last_hit_mem_pressure_limit; + } +} + void oomd_dump_swap_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix) { char swap[FORMAT_BYTES_MAX]; @@ -415,11 +489,11 @@ void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE fprintf(f, "%sPath: %s\n" - "%s\tMemory Pressure Limit: %lu%%\n" + "%s\tMemory Pressure Limit: %lu.%02lu%%\n" "%s\tPressure: Avg10: %lu.%02lu Avg60: %lu.%02lu Avg300: %lu.%02lu Total: %s\n" "%s\tCurrent Memory Usage: %s\n", strempty(prefix), ctx->path, - strempty(prefix), LOAD_INT(ctx->mem_pressure_limit), + strempty(prefix), LOAD_INT(ctx->mem_pressure_limit), LOAD_FRAC(ctx->mem_pressure_limit), strempty(prefix), LOAD_INT(ctx->memory_pressure.avg10), LOAD_FRAC(ctx->memory_pressure.avg10), LOAD_INT(ctx->memory_pressure.avg60), LOAD_FRAC(ctx->memory_pressure.avg60), @@ -431,10 +505,12 @@ void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE fprintf(f, "%s\tMemory Min: %s\n" "%s\tMemory Low: %s\n" - "%s\tPgscan: %" PRIu64 "\n", + "%s\tPgscan: %" PRIu64 "\n" + "%s\tLast Pgscan: %" PRIu64 "\n", strempty(prefix), format_bytes_cgroup_protection(mem_min, sizeof(mem_min), ctx->memory_min), strempty(prefix), format_bytes_cgroup_protection(mem_low, sizeof(mem_low), ctx->memory_low), - strempty(prefix), ctx->pgscan); + strempty(prefix), ctx->pgscan, + strempty(prefix), ctx->last_pgscan); } void oomd_dump_system_context(const OomdSystemContext *ctx, FILE *f, const char *prefix) { diff --git a/src/oom/oomd-util.h b/src/oom/oomd-util.h index 87ecda80f..51423130d 100644 --- a/src/oom/oomd-util.h +++ b/src/oom/oomd-util.h @@ -3,6 +3,7 @@ #include +#include "cgroup-util.h" #include "hashmap.h" #include "psi-util.h" @@ -29,8 +30,11 @@ struct OomdCGroupContext { uint64_t last_pgscan; uint64_t pgscan; + ManagedOOMPreference preference; + /* These are only used by oomd_pressure_above for acting on high memory pressure. */ loadavg_t mem_pressure_limit; + usec_t mem_pressure_duration_usec; usec_t last_hit_mem_pressure_limit; }; @@ -57,31 +61,55 @@ int oomd_pressure_above(Hashmap *h, usec_t duration, Set **ret); * current sum is higher than the last interval's sum (there was some reclaim activity). */ bool oomd_memory_reclaim(Hashmap *h); -/* Returns true if the amount of swap free is below the percentage of swap specified by `threshold_percent`. */ -bool oomd_swap_free_below(const OomdSystemContext *ctx, uint64_t threshold_percent); +/* Returns true if the amount of swap free is below the permyriad of swap specified by `threshold_permyriad`. */ +bool oomd_swap_free_below(const OomdSystemContext *ctx, int threshold_permyriad); + +/* The compare functions will sort from largest to smallest, putting all the contexts with "avoid" at the end + * (after the smallest values). */ +static inline int compare_pgscan_rate_and_memory_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) { + uint64_t last1, last2; + int r; -static inline int compare_pgscan(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) { assert(c1); assert(c2); - if ((*c1)->pgscan > (*c2)->pgscan) - return -1; - else if ((*c1)->pgscan < (*c2)->pgscan) - return 1; - else - return 0; + r = CMP((*c1)->preference, (*c2)->preference); + if (r != 0) + return r; + + /* If last_pgscan > pgscan, assume the cgroup was recreated and reset last_pgscan to zero. */ + last2 = (*c2)->last_pgscan; + if ((*c2)->last_pgscan > (*c2)->pgscan) { + log_info("Last pgscan %" PRIu64 "greater than current pgscan %" PRIu64 "for %s. Using last pgscan of zero.", + (*c2)->last_pgscan, (*c2)->pgscan, (*c2)->path); + last2 = 0; + } + + last1 = (*c1)->last_pgscan; + if ((*c1)->last_pgscan > (*c1)->pgscan) { + log_info("Last pgscan %" PRIu64 "greater than current pgscan %" PRIu64 "for %s. Using last pgscan of zero.", + (*c1)->last_pgscan, (*c1)->pgscan, (*c1)->path); + last1 = 0; + } + + r = CMP((*c2)->pgscan - last2, (*c1)->pgscan - last1); + if (r != 0) + return r; + + return CMP((*c2)->current_memory_usage, (*c1)->current_memory_usage); } static inline int compare_swap_usage(OomdCGroupContext * const *c1, OomdCGroupContext * const *c2) { + int r; + assert(c1); assert(c2); - if ((*c1)->swap_usage > (*c2)->swap_usage) - return -1; - else if ((*c1)->swap_usage < (*c2)->swap_usage) - return 1; - else - return 0; + r = CMP((*c1)->preference, (*c2)->preference); + if (r != 0) + return r; + + return CMP((*c2)->swap_usage, (*c1)->swap_usage); } /* Get an array of OomdCGroupContexts from `h`, qsorted from largest to smallest values according to `compare_func`. @@ -94,9 +122,10 @@ int oomd_cgroup_kill(const char *path, bool recurse, bool dry_run); /* The following oomd_kill_by_* functions return 1 if processes were killed, or negative otherwise. */ /* If `prefix` is supplied, only cgroups whose paths start with `prefix` are eligible candidates. Otherwise, - * everything in `h` is a candidate. */ -int oomd_kill_by_pgscan(Hashmap *h, const char *prefix, bool dry_run); -int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run); + * everything in `h` is a candidate. + * Returns the killed cgroup in ret_selected. */ +int oomd_kill_by_pgscan_rate(Hashmap *h, const char *prefix, bool dry_run, char **ret_selected); +int oomd_kill_by_swap_usage(Hashmap *h, bool dry_run, char **ret_selected); int oomd_cgroup_context_acquire(const char *path, OomdCGroupContext **ret); int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext *ret); @@ -107,6 +136,9 @@ int oomd_system_context_acquire(const char *proc_swaps_path, OomdSystemContext * * was no prior data to reference. */ int oomd_insert_cgroup_context(Hashmap *old_h, Hashmap *new_h, const char *path); +/* Update each OomdCGroupContext in `curr_h` with prior interval information from `old_h`. */ +void oomd_update_cgroup_contexts_between_hashmaps(Hashmap *old_h, Hashmap *curr_h); + void oomd_dump_swap_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix); void oomd_dump_memory_pressure_cgroup_context(const OomdCGroupContext *ctx, FILE *f, const char *prefix); void oomd_dump_system_context(const OomdSystemContext *ctx, FILE *f, const char *prefix); diff --git a/src/oom/oomd.c b/src/oom/oomd.c index 8cf776ec0..6e2a5889d 100644 --- a/src/oom/oomd.c +++ b/src/oom/oomd.c @@ -17,13 +17,15 @@ #include "signal-util.h" static bool arg_dry_run = false; -static int arg_swap_used_limit = -1; -static int arg_mem_pressure_limit = -1; +static int arg_swap_used_limit_permyriad = -1; +static int arg_mem_pressure_limit_permyriad = -1; +static usec_t arg_mem_pressure_usec = 0; static int parse_config(void) { static const ConfigTableItem items[] = { - { "OOM", "SwapUsedLimitPercent", config_parse_percent, 0, &arg_swap_used_limit }, - { "OOM", "DefaultMemoryPressureLimitPercent", config_parse_percent, 0, &arg_mem_pressure_limit }, + { "OOM", "SwapUsedLimit", config_parse_permyriad, 0, &arg_swap_used_limit_permyriad }, + { "OOM", "DefaultMemoryPressureLimit", config_parse_permyriad, 0, &arg_mem_pressure_limit_permyriad }, + { "OOM", "DefaultMemoryPressureDurationSec", config_parse_sec, 0, &arg_mem_pressure_usec }, {} }; @@ -51,10 +53,9 @@ static int help(void) { " --version Show package version\n" " --dry-run Only print destructive actions instead of doing them\n" " --bus-introspect=PATH Write D-Bus XML introspection data\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -121,7 +122,7 @@ static int run(int argc, char *argv[]) { unsigned long long s = 0; int r; - log_setup_service(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) @@ -140,10 +141,8 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to get SwapTotal from /proc/meminfo: %m"); r = safe_atollu(swap, &s); - if (r < 0) - return log_error_errno(r, "Failed to parse SwapTotal from /proc/meminfo: %s: %m", swap); - if (s == 0) - return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Requires swap to operate"); + if (r < 0 || s == 0) + log_warning("Swap is currently not detected; memory pressure usage will be degraded"); if (!is_pressure_supported()) return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Pressure Stall Information (PSI) is not supported"); @@ -160,13 +159,18 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to create manager: %m"); - r = manager_start(m, arg_dry_run, arg_swap_used_limit, arg_mem_pressure_limit); + r = manager_start( + m, + arg_dry_run, + arg_swap_used_limit_permyriad, + arg_mem_pressure_limit_permyriad, + arg_mem_pressure_usec); if (r < 0) return log_error_errno(r, "Failed to start up daemon: %m"); notify_msg = notify_start(NOTIFY_READY, NOTIFY_STOPPING); - log_info("systemd-oomd starting%s!", arg_dry_run ? " in dry run mode" : ""); + log_debug("systemd-oomd started%s.", arg_dry_run ? " in dry run mode" : ""); r = sd_event_loop(m->event); if (r < 0) diff --git a/src/oom/oomd.conf b/src/oom/oomd.conf index 8ac971696..d1dca0d64 100644 --- a/src/oom/oomd.conf +++ b/src/oom/oomd.conf @@ -1,16 +1,20 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. +# +# Use 'systemd-analyze cat-config systemd/oomd.conf' to display the full config. # # See oomd.conf(5) for details [OOM] -#SwapUsedLimitPercent=90% -#DefaultMemoryPressureLimitPercent=60% +#SwapUsedLimit=90% +#DefaultMemoryPressureLimit=60% +#DefaultMemoryPressureDurationSec=30s diff --git a/src/oom/test-oomd-util.c b/src/oom/test-oomd-util.c index 5df57107f..bd1c574ca 100644 --- a/src/oom/test-oomd-util.c +++ b/src/oom/test-oomd-util.c @@ -23,7 +23,7 @@ static int fork_and_sleep(unsigned sleep_min) { if (pid == 0) { timeout = sleep_min * USEC_PER_MINUTE; ts = now(CLOCK_MONOTONIC); - while (true) { + for (;;) { n = now(CLOCK_MONOTONIC); if (ts + timeout < n) { log_error("Child timed out waiting to be killed"); @@ -79,7 +79,7 @@ static void test_oomd_cgroup_kill(void) { sleep(2); assert_se(cg_is_empty(SYSTEMD_CGROUP_CONTROLLER, cgroup) == true); - assert_se(cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.systemd_oomd_kill", &v) >= 0); + assert_se(cg_get_xattr_malloc(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_kill", &v) >= 0); assert_se(memcmp(v, i == 0 ? "2" : "4", 2) == 0); } } @@ -89,6 +89,8 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) { _cleanup_(oomd_cgroup_context_freep) OomdCGroupContext *ctx = NULL; _cleanup_free_ char *cgroup = NULL; OomdCGroupContext *c1, *c2; + bool test_xattrs; + int r; if (geteuid() != 0) return (void) log_tests_skipped("not root"); @@ -101,6 +103,16 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) { assert_se(cg_pid_get_path(NULL, 0, &cgroup) >= 0); + /* If we don't have permissions to set xattrs we're likely in a userns or missing capabilities + * so skip the xattr portions of the test. */ + r = cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_test", "1", 1, 0); + test_xattrs = !ERRNO_IS_PRIVILEGE(r) && !ERRNO_IS_NOT_SUPPORTED(r); + + if (test_xattrs) { + assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_omit", "1", 1, 0) >= 0); + assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_avoid", "1", 1, 0) >= 0); + } + assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0); assert_se(streq(ctx->path, cgroup)); @@ -110,18 +122,35 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) { assert_se(ctx->swap_usage == 0); assert_se(ctx->last_pgscan == 0); assert_se(ctx->pgscan == 0); + /* omit takes precedence over avoid when both are set to true */ + if (test_xattrs) + assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_OMIT); + else + assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_NONE); + ctx = oomd_cgroup_context_free(ctx); + + /* also check when only avoid is set to true */ + if (test_xattrs) { + assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_omit", "0", 1, 0) >= 0); + assert_se(cg_set_xattr(SYSTEMD_CGROUP_CONTROLLER, cgroup, "user.oomd_avoid", "1", 1, 0) >= 0); + } + assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0); + if (test_xattrs) + assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_AVOID); ctx = oomd_cgroup_context_free(ctx); /* Test the root cgroup */ assert_se(oomd_cgroup_context_acquire("", &ctx) == 0); assert_se(streq(ctx->path, "/")); assert_se(ctx->current_memory_usage > 0); + assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_NONE); /* Test hashmap inserts */ assert_se(h1 = hashmap_new(&oomd_cgroup_ctx_hash_ops)); assert_se(oomd_insert_cgroup_context(NULL, h1, cgroup) == 0); c1 = hashmap_get(h1, cgroup); assert_se(c1); + assert_se(oomd_insert_cgroup_context(NULL, h1, cgroup) == -EEXIST); /* make sure certain values from h1 get updated in h2 */ c1->pgscan = 5555; @@ -137,6 +166,61 @@ static void test_oomd_cgroup_context_acquire_and_insert(void) { assert_se(c2->last_pgscan == 5555); assert_se(c2->mem_pressure_limit == 6789); assert_se(c2->last_hit_mem_pressure_limit == 42); + + /* Assert that avoid/omit are not set if the cgroup is not owned by root */ + if (test_xattrs) { + ctx = oomd_cgroup_context_free(ctx); + assert_se(cg_set_access(SYSTEMD_CGROUP_CONTROLLER, cgroup, 65534, 0) >= 0); + assert_se(oomd_cgroup_context_acquire(cgroup, &ctx) == 0); + assert_se(ctx->preference == MANAGED_OOM_PREFERENCE_NONE); + } +} + +static void test_oomd_update_cgroup_contexts_between_hashmaps(void) { + _cleanup_hashmap_free_ Hashmap *h_old = NULL, *h_new = NULL; + OomdCGroupContext *c_old, *c_new; + char **paths = STRV_MAKE("/0.slice", + "/1.slice"); + + OomdCGroupContext ctx_old[3] = { + { .path = paths[0], + .mem_pressure_limit = 5, + .last_hit_mem_pressure_limit = 777, + .pgscan = 57 }, + { .path = paths[1], + .mem_pressure_limit = 6, + .last_hit_mem_pressure_limit = 888, + .pgscan = 42 }, + }; + + OomdCGroupContext ctx_new[3] = { + { .path = paths[0], + .pgscan = 100 }, + { .path = paths[1], + .pgscan = 101 }, + }; + + assert_se(h_old = hashmap_new(&string_hash_ops)); + assert_se(hashmap_put(h_old, paths[0], &ctx_old[0]) >= 0); + assert_se(hashmap_put(h_old, paths[1], &ctx_old[1]) >= 0); + + assert_se(h_new = hashmap_new(&string_hash_ops)); + assert_se(hashmap_put(h_new, paths[0], &ctx_new[0]) >= 0); + assert_se(hashmap_put(h_new, paths[1], &ctx_new[1]) >= 0); + + oomd_update_cgroup_contexts_between_hashmaps(h_old, h_new); + + assert_se(c_old = hashmap_get(h_old, "/0.slice")); + assert_se(c_new = hashmap_get(h_new, "/0.slice")); + assert_se(c_old->pgscan == c_new->last_pgscan); + assert_se(c_old->mem_pressure_limit == c_new->mem_pressure_limit); + assert_se(c_old->last_hit_mem_pressure_limit == c_new->last_hit_mem_pressure_limit); + + assert_se(c_old = hashmap_get(h_old, "/1.slice")); + assert_se(c_new = hashmap_get(h_new, "/1.slice")); + assert_se(c_old->pgscan == c_new->last_pgscan); + assert_se(c_old->mem_pressure_limit == c_new->mem_pressure_limit); + assert_se(c_old->last_hit_mem_pressure_limit == c_new->last_hit_mem_pressure_limit); } static void test_oomd_system_context_acquire(void) { @@ -159,6 +243,11 @@ static void test_oomd_system_context_acquire(void) { assert_se(ctx.swap_total == 0); assert_se(ctx.swap_used == 0); + assert_se(write_string_file(path, "Filename Type Size Used Priority", WRITE_STRING_FILE_CREATE) == 0); + assert_se(oomd_system_context_acquire(path, &ctx) == 0); + assert_se(ctx.swap_total == 0); + assert_se(ctx.swap_used == 0); + assert_se(write_string_file(path, "Filename Type Size Used Priority\n" "/swapvol/swapfile file 18971644 0 -3\n" "/dev/vda2 partition 1999868 993780 -2", WRITE_STRING_FILE_CREATE) == 0); @@ -261,13 +350,19 @@ static void test_oomd_swap_free_below(void) { .swap_total = 20971512 * 1024U, .swap_used = 20971440 * 1024U, }; - assert_se(oomd_swap_free_below(&ctx, 20) == true); + assert_se(oomd_swap_free_below(&ctx, 2000) == true); ctx = (OomdSystemContext) { .swap_total = 20971512 * 1024U, .swap_used = 3310136 * 1024U, }; - assert_se(oomd_swap_free_below(&ctx, 20) == false); + assert_se(oomd_swap_free_below(&ctx, 2000) == false); + + ctx = (OomdSystemContext) { + .swap_total = 0, + .swap_used = 0, + }; + assert_se(oomd_swap_free_below(&ctx, 2000) == false); } static void test_oomd_sort_cgroups(void) { @@ -276,21 +371,47 @@ static void test_oomd_sort_cgroups(void) { char **paths = STRV_MAKE("/herp.slice", "/herp.slice/derp.scope", "/herp.slice/derp.scope/sheep.service", - "/zupa.slice"); + "/zupa.slice", + "/boop.slice", + "/omitted.slice", + "/avoid.slice"); - OomdCGroupContext ctx[4] = { + OomdCGroupContext ctx[7] = { { .path = paths[0], .swap_usage = 20, - .pgscan = 60 }, + .last_pgscan = 0, + .pgscan = 33, + .current_memory_usage = 10 }, { .path = paths[1], .swap_usage = 60, - .pgscan = 40 }, + .last_pgscan = 33, + .pgscan = 1, + .current_memory_usage = 20 }, { .path = paths[2], .swap_usage = 40, - .pgscan = 20 }, + .last_pgscan = 1, + .pgscan = 33, + .current_memory_usage = 40 }, { .path = paths[3], .swap_usage = 10, - .pgscan = 80 }, + .last_pgscan = 33, + .pgscan = 2, + .current_memory_usage = 10 }, + { .path = paths[4], + .swap_usage = 11, + .last_pgscan = 33, + .pgscan = 33, + .current_memory_usage = 10 }, + { .path = paths[5], + .swap_usage = 90, + .last_pgscan = 0, + .pgscan = UINT64_MAX, + .preference = MANAGED_OOM_PREFERENCE_OMIT }, + { .path = paths[6], + .swap_usage = 99, + .last_pgscan = 0, + .pgscan = UINT64_MAX, + .preference = MANAGED_OOM_PREFERENCE_AVOID }, }; assert_se(h = hashmap_new(&string_hash_ops)); @@ -299,26 +420,36 @@ static void test_oomd_sort_cgroups(void) { assert_se(hashmap_put(h, "/herp.slice/derp.scope", &ctx[1]) >= 0); assert_se(hashmap_put(h, "/herp.slice/derp.scope/sheep.service", &ctx[2]) >= 0); assert_se(hashmap_put(h, "/zupa.slice", &ctx[3]) >= 0); + assert_se(hashmap_put(h, "/boop.slice", &ctx[4]) >= 0); + assert_se(hashmap_put(h, "/omitted.slice", &ctx[5]) >= 0); + assert_se(hashmap_put(h, "/avoid.slice", &ctx[6]) >= 0); - assert_se(oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted_cgroups) == 4); + assert_se(oomd_sort_cgroup_contexts(h, compare_swap_usage, NULL, &sorted_cgroups) == 6); assert_se(sorted_cgroups[0] == &ctx[1]); assert_se(sorted_cgroups[1] == &ctx[2]); assert_se(sorted_cgroups[2] == &ctx[0]); - assert_se(sorted_cgroups[3] == &ctx[3]); + assert_se(sorted_cgroups[3] == &ctx[4]); + assert_se(sorted_cgroups[4] == &ctx[3]); + assert_se(sorted_cgroups[5] == &ctx[6]); sorted_cgroups = mfree(sorted_cgroups); - assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan, NULL, &sorted_cgroups) == 4); - assert_se(sorted_cgroups[0] == &ctx[3]); - assert_se(sorted_cgroups[1] == &ctx[0]); - assert_se(sorted_cgroups[2] == &ctx[1]); - assert_se(sorted_cgroups[3] == &ctx[2]); - sorted_cgroups = mfree(sorted_cgroups); - - assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan, "/herp.slice/derp.scope", &sorted_cgroups) == 2); - assert_se(sorted_cgroups[0] == &ctx[1]); + assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, NULL, &sorted_cgroups) == 6); + assert_se(sorted_cgroups[0] == &ctx[0]); assert_se(sorted_cgroups[1] == &ctx[2]); + assert_se(sorted_cgroups[2] == &ctx[3]); + assert_se(sorted_cgroups[3] == &ctx[1]); + assert_se(sorted_cgroups[4] == &ctx[4]); + assert_se(sorted_cgroups[5] == &ctx[6]); + sorted_cgroups = mfree(sorted_cgroups); + + assert_se(oomd_sort_cgroup_contexts(h, compare_pgscan_rate_and_memory_usage, "/herp.slice/derp.scope", &sorted_cgroups) == 2); + assert_se(sorted_cgroups[0] == &ctx[2]); + assert_se(sorted_cgroups[1] == &ctx[1]); assert_se(sorted_cgroups[2] == 0); assert_se(sorted_cgroups[3] == 0); + assert_se(sorted_cgroups[4] == 0); + assert_se(sorted_cgroups[5] == 0); + assert_se(sorted_cgroups[6] == 0); sorted_cgroups = mfree(sorted_cgroups); } @@ -327,6 +458,7 @@ int main(void) { test_setup_logging(LOG_DEBUG); + test_oomd_update_cgroup_contexts_between_hashmaps(); test_oomd_system_context_acquire(); test_oomd_pressure_above(); test_oomd_memory_reclaim(); diff --git a/src/partition/growfs.c b/src/partition/growfs.c index 9406ae837..15c56d058 100644 --- a/src/partition/growfs.c +++ b/src/partition/growfs.c @@ -140,10 +140,9 @@ static int help(void) { " -h --help Show this help and exit\n" " --version Print version string and exit\n" " -n --dry-run Just print what would be done\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -202,7 +201,7 @@ static int run(int argc, char *argv[]) { dev_t devno; int r; - log_setup_service(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/partition/makefs.c b/src/partition/makefs.c index fd924d223..7c94fbfed 100644 --- a/src/partition/makefs.c +++ b/src/partition/makefs.c @@ -24,7 +24,7 @@ static int run(int argc, char *argv[]) { struct stat st; int r; - log_setup_service(); + log_setup(); if (argc != 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/partition/repart.c b/src/partition/repart.c index 6db413ed5..f6d337ee2 100644 --- a/src/partition/repart.c +++ b/src/partition/repart.c @@ -34,6 +34,7 @@ #include "format-util.h" #include "fs-util.h" #include "gpt.h" +#include "hexdecoct.h" #include "id128-util.h" #include "json.h" #include "list.h" @@ -43,6 +44,7 @@ #include "mkdir.h" #include "mkfs-util.h" #include "mount-util.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -54,9 +56,11 @@ #include "specifier.h" #include "stat-util.h" #include "stdio-util.h" +#include "string-table.h" #include "string-util.h" #include "strv.h" #include "terminal-util.h" +#include "tpm2-util.h" #include "user-util.h" #include "utf8.h" @@ -103,19 +107,32 @@ static bool arg_randomize = false; static int arg_pretty = -1; static uint64_t arg_size = UINT64_MAX; static bool arg_size_auto = false; -static bool arg_json = false; -static JsonFormatFlags arg_json_format_flags = 0; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; +static PagerFlags arg_pager_flags = 0; +static bool arg_legend = true; static void *arg_key = NULL; static size_t arg_key_size = 0; +static char *arg_tpm2_device = NULL; +static uint32_t arg_tpm2_pcr_mask = UINT32_MAX; STATIC_DESTRUCTOR_REGISTER(arg_root, freep); STATIC_DESTRUCTOR_REGISTER(arg_definitions, freep); STATIC_DESTRUCTOR_REGISTER(arg_key, erase_and_freep); +STATIC_DESTRUCTOR_REGISTER(arg_tpm2_device, freep); typedef struct Partition Partition; typedef struct FreeArea FreeArea; typedef struct Context Context; +typedef enum EncryptMode { + ENCRYPT_OFF, + ENCRYPT_KEY_FILE, + ENCRYPT_TPM2, + ENCRYPT_KEY_FILE_TPM2, + _ENCRYPT_MODE_MAX, + _ENCRYPT_MODE_INVALID = -EINVAL, +} EncryptMode; + struct Partition { char *definition_path; @@ -149,7 +166,7 @@ struct Partition { char *format; char **copy_files; - bool encrypt; + EncryptMode encrypt; LIST_FIELDS(Partition, partitions); }; @@ -177,6 +194,15 @@ struct Context { sd_id128_t seed; }; +static const char *encrypt_mode_table[_ENCRYPT_MODE_MAX] = { + [ENCRYPT_OFF] = "off", + [ENCRYPT_KEY_FILE] = "key-file", + [ENCRYPT_TPM2] = "tpm2", + [ENCRYPT_KEY_FILE_TPM2] = "key-file+tpm2", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(encrypt_mode, EncryptMode, ENCRYPT_KEY_FILE); + static uint64_t round_down_size(uint64_t v, uint64_t p) { return (v / p) * p; } @@ -388,12 +414,12 @@ static uint64_t partition_min_size(const Partition *p) { if (!PARTITION_EXISTS(p)) { uint64_t d = 0; - if (p->encrypt) + if (p->encrypt != ENCRYPT_OFF) d += round_up_size(LUKS2_METADATA_SIZE, 4096); if (p->copy_blocks_size != UINT64_MAX) d += round_up_size(p->copy_blocks_size, 4096); - else if (p->format || p->encrypt) { + else if (p->format || p->encrypt != ENCRYPT_OFF) { uint64_t f; /* If we shall synthesize a file system, take minimal fs size into account (assumed to be 4K if not known) */ @@ -934,7 +960,6 @@ static int config_parse_label( void *data, void *userdata) { - _cleanup_free_ char16_t *recoded = NULL; _cleanup_free_ char *resolved = NULL; char **label = data; int r; @@ -955,11 +980,14 @@ static int config_parse_label( return 0; } - recoded = utf8_to_utf16(resolved, strlen(resolved)); - if (!recoded) - return log_oom(); - - if (char16_strlen(recoded) > 36) { + r = gpt_partition_label_valid(resolved); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to check if string is valid as GPT partition label, ignoring: \"%s\" (from \"%s\")", + resolved, rvalue); + return 0; + } + if (!r) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Partition label too long for GPT table, ignoring: \"%s\" (from \"%s\")", resolved, rvalue); @@ -1137,6 +1165,8 @@ static int config_parse_copy_files( return 0; } +static DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(config_parse_encrypt, encrypt_mode, EncryptMode, ENCRYPT_OFF, "Invalid encryption mode"); + static int partition_read_definition(Partition *p, const char *path) { ConfigTableItem table[] = { @@ -1154,7 +1184,7 @@ static int partition_read_definition(Partition *p, const char *path) { { "Partition", "CopyBlocks", config_parse_path, 0, &p->copy_blocks_path }, { "Partition", "Format", config_parse_fstype, 0, &p->format }, { "Partition", "CopyFiles", config_parse_copy_files, 0, p }, - { "Partition", "Encrypt", config_parse_bool, 0, &p->encrypt }, + { "Partition", "Encrypt", config_parse_encrypt, 0, &p->encrypt }, {} }; int r; @@ -1188,7 +1218,7 @@ static int partition_read_definition(Partition *p, const char *path) { return log_syntax(NULL, LOG_ERR, path, 1, SYNTHETIC_ERRNO(EINVAL), "Format=swap and CopyFiles= cannot be combined, refusing."); - if (!p->format && (!strv_isempty(p->copy_files) || (p->encrypt && !p->copy_blocks_path))) { + if (!p->format && (!strv_isempty(p->copy_files) || (p->encrypt != ENCRYPT_OFF && !p->copy_blocks_path))) { /* Pick "ext4" as file system if we are configured to copy files or encrypt the device */ p->format = strdup("ext4"); if (!p->format) @@ -1240,10 +1270,10 @@ static int context_read_definitions( return 0; } -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_context*, fdisk_unref_context); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_partition*, fdisk_unref_partition); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_parttype*, fdisk_unref_parttype); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct fdisk_table*, fdisk_unref_table); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_context*, fdisk_unref_context, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_partition*, fdisk_unref_partition, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_parttype*, fdisk_unref_parttype, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct fdisk_table*, fdisk_unref_table, NULL); static int determine_current_padding( struct fdisk_context *c, @@ -1798,7 +1828,7 @@ static int context_dump_partitions(Context *context, const char *node) { Partition *p; int r; - if (!arg_json && context->n_partitions == 0) { + if ((arg_json_format_flags & JSON_FORMAT_OFF) && context->n_partitions == 0) { log_info("Empty partition table."); return 0; } @@ -1808,12 +1838,12 @@ static int context_dump_partitions(Context *context, const char *node) { return log_oom(); if (!DEBUG_LOGGING) { - if (arg_json) + if (arg_json_format_flags & JSON_FORMAT_OFF) (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, - (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12, (size_t) -1); + (size_t) 8, (size_t) 11); else (void) table_set_display(t, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, - (size_t) 8, (size_t) 11, (size_t) -1); + (size_t) 5, (size_t) 6, (size_t) 7, (size_t) 9, (size_t) 10, (size_t) 12); } (void) table_set_align_percent(t, table_get_cell(t, 0, 4), 100); @@ -1867,7 +1897,7 @@ static int context_dump_partitions(Context *context, const char *node) { return table_log_add_error(r); } - if (!arg_json && (sum_padding > 0 || sum_size > 0)) { + if ((arg_json_format_flags & JSON_FORMAT_OFF) && (sum_padding > 0 || sum_size > 0)) { char s[FORMAT_BYTES_MAX]; const char *a, *b; @@ -1893,14 +1923,7 @@ static int context_dump_partitions(Context *context, const char *node) { return table_log_add_error(r); } - if (arg_json) - r = table_print_json(t, stdout, arg_json_format_flags); - else - r = table_print(t, stdout); - if (r < 0) - return log_error_errno(r, "Failed to dump table: %m"); - - return 0; + return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); } static void context_bar_char_process_partition( @@ -2376,7 +2399,9 @@ static int partition_encrypt( int r; assert(p); - assert(p->encrypt); + assert(p->encrypt != ENCRYPT_OFF); + + log_debug("Encryption mode for partition %" PRIu64 ": %s", p->partno, encrypt_mode_to_string(p->encrypt)); r = dlopen_cryptsetup(); if (r < 0) @@ -2425,15 +2450,61 @@ static int partition_encrypt( if (r < 0) return log_error_errno(r, "Failed to LUKS2 format future partition: %m"); - r = sym_crypt_keyslot_add_by_volume_key( - cd, - CRYPT_ANY_SLOT, - volume_key, - volume_key_size, - strempty(arg_key), - arg_key_size); - if (r < 0) - return log_error_errno(r, "Failed to add LUKS2 key: %m"); + if (IN_SET(p->encrypt, ENCRYPT_KEY_FILE, ENCRYPT_KEY_FILE_TPM2)) { + r = sym_crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + strempty(arg_key), + arg_key_size); + if (r < 0) + return log_error_errno(r, "Failed to add LUKS2 key: %m"); + } + + if (IN_SET(p->encrypt, ENCRYPT_TPM2, ENCRYPT_KEY_FILE_TPM2)) { +#if HAVE_TPM2 + _cleanup_(erase_and_freep) char *base64_encoded = NULL; + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + _cleanup_(erase_and_freep) void *secret = NULL; + _cleanup_free_ void *blob = NULL, *hash = NULL; + size_t secret_size, blob_size, hash_size; + int keyslot; + + r = tpm2_seal(arg_tpm2_device, arg_tpm2_pcr_mask, &secret, &secret_size, &blob, &blob_size, &hash, &hash_size); + if (r < 0) + return log_error_errno(r, "Failed to seal to TPM2: %m"); + + r = base64mem(secret, secret_size, &base64_encoded); + if (r < 0) + return log_error_errno(r, "Failed to base64 encode secret key: %m"); + + r = cryptsetup_set_minimal_pbkdf(cd); + if (r < 0) + return log_error_errno(r, "Failed to set minimal PBKDF: %m"); + + keyslot = sym_crypt_keyslot_add_by_volume_key( + cd, + CRYPT_ANY_SLOT, + volume_key, + volume_key_size, + base64_encoded, + strlen(base64_encoded)); + if (keyslot < 0) + return log_error_errno(keyslot, "Failed to add new TPM2 key to %s: %m", node); + + r = tpm2_make_luks2_json(keyslot, arg_tpm2_pcr_mask, blob, blob_size, hash, hash_size, &v); + if (r < 0) + return log_error_errno(r, "Failed to prepare TPM2 JSON token object: %m"); + + r = cryptsetup_add_token_json(cd, v); + if (r < 0) + return log_error_errno(r, "Failed to add TPM2 JSON token to LUKS2 header: %m"); +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "Support for TPM2 enrollment not enabled."); +#endif + } r = sym_crypt_activate_by_volume_key( cd, @@ -2521,7 +2592,7 @@ static int context_copy_blocks(Context *context) { if (whole_fd < 0) assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0); - if (p->encrypt) { + if (p->encrypt != ENCRYPT_OFF) { r = loop_device_make(whole_fd, O_RDWR, p->offset, p->new_size, 0, &d); if (r < 0) return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno); @@ -2554,7 +2625,7 @@ static int context_copy_blocks(Context *context) { if (fsync(target_fd) < 0) return log_error_errno(r, "Failed to synchronize copied data blocks: %m"); - if (p->encrypt) { + if (p->encrypt != ENCRYPT_OFF) { encrypted_dev_fd = safe_close(encrypted_dev_fd); r = deactivate_luks(cd, encrypted); @@ -2743,7 +2814,7 @@ static int context_mkfs(Context *context) { if (r < 0) return log_error_errno(r, "Failed to lock loopback device: %m"); - if (p->encrypt) { + if (p->encrypt != ENCRYPT_OFF) { r = partition_encrypt(p, d->node, &cd, &encrypted, &encrypted_dev_fd); if (r < 0) return log_error_errno(r, "Failed to encrypt device: %m"); @@ -2773,7 +2844,7 @@ static int context_mkfs(Context *context) { log_info("Successfully formatted future partition %" PRIu64 ".", p->partno); /* The file system is now created, no need to delay udev further */ - if (p->encrypt) + if (p->encrypt != ENCRYPT_OFF) if (flock(encrypted_dev_fd, LOCK_UN) < 0) return log_error_errno(errno, "Failed to unlock LUKS device: %m"); @@ -2788,7 +2859,7 @@ static int context_mkfs(Context *context) { * if we don't sync before detaching a block device the in-flight sectors possibly won't hit * the disk. */ - if (p->encrypt) { + if (p->encrypt != ENCRYPT_OFF) { if (fsync(encrypted_dev_fd) < 0) return log_error_errno(r, "Failed to synchronize LUKS volume: %m"); encrypted_dev_fd = safe_close(encrypted_dev_fd); @@ -2923,8 +2994,6 @@ static int partition_acquire_label(Context *context, Partition *p, char **ret) { break; label = mfree(label); - - if (asprintf(&label, "%s-%u", prefix, ++k) < 0) return log_oom(); } @@ -3129,13 +3198,13 @@ static int context_write_partition_table( if (arg_pretty > 0 || (arg_pretty < 0 && isatty(STDOUT_FILENO) > 0) || - arg_json) { + !FLAGS_SET(arg_json_format_flags, JSON_FORMAT_OFF)) { (void) context_dump_partitions(context, node); putc('\n', stdout); - if (!arg_json) + if (arg_json_format_flags & JSON_FORMAT_OFF) (void) context_dump_partition_bar(context, node); putc('\n', stdout); fflush(stdout); @@ -3409,6 +3478,8 @@ static int help(void) { "\n%sGrow and add partitions to partition table.%s\n\n" " -h --help Show this help\n" " --version Show package version\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" " --dry-run=BOOL Whether to run dry-run operation\n" " --empty=MODE One of refuse, allow, require, force, create; controls\n" " how to handle empty disks lacking partition tables\n" @@ -3418,17 +3489,20 @@ static int help(void) { " them\n" " --can-factory-reset Test whether factory reset is defined\n" " --root=PATH Operate relative to root path\n" - " --definitions=DIR Find partitions in specified directory\n" + " --definitions=DIR Find partition definitions in specified directory\n" " --key-file=PATH Key to use when encrypting partitions\n" + " --tpm2-device=PATH Path to TPM2 device node to use\n" + " --tpm2-pcrs=PCR1,PCR2,…\n" + " TPM2 PCR indexes to use for TPM2 enrollment\n" " --seed=UUID 128bit seed UUID to derive all UUIDs from\n" " --size=BYTES Grow loopback file to specified size\n" " --json=pretty|short|off\n" " Generate JSON output\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -3437,6 +3511,8 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, ARG_DRY_RUN, ARG_EMPTY, ARG_DISCARD, @@ -3449,11 +3525,15 @@ static int parse_argv(int argc, char *argv[]) { ARG_SIZE, ARG_JSON, ARG_KEY_FILE, + ARG_TPM2_DEVICE, + ARG_TPM2_PCRS, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, { "dry-run", required_argument, NULL, ARG_DRY_RUN }, { "empty", required_argument, NULL, ARG_EMPTY }, { "discard", required_argument, NULL, ARG_DISCARD }, @@ -3466,6 +3546,8 @@ static int parse_argv(int argc, char *argv[]) { { "size", required_argument, NULL, ARG_SIZE }, { "json", required_argument, NULL, ARG_JSON }, { "key-file", required_argument, NULL, ARG_KEY_FILE }, + { "tpm2-device", required_argument, NULL, ARG_TPM2_DEVICE }, + { "tpm2-pcrs", required_argument, NULL, ARG_TPM2_PCRS }, {} }; @@ -3484,12 +3566,18 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); - case ARG_DRY_RUN: - r = parse_boolean(optarg); - if (r < 0) - return log_error_errno(r, "Failed to parse --dry-run= parameter: %s", optarg); + case ARG_NO_PAGER: + arg_pager_flags |= PAGER_DISABLE; + break; - dry_run = r; + case ARG_NO_LEGEND: + arg_legend = false; + break; + + case ARG_DRY_RUN: + r = parse_boolean_argument("--dry-run=", optarg, &arg_dry_run); + if (r < 0) + return r; break; case ARG_EMPTY: @@ -3514,18 +3602,15 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_DISCARD: - r = parse_boolean(optarg); + r = parse_boolean_argument("--discard=", optarg, &arg_discard); if (r < 0) - return log_error_errno(r, "Failed to parse --discard= parameter: %s", optarg); - - arg_discard = r; + return r; break; case ARG_FACTORY_RESET: - r = parse_boolean(optarg); + r = parse_boolean_argument("--factory-reset=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --factory-reset= parameter: %s", optarg); - + return r; arg_factory_reset = r; break; @@ -3534,7 +3619,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, false, &arg_root); + r = parse_path_argument(optarg, false, &arg_root); if (r < 0) return r; break; @@ -3556,15 +3641,14 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_PRETTY: - r = parse_boolean(optarg); + r = parse_boolean_argument("--pretty=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --pretty= parameter: %s", optarg); - + return r; arg_pretty = r; break; case ARG_DEFINITIONS: - r = parse_path_argument_and_warn(optarg, false, &arg_definitions); + r = parse_path_argument(optarg, false, &arg_definitions); if (r < 0) return r; break; @@ -3598,22 +3682,9 @@ static int parse_argv(int argc, char *argv[]) { } case ARG_JSON: - if (streq(optarg, "pretty")) { - arg_json = true; - arg_json_format_flags = JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR_AUTO; - } else if (streq(optarg, "short")) { - arg_json = true; - arg_json_format_flags = JSON_FORMAT_NEWLINE; - } else if (streq(optarg, "off")) { - arg_json = false; - arg_json_format_flags = 0; - } else if (streq(optarg, "help")) { - puts("pretty\n" - "short\n" - "off"); - return 0; - } else - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown argument to --json=: %s", optarg); + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; break; @@ -3621,7 +3692,11 @@ static int parse_argv(int argc, char *argv[]) { _cleanup_(erase_and_freep) char *k = NULL; size_t n = 0; - r = read_full_file_full(AT_FDCWD, optarg, READ_FULL_FILE_SECURE|READ_FULL_FILE_CONNECT_SOCKET, NULL, &k, &n); + r = read_full_file_full( + AT_FDCWD, optarg, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_SECURE|READ_FULL_FILE_WARN_WORLD_READABLE|READ_FULL_FILE_CONNECT_SOCKET, + NULL, + &k, &n); if (r < 0) return log_error_errno(r, "Failed to read key file '%s': %m", optarg); @@ -3631,6 +3706,43 @@ static int parse_argv(int argc, char *argv[]) { break; } + case ARG_TPM2_DEVICE: { + _cleanup_free_ char *device = NULL; + + if (streq(optarg, "list")) + return tpm2_list_devices(); + + if (!streq(optarg, "auto")) { + device = strdup(optarg); + if (!device) + return log_oom(); + } + + free(arg_tpm2_device); + arg_tpm2_device = TAKE_PTR(device); + break; + } + + case ARG_TPM2_PCRS: { + uint32_t mask; + + if (isempty(optarg)) { + arg_tpm2_pcr_mask = 0; + break; + } + + r = tpm2_parse_pcrs(optarg, &mask); + if (r < 0) + return r; + + if (arg_tpm2_pcr_mask == UINT32_MAX) + arg_tpm2_pcr_mask = mask; + else + arg_tpm2_pcr_mask |= mask; + + break; + } + case '?': return -EINVAL; @@ -3663,6 +3775,9 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "A path to a device node or loopback file must be specified when --empty=force, --empty=require or --empty=create are used."); + if (arg_tpm2_pcr_mask == UINT32_MAX) + arg_tpm2_pcr_mask = TPM2_PCR_MASK_DEFAULT; + return 1; } @@ -3732,7 +3847,7 @@ static int remove_efi_variable_factory_reset(void) { static int acquire_root_devno(const char *p, int mode, char **ret, int *ret_fd) { _cleanup_close_ int fd = -1; struct stat st; - dev_t devno, fd_devno = (mode_t) -1; + dev_t devno, fd_devno = MODE_INVALID; int r; assert(p); @@ -3790,7 +3905,7 @@ static int acquire_root_devno(const char *p, int mode, char **ret, int *ret_fd) /* Only if we still lock at the same block device we can reuse the fd. Otherwise return an * invalidated fd. */ - *ret_fd = fd_devno != (mode_t) -1 && fd_devno == devno ? TAKE_FD(fd) : -1; + *ret_fd = fd_devno != MODE_INVALID && fd_devno == devno ? TAKE_FD(fd) : -1; return 0; } @@ -3860,6 +3975,40 @@ static int find_root(char **ret, int *ret_fd) { return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "Failed to discover root block device."); } +static int resize_pt(int fd) { + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_(fdisk_unref_contextp) struct fdisk_context *c = NULL; + int r; + + /* After resizing the backing file we need to resize the partition table itself too, so that it takes + * possession of the enlarged backing file. For this it suffices to open the device with libfdisk and + * immediately write it again, with no changes. */ + + c = fdisk_new_context(); + if (!c) + return log_oom(); + + xsprintf(procfs_path, "/proc/self/fd/%i", fd); + r = fdisk_assign_device(c, procfs_path, 0); + if (r < 0) + return log_error_errno(r, "Failed to open device '%s': %m", procfs_path); + + r = fdisk_has_label(c); + if (r < 0) + return log_error_errno(r, "Failed to determine whether disk '%s' has a disk label: %m", procfs_path); + if (r == 0) { + log_debug("Not resizing partition table, as there currently is none."); + return 0; + } + + r = fdisk_write_disklabel(c); + if (r < 0) + return log_error_errno(r, "Failed to write resized partition table: %m"); + + log_info("Resized partition table."); + return 1; +} + static int resize_backing_fd(const char *node, int *fd) { char buf1[FORMAT_BYTES_MAX], buf2[FORMAT_BYTES_MAX]; _cleanup_close_ int writable_fd = -1; @@ -3912,6 +4061,10 @@ static int resize_backing_fd(const char *node, int *fd) { /* Fallback to truncation, if fallocate() is not supported. */ log_debug("Backing file system does not support fallocate(), falling back to ftruncate()."); } else { + r = resize_pt(writable_fd); + if (r < 0) + return r; + if (st.st_size == 0) /* Likely regular file just created by us */ log_info("Allocated %s for '%s'.", buf2, node); else @@ -3925,6 +4078,10 @@ static int resize_backing_fd(const char *node, int *fd) { return log_error_errno(errno, "Failed to grow '%s' from %s to %s by truncation: %m", node, buf1, buf2); + r = resize_pt(writable_fd); + if (r < 0) + return r; + if (st.st_size == 0) /* Likely regular file just created by us */ log_info("Sized '%s' to %s.", node, buf2); else diff --git a/src/partition/test-repart.sh b/src/partition/test-repart.sh index 9af3049b6..d21865dd6 100755 --- a/src/partition/test-repart.sh +++ b/src/partition/test-repart.sh @@ -1,7 +1,8 @@ #!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later set -ex -[[ -f /dev/loop-control ]] || exit 77 +[[ -e /dev/loop-control ]] || exit 77 repart=$1 test -x $repart diff --git a/src/path/path.c b/src/path/path.c index 5f1bb14e4..aec75f1fb 100644 --- a/src/path/path.c +++ b/src/path/path.c @@ -142,10 +142,9 @@ static int help(void) { " -h --help Show this help\n" " --version Show package version\n" " --suffix=SUFFIX Suffix to append to paths\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } diff --git a/src/portable/org.freedesktop.portable1.conf b/src/portable/org.freedesktop.portable1.conf index 1343e1d54..5a09f5c2d 100644 --- a/src/portable/org.freedesktop.portable1.conf +++ b/src/portable/org.freedesktop.portable1.conf @@ -61,6 +61,10 @@ send_interface="org.freedesktop.portable1.Manager" send_member="DetachImage"/> + + @@ -99,6 +103,10 @@ send_interface="org.freedesktop.portable1.Image" send_member="Detach"/> + + diff --git a/src/portable/portable.c b/src/portable/portable.c index ed7eac029..6c09e8bbd 100644 --- a/src/portable/portable.c +++ b/src/portable/portable.c @@ -8,7 +8,9 @@ #include "copy.h" #include "def.h" #include "dirent-util.h" +#include "discover-image.h" #include "dissect-image.h" +#include "errno-list.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -16,7 +18,6 @@ #include "io-util.h" #include "locale-util.h" #include "loop-util.h" -#include "machine-image.h" #include "mkdir.h" #include "nulstr-util.h" #include "os-util.h" @@ -495,7 +496,7 @@ int portable_extract( assert(name_or_path); - r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image); + r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image); if (r < 0) return r; @@ -591,7 +592,7 @@ static int unit_file_is_active( static int portable_changes_add( PortableChange **changes, size_t *n_changes, - PortableChangeType type, + int type_or_errno, /* PORTABLE_COPY, PORTABLE_SYMLINK, … if positive, or errno if negative */ const char *path, const char *source) { @@ -601,6 +602,11 @@ static int portable_changes_add( assert(path); assert(!changes == !n_changes); + if (type_or_errno >= 0) + assert(type_or_errno < _PORTABLE_CHANGE_TYPE_MAX); + else + assert(type_or_errno >= -ERRNO_MAX); + if (!changes) return 0; @@ -624,7 +630,7 @@ static int portable_changes_add( } c[(*n_changes)++] = (PortableChange) { - .type = type, + .type_or_errno = type_or_errno, .path = TAKE_PTR(p), .source = TAKE_PTR(s), }; @@ -635,7 +641,7 @@ static int portable_changes_add( static int portable_changes_add_with_prefix( PortableChange **changes, size_t *n_changes, - PortableChangeType type, + int type_or_errno, const char *prefix, const char *path, const char *source) { @@ -653,7 +659,7 @@ static int portable_changes_add_with_prefix( source = prefix_roota(prefix, source); } - return portable_changes_add(changes, n_changes, type, path, source); + return portable_changes_add(changes, n_changes, type_or_errno, path, source); } void portable_changes_free(PortableChange *changes, size_t n_changes) { @@ -710,9 +716,7 @@ static int install_chroot_dropin( IN_SET(type, IMAGE_DIRECTORY, IMAGE_SUBVOLUME) ? "RootDirectory=" : "RootImage=", image_path, "\n" "Environment=PORTABLE=", basename(image_path), "\n" "BindReadOnlyPaths=", os_release_source, ":/run/host/os-release\n" - "LogExtraFields=PORTABLE=", basename(image_path), "\n", - NULL)) - + "LogExtraFields=PORTABLE=", basename(image_path), "\n")) return -ENOMEM; } @@ -955,7 +959,7 @@ static int install_image_symlink( /* If the image is outside of the image search also link it into it, so that it can be found with short image * names and is listed among the images. */ - if (image_in_search_path(IMAGE_PORTABLE, image_path)) + if (image_in_search_path(IMAGE_PORTABLE, NULL, image_path)) return 0; r = image_symlink(image_path, flags, &sl); @@ -989,7 +993,7 @@ int portable_attach( assert(name_or_path); - r = image_find_harder(IMAGE_PORTABLE, name_or_path, &image); + r = image_find_harder(IMAGE_PORTABLE, name_or_path, NULL, &image); if (r < 0) return r; @@ -1005,13 +1009,13 @@ int portable_attach( r = unit_file_exists(UNIT_FILE_SYSTEM, &paths, item->name); if (r < 0) return sd_bus_error_set_errnof(error, r, "Failed to determine whether unit '%s' exists on the host: %m", item->name); - if (r > 0) + if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' exists on the host already, refusing.", item->name); r = unit_file_is_active(bus, item->name, error); if (r < 0) return r; - if (r > 0) + if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active already, refusing.", item->name); } @@ -1037,10 +1041,14 @@ static bool marker_matches_image(const char *marker, const char *name_or_path) { a = last_path_component(marker); if (image_name_is_valid(name_or_path)) { - const char *e; + const char *e, *underscore; /* We shall match against an image name. In that case let's compare the last component, and optionally - * allow either a suffix of ".raw" or a series of "/". */ + * allow either a suffix of ".raw" or a series of "/". + * But allow matching on a different version of the same image, when a "_" is used as a separator. */ + underscore = strchr(name_or_path, '_'); + if (underscore) + return strneq(a, name_or_path, underscore - name_or_path); e = startswith(a, name_or_path); if (!e) @@ -1050,7 +1058,7 @@ static bool marker_matches_image(const char *marker, const char *name_or_path) { e[strspn(e, "/")] == 0 || streq(e, ".raw"); } else { - const char *b; + const char *b, *underscore; size_t l; /* We shall match against a path. Let's ignore any prefix here though, as often there are many ways to @@ -1062,7 +1070,11 @@ static bool marker_matches_image(const char *marker, const char *name_or_path) { if (strcspn(b, "/") != l) return false; - return memcmp(a, b, l) == 0; + underscore = strchr(b, '_'); + if (underscore) + l = underscore - b; + + return strneq(a, b, l); } } @@ -1187,7 +1199,7 @@ int portable_detach( r = unit_file_is_active(bus, de->d_name, error); if (r < 0) return r; - if (r > 0) + if (!FLAGS_SET(flags, PORTABLE_REATTACH) && r > 0) return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit file '%s' is active, can't detach.", de->d_name); r = set_put_strdup(&unit_files, de->d_name); @@ -1195,7 +1207,7 @@ int portable_detach( return log_debug_errno(r, "Failed to add unit name '%s' to set: %m", de->d_name); if (path_is_absolute(marker) && - !image_in_search_path(IMAGE_PORTABLE, marker)) { + !image_in_search_path(IMAGE_PORTABLE, NULL, marker)) { r = set_ensure_consume(&markers, &path_hash_ops_free, TAKE_PTR(marker)); if (r < 0) @@ -1411,7 +1423,7 @@ static const char* const portable_change_type_table[_PORTABLE_CHANGE_TYPE_MAX] = [PORTABLE_WRITE] = "write", }; -DEFINE_STRING_TABLE_LOOKUP(portable_change_type, PortableChangeType); +DEFINE_STRING_TABLE_LOOKUP(portable_change_type, int); static const char* const portable_state_table[_PORTABLE_STATE_MAX] = { [PORTABLE_DETACHED] = "detached", diff --git a/src/portable/portable.h b/src/portable/portable.h index fd9605ed8..5694bd2b6 100644 --- a/src/portable/portable.h +++ b/src/portable/portable.h @@ -21,17 +21,20 @@ typedef enum PortableFlags { PORTABLE_PREFER_COPY = 1 << 0, PORTABLE_PREFER_SYMLINK = 1 << 1, PORTABLE_RUNTIME = 1 << 2, + PORTABLE_REATTACH = 1 << 3, } PortableFlags; -typedef enum PortableChangeType { +/* This enum is anonymous, since we usually store it in an 'int', as we overload it with negative errno + * values. */ +enum { PORTABLE_COPY, PORTABLE_SYMLINK, PORTABLE_UNLINK, PORTABLE_WRITE, PORTABLE_MKDIR, _PORTABLE_CHANGE_TYPE_MAX, - _PORTABLE_CHANGE_TYPE_INVALID = INT_MIN, -} PortableChangeType; + _PORTABLE_CHANGE_TYPE_INVALID = -EINVAL, +}; typedef enum PortableState { PORTABLE_DETACHED, @@ -42,11 +45,11 @@ typedef enum PortableState { PORTABLE_RUNNING, PORTABLE_RUNNING_RUNTIME, _PORTABLE_STATE_MAX, - _PORTABLE_STATE_INVALID = -1 + _PORTABLE_STATE_INVALID = -EINVAL, } PortableState; typedef struct PortableChange { - int type; /* PortableFileChangeType or negative error number */ + int type_or_errno; /* PORTABLE_COPY, PORTABLE_SYMLINK, … if positive, errno if negative */ char *path; char *source; } PortableChange; @@ -67,8 +70,8 @@ int portable_get_profiles(char ***ret); void portable_changes_free(PortableChange *changes, size_t n_changes); -const char *portable_change_type_to_string(PortableChangeType t) _const_; -PortableChangeType portable_change_type_from_string(const char *t) _pure_; +const char *portable_change_type_to_string(int t) _const_; +int portable_change_type_from_string(const char *t) _pure_; const char *portable_state_to_string(PortableState t) _const_; PortableState portable_state_from_string(const char *t) _pure_; diff --git a/src/portable/portablectl.c b/src/portable/portablectl.c index 457170e68..77fcd4fe6 100644 --- a/src/portable/portablectl.c +++ b/src/portable/portablectl.c @@ -18,8 +18,8 @@ #include "format-table.h" #include "fs-util.h" #include "locale-util.h" -#include "machine-image.h" #include "main-func.h" +#include "os-util.h" #include "pager.h" #include "parse-util.h" #include "path-util.h" @@ -45,6 +45,10 @@ static bool arg_enable = false; static bool arg_now = false; static bool arg_no_block = false; +static bool is_portable_managed(const char *unit) { + return ENDSWITH_SET(unit, ".service", ".target", ".socket", ".path", ".timer"); +} + static int determine_image(const char *image, bool permit_non_existing, char **ret) { int r; @@ -436,12 +440,14 @@ static int maybe_enable_disable(sd_bus *bus, const char *path, bool enable) { return 0; } -static int maybe_start_stop(sd_bus *bus, const char *path, bool start, BusWaitForJobs *wait) { +static int maybe_start_stop_restart(sd_bus *bus, const char *path, const char *method, BusWaitForJobs *wait) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char *name = (char *)basename(path), *job = NULL; int r; + assert(STR_IN_SET(method, "StartUnit", "StopUnit", "RestartUnit")); + if (!arg_now) return 0; @@ -450,13 +456,13 @@ static int maybe_start_stop(sd_bus *bus, const char *path, bool start, BusWaitFo "org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", - start ? "StartUnit" : "StopUnit", + method, &error, &reply, "ss", name, "replace"); if (r < 0) - return log_error_errno(r, "Failed to %s the portable service %s: %s", - start ? "start" : "stop", + return log_error_errno(r, "Failed to call %s on the portable service %s: %s", + method, path, bus_error_message(&error, r)); @@ -465,13 +471,13 @@ static int maybe_start_stop(sd_bus *bus, const char *path, bool start, BusWaitFo return bus_log_parse_error(r); if (!arg_quiet) - log_info("Queued %s to %s portable service %s.", job, start ? "start" : "stop", name); + log_info("Queued %s to call %s on portable service %s.", job, method, name); if (wait) { r = bus_wait_for_jobs_add(wait, job); if (r < 0) - return log_error_errno(r, "Failed to watch %s job for %s %s: %m", - job, start ? "starting" : "stopping", name); + return log_error_errno(r, "Failed to watch %s job to call %s on %s: %m", + job, method, name); } return 0; @@ -506,9 +512,83 @@ static int maybe_enable_start(sd_bus *bus, sd_bus_message *reply) { if (r == 0) break; - if (STR_IN_SET(type, "symlink", "copy") && ENDSWITH_SET(path, ".service", ".target", ".socket")) { + if (STR_IN_SET(type, "symlink", "copy") && is_portable_managed(path)) { (void) maybe_enable_disable(bus, path, true); - (void) maybe_start_stop(bus, path, true, wait); + (void) maybe_start_stop_restart(bus, path, "StartUnit", wait); + } + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + if (!arg_no_block) { + r = bus_wait_for_jobs(wait, arg_quiet, NULL); + if (r < 0) + return r; + } + + return 0; +} + +static int maybe_stop_enable_restart(sd_bus *bus, sd_bus_message *reply) { + _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *wait = NULL; + int r; + + if (!arg_enable && !arg_now) + return 0; + + if (!arg_no_block) { + r = bus_wait_for_jobs_new(bus, &wait); + if (r < 0) + return log_error_errno(r, "Could not watch jobs: %m"); + } + + r = sd_bus_message_rewind(reply, true); + if (r < 0) + return r; + + /* First we get a list of units that were definitely removed, not just re-attached, + * so we can also stop them if the user asked us to. */ + r = sd_bus_message_enter_container(reply, 'a', "(sss)"); + if (r < 0) + return bus_log_parse_error(r); + + for (;;) { + char *type, *path, *source; + + r = sd_bus_message_read(reply, "(sss)", &type, &path, &source); + if (r < 0) + return bus_log_parse_error(r); + if (r == 0) + break; + + if (streq(type, "unlink") && is_portable_managed(path)) + (void) maybe_start_stop_restart(bus, path, "StopUnit", wait); + } + + r = sd_bus_message_exit_container(reply); + if (r < 0) + return r; + + /* Then we get a list of units that were either added or changed, so that we can + * enable them and/or restart them if the user asked us to. */ + r = sd_bus_message_enter_container(reply, 'a', "(sss)"); + if (r < 0) + return bus_log_parse_error(r); + + for (;;) { + char *type, *path, *source; + + r = sd_bus_message_read(reply, "(sss)", &type, &path, &source); + if (r < 0) + return bus_log_parse_error(r); + if (r == 0) + break; + + if (STR_IN_SET(type, "symlink", "copy") && is_portable_managed(path)) { + (void) maybe_enable_disable(bus, path, true); + (void) maybe_start_stop_restart(bus, path, "RestartUnit", wait); } } @@ -588,7 +668,7 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) { if (r < 0) return bus_log_parse_error(r); - (void) maybe_start_stop(bus, name, false, wait); + (void) maybe_start_stop_restart(bus, name, "StopUnit", wait); (void) maybe_enable_disable(bus, name, false); } @@ -604,7 +684,7 @@ static int maybe_stop_disable(sd_bus *bus, char *image, char *argv[]) { return 0; } -static int attach_image(int argc, char *argv[], void *userdata) { +static int attach_reattach_image(int argc, char *argv[], const char *method) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; @@ -612,6 +692,9 @@ static int attach_image(int argc, char *argv[], void *userdata) { _cleanup_free_ char *image = NULL; int r; + assert(method); + assert(STR_IN_SET(method, "AttachImage", "ReattachImage")); + r = determine_image(argv[1], false, &image); if (r < 0) return r; @@ -626,7 +709,7 @@ static int attach_image(int argc, char *argv[], void *userdata) { (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); - r = bus_message_new_method_call(bus, &m, bus_portable_mgr, "AttachImage"); + r = bus_message_new_method_call(bus, &m, bus_portable_mgr, method); if (r < 0) return bus_log_create_error(r); @@ -644,17 +727,31 @@ static int attach_image(int argc, char *argv[], void *userdata) { r = sd_bus_call(bus, m, 0, &error, &reply); if (r < 0) - return log_error_errno(r, "Failed to attach image: %s", bus_error_message(&error, r)); + return log_error_errno(r, "%s failed: %s", method, bus_error_message(&error, r)); (void) maybe_reload(&bus); print_changes(reply); - (void) maybe_enable_start(bus, reply); + if (streq(method, "AttachImage")) + (void) maybe_enable_start(bus, reply); + else { + /* ReattachImage returns 2 lists - removed units first, and changed/added second */ + print_changes(reply); + (void) maybe_stop_enable_restart(bus, reply); + } return 0; } +static int attach_image(int argc, char *argv[], void *userdata) { + return attach_reattach_image(argc, argv, "AttachImage"); +} + +static int reattach_image(int argc, char *argv[], void *userdata) { + return attach_reattach_image(argc, argv, "ReattachImage"); +} + static int detach_image(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -737,7 +834,7 @@ static int list_images(int argc, char *argv[], void *userdata) { return bus_log_parse_error(r); if (table_get_rows(table) > 1) { - r = table_set_sort(table, (size_t) 0, (size_t) -1); + r = table_set_sort(table, (size_t) 0); if (r < 0) return table_log_sort_error(r); @@ -826,7 +923,7 @@ static int set_limit(int argc, char *argv[], void *userdata) { (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); if (STR_IN_SET(argv[argc-1], "-", "none", "infinity")) - limit = (uint64_t) -1; + limit = UINT64_MAX; else { r = parse_size(argv[argc-1], 1024, &limit); if (r < 0) @@ -920,6 +1017,8 @@ static int help(int argc, char *argv[], void *userdata) { " Attach the specified portable service image\n" " detach NAME|PATH [PREFIX...]\n" " Detach the specified portable service image\n" + " reattach NAME|PATH [PREFIX...]\n" + " Reattach the specified portable service image\n" " inspect NAME|PATH [PREFIX...]\n" " Show details of specified portable service image\n" " is-attached NAME|PATH Query if portable service image is attached\n" @@ -946,12 +1045,11 @@ static int help(int argc, char *argv[], void *userdata) { " --now Immediately start/stop the portable service after\n" " attach/before detach\n" " --no-block Don't block waiting for attach --now to complete\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -1109,12 +1207,13 @@ static int run(int argc, char *argv[]) { { "read-only", 2, 3, 0, read_only_image }, { "remove", 2, VERB_ANY, 0, remove_image }, { "set-limit", 3, 3, 0, set_limit }, + { "reattach", 2, VERB_ANY, 0, reattach_image }, {} }; int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/portable/portabled-bus.c b/src/portable/portabled-bus.c index cf50d58c7..6d0dee99c 100644 --- a/src/portable/portabled-bus.c +++ b/src/portable/portabled-bus.c @@ -3,10 +3,11 @@ #include "alloc-util.h" #include "btrfs-util.h" #include "bus-common-errors.h" +#include "bus-object.h" #include "bus-polkit.h" +#include "discover-image.h" #include "fd-util.h" #include "io-util.h" -#include "machine-image.h" #include "missing_capability.h" #include "portable.h" #include "portabled-bus.h" @@ -41,7 +42,7 @@ static int property_get_pool_usage( sd_bus_error *error) { _cleanup_close_ int fd = -1; - uint64_t usage = (uint64_t) -1; + uint64_t usage = UINT64_MAX; assert(bus); assert(reply); @@ -67,7 +68,7 @@ static int property_get_pool_limit( sd_bus_error *error) { _cleanup_close_ int fd = -1; - uint64_t size = (uint64_t) -1; + uint64_t size = UINT64_MAX; assert(bus); assert(reply); @@ -299,6 +300,10 @@ finish: return r; } +static int method_reattach_image(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return redirect_method_to_image(userdata, message, error, bus_image_common_reattach); +} + static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) { return redirect_method_to_image(userdata, message, error, bus_image_common_remove); } @@ -355,39 +360,108 @@ const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0), SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0), SD_BUS_PROPERTY("Profiles", "as", property_get_profiles, 0, 0), - SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("ListImages", NULL, "a(ssbtttso)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetImageOSRelease", "s", "a{ss}", method_get_image_os_release, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetImageMetadata", "sas", "saya{say}", method_get_image_metadata, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetImageState", "s", "s", method_get_image_state, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("AttachImage", "sassbs", "a(sss)", method_attach_image, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("DetachImage", "sb", "a(sss)", method_detach_image, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetImage", + SD_BUS_ARGS("s", image), + SD_BUS_RESULT("o", object), + method_get_image, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ListImages", + SD_BUS_NO_ARGS, + SD_BUS_RESULT("a(ssbtttso)", images), + method_list_images, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetImageOSRelease", + SD_BUS_ARGS("s", image), + SD_BUS_RESULT("a{ss}", os_release), + method_get_image_os_release, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetImageMetadata", + SD_BUS_ARGS("s", image, + "as", matches), + SD_BUS_RESULT("s", image, + "ay", os_release, + "a{say}", units), + method_get_image_metadata, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetImageState", + SD_BUS_ARGS("s", image), + SD_BUS_RESULT("s", state), + method_get_image_state, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("AttachImage", + SD_BUS_ARGS("s", image, + "as", matches, + "s", profile, + "b", runtime, + "s", copy_mode), + SD_BUS_RESULT("a(sss)", changes), + method_attach_image, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("DetachImage", + SD_BUS_ARGS("s", image, + "b", runtime), + SD_BUS_RESULT("a(sss)", changes), + method_detach_image, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("ReattachImage", + SD_BUS_ARGS("s", image, + "as", matches, + "s", profile, + "b", runtime, + "s", copy_mode), + SD_BUS_RESULT("a(sss)", changes_removed, + "a(sss)", changes_updated), + method_reattach_image, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("RemoveImage", + SD_BUS_ARGS("s", image), + SD_BUS_NO_RESULT, + method_remove_image, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("MarkImageReadOnly", + SD_BUS_ARGS("s", image, + "b", read_only), + SD_BUS_NO_RESULT, + method_mark_image_read_only, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetImageLimit", + SD_BUS_ARGS("s", image, + "t", limit), + SD_BUS_NO_RESULT, + method_set_image_limit, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetPoolLimit", + SD_BUS_ARGS("t", limit), + SD_BUS_NO_RESULT, + method_set_pool_limit, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; -int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, size_t n_changes) { - _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; +const BusObjectImplementation manager_object = { + "/org/freedesktop/portable1", + "org.freedesktop.portable1.Manager", + .vtables = BUS_VTABLES(manager_vtable), + .children = BUS_IMPLEMENTATIONS(&image_object), +}; + +static int reply_portable_compose_message(sd_bus_message *reply, const PortableChange *changes, size_t n_changes) { size_t i; int r; - assert(m); + assert(reply); assert(changes || n_changes == 0); - r = sd_bus_message_new_method_return(m, &reply); - if (r < 0) - return r; - r = sd_bus_message_open_container(reply, 'a', "(sss)"); if (r < 0) return r; for (i = 0; i < n_changes; i++) { + if (changes[i].type_or_errno < 0) + continue; + r = sd_bus_message_append(reply, "(sss)", - portable_change_type_to_string(changes[i].type), + portable_change_type_to_string(changes[i].type_or_errno), changes[i].path, changes[i].source); if (r < 0) @@ -398,5 +472,49 @@ int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, siz if (r < 0) return r; + return 0; +} + +int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, size_t n_changes) { + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; + + assert(m); + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = reply_portable_compose_message(reply, changes, n_changes); + if (r < 0) + return r; + + return sd_bus_send(NULL, reply, NULL); +} + +int reply_portable_changes_pair( + sd_bus_message *m, + const PortableChange *changes_first, + size_t n_changes_first, + const PortableChange *changes_second, + size_t n_changes_second) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + int r; + + assert(m); + + r = sd_bus_message_new_method_return(m, &reply); + if (r < 0) + return r; + + r = reply_portable_compose_message(reply, changes_first, n_changes_first); + if (r < 0) + return r; + + r = reply_portable_compose_message(reply, changes_second, n_changes_second); + if (r < 0) + return r; + return sd_bus_send(NULL, reply, NULL); } diff --git a/src/portable/portabled-bus.h b/src/portable/portabled-bus.h index e8e4c3a60..7da366c1c 100644 --- a/src/portable/portabled-bus.h +++ b/src/portable/portabled-bus.h @@ -8,3 +8,4 @@ extern const sd_bus_vtable manager_vtable[]; int reply_portable_changes(sd_bus_message *m, const PortableChange *changes, size_t n_changes); +int reply_portable_changes_pair(sd_bus_message *m, const PortableChange *changes_first, size_t n_changes_first, const PortableChange *changes_second, size_t n_changes_second); diff --git a/src/portable/portabled-image-bus.c b/src/portable/portabled-image-bus.c index eb0786e4b..8332332c9 100644 --- a/src/portable/portabled-image-bus.c +++ b/src/portable/portabled-image-bus.c @@ -9,13 +9,15 @@ #include "bus-common-errors.h" #include "bus-get-properties.h" #include "bus-label.h" +#include "bus-object.h" #include "bus-polkit.h" #include "bus-util.h" +#include "discover-image.h" #include "fd-util.h" #include "fileio.h" #include "io-util.h" -#include "machine-image.h" #include "missing_capability.h" +#include "os-util.h" #include "portable.h" #include "portabled-bus.h" #include "portabled-image-bus.h" @@ -422,6 +424,186 @@ static int bus_image_method_remove(sd_bus_message *message, void *userdata, sd_b return bus_image_common_remove(NULL, message, NULL, userdata, error); } +/* Given two PortableChange arrays, return a new array that has all elements of the first that are + * not also present in the second, comparing the basename of the path values. */ +static int normalize_portable_changes( + const PortableChange *changes_attached, + size_t n_changes_attached, + const PortableChange *changes_detached, + size_t n_changes_detached, + PortableChange **ret_changes, + size_t *ret_n_changes) { + + PortableChange *changes = NULL; + size_t n_changes = 0; + int r = 0; + + assert(ret_n_changes); + assert(ret_changes); + + if (n_changes_detached == 0) + return 0; /* Nothing to do */ + + changes = new0(PortableChange, n_changes_attached + n_changes_detached); + if (!changes) + return -ENOMEM; + + /* Corner case: only detached, nothing attached */ + if (n_changes_attached == 0) { + memcpy(changes, changes_detached, sizeof(PortableChange) * n_changes_detached); + *ret_changes = TAKE_PTR(changes); + *ret_n_changes = n_changes_detached; + + return 0; + } + + for (size_t i = 0; i < n_changes_detached; ++i) { + bool found = false; + + for (size_t j = 0; j < n_changes_attached; ++j) + if (streq(basename(changes_detached[i].path), basename(changes_attached[j].path))) { + found = true; + break; + } + + if (!found) { + _cleanup_free_ char *path = NULL, *source = NULL; + + path = strdup(changes_detached[i].path); + if (!path) { + r = -ENOMEM; + goto fail; + } + + if (changes_detached[i].source) { + source = strdup(changes_detached[i].source); + if (!source) { + r = -ENOMEM; + goto fail; + } + } + + changes[n_changes++] = (PortableChange) { + .type_or_errno = changes_detached[i].type_or_errno, + .path = TAKE_PTR(path), + .source = TAKE_PTR(source), + }; + } + } + + *ret_n_changes = n_changes; + *ret_changes = TAKE_PTR(changes); + + return 0; + +fail: + portable_changes_free(changes, n_changes); + return r; +} + +int bus_image_common_reattach( + Manager *m, + sd_bus_message *message, + const char *name_or_path, + Image *image, + sd_bus_error *error) { + + PortableChange *changes_detached = NULL, *changes_attached = NULL, *changes_gone = NULL; + size_t n_changes_detached = 0, n_changes_attached = 0, n_changes_gone = 0; + _cleanup_strv_free_ char **matches = NULL; + PortableFlags flags = PORTABLE_REATTACH; + const char *profile, *copy_mode; + int runtime, r; + + assert(message); + assert(name_or_path || image); + + if (!m) { + assert(image); + m = image->userdata; + } + + r = sd_bus_message_read_strv(message, &matches); + if (r < 0) + return r; + + r = sd_bus_message_read(message, "sbs", &profile, &runtime, ©_mode); + if (r < 0) + return r; + + if (streq(copy_mode, "symlink")) + flags |= PORTABLE_PREFER_SYMLINK; + else if (streq(copy_mode, "copy")) + flags |= PORTABLE_PREFER_COPY; + else if (!isempty(copy_mode)) + return sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_ARGS, "Unknown copy mode '%s'", copy_mode); + + if (runtime) + flags |= PORTABLE_RUNTIME; + + r = bus_image_acquire(m, + message, + name_or_path, + image, + BUS_IMAGE_AUTHENTICATE_ALL, + "org.freedesktop.portable1.attach-images", + &image, + error); + if (r < 0) + return r; + if (r == 0) /* Will call us back */ + return 1; + + r = portable_detach( + sd_bus_message_get_bus(message), + image->path, + flags, + &changes_detached, + &n_changes_detached, + error); + if (r < 0) + goto finish; + + r = portable_attach( + sd_bus_message_get_bus(message), + image->path, + matches, + profile, + flags, + &changes_attached, + &n_changes_attached, + error); + if (r < 0) + goto finish; + + /* We want to return the list of units really removed by the detach, + * and not added again by the attach */ + r = normalize_portable_changes(changes_attached, n_changes_attached, + changes_detached, n_changes_detached, + &changes_gone, &n_changes_gone); + if (r < 0) + goto finish; + + /* First, return the units that are gone (so that the caller can stop them) + * Then, return the units that are changed/added (so that the caller can + * start/restart/enable them) */ + r = reply_portable_changes_pair(message, + changes_gone, n_changes_gone, + changes_attached, n_changes_attached); + if (r < 0) + goto finish; + +finish: + portable_changes_free(changes_detached, n_changes_detached); + portable_changes_free(changes_attached, n_changes_attached); + portable_changes_free(changes_gone, n_changes_gone); + return r; +} + +static int bus_image_method_reattach(sd_bus_message *message, void *userdata, sd_bus_error *error) { + return bus_image_common_reattach(NULL, message, NULL, userdata, error); +} + int bus_image_common_mark_read_only( Manager *m, sd_bus_message *message, @@ -527,14 +709,60 @@ const sd_bus_vtable image_vtable[] = { SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0), SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0), SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0), - SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetMetadata", "as", "saya{say}", bus_image_method_get_metadata, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("GetState", NULL, "s", bus_image_method_get_state, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Attach", "assbs", "a(sss)", bus_image_method_attach, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Detach", "b", "a(sss)", bus_image_method_detach, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED), - SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetOSRelease", + SD_BUS_NO_ARGS, + SD_BUS_RESULT("a{ss}", os_release), + bus_image_method_get_os_release, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetMetadata", + SD_BUS_ARGS("as", matches), + SD_BUS_RESULT("s", image, + "ay", os_release, + "a{say}", units), + bus_image_method_get_metadata, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("GetState", + SD_BUS_NO_ARGS, + SD_BUS_RESULT("s", state), + bus_image_method_get_state, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Attach", + SD_BUS_ARGS("as", matches, + "s", profile, + "b", runtime, + "s", copy_mode), + SD_BUS_RESULT("a(sss)", changes), + bus_image_method_attach, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Detach", + SD_BUS_ARGS("b", runtime), + SD_BUS_RESULT("a(sss)", changes), + bus_image_method_detach, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Reattach", + SD_BUS_ARGS("as", matches, + "s", profile, + "b", runtime, + "s", copy_mode), + SD_BUS_RESULT("a(sss)", changes_removed, + "a(sss)", changes_updated), + bus_image_method_reattach, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("Remove", + SD_BUS_NO_ARGS, + SD_BUS_NO_RESULT, + bus_image_method_remove, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("MarkReadOnly", + SD_BUS_ARGS("b", read_only), + SD_BUS_NO_RESULT, + bus_image_method_mark_read_only, + SD_BUS_VTABLE_UNPRIVILEGED), + SD_BUS_METHOD_WITH_ARGS("SetLimit", + SD_BUS_ARGS("t", limit), + SD_BUS_NO_RESULT, + bus_image_method_set_limit, + SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_VTABLE_END }; @@ -606,7 +834,7 @@ int bus_image_acquire( if (image_name_is_valid(name_or_path)) { /* If it's a short name, let's search for it */ - r = image_find(IMAGE_PORTABLE, name_or_path, &loaded); + r = image_find(IMAGE_PORTABLE, name_or_path, NULL, &loaded); if (r == -ENOENT) return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PORTABLE_IMAGE, "No image '%s' found.", name_or_path); @@ -738,3 +966,10 @@ int bus_image_node_enumerator(sd_bus *bus, const char *path, void *userdata, cha return 1; } + +const BusObjectImplementation image_object = { + "/org/freedesktop/portable1/image", + "org.freedesktop.portable1.Image", + .fallback_vtables = BUS_FALLBACK_VTABLES({image_vtable, bus_image_object_find}), + .node_enumerator = bus_image_node_enumerator, +}; diff --git a/src/portable/portabled-image-bus.h b/src/portable/portabled-image-bus.h index aa2a3ade7..763a0890f 100644 --- a/src/portable/portabled-image-bus.h +++ b/src/portable/portabled-image-bus.h @@ -3,17 +3,19 @@ #include "sd-bus.h" -#include "machine-image.h" +#include "discover-image.h" #include "portabled.h" int bus_image_common_get_os_release(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); int bus_image_common_get_metadata(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); int bus_image_common_attach(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); int bus_image_common_remove(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); +int bus_image_common_reattach(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); int bus_image_common_mark_read_only(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); int bus_image_common_set_limit(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, sd_bus_error *error); extern const sd_bus_vtable image_vtable[]; +extern const BusObjectImplementation image_object; int bus_image_path(Image *image, char **ret); @@ -32,7 +34,7 @@ typedef enum ImageAcquireMode { BUS_IMAGE_AUTHENTICATE_BY_PATH, /* allow by name + polkit by path */ BUS_IMAGE_AUTHENTICATE_ALL, /* polkit by name + polkit by path */ _BUS_IMAGE_ACQUIRE_MODE_MAX, - _BUS_IMAGE_ACQUIRE_MODE_INVALID = -1 + _BUS_IMAGE_ACQUIRE_MODE_INVALID = -EINVAL, } ImageAcquireMode; int bus_image_acquire(Manager *m, sd_bus_message *message, const char *name_or_path, Image *image, ImageAcquireMode mode, const char *polkit_action, Image **ret, sd_bus_error *error); diff --git a/src/portable/portabled-image.c b/src/portable/portabled-image.c index b025c2054..40548fb65 100644 --- a/src/portable/portabled-image.c +++ b/src/portable/portabled-image.c @@ -92,7 +92,7 @@ int manager_image_cache_discover(Manager *m, Hashmap *images, sd_bus_error *erro /* A wrapper around image_discover() (for finding images in search path) and portable_discover_attached() (for * finding attached images). */ - r = image_discover(IMAGE_PORTABLE, images); + r = image_discover(IMAGE_PORTABLE, NULL, images); if (r < 0) return r; diff --git a/src/portable/portabled-image.h b/src/portable/portabled-image.h index eeefffee6..753f389f8 100644 --- a/src/portable/portabled-image.h +++ b/src/portable/portabled-image.h @@ -1,8 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "discover-image.h" #include "hashmap.h" -#include "machine-image.h" #include "portabled.h" Image *manager_image_cache_get(Manager *m, const char *name_or_path); diff --git a/src/portable/portabled.c b/src/portable/portabled.c index f008f84e5..3c8e20e0f 100644 --- a/src/portable/portabled.c +++ b/src/portable/portabled.c @@ -15,6 +15,7 @@ #include "portabled-image-bus.h" #include "portabled.h" #include "process-util.h" +#include "service-util.h" #include "signal-util.h" static Manager* manager_unref(Manager *m); @@ -73,17 +74,9 @@ static int manager_connect_bus(Manager *m) { if (r < 0) return log_error_errno(r, "Failed to connect to system bus: %m"); - r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/portable1", "org.freedesktop.portable1.Manager", manager_vtable, m); + r = bus_add_implementation(m->bus, &manager_object, m); if (r < 0) - return log_error_errno(r, "Failed to add manager object vtable: %m"); - - r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/portable1/image", "org.freedesktop.portable1.Image", image_vtable, bus_image_object_find, m); - if (r < 0) - return log_error_errno(r, "Failed to add image object vtable: %m"); - - r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/portable1/image", bus_image_node_enumerator, m); - if (r < 0) - return log_error_errno(r, "Failed to add image enumerator: %m"); + return r; r = bus_log_control_api_register(m->bus); if (r < 0) @@ -135,7 +128,15 @@ static int run(int argc, char *argv[]) { _cleanup_(manager_unrefp) Manager *m = NULL; int r; - log_setup_service(); + log_setup(); + + r = service_parse_argv("systemd-portabled.service", + "Manage registrations of portable images.", + BUS_IMPLEMENTATIONS(&manager_object, + &log_control_object), + argc, argv); + if (r <= 0) + return r; umask(0022); diff --git a/src/portable/portabled.h b/src/portable/portabled.h index 03a999691..71ec41d4f 100644 --- a/src/portable/portabled.h +++ b/src/portable/portabled.h @@ -4,6 +4,7 @@ #include "sd-bus.h" #include "sd-event.h" +#include "bus-object.h" #include "hashmap.h" #include "list.h" @@ -23,3 +24,5 @@ struct Manager { LIST_HEAD(Operation, operations); unsigned n_operations; }; + +extern const BusObjectImplementation manager_object; diff --git a/src/portable/profile/default/service.conf b/src/portable/profile/default/service.conf index 792be5022..230aa6078 100644 --- a/src/portable/profile/default/service.conf +++ b/src/portable/profile/default/service.conf @@ -2,8 +2,6 @@ [Service] MountAPIVFS=yes -TemporaryFileSystem=/run -BindReadOnlyPaths=/run/systemd/notify BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout BindReadOnlyPaths=/etc/machine-id BindReadOnlyPaths=/etc/resolv.conf diff --git a/src/portable/profile/nonetwork/service.conf b/src/portable/profile/nonetwork/service.conf index c81cebe03..cd7f75c2e 100644 --- a/src/portable/profile/nonetwork/service.conf +++ b/src/portable/profile/nonetwork/service.conf @@ -2,8 +2,6 @@ [Service] MountAPIVFS=yes -TemporaryFileSystem=/run -BindReadOnlyPaths=/run/systemd/notify BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout BindReadOnlyPaths=/etc/machine-id BindReadOnlyPaths=/run/dbus/system_bus_socket diff --git a/src/portable/profile/strict/service.conf b/src/portable/profile/strict/service.conf index d10fb5a1e..f924e1096 100644 --- a/src/portable/profile/strict/service.conf +++ b/src/portable/profile/strict/service.conf @@ -2,8 +2,6 @@ [Service] MountAPIVFS=yes -TemporaryFileSystem=/run -BindReadOnlyPaths=/run/systemd/notify BindReadOnlyPaths=/dev/log /run/systemd/journal/socket /run/systemd/journal/stdout BindReadOnlyPaths=/etc/machine-id DynamicUser=yes diff --git a/src/pstore/meson.build b/src/pstore/meson.build index 6c0ab0563..8e01af751 100644 --- a/src/pstore/meson.build +++ b/src/pstore/meson.build @@ -4,7 +4,7 @@ systemd_pstore_sources = files(''' pstore.c '''.split()) -if conf.get('ENABLE_PSTORE') == 1 and install_sysconfdir +if conf.get('ENABLE_PSTORE') == 1 and install_sysconfdir_samples install_data('pstore.conf', install_dir : pkgsysconfdir) endif diff --git a/src/pstore/pstore.c b/src/pstore/pstore.c index db8a71fba..6ce38f10a 100644 --- a/src/pstore/pstore.c +++ b/src/pstore/pstore.c @@ -53,7 +53,7 @@ typedef enum PStoreStorage { PSTORE_STORAGE_EXTERNAL, PSTORE_STORAGE_JOURNAL, _PSTORE_STORAGE_MAX, - _PSTORE_STORAGE_INVALID = -1 + _PSTORE_STORAGE_INVALID = -EINVAL, } PStoreStorage; static const char* const pstore_storage_table[_PSTORE_STORAGE_MAX] = { @@ -342,7 +342,7 @@ static int list_files(PStoreList *list, const char *sourcepath) { size_t buf_size; /* Now read contents of pstore file */ - r = read_full_file(ifd_path, &buf, &buf_size); + r = read_full_virtual_file(ifd_path, &buf, &buf_size); if (r < 0) { log_warning_errno(r, "Failed to read file %s, skipping: %m", ifd_path); continue; @@ -367,7 +367,7 @@ static int run(int argc, char *argv[]) { _cleanup_(pstore_entries_reset) PStoreList list = {}; int r; - log_setup_service(); + log_setup(); if (argc == 3) { arg_sourcedir = argv[1]; diff --git a/src/pstore/pstore.conf b/src/pstore/pstore.conf index 93a8b6707..7b7b1e849 100644 --- a/src/pstore/pstore.conf +++ b/src/pstore/pstore.conf @@ -1,13 +1,14 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # # See pstore.conf(5) for details. diff --git a/src/quotacheck/quotacheck.c b/src/quotacheck/quotacheck.c index d617b0bf3..575965c47 100644 --- a/src/quotacheck/quotacheck.c +++ b/src/quotacheck/quotacheck.c @@ -58,7 +58,7 @@ static void test_files(void) { static int run(int argc, char *argv[]) { int r; - log_setup_service(); + log_setup(); if (argc > 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/random-seed/random-seed.c b/src/random-seed/random-seed.c index 8f8766cdd..4caf96780 100644 --- a/src/random-seed/random-seed.c +++ b/src/random-seed/random-seed.c @@ -110,7 +110,7 @@ static int run(int argc, char *argv[]) { ssize_t k; int r; - log_setup_service(); + log_setup(); if (argc != 2) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/remount-fs/remount-fs.c b/src/remount-fs/remount-fs.c index 19f5bd0d1..d747d60d5 100644 --- a/src/remount-fs/remount-fs.c +++ b/src/remount-fs/remount-fs.c @@ -31,17 +31,15 @@ static int track_pid(Hashmap **h, const char *path, pid_t pid) { assert(path); assert(pid_is_valid(pid)); - r = hashmap_ensure_allocated(h, NULL); - if (r < 0) - return log_oom(); - c = strdup(path); if (!c) return log_oom(); - r = hashmap_put(*h, PID_TO_PTR(pid), c); - if (r < 0) + r = hashmap_ensure_put(h, NULL, PID_TO_PTR(pid), c); + if (r == -ENOMEM) return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to store pid " PID_FMT, pid); TAKE_PTR(c); return 0; @@ -79,7 +77,7 @@ static int run(int argc, char *argv[]) { struct mntent* me; int r; - log_setup_service(); + log_setup(); if (argc > 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/reply-password/reply-password.c b/src/reply-password/reply-password.c index a73334e2b..a9aa4b832 100644 --- a/src/reply-password/reply-password.c +++ b/src/reply-password/reply-password.c @@ -39,7 +39,7 @@ static int run(int argc, char *argv[]) { size_t length = 0; int r; - log_setup_service(); + log_setup(); if (argc != 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Wrong number of arguments."); diff --git a/src/resolve/dns-type.h b/src/resolve/dns-type.h index 4370db9cf..f0bb3be7b 100644 --- a/src/resolve/dns-type.h +++ b/src/resolve/dns-type.h @@ -90,7 +90,7 @@ enum { DNS_TYPE_DLV, _DNS_TYPE_MAX, - _DNS_TYPE_INVALID = -1 + _DNS_TYPE_INVALID = -EINVAL, }; assert_cc(DNS_TYPE_SSHFP == 44); @@ -103,7 +103,7 @@ enum { DNS_CLASS_ANY = 0xFF, _DNS_CLASS_MAX, - _DNS_CLASS_INVALID = -1 + _DNS_CLASS_INVALID = -EINVAL, }; #define _DNS_CLASS_STRING_MAX (sizeof "CLASS" + DECIMAL_STR_MAX(uint16_t)) diff --git a/src/resolve/dns_type-to-name.awk b/src/resolve/dns_type-to-name.awk index badb1824b..2d9794b76 100644 --- a/src/resolve/dns_type-to-name.awk +++ b/src/resolve/dns_type-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "const char *dns_type_to_string(int type) {\n\tswitch(type) {" } diff --git a/src/fuzz/fuzz-dns-packet.c b/src/resolve/fuzz-dns-packet.c similarity index 100% rename from src/fuzz/fuzz-dns-packet.c rename to src/resolve/fuzz-dns-packet.c diff --git a/src/fuzz/fuzz-dns-packet.options b/src/resolve/fuzz-dns-packet.options similarity index 100% rename from src/fuzz/fuzz-dns-packet.options rename to src/resolve/fuzz-dns-packet.options diff --git a/src/resolve/generate-dns_type-gperf.py b/src/resolve/generate-dns_type-gperf.py index d4f7b9473..0d818fb3d 100755 --- a/src/resolve/generate-dns_type-gperf.py +++ b/src/resolve/generate-dns_type-gperf.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later """Generate %-from-name.gperf from %-list.txt """ diff --git a/src/resolve/generate-dns_type-list.sed b/src/resolve/generate-dns_type-list.sed index b7bc30f1f..32af08c37 100644 --- a/src/resolve/generate-dns_type-list.sed +++ b/src/resolve/generate-dns_type-list.sed @@ -1 +1,2 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later s/.* DNS_TYPE_(\w+).*/\1/p diff --git a/src/resolve/meson.build b/src/resolve/meson.build index 8e7bad065..b1d97736a 100644 --- a/src/resolve/meson.build +++ b/src/resolve/meson.build @@ -1,5 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +resolve_includes = [includes, include_directories('.')] + basic_dns_sources = files(''' resolved-dns-dnssec.c resolved-dns-dnssec.h @@ -11,11 +13,12 @@ basic_dns_sources = files(''' resolved-dns-answer.h resolved-dns-question.c resolved-dns-question.h + resolved-util.c + resolved-util.h dns-type.c + dns-type.h '''.split()) -dns_type_h = files('dns-type.h')[0] - systemd_resolved_sources = files(''' resolved-bus.c resolved-bus.h @@ -63,6 +66,8 @@ systemd_resolved_sources = files(''' resolved-mdns.h resolved-resolv-conf.c resolved-resolv-conf.h + resolved-socket-graveyard.c + resolved-socket-graveyard.h resolved-varlink.c resolved-varlink.h resolved.c @@ -79,78 +84,67 @@ resolvectl_sources = files(''' dns_type_list_txt = custom_target( 'dns_type-list.txt', - input : ['generate-dns_type-list.sed', dns_type_h], + input : ['generate-dns_type-list.sed', 'dns-type.h'], output : 'dns_type-list.txt', command : [sed, '-n', '-r', '-f', '@INPUT0@', '@INPUT1@'], capture : true) generate_dns_type_gperf = find_program('generate-dns_type-gperf.py') -dns_type_headers = [dns_type_h] -foreach item : [['dns_type', dns_type_list_txt, 'dns_type', 'DNS_TYPE_']] +gperf_file = custom_target( + 'dns_type-from-name.gperf', + input : dns_type_list_txt, + output : 'dns_type-from-name.gperf', + command : [generate_dns_type_gperf, 'dns_type', 'DNS_TYPE_', '@INPUT@'], + capture : true) - fname = '@0@-from-name.gperf'.format(item[0]) - gperf_file = custom_target( - fname, - input : item[1], - output : fname, - command : [generate_dns_type_gperf, item[2], item[3], '@INPUT@'], - capture : true) +basic_dns_sources += custom_target( + 'dns_type-from-name.h', + input : gperf_file, + output : 'dns_type-from-name.h', + command : [gperf, + '-L', 'ANSI-C', '-t', '--ignore-case', + '-N', 'lookup_dns_type', + '-H', 'hash_dns_type_name', + '-p', '-C', + '@INPUT@'], + capture : true) - fname = '@0@-from-name.h'.format(item[0]) - target1 = custom_target( - fname, - input : gperf_file, - output : fname, - command : [gperf, - '-L', 'ANSI-C', '-t', '--ignore-case', - '-N', 'lookup_@0@'.format(item[2]), - '-H', 'hash_@0@_name'.format(item[2]), - '-p', '-C', - '@INPUT@'], - capture : true) +basic_dns_sources += custom_target( + 'dns_type-to-name.h', + input : ['dns_type-to-name.awk', dns_type_list_txt], + output : 'dns_type-to-name.h', + command : [awk, '-f', '@INPUT0@', '@INPUT1@'], + capture : true) - fname = '@0@-to-name.h'.format(item[0]) - awkscript = '@0@-to-name.awk'.format(item[0]) - target2 = custom_target( - fname, - input : [awkscript, item[1]], - output : fname, - command : [awk, '-f', '@INPUT0@', '@INPUT1@'], - capture : true) +libsystemd_resolve_core = static_library( + 'systemd-resolve-core', + basic_dns_sources, + include_directories : includes) - dns_type_headers += [target1, target2] -endforeach - -resolved_gperf_c = custom_target( +systemd_resolved_sources += custom_target( 'resolved_gperf.c', input : 'resolved-gperf.gperf', output : 'resolved-gperf.c', command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) -resolved_dnssd_gperf_c = custom_target( +systemd_resolved_sources += custom_target( 'resolved_dnssd_gperf.c', input : 'resolved-dnssd-gperf.gperf', output : 'resolved-dnssd-gperf.c', command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) -libsystemd_resolve_core = static_library( - 'systemd-resolve-core', - basic_dns_sources, - dns_type_headers, - include_directories : includes) - -systemd_resolved_sources += [resolved_gperf_c, resolved_dnssd_gperf_c] - systemd_resolved_dependencies = [threads, libgpg_error, libm] if conf.get('ENABLE_DNS_OVER_TLS') == 1 if conf.get('DNS_OVER_TLS_USE_GNUTLS') == 1 - systemd_resolved_sources += files('resolved-dnstls-gnutls.c', - 'resolved-dnstls-gnutls.h') + systemd_resolved_sources += files( + 'resolved-dnstls-gnutls.c', + 'resolved-dnstls-gnutls.h') systemd_resolved_dependencies += libgnutls elif conf.get('DNS_OVER_TLS_USE_OPENSSL') == 1 - systemd_resolved_sources += files('resolved-dnstls-openssl.c', - 'resolved-dnstls-openssl.h') + systemd_resolved_sources += files( + 'resolved-dnstls-openssl.c', + 'resolved-dnstls-openssl.h') systemd_resolved_dependencies += libopenssl else error('unknown dependency for supporting DNS-over-TLS') @@ -169,7 +163,7 @@ if conf.get('ENABLE_RESOLVE') == 1 input : 'resolved.conf.in', output : 'resolved.conf', configuration : substs) - if install_sysconfdir + if install_sysconfdir_samples install_data(resolved_conf, install_dir : pkgsysconfdir) endif @@ -178,25 +172,22 @@ if conf.get('ENABLE_RESOLVE') == 1 install_dir : rootlibexecdir) endif -tests += [ - [['src/resolve/test-resolve-tables.c', - dns_type_headers, - 'src/shared/test-tables.h'], - [libsystemd_resolve_core, - libshared], - [libgcrypt, - libgpg_error, - libm], - 'ENABLE_RESOLVE'], +############################################################ - [['src/resolve/test-dns-packet.c', - dns_type_headers], +tests += [ + [['src/resolve/test-resolve-tables.c'], [libsystemd_resolve_core, libshared], [libgcrypt, libgpg_error, - libm], - 'ENABLE_RESOLVE'], + libm]], + + [['src/resolve/test-dns-packet.c'], + [libsystemd_resolve_core, + libshared], + [libgcrypt, + libgpg_error, + libm]], [['src/resolve/test-resolved-etc-hosts.c', 'src/resolve/resolved-etc-hosts.c', @@ -205,31 +196,36 @@ tests += [ libshared], [libgcrypt, libgpg_error, - libm], - 'ENABLE_RESOLVE'], + libm]], - [['src/resolve/test-resolved-packet.c', - dns_type_headers], + [['src/resolve/test-resolved-packet.c'], + [libsystemd_resolve_core, + libshared], + [libgcrypt, + libgpg_error, + libm]], + + [['src/resolve/test-dnssec.c'], + [libsystemd_resolve_core, + libshared], + [libgcrypt, + libgpg_error, + libm]], + + [['src/resolve/test-dnssec-complex.c'], [libsystemd_resolve_core, libshared], [libgcrypt, libgpg_error, libm], - 'ENABLE_RESOLVE'], - - [['src/resolve/test-dnssec.c', - dns_type_headers], - [libsystemd_resolve_core, - libshared], - [libgcrypt, - libgpg_error, - libm], - 'ENABLE_RESOLVE'], - - [['src/resolve/test-dnssec-complex.c', - 'src/resolve/dns-type.c', - dns_type_headers], - [], - [], - 'ENABLE_RESOLVE', 'manual'], + [], '', 'manual'], +] + +fuzzers += [ + [['src/resolve/fuzz-dns-packet.c'], + [libsystemd_resolve_core, + libshared], + [libgcrypt, + libgpg_error, + libm]], ] diff --git a/src/resolve/resolvconf-compat.c b/src/resolve/resolvconf-compat.c index 5bc936faa..b3f1e12fa 100644 --- a/src/resolve/resolvconf-compat.c +++ b/src/resolve/resolvconf-compat.c @@ -43,10 +43,9 @@ static int resolvconf_help(void) { "implementations are not supported and will cause the invocation to fail: -u,\n" "-I, -i, -l, -R, -r, -v, -V, --enable-updates, --disable-updates,\n" "--updates-are-enabled.\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link); return 0; } diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c index b47933576..52bbae329 100644 --- a/src/resolve/resolvectl.c +++ b/src/resolve/resolvectl.c @@ -19,16 +19,20 @@ #include "format-table.h" #include "format-util.h" #include "gcrypt-util.h" +#include "hostname-util.h" #include "main-func.h" #include "missing_network.h" #include "netlink-util.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "pretty-print.h" +#include "process-util.h" #include "resolvconf-compat.h" #include "resolvectl.h" #include "resolved-def.h" #include "resolved-dns-packet.h" +#include "resolved-util.h" #include "socket-netlink.h" #include "sort-util.h" #include "stdio-util.h" @@ -155,9 +159,22 @@ static void print_source(uint64_t flags, usec_t rtt) { assert_se(format_timespan(rtt_str, sizeof(rtt_str), rtt, 100)); printf(" in %s.%s\n" - "%s-- Data is authenticated: %s%s\n", + "%s-- Data is authenticated: %s; Data was acquired via local or encrypted transport: %s%s\n", rtt_str, ansi_normal(), - ansi_grey(), yes_no(flags & SD_RESOLVED_AUTHENTICATED), ansi_normal()); + ansi_grey(), + yes_no(flags & SD_RESOLVED_AUTHENTICATED), + yes_no(flags & SD_RESOLVED_CONFIDENTIAL), + ansi_normal()); + + if ((flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)) != 0) + printf("%s-- Data from:%s%s%s%s%s%s\n", + ansi_grey(), + FLAGS_SET(flags, SD_RESOLVED_SYNTHETIC) ? " synthetic" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_CACHE) ? " cache" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_ZONE) ? " zone" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_TRUST_ANCHOR) ? " trust-anchor" : "", + FLAGS_SET(flags, SD_RESOLVED_FROM_NETWORK) ? " network" : "", + ansi_normal()); } static void print_ifindex_comment(int printed_so_far, int ifindex) { @@ -407,19 +424,70 @@ static int output_rr_packet(const void *d, size_t l, int ifindex) { return 0; } +static int idna_candidate(const char *name, char **ret) { + _cleanup_free_ char *idnafied = NULL; + int r; + + assert(name); + assert(ret); + + r = dns_name_apply_idna(name, &idnafied); + if (r < 0) + return log_error_errno(r, "Failed to apply IDNA to name '%s': %m", name); + if (r > 0 && !streq(name, idnafied)) { + *ret = TAKE_PTR(idnafied); + return true; + } + + *ret = NULL; + return false; +} + +static bool single_label_nonsynthetic(const char *name) { + _cleanup_free_ char *first_label = NULL; + int r; + + if (!dns_name_is_single_label(name)) + return false; + + if (is_localhost(name) || is_gateway_hostname(name)) + return false; + + r = resolve_system_hostname(NULL, &first_label); + if (r < 0) { + log_warning_errno(r, "Failed to determine the hostname: %m"); + return false; + } + + return !streq(name, first_label); +} + static int resolve_record(sd_bus *bus, const char *name, uint16_t class, uint16_t type, bool warn_missing) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *idnafied = NULL; + bool needs_authentication = false; unsigned n = 0; uint64_t flags; - int r; usec_t ts; - bool needs_authentication = false; + int r; assert(name); log_debug("Resolving %s %s %s (interface %s).", name, dns_class_to_string(class), dns_type_to_string(type), isempty(arg_ifname) ? "*" : arg_ifname); + if (dns_name_dot_suffixed(name) == 0 && single_label_nonsynthetic(name)) + log_notice("(Note that search domains are not appended when --type= is specified. " + "Please specify fully qualified domain names, or remove --type= switch from invocation in order to request regular hostname resolution.)"); + + r = idna_candidate(name, &idnafied); + if (r < 0) + return r; + if (r > 0) + log_notice("(Note that IDNA translation is not applied when --type= is specified. " + "Please specify translated domain names — i.e. '%s' — when resolving raw records, or remove --type= switch from invocation in order to request regular hostname resolution.", + idnafied); + r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveRecord"); if (r < 0) return bus_log_create_error(r); @@ -566,8 +634,7 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) { r = dns_class_from_string(t); if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown DNS class %s.", t); + return log_error_errno(r, "Unknown DNS class %s.", t); class = r; @@ -595,8 +662,7 @@ static int resolve_rfc4501(sd_bus *bus, const char *name) { r = dns_type_from_string(t); if (r < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Unknown DNS type %s.", t); + return log_error_errno(r, "Unknown DNS type %s: %m", t); type = r; @@ -2568,12 +2634,11 @@ static int compat_help(void) { " --set-dnssec=MODE Set per-interface DNSSEC mode\n" " --set-nta=DOMAIN Set per-interface DNSSEC NTA\n" " --revert Revert per-interface configuration\n" - "\nSee the %4$s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %4$s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -2623,18 +2688,23 @@ static int native_help(void) { " --service-address=BOOL Resolve address for services (default: yes)\n" " --service-txt=BOOL Resolve TXT records for services (default: yes)\n" " --cname=BOOL Follow CNAME redirects (default: yes)\n" - " --search=BOOL Use search domains for single-label names\n" - " (default: yes)\n" + " --validate=BOOL Allow DNSSEC validation (default: yes)\n" + " --synthesize=BOOL Allow synthetic response (default: yes)\n" + " --cache=BOOL Allow response from cache (default: yes)\n" + " --zone=BOOL Allow response from locally registered mDNS/LLMNR\n" + " records (default: yes)\n" + " --trust-anchor=BOOL Allow response from local trust anchor (default: yes)\n" + " --network=BOOL Allow response from network (default: yes)\n" + " --search=BOOL Use search domains for single-label names (default: yes)\n" " --raw[=payload|packet] Dump the answer as binary data\n" " --legend=BOOL Print headers and additional info (default: yes)\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -2739,10 +2809,9 @@ static int compat_parse_argv(int argc, char *argv[]) { } r = dns_type_from_string(optarg); - if (r < 0) { - log_error("Failed to parse RR record type %s", optarg); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to parse RR record type %s: %m", optarg); + arg_type = (uint16_t) r; assert((int) arg_type == r); @@ -2756,21 +2825,18 @@ static int compat_parse_argv(int argc, char *argv[]) { } r = dns_class_from_string(optarg); - if (r < 0) { - log_error("Failed to parse RR record class %s", optarg); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to parse RR record class %s: %m", optarg); + arg_class = (uint16_t) r; assert((int) arg_class == r); break; case ARG_LEGEND: - r = parse_boolean(optarg); + r = parse_boolean_argument("--legend=", optarg, &arg_legend); if (r < 0) - return log_error_errno(r, "Failed to parse --legend= argument"); - - arg_legend = r; + return r; break; case 'p': @@ -2832,30 +2898,30 @@ static int compat_parse_argv(int argc, char *argv[]) { break; case ARG_CNAME: - r = parse_boolean(optarg); + r = parse_boolean_argument("--cname=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --cname= argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0); break; case ARG_SERVICE_ADDRESS: - r = parse_boolean(optarg); + r = parse_boolean_argument("--service-address=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --service-address= argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0); break; case ARG_SERVICE_TXT: - r = parse_boolean(optarg); + r = parse_boolean_argument("--service-txt=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --service-txt= argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0); break; case ARG_SEARCH: - r = parse_boolean(optarg); + r = parse_boolean_argument("--search=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --search argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0); break; @@ -2967,6 +3033,12 @@ static int native_parse_argv(int argc, char *argv[]) { ARG_VERSION = 0x100, ARG_LEGEND, ARG_CNAME, + ARG_VALIDATE, + ARG_SYNTHESIZE, + ARG_CACHE, + ARG_ZONE, + ARG_TRUST_ANCHOR, + ARG_NETWORK, ARG_SERVICE_ADDRESS, ARG_SERVICE_TXT, ARG_RAW, @@ -2983,6 +3055,12 @@ static int native_parse_argv(int argc, char *argv[]) { { "interface", required_argument, NULL, 'i' }, { "protocol", required_argument, NULL, 'p' }, { "cname", required_argument, NULL, ARG_CNAME }, + { "validate", required_argument, NULL, ARG_VALIDATE }, + { "synthesize", required_argument, NULL, ARG_SYNTHESIZE }, + { "cache", required_argument, NULL, ARG_CACHE }, + { "zone", required_argument, NULL, ARG_ZONE }, + { "trust-anchor", required_argument, NULL, ARG_TRUST_ANCHOR }, + { "network", required_argument, NULL, ARG_NETWORK }, { "service-address", required_argument, NULL, ARG_SERVICE_ADDRESS }, { "service-txt", required_argument, NULL, ARG_SERVICE_TXT }, { "raw", optional_argument, NULL, ARG_RAW }, @@ -3026,10 +3104,9 @@ static int native_parse_argv(int argc, char *argv[]) { } r = dns_type_from_string(optarg); - if (r < 0) { - log_error("Failed to parse RR record type %s", optarg); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to parse RR record type %s: %m", optarg); + arg_type = (uint16_t) r; assert((int) arg_type == r); @@ -3042,21 +3119,18 @@ static int native_parse_argv(int argc, char *argv[]) { } r = dns_class_from_string(optarg); - if (r < 0) { - log_error("Failed to parse RR record class %s", optarg); - return r; - } + if (r < 0) + return log_error_errno(r, "Failed to parse RR record class %s: %m", optarg); + arg_class = (uint16_t) r; assert((int) arg_class == r); break; case ARG_LEGEND: - r = parse_boolean(optarg); + r = parse_boolean_argument("--legend=", optarg, &arg_legend); if (r < 0) - return log_error_errno(r, "Failed to parse --legend= argument"); - - arg_legend = r; + return r; break; case 'p': @@ -3102,30 +3176,72 @@ static int native_parse_argv(int argc, char *argv[]) { break; case ARG_CNAME: - r = parse_boolean(optarg); + r = parse_boolean_argument("--cname=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --cname= argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_CNAME, r == 0); break; - case ARG_SERVICE_ADDRESS: - r = parse_boolean(optarg); + case ARG_VALIDATE: + r = parse_boolean_argument("--validate=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --service-address= argument."); + return r; + SET_FLAG(arg_flags, SD_RESOLVED_NO_VALIDATE, r == 0); + break; + + case ARG_SYNTHESIZE: + r = parse_boolean_argument("--synthesize=", optarg, NULL); + if (r < 0) + return r; + SET_FLAG(arg_flags, SD_RESOLVED_NO_SYNTHESIZE, r == 0); + break; + + case ARG_CACHE: + r = parse_boolean_argument("--cache=", optarg, NULL); + if (r < 0) + return r; + SET_FLAG(arg_flags, SD_RESOLVED_NO_CACHE, r == 0); + break; + + case ARG_ZONE: + r = parse_boolean_argument("--zone=", optarg, NULL); + if (r < 0) + return r; + SET_FLAG(arg_flags, SD_RESOLVED_NO_ZONE, r == 0); + break; + + case ARG_TRUST_ANCHOR: + r = parse_boolean_argument("--trust-anchor=", optarg, NULL); + if (r < 0) + return r; + SET_FLAG(arg_flags, SD_RESOLVED_NO_TRUST_ANCHOR, r == 0); + break; + + case ARG_NETWORK: + r = parse_boolean_argument("--network=", optarg, NULL); + if (r < 0) + return r; + SET_FLAG(arg_flags, SD_RESOLVED_NO_NETWORK, r == 0); + break; + + case ARG_SERVICE_ADDRESS: + r = parse_boolean_argument("--service-address=", optarg, NULL); + if (r < 0) + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_ADDRESS, r == 0); break; case ARG_SERVICE_TXT: - r = parse_boolean(optarg); + r = parse_boolean_argument("--service-txt=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --service-txt= argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_TXT, r == 0); break; case ARG_SEARCH: - r = parse_boolean(optarg); + r = parse_boolean_argument("--search=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --search argument."); + return r; SET_FLAG(arg_flags, SD_RESOLVED_NO_SEARCH, r == 0); break; @@ -3298,11 +3414,11 @@ static int run(int argc, char **argv) { int r; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); - if (streq(program_invocation_short_name, "resolvconf")) + if (invoked_as(argv, "resolvconf")) r = resolvconf_parse_argv(argc, argv); - else if (streq(program_invocation_short_name, "systemd-resolve")) + else if (invoked_as(argv, "systemd-resolve")) r = compat_parse_argv(argc, argv); else r = native_parse_argv(argc, argv); diff --git a/src/resolve/resolvectl.h b/src/resolve/resolvectl.h index 830c81d69..468a87957 100644 --- a/src/resolve/resolvectl.h +++ b/src/resolve/resolvectl.h @@ -18,7 +18,7 @@ typedef enum ExecutionMode { MODE_STATUS, MODE_SET_LINK, MODE_REVERT_LINK, - _MODE_INVALID = -1, + _MODE_INVALID = -EINVAL, } ExecutionMode; extern ExecutionMode arg_mode; diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index dca9b885f..c3624669c 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -7,6 +7,7 @@ #include "bus-message-util.h" #include "bus-polkit.h" #include "dns-domain.h" +#include "format-util.h" #include "memory-util.h" #include "missing_capability.h" #include "resolved-bus.h" @@ -101,6 +102,12 @@ static int reply_query_state(DnsQuery *q) { * thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */ return sd_bus_reply_method_errorf(q->bus_request, _BUS_ERROR_DNS "NXDOMAIN", "'%s' not found", dns_query_string(q)); + case DNS_TRANSACTION_NO_SOURCE: + return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_NO_SOURCE, "All suitable resolution sources turned off"); + + case DNS_TRANSACTION_STUB_LOOP: + return sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_STUB_LOOP, "Configured DNS server loops back to us"); + case DNS_TRANSACTION_RCODE_FAILURE: { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -188,14 +195,14 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { goto finish; } - r = dns_query_process_cname(q); + r = dns_query_process_cname_many(q); if (r == -ELOOP) { r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q)); goto finish; } if (r < 0) goto finish; - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; r = sd_bus_message_new_method_return(q->bus_request, &reply); @@ -246,7 +253,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) { r = sd_bus_message_append( reply, "st", normalized, - SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -274,8 +281,8 @@ static int validate_and_mangle_flags( * * 1. Checks that the interface index is either 0 (meaning *all* interfaces) or positive * - * 2. Only the protocols flags and the NO_CNAME flag are set, at most. Plus additional flags specific - * to our method, passed in the "ok" parameter. + * 2. Only the protocols flags and a bunch of NO_XYZ flags are set, at most. Plus additional flags + * specific to our method, passed in the "ok" parameter. * * 3. If zero protocol flags are specified it is automatically turned into *all* protocols. This way * clients can simply pass 0 as flags and all will work as it should. They can also use this so @@ -283,7 +290,15 @@ static int validate_and_mangle_flags( * to mean "all supported protocols". */ - if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok)) + if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL| + SD_RESOLVED_NO_CNAME| + SD_RESOLVED_NO_VALIDATE| + SD_RESOLVED_NO_SYNTHESIZE| + SD_RESOLVED_NO_CACHE| + SD_RESOLVED_NO_ZONE| + SD_RESOLVED_NO_TRUST_ANCHOR| + SD_RESOLVED_NO_NETWORK| + ok)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid flags parameter"); if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */ @@ -353,13 +368,39 @@ static int parse_as_address(sd_bus_message *m, int ifindex, const char *hostname return r; r = sd_bus_message_append(reply, "st", canonical, - SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true)); + SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(flags), ff, true, true) | + SD_RESOLVED_SYNTHETIC); if (r < 0) return r; return sd_bus_send(sd_bus_message_get_bus(m), reply, NULL); } +void bus_client_log(sd_bus_message *m, const char *what) { + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + const char *comm = NULL; + uid_t uid = UID_INVALID; + pid_t pid = 0; + int r; + + assert(m); + assert(what); + + if (!DEBUG_LOGGING) + return; + + r = sd_bus_query_sender_creds(m, SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_COMM|SD_BUS_CREDS_AUGMENT, &creds); + if (r < 0) + return (void) log_debug_errno(r, "Failed to query client credentials, ignoring: %m"); + + (void) sd_bus_creds_get_uid(creds, &uid); + (void) sd_bus_creds_get_pid(creds, &pid); + (void) sd_bus_creds_get_comm(creds, &comm); + + log_debug("D-Bus %s request from client PID " PID_FMT " (%s) with UID " UID_FMT, + what, pid, strna(comm), uid); +} + static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_(dns_question_unrefp) DnsQuestion *question_idna = NULL, *question_utf8 = NULL; Manager *m = userdata; @@ -406,7 +447,9 @@ static int bus_method_resolve_hostname(sd_bus_message *message, void *userdata, if (r < 0 && r != -EALREADY) return r; - r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, ifindex, flags); + bus_client_log(message, "hostname resolution"); + + r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, NULL, ifindex, flags); if (r < 0) return r; @@ -443,14 +486,14 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { goto finish; } - r = dns_query_process_cname(q); + r = dns_query_process_cname_many(q); if (r == -ELOOP) { r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q)); goto finish; } if (r < 0) goto finish; - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; r = sd_bus_message_new_method_return(q->bus_request, &reply); @@ -496,7 +539,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + r = sd_bus_message_append(reply, "t", dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -548,7 +591,9 @@ static int bus_method_resolve_address(sd_bus_message *message, void *userdata, s if (r < 0) return r; - r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH); + bus_client_log(message, "address resolution"); + + r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH); if (r < 0) return r; @@ -615,14 +660,14 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { goto finish; } - r = dns_query_process_cname(q); + r = dns_query_process_cname_many(q); if (r == -ELOOP) { r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q)); goto finish; } if (r < 0) goto finish; - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; r = sd_bus_message_new_method_return(q->bus_request, &reply); @@ -658,7 +703,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) { if (r < 0) goto finish; - r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + r = sd_bus_message_append(reply, "t", dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -724,14 +769,14 @@ static int bus_method_resolve_record(sd_bus_message *message, void *userdata, sd if (r < 0) return r; - r = dns_query_new(m, &q, question, question, ifindex, flags|SD_RESOLVED_NO_SEARCH); + bus_client_log(message, "resource record resolution"); + + /* Setting SD_RESOLVED_CLAMP_TTL: let's request that the TTL is fixed up for locally cached entries, + * after all we return it in the wire format blob. */ + r = dns_query_new(m, &q, question, question, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH|SD_RESOLVED_CLAMP_TTL); if (r < 0) return r; - /* Let's request that the TTL is fixed up for locally cached entries, after all we return it in the wire format - * blob */ - q->clamp_ttl = true; - q->bus_request = sd_bus_message_ref(message); q->complete = bus_method_resolve_record_complete; @@ -1036,7 +1081,7 @@ static void resolve_service_all_complete(DnsQuery *q) { reply, "ssst", name, type, domain, - SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q))); + dns_query_reply_flags_make(q)); if (r < 0) goto finish; @@ -1062,8 +1107,8 @@ static void resolve_service_hostname_complete(DnsQuery *q) { return; } - r = dns_query_process_cname(q); - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + r = dns_query_process_cname_many(q); + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; /* This auxiliary lookup is finished or failed, let's see if all are finished now. */ @@ -1088,7 +1133,7 @@ static int resolve_service_hostname(DnsQuery *q, DnsResourceRecord *rr, int ifin if (r < 0) return r; - r = dns_query_new(q->manager, &aux, question, question, ifindex, q->flags|SD_RESOLVED_NO_SEARCH); + r = dns_query_new(q->manager, &aux, question, question, NULL, ifindex, q->flags|SD_RESOLVED_NO_SEARCH); if (r < 0) return r; @@ -1135,14 +1180,14 @@ static void bus_method_resolve_service_complete(DnsQuery *q) { goto finish; } - r = dns_query_process_cname(q); + r = dns_query_process_cname_many(q); if (r == -ELOOP) { r = sd_bus_reply_method_errorf(q->bus_request, BUS_ERROR_CNAME_LOOP, "CNAME loop detected, or CNAME resolving disabled on '%s'", dns_query_string(q)); goto finish; } if (r < 0) goto finish; - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; question = dns_query_question_for_protocol(q, q->answer_protocol); @@ -1258,7 +1303,9 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s if (r < 0) return r; - r = dns_query_new(m, &q, question_utf8, question_idna, ifindex, flags|SD_RESOLVED_NO_SEARCH); + bus_client_log(message, "service resolution"); + + r = dns_query_new(m, &q, question_utf8, question_idna, NULL, ifindex, flags|SD_RESOLVED_NO_SEARCH); if (r < 0) return r; @@ -1650,6 +1697,8 @@ static int bus_method_reset_statistics(sd_bus_message *message, void *userdata, assert(message); assert(m); + bus_client_log(message, "statistics reset"); + LIST_FOREACH(scopes, s, m->dns_scopes) s->cache.n_hit = s->cache.n_miss = 0; @@ -1762,7 +1811,9 @@ static int bus_method_flush_caches(sd_bus_message *message, void *userdata, sd_b assert(message); assert(m); - manager_flush_caches(m); + bus_client_log(message, "cache flush"); + + manager_flush_caches(m, LOG_INFO); return sd_bus_reply_method_return(message, NULL); } @@ -1773,6 +1824,8 @@ static int bus_method_reset_server_features(sd_bus_message *message, void *userd assert(message); assert(m); + bus_client_log(message, "server feature reset"); + manager_reset_server_features(m); return sd_bus_reply_method_return(message, NULL); @@ -1943,11 +1996,7 @@ static int bus_method_register_service(sd_bus_message *message, void *userdata, if (r == 0) return 1; /* Polkit will call us back */ - r = hashmap_ensure_allocated(&m->dnssd_services, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(m->dnssd_services, service->name, service); + r = hashmap_ensure_put(&m->dnssd_services, &string_hash_ops, service->name, service); if (r < 0) return r; diff --git a/src/resolve/resolved-bus.h b/src/resolve/resolved-bus.h index 8628d8ba6..6c2bd2668 100644 --- a/src/resolve/resolved-bus.h +++ b/src/resolve/resolved-bus.h @@ -13,3 +13,5 @@ int bus_dns_server_append(sd_bus_message *reply, DnsServer *s, bool with_ifindex int bus_property_get_resolve_support(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); + +void bus_client_log(sd_bus_message *m, const char *what); diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index f2a331625..87d1794a7 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -348,7 +348,7 @@ int config_parse_dnssd_txt( int r; r = extract_first_word(&rvalue, &word, NULL, - EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX); + EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX); if (r == 0) break; if (r == -ENOMEM) diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h index 21eb6994e..702d3f8b4 100644 --- a/src/resolve/resolved-def.h +++ b/src/resolve/resolved-def.h @@ -27,8 +27,53 @@ /* Output: Result is authenticated */ #define SD_RESOLVED_AUTHENTICATED (UINT64_C(1) << 9) +/* Input: Don't DNSSEC validate request */ +#define SD_RESOLVED_NO_VALIDATE (UINT64_C(1) << 10) + +/* Input: Don't answer request from locally synthesized records (which includes /etc/hosts) */ +#define SD_RESOLVED_NO_SYNTHESIZE (UINT64_C(1) << 11) + +/* Input: Don't answer request from cache */ +#define SD_RESOLVED_NO_CACHE (UINT64_C(1) << 12) + +/* Input: Don't answer request from locally registered public LLMNR/mDNS RRs */ +#define SD_RESOLVED_NO_ZONE (UINT64_C(1) << 13) + +/* Input: Don't answer request from locally registered public LLMNR/mDNS RRs */ +#define SD_RESOLVED_NO_TRUST_ANCHOR (UINT64_C(1) << 14) + +/* Input: Don't go to network for this request */ +#define SD_RESOLVED_NO_NETWORK (UINT64_C(1) << 15) + +/* Input: Require that request is answered from a "primary" answer, i.e. not from RRs acquired as + * side-effect of a previous transaction */ +#define SD_RESOLVED_REQUIRE_PRIMARY (UINT64_C(1) << 16) + +/* Input: If reply is answered from cache, the TTLs will be adjusted by age of cache entry */ +#define SD_RESOLVED_CLAMP_TTL (UINT64_C(1) << 17) + +/* Output: Result was only sent via encrypted channels, or never left this system */ +#define SD_RESOLVED_CONFIDENTIAL (UINT64_C(1) << 18) + +/* Output: Result was (at least partially) synthesized locally */ +#define SD_RESOLVED_SYNTHETIC (UINT64_C(1) << 19) + +/* Output: Result was (at least partially) answered from cache */ +#define SD_RESOLVED_FROM_CACHE (UINT64_C(1) << 20) + +/* Output: Result was (at least partially) answered from local zone */ +#define SD_RESOLVED_FROM_ZONE (UINT64_C(1) << 21) + +/* Output: Result was (at least partially) answered from trust anchor */ +#define SD_RESOLVED_FROM_TRUST_ANCHOR (UINT64_C(1) << 22) + +/* Output: Result was (at least partially) answered from network */ +#define SD_RESOLVED_FROM_NETWORK (UINT64_C(1) << 23) + #define SD_RESOLVED_LLMNR (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) #define SD_RESOLVED_MDNS (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6) #define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) +#define SD_RESOLVED_FROM_MASK (SD_RESOLVED_FROM_CACHE|SD_RESOLVED_FROM_ZONE|SD_RESOLVED_FROM_TRUST_ANCHOR|SD_RESOLVED_FROM_NETWORK) + #define SD_RESOLVED_QUERY_TIMEOUT_USEC (120 * USEC_PER_SEC) diff --git a/src/resolve/resolved-dns-answer.c b/src/resolve/resolved-dns-answer.c index 5b762a82e..a032ac157 100644 --- a/src/resolve/resolved-dns-answer.c +++ b/src/resolve/resolved-dns-answer.c @@ -4,34 +4,73 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "random-util.h" #include "resolved-dns-answer.h" #include "resolved-dns-dnssec.h" #include "string-util.h" +static void dns_answer_item_hash_func(const DnsAnswerItem *a, struct siphash *state) { + assert(a); + assert(state); + + siphash24_compress(&a->ifindex, sizeof(a->ifindex), state); + + dns_resource_record_hash_func(a->rr, state); +} + +static int dns_answer_item_compare_func(const DnsAnswerItem *a, const DnsAnswerItem *b) { + int r; + + assert(a); + assert(b); + + r = CMP(a->ifindex, b->ifindex); + if (r != 0) + return r; + + return dns_resource_record_compare_func(a->rr, b->rr); +} + +DEFINE_PRIVATE_HASH_OPS(dns_answer_item_hash_ops, DnsAnswerItem, dns_answer_item_hash_func, dns_answer_item_compare_func); + DnsAnswer *dns_answer_new(size_t n) { + _cleanup_set_free_ Set *s = NULL; DnsAnswer *a; if (n > UINT16_MAX) /* We can only place 64K RRs in an answer at max */ n = UINT16_MAX; + s = set_new(&dns_answer_item_hash_ops); + if (!s) + return NULL; + + /* Higher multipliers give slightly higher efficiency through hash collisions, but the gains + * quickly drop off after 2. */ + if (set_reserve(s, n * 2) < 0) + return NULL; + a = malloc0(offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * n); if (!a) return NULL; a->n_ref = 1; a->n_allocated = n; - + a->set_items = TAKE_PTR(s); return a; } static void dns_answer_flush(DnsAnswer *a) { - DnsResourceRecord *rr; + DnsAnswerItem *item; if (!a) return; - DNS_ANSWER_FOREACH(rr, a) - dns_resource_record_unref(rr); + a->set_items = set_free(a->set_items); + + DNS_ANSWER_FOREACH_ITEM(item, a) { + dns_resource_record_unref(item->rr); + dns_resource_record_unref(item->rrsig); + } a->n_rrs = 0; } @@ -45,7 +84,15 @@ static DnsAnswer *dns_answer_free(DnsAnswer *a) { DEFINE_TRIVIAL_REF_UNREF_FUNC(DnsAnswer, dns_answer, dns_answer_free); -static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) { +static int dns_answer_add_raw( + DnsAnswer *a, + DnsResourceRecord *rr, + int ifindex, + DnsAnswerFlags flags, + DnsResourceRecord *rrsig) { + + int r; + assert(rr); if (!a) @@ -54,22 +101,36 @@ static int dns_answer_add_raw(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, if (a->n_rrs >= a->n_allocated) return -ENOSPC; - a->items[a->n_rrs++] = (DnsAnswerItem) { - .rr = dns_resource_record_ref(rr), + a->items[a->n_rrs] = (DnsAnswerItem) { + .rr = rr, .ifindex = ifindex, .flags = flags, + .rrsig = dns_resource_record_ref(rrsig), }; + r = set_put(a->set_items, &a->items[a->n_rrs]); + if (r < 0) + return r; + if (r == 0) + return -EEXIST; + + dns_resource_record_ref(rr); + a->n_rrs++; + return 1; } static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) { - DnsResourceRecord *rr; - DnsAnswerFlags flags; - int ifindex, r; + DnsAnswerItem *item; + int r; - DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, source) { - r = dns_answer_add_raw(a, rr, ifindex, flags); + DNS_ANSWER_FOREACH_ITEM(item, source) { + r = dns_answer_add_raw( + a, + item->rr, + item->ifindex, + item->flags, + item->rrsig); if (r < 0) return r; } @@ -77,9 +138,14 @@ static int dns_answer_add_raw_all(DnsAnswer *a, DnsAnswer *source) { return 0; } -int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) { - size_t i; - int r; +int dns_answer_add( + DnsAnswer *a, + DnsResourceRecord *rr, + int ifindex, + DnsAnswerFlags flags, + DnsResourceRecord *rrsig) { + + DnsAnswerItem tmp, *exist; assert(rr); @@ -88,49 +154,45 @@ int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFl if (a->n_ref > 1) return -EBUSY; - for (i = 0; i < a->n_rrs; i++) { - if (a->items[i].ifindex != ifindex) - continue; - - r = dns_resource_key_equal(a->items[i].rr->key, rr->key); - if (r < 0) - return r; - if (r == 0) - continue; + tmp = (DnsAnswerItem) { + .rr = rr, + .ifindex = ifindex, + }; + exist = set_get(a->set_items, &tmp); + if (exist) { /* There's already an RR of the same RRset in place! Let's see if the TTLs more or less * match. We don't really care if they match precisely, but we do care whether one is 0 and * the other is not. See RFC 2181, Section 5.2. */ - if ((rr->ttl == 0) != (a->items[i].rr->ttl == 0)) + if ((rr->ttl == 0) != (exist->rr->ttl == 0)) return -EINVAL; - r = dns_resource_record_payload_equal(a->items[i].rr, rr); - if (r < 0) - return r; - if (r == 0) - continue; + /* Entry already exists, keep the entry with the higher TTL. */ + if (rr->ttl > exist->rr->ttl) { + dns_resource_record_unref(exist->rr); + exist->rr = dns_resource_record_ref(rr); - /* Entry already exists, keep the entry with the higher RR. */ - if (rr->ttl > a->items[i].rr->ttl) { - dns_resource_record_ref(rr); - dns_resource_record_unref(a->items[i].rr); - a->items[i].rr = rr; + /* Update RRSIG and RR at the same time */ + if (rrsig) { + dns_resource_record_ref(rrsig); + dns_resource_record_unref(exist->rrsig); + exist->rrsig = rrsig; + } } - a->items[i].flags |= flags; + exist->flags |= flags; return 0; } - return dns_answer_add_raw(a, rr, ifindex, flags); + return dns_answer_add_raw(a, rr, ifindex, flags, rrsig); } static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) { - DnsResourceRecord *rr; - DnsAnswerFlags flags; - int ifindex, r; + DnsAnswerItem *item; + int r; - DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, b) { - r = dns_answer_add(a, rr, ifindex, flags); + DNS_ANSWER_FOREACH_ITEM(item, b) { + r = dns_answer_add(a, item->rr, item->ifindex, item->flags, item->rrsig); if (r < 0) return r; } @@ -138,7 +200,13 @@ static int dns_answer_add_all(DnsAnswer *a, DnsAnswer *b) { return 0; } -int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags) { +int dns_answer_add_extend( + DnsAnswer **a, + DnsResourceRecord *rr, + int ifindex, + DnsAnswerFlags flags, + DnsResourceRecord *rrsig) { + int r; assert(a); @@ -148,7 +216,7 @@ int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, Dns if (r < 0) return r; - return dns_answer_add(*a, rr, ifindex, flags); + return dns_answer_add(*a, rr, ifindex, flags, rrsig); } int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex) { @@ -174,7 +242,7 @@ int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex soa->soa.expire = 1; soa->soa.minimum = ttl; - return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED); + return dns_answer_add(a, soa, ifindex, DNS_ANSWER_AUTHENTICATED, NULL); } int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *ret_flags) { @@ -212,10 +280,9 @@ int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a) { DnsResourceRecord *i; - DNS_ANSWER_FOREACH(i, a) { + DNS_ANSWER_FOREACH(i, a) if (IN_SET(i->key->type, DNS_TYPE_NSEC, DNS_TYPE_NSEC3)) return true; - } return false; } @@ -247,7 +314,22 @@ int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone) { return false; } -int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) { +int dns_answer_contains(DnsAnswer *answer, DnsResourceRecord *rr) { + DnsResourceRecord *i; + + DNS_ANSWER_FOREACH(i, answer) + if (dns_resource_record_equal(i, rr)) + return true; + + return false; +} + +int dns_answer_find_soa( + DnsAnswer *a, + const DnsResourceKey *key, + DnsResourceRecord **ret, + DnsAnswerFlags *ret_flags) { + DnsResourceRecord *rr, *soa = NULL; DnsAnswerFlags rr_flags, soa_flags = 0; int r; @@ -256,7 +338,7 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco /* For a SOA record we can never find a matching SOA record */ if (key->type == DNS_TYPE_SOA) - return 0; + goto not_found; DNS_ANSWER_FOREACH_FLAGS(rr, rr_flags, a) { r = dns_resource_key_match_soa(key, rr->key); @@ -278,17 +360,30 @@ int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceReco } if (!soa) - return 0; + goto not_found; if (ret) *ret = soa; - if (flags) - *flags = soa_flags; + if (ret_flags) + *ret_flags = soa_flags; return 1; + +not_found: + if (ret) + *ret = NULL; + if (ret_flags) + *ret_flags = 0; + + return 0; } -int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags) { +int dns_answer_find_cname_or_dname( + DnsAnswer *a, + const DnsResourceKey *key, + DnsResourceRecord **ret, + DnsAnswerFlags *ret_flags) { + DnsResourceRecord *rr; DnsAnswerFlags rr_flags; int r; @@ -306,12 +401,17 @@ int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsR if (r > 0) { if (ret) *ret = rr; - if (flags) - *flags = rr_flags; + if (ret_flags) + *ret_flags = rr_flags; return 1; } } + if (ret) + *ret = NULL; + if (ret_flags) + *ret_flags = 0; + return 0; } @@ -403,21 +503,20 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) { if ((*a)->n_ref > 1) { _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL; - DnsAnswerFlags flags; - int ifindex; + DnsAnswerItem *item; copy = dns_answer_new((*a)->n_rrs); if (!copy) return -ENOMEM; - DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) { - r = dns_resource_key_equal(rr->key, key); + DNS_ANSWER_FOREACH_ITEM(item, *a) { + r = dns_resource_key_equal(item->rr->key, key); if (r < 0) return r; if (r > 0) continue; - r = dns_answer_add_raw(copy, rr, ifindex, flags); + r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig); if (r < 0) return r; } @@ -442,6 +541,8 @@ int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key) { /* Kill this entry */ dns_resource_record_unref((*a)->items[i].rr); + dns_resource_record_unref((*a)->items[i].rrsig); + memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); (*a)->n_rrs--; continue; @@ -488,21 +589,20 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) { if ((*a)->n_ref > 1) { _cleanup_(dns_answer_unrefp) DnsAnswer *copy = NULL; - DnsAnswerFlags flags; - int ifindex; + DnsAnswerItem *item; copy = dns_answer_new((*a)->n_rrs); if (!copy) return -ENOMEM; - DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, *a) { - r = dns_resource_record_equal(rr, rm); + DNS_ANSWER_FOREACH_ITEM(item, *a) { + r = dns_resource_record_equal(item->rr, rm); if (r < 0) return r; if (r > 0) continue; - r = dns_answer_add_raw(copy, rr, ifindex, flags); + r = dns_answer_add_raw(copy, item->rr, item->ifindex, item->flags, item->rrsig); if (r < 0) return r; } @@ -527,6 +627,7 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) { /* Kill this entry */ dns_resource_record_unref((*a)->items[i].rr); + dns_resource_record_unref((*a)->items[i].rrsig); memmove((*a)->items + i, (*a)->items + i + 1, sizeof(DnsAnswerItem) * ((*a)->n_rrs - i - 1)); (*a)->n_rrs--; continue; @@ -539,19 +640,49 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rm) { return 1; } -int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags) { - DnsResourceRecord *rr_source; - int ifindex_source, r; - DnsAnswerFlags flags_source; +int dns_answer_remove_by_answer_keys(DnsAnswer **a, DnsAnswer *b) { + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *prev = NULL; + DnsAnswerItem *item; + int r; + + /* Removes all items from '*a' that have a matching key in 'b' */ + + DNS_ANSWER_FOREACH_ITEM(item, b) { + + if (prev && dns_resource_key_equal(item->rr->key, prev)) /* Skip this one, we already looked at it */ + continue; + + r = dns_answer_remove_by_key(a, item->rr->key); + if (r < 0) + return r; + + /* Let's remember this entry's RR key, to optimize the loop a bit: if we have an RRset with + * more than one item then we don't need to remove the key multiple times */ + dns_resource_key_unref(prev); + prev = dns_resource_key_ref(item->rr->key); + } + + return 0; +} + +int dns_answer_copy_by_key( + DnsAnswer **a, + DnsAnswer *source, + const DnsResourceKey *key, + DnsAnswerFlags or_flags, + DnsResourceRecord *rrsig) { + + DnsAnswerItem *item; + int r; assert(a); assert(key); /* Copy all RRs matching the specified key from source into *a */ - DNS_ANSWER_FOREACH_FULL(rr_source, ifindex_source, flags_source, source) { + DNS_ANSWER_FOREACH_ITEM(item, source) { - r = dns_resource_key_equal(rr_source->key, key); + r = dns_resource_key_equal(item->rr->key, key); if (r < 0) return r; if (r == 0) @@ -562,7 +693,7 @@ int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKe if (r < 0) return r; - r = dns_answer_add(*a, rr_source, ifindex_source, flags_source|or_flags); + r = dns_answer_add(*a, item->rr, item->ifindex, item->flags|or_flags, rrsig ?: item->rrsig); if (r < 0) return r; } @@ -570,14 +701,19 @@ int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKe return 0; } -int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags) { +int dns_answer_move_by_key( + DnsAnswer **to, + DnsAnswer **from, + const DnsResourceKey *key, + DnsAnswerFlags or_flags, + DnsResourceRecord *rrsig) { int r; assert(to); assert(from); assert(key); - r = dns_answer_copy_by_key(to, *from, key, or_flags); + r = dns_answer_copy_by_key(to, *from, key, or_flags, rrsig); if (r < 0) return r; @@ -602,10 +738,7 @@ void dns_answer_order_by_scope(DnsAnswer *a, bool prefer_link_local) { items = newa(DnsAnswerItem, a->n_rrs); for (i = 0; i < a->n_rrs; i++) { - - if (a->items[i].rr->key->class == DNS_CLASS_IN && - ((a->items[i].rr->key->type == DNS_TYPE_A && in_addr_is_link_local(AF_INET, (union in_addr_union*) &a->items[i].rr->a.in_addr) != prefer_link_local) || - (a->items[i].rr->key->type == DNS_TYPE_AAAA && in_addr_is_link_local(AF_INET6, (union in_addr_union*) &a->items[i].rr->aaaa.in6_addr) != prefer_link_local))) + if (dns_resource_record_is_link_local_address(a->items[i].rr) != prefer_link_local) /* Order address records that are not preferred to the end of the array */ items[end--] = a->items[i]; else @@ -627,27 +760,45 @@ int dns_answer_reserve(DnsAnswer **a, size_t n_free) { if (*a) { size_t ns; + int r; if ((*a)->n_ref > 1) return -EBUSY; - ns = (*a)->n_rrs + n_free; - if (ns > UINT16_MAX) /* Maximum number of RRs we can stick into a DNS packet section */ + ns = (*a)->n_rrs; + assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */ + + if (n_free > UINT16_MAX - ns) /* overflow check */ ns = UINT16_MAX; + else + ns += n_free; if ((*a)->n_allocated >= ns) return 0; - /* Allocate more than we need */ - ns *= 2; - if (ns > UINT16_MAX) + /* Allocate more than we need, but not more than UINT16_MAX */ + if (ns <= UINT16_MAX/2) + ns *= 2; + else ns = UINT16_MAX; + /* This must be done before realloc() below. Otherwise, the original DnsAnswer object + * may be broken. */ + r = set_reserve((*a)->set_items, ns); + if (r < 0) + return r; + n = realloc(*a, offsetof(DnsAnswer, items) + sizeof(DnsAnswerItem) * ns); if (!n) return -ENOMEM; n->n_allocated = ns; + + /* Previously all items are stored in the set, and the enough memory area is allocated + * in the above. So set_put() in the below cannot fail. */ + set_clear(n->set_items); + for (size_t i = 0; i < n->n_rrs; i++) + assert_se(set_put(n->set_items, &n->items[i]) > 0); } else { n = dns_answer_new(n_free); if (!n) @@ -659,33 +810,50 @@ int dns_answer_reserve(DnsAnswer **a, size_t n_free) { } int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) { - _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL; int r; assert(a); - /* Tries to extend the DnsAnswer object. And if that's not - * possible, since we are not the sole owner, then allocate a - * new, appropriately sized one. Either way, after this call - * the object will only have a single reference, and has room - * for at least the specified number of RRs. */ + /* Tries to extend the DnsAnswer object. And if that's not possible, since we are not the sole owner, + * then allocate a new, appropriately sized one. Either way, after this call the object will only + * have a single reference, and has room for at least the specified number of RRs. */ - r = dns_answer_reserve(a, n_free); - if (r != -EBUSY) - return r; + if (*a && (*a)->n_ref > 1) { + _cleanup_(dns_answer_unrefp) DnsAnswer *n = NULL; + size_t ns; - assert(*a); + ns = (*a)->n_rrs; + assert(ns <= UINT16_MAX); /* Maximum number of RRs we can stick into a DNS packet section */ - n = dns_answer_new(((*a)->n_rrs + n_free) * 2); - if (!n) - return -ENOMEM; + if (n_free > UINT16_MAX - ns) /* overflow check */ + ns = UINT16_MAX; + else if (n_free > 0) { /* Increase size and double the result, just in case — except if the + * increase is specified as 0, in which case we just allocate the + * exact amount as before, under the assumption this is just a request + * to copy the answer. */ + ns += n_free; - r = dns_answer_add_raw_all(n, *a); - if (r < 0) - return r; + if (ns <= UINT16_MAX/2) /* overflow check */ + ns *= 2; + else + ns = UINT16_MAX; + } - dns_answer_unref(*a); - *a = TAKE_PTR(n); + n = dns_answer_new(ns); + if (!n) + return -ENOMEM; + + r = dns_answer_add_raw_all(n, *a); + if (r < 0) + return r; + + dns_answer_unref(*a); + assert_se(*a = TAKE_PTR(n)); + } else if (n_free > 0) { + r = dns_answer_reserve(a, n_free); + if (r < 0) + return r; + } return 0; } @@ -694,41 +862,46 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free) { * This function is not used in the code base, but is useful when debugging. Do not delete. */ void dns_answer_dump(DnsAnswer *answer, FILE *f) { - DnsResourceRecord *rr; - DnsAnswerFlags flags; - int ifindex; + DnsAnswerItem *item; if (!f) f = stdout; - DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) { + DNS_ANSWER_FOREACH_ITEM(item, answer) { const char *t; fputc('\t', f); - t = dns_resource_record_to_string(rr); + t = dns_resource_record_to_string(item->rr); if (!t) { log_oom(); continue; } fputs(t, f); + fputs("\t;", f); + fprintf(f, " ttl=%" PRIu32, item->rr->ttl); - if (ifindex != 0 || flags != 0) - fputs("\t;", f); - - if (ifindex != 0) - fprintf(f, " ifindex=%i", ifindex); - if (flags & DNS_ANSWER_AUTHENTICATED) + if (item->ifindex != 0) + fprintf(f, " ifindex=%i", item->ifindex); + if (item->rrsig) + fputs(" rrsig", f); + if (item->flags & DNS_ANSWER_AUTHENTICATED) fputs(" authenticated", f); - if (flags & DNS_ANSWER_CACHEABLE) + if (item->flags & DNS_ANSWER_CACHEABLE) fputs(" cacheable", f); - if (flags & DNS_ANSWER_SHARED_OWNER) + if (item->flags & DNS_ANSWER_SHARED_OWNER) fputs(" shared-owner", f); - if (flags & DNS_ANSWER_CACHE_FLUSH) + if (item->flags & DNS_ANSWER_CACHE_FLUSH) fputs(" cache-flush", f); - if (flags & DNS_ANSWER_GOODBYE) + if (item->flags & DNS_ANSWER_GOODBYE) fputs(" goodbye", f); + if (item->flags & DNS_ANSWER_SECTION_ANSWER) + fputs(" section-answer", f); + if (item->flags & DNS_ANSWER_SECTION_AUTHORITY) + fputs(" section-authority", f); + if (item->flags & DNS_ANSWER_SECTION_ADDITIONAL) + fputs(" section-additional", f); fputc('\n', f); } @@ -769,3 +942,42 @@ int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) { return 0; } + +void dns_answer_randomize(DnsAnswer *a) { + size_t n; + + /* Permutes the answer list randomly (Knuth shuffle) */ + + n = dns_answer_size(a); + if (n <= 1) + return; + + for (size_t i = 0; i < n; i++) { + size_t k; + + k = random_u64_range(n); + if (k == i) + continue; + + SWAP_TWO(a->items[i], a->items[k]); + } +} + +uint32_t dns_answer_min_ttl(DnsAnswer *a) { + uint32_t ttl = UINT32_MAX; + DnsResourceRecord *rr; + + /* Return the smallest TTL of all RRs in this answer */ + + DNS_ANSWER_FOREACH(rr, a) { + /* Don't consider OPT (where the TTL field is used for other purposes than an actual TTL) */ + + if (dns_type_is_pseudo(rr->key->type) || + dns_class_is_pseudo(rr->key->class)) + continue; + + ttl = MIN(ttl, rr->ttl); + } + + return ttl; +} diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index fd94c516d..447da5d6c 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -6,30 +6,38 @@ typedef struct DnsAnswerItem DnsAnswerItem; #include "macro.h" #include "resolved-dns-rr.h" +#include "set.h" -/* A simple array of resource records. We keep track of the - * originating ifindex for each RR where that makes sense, so that we - * can qualify A and AAAA RRs referring to a local link with the - * right ifindex. +/* A simple array of resource records. We keep track of the originating ifindex for each RR where that makes + * sense, so that we can qualify A and AAAA RRs referring to a local link with the right ifindex. * * Note that we usually encode the empty DnsAnswer object as a simple NULL. */ typedef enum DnsAnswerFlags { - DNS_ANSWER_AUTHENTICATED = 1 << 0, /* Item has been authenticated */ - DNS_ANSWER_CACHEABLE = 1 << 1, /* Item is subject to caching */ - DNS_ANSWER_SHARED_OWNER = 1 << 2, /* For mDNS: RRset may be owner by multiple peers */ - DNS_ANSWER_CACHE_FLUSH = 1 << 3, /* For mDNS: sets cache-flush bit in the rrclass of response records */ - DNS_ANSWER_GOODBYE = 1 << 4, /* For mDNS: item is subject to disappear */ + DNS_ANSWER_AUTHENTICATED = 1 << 0, /* Item has been authenticated */ + DNS_ANSWER_CACHEABLE = 1 << 1, /* Item is subject to caching */ + DNS_ANSWER_SHARED_OWNER = 1 << 2, /* For mDNS: RRset may be owner by multiple peers */ + DNS_ANSWER_CACHE_FLUSH = 1 << 3, /* For mDNS: sets cache-flush bit in the rrclass of response records */ + DNS_ANSWER_GOODBYE = 1 << 4, /* For mDNS: item is subject to disappear */ + DNS_ANSWER_SECTION_ANSWER = 1 << 5, /* When parsing: RR originates from answer section */ + DNS_ANSWER_SECTION_AUTHORITY = 1 << 6, /* When parsing: RR originates from authority section */ + DNS_ANSWER_SECTION_ADDITIONAL = 1 << 7, /* When parsing: RR originates from additional section */ + + DNS_ANSWER_MASK_SECTIONS = DNS_ANSWER_SECTION_ANSWER| + DNS_ANSWER_SECTION_AUTHORITY| + DNS_ANSWER_SECTION_ADDITIONAL, } DnsAnswerFlags; struct DnsAnswerItem { DnsResourceRecord *rr; + DnsResourceRecord *rrsig; /* Optionally, also store RRSIG RR that successfully validates this item */ int ifindex; DnsAnswerFlags flags; }; struct DnsAnswer { unsigned n_ref; + Set *set_items; /* Used by dns_answer_add() for optimization. */ size_t n_rrs, n_allocated; DnsAnswerItem items[0]; }; @@ -38,16 +46,17 @@ DnsAnswer *dns_answer_new(size_t n); DnsAnswer *dns_answer_ref(DnsAnswer *a); DnsAnswer *dns_answer_unref(DnsAnswer *a); -int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); -int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags); +int dns_answer_add(DnsAnswer *a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags, DnsResourceRecord *rrsig); +int dns_answer_add_extend(DnsAnswer **a, DnsResourceRecord *rr, int ifindex, DnsAnswerFlags flags, DnsResourceRecord *rrsig); int dns_answer_add_soa(DnsAnswer *a, const char *name, uint32_t ttl, int ifindex); int dns_answer_match_key(DnsAnswer *a, const DnsResourceKey *key, DnsAnswerFlags *combined_flags); int dns_answer_contains_nsec_or_nsec3(DnsAnswer *a); int dns_answer_contains_zone_nsec3(DnsAnswer *answer, const char *zone); +int dns_answer_contains(DnsAnswer *answer, DnsResourceRecord *rr); -int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags); -int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *flags); +int dns_answer_find_soa(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *ret_flags); +int dns_answer_find_cname_or_dname(DnsAnswer *a, const DnsResourceKey *key, DnsResourceRecord **ret, DnsAnswerFlags *ret_flags); int dns_answer_merge(DnsAnswer *a, DnsAnswer *b, DnsAnswer **ret); int dns_answer_extend(DnsAnswer **a, DnsAnswer *b); @@ -59,9 +68,10 @@ int dns_answer_reserve_or_clone(DnsAnswer **a, size_t n_free); int dns_answer_remove_by_key(DnsAnswer **a, const DnsResourceKey *key); int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr); +int dns_answer_remove_by_answer_keys(DnsAnswer **a, DnsAnswer *b); -int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags); -int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags); +int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags, DnsResourceRecord *rrsig); +int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags, DnsResourceRecord *rrsig); int dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname); @@ -75,6 +85,10 @@ static inline bool dns_answer_isempty(DnsAnswer *a) { void dns_answer_dump(DnsAnswer *answer, FILE *f); +void dns_answer_randomize(DnsAnswer *a); + +uint32_t dns_answer_min_ttl(DnsAnswer *a); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref); #define _DNS_ANSWER_FOREACH(q, kk, a) \ @@ -113,17 +127,13 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref); #define DNS_ANSWER_FOREACH_FLAGS(kk, flags, a) _DNS_ANSWER_FOREACH_FLAGS(UNIQ, kk, flags, a) -#define _DNS_ANSWER_FOREACH_FULL(q, kk, ifi, fl, a) \ +#define _DNS_ANSWER_FOREACH_ITEM(q, item, a) \ for (size_t UNIQ_T(i, q) = ({ \ - (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \ - (ifi) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \ - (fl) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].flags : 0; \ + (item) = dns_answer_isempty(a) ? NULL : (a)->items; \ 0; \ }); \ - (a) && (UNIQ_T(i, q) < (a)->n_rrs); \ + UNIQ_T(i, q) < dns_answer_size(a); \ UNIQ_T(i, q)++, \ - (kk) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].rr : NULL), \ - (ifi) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].ifindex : 0), \ - (fl) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].flags : 0)) + (item) = ((UNIQ_T(i, q) < dns_answer_size(a)) ? (a)->items + UNIQ_T(i, q) : NULL)) -#define DNS_ANSWER_FOREACH_FULL(kk, ifindex, flags, a) _DNS_ANSWER_FOREACH_FULL(UNIQ, kk, ifindex, flags, a) +#define DNS_ANSWER_FOREACH_ITEM(item, a) _DNS_ANSWER_FOREACH_ITEM(UNIQ, item, a) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index 75f1ccb64..c019dc38c 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -22,6 +22,8 @@ * now) */ #define CACHE_TTL_STRANGE_RCODE_USEC (10 * USEC_PER_SEC) +#define CACHEABLE_QUERY_FLAGS (SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL) + typedef enum DnsCacheItemType DnsCacheItemType; typedef struct DnsCacheItem DnsCacheItem; @@ -34,13 +36,16 @@ enum DnsCacheItemType { struct DnsCacheItem { DnsCacheItemType type; - DnsResourceKey *key; - DnsResourceRecord *rr; + DnsResourceKey *key; /* The key for this item, i.e. the lookup key */ + DnsResourceRecord *rr; /* The RR for this item, i.e. the lookup value for positive queries */ + DnsAnswer *answer; /* The full validated answer, if this is an RRset acquired via a "primary" lookup */ + DnsPacket *full_packet; /* The full packet this information was acquired with */ int rcode; usec_t until; - bool authenticated:1; bool shared_owner:1; + uint64_t query_flags; /* SD_RESOLVED_AUTHENTICATED and/or SD_RESOLVED_CONFIDENTIAL */ + DnssecResult dnssec_result; int ifindex; int owner_family; @@ -50,6 +55,12 @@ struct DnsCacheItem { LIST_FIELDS(DnsCacheItem, by_key); }; +/* Returns true if this is a cache item created as result of an explicit lookup, or created as "side-effect" + * of another request. "Primary" entries will carry the full answer data (with NSEC, …) that can aso prove + * wildcard expansion, non-existance and such, while entries that were created as "side-effect" just contain + * immediate RR data for the specified RR key, but nothing else. */ +#define DNS_CACHE_ITEM_IS_PRIMARY(item) (!!(item)->answer) + static const char *dns_cache_item_type_to_string(DnsCacheItem *item) { assert(item); @@ -71,15 +82,16 @@ static const char *dns_cache_item_type_to_string(DnsCacheItem *item) { return NULL; } -static void dns_cache_item_free(DnsCacheItem *i) { +static DnsCacheItem* dns_cache_item_free(DnsCacheItem *i) { if (!i) - return; + return NULL; dns_resource_record_unref(i->rr); dns_resource_key_unref(i->key); - free(i); + dns_answer_unref(i->answer); + dns_packet_unref(i->full_packet); + return mfree(i); } - DEFINE_TRIVIAL_CLEANUP_FUNC(DnsCacheItem*, dns_cache_item_free); static void dns_cache_item_unlink_and_free(DnsCache *c, DnsCacheItem *i) { @@ -300,19 +312,23 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) { return NULL; } -static usec_t calculate_until(DnsResourceRecord *rr, uint32_t nsec_ttl, usec_t timestamp, bool use_soa_minimum) { +static usec_t calculate_until( + DnsResourceRecord *rr, + uint32_t min_ttl, + uint32_t nsec_ttl, + usec_t timestamp, + bool use_soa_minimum) { + uint32_t ttl; usec_t u; assert(rr); - ttl = MIN(rr->ttl, nsec_ttl); + ttl = MIN(min_ttl, nsec_ttl); if (rr->key->type == DNS_TYPE_SOA && use_soa_minimum) { - /* If this is a SOA RR, and it is requested, clamp to - * the SOA's minimum field. This is used when we do - * negative caching, to determine the TTL for the - * negative caching entry. See RFC 2308, Section - * 5. */ + /* If this is a SOA RR, and it is requested, clamp to the SOA's minimum field. This is used + * when we do negative caching, to determine the TTL for the negative caching entry. See RFC + * 2308, Section 5. */ if (ttl > rr->soa.minimum) ttl = rr->soa.minimum; @@ -325,8 +341,7 @@ static usec_t calculate_until(DnsResourceRecord *rr, uint32_t nsec_ttl, usec_t t if (rr->expiry != USEC_INFINITY) { usec_t left; - /* Make use of the DNSSEC RRSIG expiry info, if we - * have it */ + /* Make use of the DNSSEC RRSIG expiry info, if we have it */ left = LESS_BY(rr->expiry, now(CLOCK_REALTIME)); if (u > left) @@ -340,8 +355,12 @@ static void dns_cache_item_update_positive( DnsCache *c, DnsCacheItem *i, DnsResourceRecord *rr, - bool authenticated, + DnsAnswer *answer, + DnsPacket *full_packet, + uint32_t min_ttl, + uint64_t query_flags, bool shared_owner, + DnssecResult dnssec_result, usec_t timestamp, int ifindex, int owner_family, @@ -367,9 +386,18 @@ static void dns_cache_item_update_positive( dns_resource_key_unref(i->key); i->key = dns_resource_key_ref(rr->key); - i->until = calculate_until(rr, (uint32_t) -1, timestamp, false); - i->authenticated = authenticated; + dns_answer_ref(answer); + dns_answer_unref(i->answer); + i->answer = answer; + + dns_packet_ref(full_packet); + dns_packet_unref(i->full_packet); + i->full_packet = full_packet; + + i->until = calculate_until(rr, min_ttl, UINT32_MAX, timestamp, false); + i->query_flags = query_flags & CACHEABLE_QUERY_FLAGS; i->shared_owner = shared_owner; + i->dnssec_result = dnssec_result; i->ifindex = ifindex; @@ -382,17 +410,21 @@ static void dns_cache_item_update_positive( static int dns_cache_put_positive( DnsCache *c, DnsResourceRecord *rr, - bool authenticated, + DnsAnswer *answer, + DnsPacket *full_packet, + uint64_t query_flags, bool shared_owner, + DnssecResult dnssec_result, usec_t timestamp, int ifindex, int owner_family, const union in_addr_union *owner_address) { _cleanup_(dns_cache_item_freep) DnsCacheItem *i = NULL; - DnsCacheItem *existing; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; - int r, k; + DnsCacheItem *existing; + uint32_t min_ttl; + int r; assert(c); assert(rr); @@ -404,11 +436,16 @@ static int dns_cache_put_positive( if (dns_type_is_pseudo(rr->key->type)) return 0; + /* Determine the minimal TTL of all RRs in the answer plus the one by the main RR we are supposed to + * cache. Since we cache whole answers to questions we should never return answers where only some + * RRs are still valid, hence find the lowest here */ + min_ttl = MIN(dns_answer_min_ttl(answer), rr->ttl); + /* New TTL is 0? Delete this specific entry... */ - if (rr->ttl <= 0) { - k = dns_cache_remove_by_rr(c, rr); + if (min_ttl <= 0) { + r = dns_cache_remove_by_rr(c, rr); log_debug("%s: %s", - k > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry", + r > 0 ? "Removed zero TTL entry from cache" : "Not caching zero TTL cache entry", dns_resource_key_to_string(rr->key, key_str, sizeof key_str)); return 0; } @@ -420,8 +457,12 @@ static int dns_cache_put_positive( c, existing, rr, - authenticated, + answer, + full_packet, + min_ttl, + query_flags, shared_owner, + dnssec_result, timestamp, ifindex, owner_family, @@ -444,9 +485,12 @@ static int dns_cache_put_positive( .type = DNS_CACHE_POSITIVE, .key = dns_resource_key_ref(rr->key), .rr = dns_resource_record_ref(rr), - .until = calculate_until(rr, (uint32_t) -1, timestamp, false), - .authenticated = authenticated, + .answer = dns_answer_ref(answer), + .full_packet = dns_packet_ref(full_packet), + .until = calculate_until(rr, min_ttl, UINT32_MAX, timestamp, false), + .query_flags = query_flags & CACHEABLE_QUERY_FLAGS, .shared_owner = shared_owner, + .dnssec_result = dnssec_result, .ifindex = ifindex, .owner_family = owner_family, .owner_address = *owner_address, @@ -463,8 +507,9 @@ static int dns_cache_put_positive( (void) in_addr_to_string(i->owner_family, &i->owner_address, &t); - log_debug("Added positive %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s", - i->authenticated ? "authenticated" : "unauthenticated", + log_debug("Added positive %s %s%s cache entry for %s "USEC_FMT"s on %s/%s/%s", + FLAGS_SET(i->query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unauthenticated", + FLAGS_SET(i->query_flags, SD_RESOLVED_CONFIDENTIAL) ? "confidential" : "non-confidential", i->shared_owner ? " shared" : "", dns_resource_key_to_string(i->key, key_str, sizeof key_str), (i->until - timestamp) / USEC_PER_SEC, @@ -481,7 +526,10 @@ static int dns_cache_put_negative( DnsCache *c, DnsResourceKey *key, int rcode, - bool authenticated, + DnsAnswer *answer, + DnsPacket *full_packet, + uint64_t query_flags, + DnssecResult dnssec_result, uint32_t nsec_ttl, usec_t timestamp, DnsResourceRecord *soa, @@ -531,16 +579,22 @@ static int dns_cache_put_negative( .type = rcode == DNS_RCODE_SUCCESS ? DNS_CACHE_NODATA : rcode == DNS_RCODE_NXDOMAIN ? DNS_CACHE_NXDOMAIN : DNS_CACHE_RCODE, - .authenticated = authenticated, + .query_flags = query_flags & CACHEABLE_QUERY_FLAGS, + .dnssec_result = dnssec_result, .owner_family = owner_family, .owner_address = *owner_address, .prioq_idx = PRIOQ_IDX_NULL, .rcode = rcode, + .answer = dns_answer_ref(answer), + .full_packet = dns_packet_ref(full_packet), }; + /* Determine how long to cache this entry. In case we have some RRs in the answer use the lowest TTL + * of any of them. Typically that's the SOA's TTL, which is OK, but could possibly be lower because + * of some other RR. Let's better take the lowest option here than a needlessly high one */ i->until = i->type == DNS_CACHE_RCODE ? timestamp + CACHE_TTL_STRANGE_RCODE_USEC : - calculate_until(soa, nsec_ttl, timestamp, true); + calculate_until(soa, dns_answer_min_ttl(answer), nsec_ttl, timestamp, true); if (i->type == DNS_CACHE_NXDOMAIN) { /* NXDOMAIN entries should apply equally to all types, so we use ANY as @@ -630,17 +684,20 @@ int dns_cache_put( DnsResourceKey *key, int rcode, DnsAnswer *answer, - bool authenticated, + DnsPacket *full_packet, + uint64_t query_flags, + DnssecResult dnssec_result, uint32_t nsec_ttl, - usec_t timestamp, int owner_family, const union in_addr_union *owner_address) { - DnsResourceRecord *soa = NULL, *rr; + DnsResourceRecord *soa = NULL; bool weird_rcode = false; + DnsAnswerItem *item; DnsAnswerFlags flags; unsigned cache_keys; - int r, ifindex; + usec_t timestamp; + int r; assert(c); assert(owner_address); @@ -653,13 +710,14 @@ int dns_cache_put( * short time.) */ if (IN_SET(rcode, DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN)) { - if (dns_answer_size(answer) <= 0) { + if (dns_answer_isempty(answer)) { if (key) { char key_str[DNS_RESOURCE_KEY_STRING_MAX]; log_debug("Not caching negative entry without a SOA record: %s", dns_resource_key_to_string(key, key_str, sizeof key_str)); } + return 0; } @@ -679,23 +737,54 @@ int dns_cache_put( /* Make some space for our new entries */ dns_cache_make_space(c, cache_keys); - if (timestamp <= 0) - timestamp = now(clock_boottime_or_monotonic()); + timestamp = now(clock_boottime_or_monotonic()); /* Second, add in positive entries for all contained RRs */ - DNS_ANSWER_FOREACH_FULL(rr, ifindex, flags, answer) { - if ((flags & DNS_ANSWER_CACHEABLE) == 0 || - !rr_eligible(rr)) + DNS_ANSWER_FOREACH_ITEM(item, answer) { + int primary = false; + + if (!FLAGS_SET(item->flags, DNS_ANSWER_CACHEABLE) || + !rr_eligible(item->rr)) continue; + if (key) { + /* We store the auxiliary RRs and packet data in the cache only if they were in + * direct response to the original query. If we cache an RR we also received, and + * that is just auxiliary information we can't use the data, hence don't. */ + + primary = dns_resource_key_match_rr(key, item->rr, NULL); + if (primary < 0) + return primary; + if (primary == 0) { + primary = dns_resource_key_match_cname_or_dname(key, item->rr->key, NULL); + if (primary < 0) + return primary; + } + } + + if (!primary) { + DnsCacheItem *first; + + /* Do not replace existing cache items for primary lookups with non-primary + * data. After all the primary lookup data is a lot more useful. */ + first = hashmap_get(c->by_key, item->rr->key); + if (first && DNS_CACHE_ITEM_IS_PRIMARY(first)) + return 0; + } + r = dns_cache_put_positive( c, - rr, - flags & DNS_ANSWER_AUTHENTICATED, - flags & DNS_ANSWER_SHARED_OWNER, + item->rr, + primary ? answer : NULL, + primary ? full_packet : NULL, + ((item->flags & DNS_ANSWER_AUTHENTICATED) ? SD_RESOLVED_AUTHENTICATED : 0) | + (query_flags & SD_RESOLVED_CONFIDENTIAL), + item->flags & DNS_ANSWER_SHARED_OWNER, + dnssec_result, timestamp, - ifindex, - owner_family, owner_address); + item->ifindex, + owner_family, + owner_address); if (r < 0) goto fail; } @@ -710,9 +799,8 @@ int dns_cache_put( if (r > 0) return 0; - /* But not if it has a matching CNAME/DNAME (the negative - * caching will be done on the canonical name, not on the - * alias) */ + /* But not if it has a matching CNAME/DNAME (the negative caching will be done on the canonical name, + * not on the alias) */ r = dns_answer_find_cname_or_dname(answer, key, NULL, NULL); if (r < 0) goto fail; @@ -728,16 +816,16 @@ int dns_cache_put( if (r == 0 && !weird_rcode) return 0; if (r > 0) { - /* Refuse using the SOA data if it is unsigned, but the key is - * signed */ - if (authenticated && (flags & DNS_ANSWER_AUTHENTICATED) == 0) + /* Refuse using the SOA data if it is unsigned, but the key is signed */ + if (FLAGS_SET(query_flags, SD_RESOLVED_AUTHENTICATED) && + (flags & DNS_ANSWER_AUTHENTICATED) == 0) return 0; } if (cache_mode == DNS_CACHE_MODE_NO_NEGATIVE) { char key_str[DNS_RESOURCE_KEY_STRING_MAX]; log_debug("Not caching negative entry for: %s, cache mode set to no-negative", - dns_resource_key_to_string(key, key_str, sizeof key_str)); + dns_resource_key_to_string(key, key_str, sizeof key_str)); return 0; } @@ -745,7 +833,10 @@ int dns_cache_put( c, key, rcode, - authenticated, + answer, + full_packet, + query_flags, + dnssec_result, nsec_ttl, timestamp, soa, @@ -762,11 +853,11 @@ fail: if (key) dns_cache_remove_by_key(c, key); - DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { - if ((flags & DNS_ANSWER_CACHEABLE) == 0) + DNS_ANSWER_FOREACH_ITEM(item, answer) { + if ((item->flags & DNS_ANSWER_CACHEABLE) == 0) continue; - dns_cache_remove_by_key(c, rr->key); + dns_cache_remove_by_key(c, item->rr->key); } return r; @@ -827,37 +918,90 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, D return NULL; } -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcode, DnsAnswer **ret, bool *authenticated) { +static int answer_add_clamp_ttl( + DnsAnswer **answer, + DnsResourceRecord *rr, + int ifindex, + DnsAnswerFlags answer_flags, + DnsResourceRecord *rrsig, + uint64_t query_flags, + usec_t until, + usec_t current) { + + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *patched = NULL, *patched_rrsig = NULL; + int r; + + assert(answer); + assert(rr); + + if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) { + uint32_t left_ttl; + + /* Let's determine how much time is left for this cache entry. Note that we round down, but + * clamp this to be 1s at minimum, since we usually want records to remain cached better too + * short a time than too long a time, but otoh don't want to return 0 ever, since that has + * special semantics in various contexts — in particular in mDNS */ + + left_ttl = MAX(1U, LESS_BY(until, current) / USEC_PER_SEC); + + patched = dns_resource_record_ref(rr); + + r = dns_resource_record_clamp_ttl(&patched, left_ttl); + if (r < 0) + return r; + + rr = patched; + + if (rrsig) { + patched_rrsig = dns_resource_record_ref(rrsig); + r = dns_resource_record_clamp_ttl(&patched_rrsig, left_ttl); + if (r < 0) + return r; + + rrsig = patched_rrsig; + } + } + + r = dns_answer_add_extend(answer, rr, ifindex, answer_flags, rrsig); + if (r < 0) + return r; + + return 0; +} + +int dns_cache_lookup( + DnsCache *c, + DnsResourceKey *key, + uint64_t query_flags, + int *ret_rcode, + DnsAnswer **ret_answer, + DnsPacket **ret_full_packet, + uint64_t *ret_query_flags, + DnssecResult *ret_dnssec_result) { + + _cleanup_(dns_packet_unrefp) DnsPacket *full_packet = NULL; _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; unsigned n = 0; int r; bool nxdomain = false; DnsCacheItem *j, *first, *nsec = NULL; - bool have_authenticated = false, have_non_authenticated = false; + bool have_authenticated = false, have_non_authenticated = false, have_confidential = false, have_non_confidential = false; usec_t current; int found_rcode = -1; + DnssecResult dnssec_result = -1; + int have_dnssec_result = -1; assert(c); assert(key); - assert(rcode); - assert(ret); - assert(authenticated); if (key->type == DNS_TYPE_ANY || key->class == DNS_CLASS_ANY) { - /* If we have ANY lookups we don't use the cache, so - * that the caller refreshes via the network. */ + /* If we have ANY lookups we don't use the cache, so that the caller refreshes via the + * network. */ log_debug("Ignoring cache for ANY lookup: %s", dns_resource_key_to_string(key, key_str, sizeof key_str)); - - c->n_miss++; - - *ret = NULL; - *rcode = DNS_RCODE_SUCCESS; - *authenticated = false; - - return 0; + goto miss; } first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key); @@ -866,31 +1010,101 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod log_debug("Cache miss for %s", dns_resource_key_to_string(key, key_str, sizeof key_str)); - - c->n_miss++; - - *ret = NULL; - *rcode = DNS_RCODE_SUCCESS; - *authenticated = false; - - return 0; + goto miss; } + if (FLAGS_SET(query_flags, SD_RESOLVED_CLAMP_TTL)) + current = now(clock_boottime_or_monotonic()); + LIST_FOREACH(by_key, j, first) { - if (j->rr) { + /* If the caller doesn't allow us to answer questions from cache data learned from + * "side-effect", skip this entry. */ + if (FLAGS_SET(query_flags, SD_RESOLVED_REQUIRE_PRIMARY) && + !DNS_CACHE_ITEM_IS_PRIMARY(j)) { + log_debug("Primary answer was requested for cache lookup for %s, which we don't have.", + dns_resource_key_to_string(key, key_str, sizeof key_str)); + + goto miss; + } + + if (j->type == DNS_CACHE_NXDOMAIN) + nxdomain = true; + else if (j->type == DNS_CACHE_RCODE) + found_rcode = j->rcode; + else if (j->rr) { if (j->rr->key->type == DNS_TYPE_NSEC) nsec = j; n++; - } else if (j->type == DNS_CACHE_NXDOMAIN) - nxdomain = true; - else if (j->type == DNS_CACHE_RCODE) - found_rcode = j->rcode; + } - if (j->authenticated) + if (FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED)) have_authenticated = true; else have_non_authenticated = true; + + if (FLAGS_SET(j->query_flags, SD_RESOLVED_CONFIDENTIAL)) + have_confidential = true; + else + have_non_confidential = true; + + if (j->dnssec_result < 0) { + have_dnssec_result = false; /* an entry without dnssec result? then invalidate things for good */ + dnssec_result = _DNSSEC_RESULT_INVALID; + } else if (have_dnssec_result < 0) { + have_dnssec_result = true; /* So far no result seen, let's pick this one up */ + dnssec_result = j->dnssec_result; + } else if (have_dnssec_result > 0 && j->dnssec_result != dnssec_result) { + have_dnssec_result = false; /* conflicting result seen? then invalidate for good */ + dnssec_result = _DNSSEC_RESULT_INVALID; + } + + /* Append the answer RRs to our answer. Ideally we have the answer object, which we + * preferably use. But if the cached entry was generated as "side-effect" of a reply, + * i.e. from validated auxiliary records rather than from the main reply, then we use the + * individual RRs only instead. */ + if (j->answer) { + + /* Minor optimization, if the full answer object of this and the previous RR is the + * same, don't bother adding it again. Typically we store a full RRset here, hence + * that should be the case. */ + if (!j->by_key_prev || j->answer != j->by_key_prev->answer) { + DnsAnswerItem *item; + + DNS_ANSWER_FOREACH_ITEM(item, j->answer) { + r = answer_add_clamp_ttl( + &answer, + item->rr, + item->ifindex, + item->flags, + item->rrsig, + query_flags, + j->until, + current); + if (r < 0) + return r; + } + } + + } else if (j->rr) { + r = answer_add_clamp_ttl( + &answer, + j->rr, + j->ifindex, + FLAGS_SET(j->query_flags, SD_RESOLVED_AUTHENTICATED) ? DNS_ANSWER_AUTHENTICATED : 0, + NULL, + query_flags, + j->until, + current); + if (r < 0) + return r; + } + + /* We'll return any packet we have for this. Typically all cache entries for the same key + * should come from the same packet anyway, hence it doesn't really matter which packet we + * return here, they should all resolve to the same anyway. */ + if (!full_packet && j->full_packet) + full_packet = dns_packet_ref(j->full_packet); } if (found_rcode >= 0) { @@ -898,28 +1112,41 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod dns_rcode_to_string(found_rcode), dns_resource_key_to_string(key, key_str, sizeof(key_str))); - *ret = NULL; - *rcode = found_rcode; - *authenticated = false; + if (ret_rcode) + *ret_rcode = found_rcode; + if (ret_answer) + *ret_answer = TAKE_PTR(answer); + if (ret_full_packet) + *ret_full_packet = TAKE_PTR(full_packet); + if (ret_query_flags) + *ret_query_flags = 0; + if (ret_dnssec_result) + *ret_dnssec_result = dnssec_result; c->n_hit++; return 1; } if (nsec && !IN_SET(key->type, DNS_TYPE_NSEC, DNS_TYPE_DS)) { - /* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC RRs from - * the lower-zone of a zone cut, but the DS RRs are on the upper zone. */ + /* Note that we won't derive information for DS RRs from an NSEC, because we only cache NSEC + * RRs from the lower-zone of a zone cut, but the DS RRs are on the upper zone. */ log_debug("NSEC NODATA cache hit for %s", dns_resource_key_to_string(key, key_str, sizeof key_str)); - /* We only found an NSEC record that matches our name. - * If it says the type doesn't exist report - * NODATA. Otherwise report a cache miss. */ + /* We only found an NSEC record that matches our name. If it says the type doesn't exist + * report NODATA. Otherwise report a cache miss. */ - *ret = NULL; - *rcode = DNS_RCODE_SUCCESS; - *authenticated = nsec->authenticated; + if (ret_rcode) + *ret_rcode = DNS_RCODE_SUCCESS; + if (ret_answer) + *ret_answer = TAKE_PTR(answer); + if (ret_full_packet) + *ret_full_packet = TAKE_PTR(full_packet); + if (ret_query_flags) + *ret_query_flags = nsec->query_flags; + if (ret_dnssec_result) + *ret_dnssec_result = nsec->dnssec_result; if (!bitmap_isset(nsec->rr->nsec.types, key->type) && !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) && @@ -940,46 +1167,53 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcod if (n <= 0) { c->n_hit++; - *ret = NULL; - *rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS; - *authenticated = have_authenticated && !have_non_authenticated; + if (ret_rcode) + *ret_rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS; + if (ret_answer) + *ret_answer = TAKE_PTR(answer); + if (ret_full_packet) + *ret_full_packet = TAKE_PTR(full_packet); + if (ret_query_flags) + *ret_query_flags = + ((have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0) | + ((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0); + if (ret_dnssec_result) + *ret_dnssec_result = dnssec_result; + return 1; } - answer = dns_answer_new(n); - if (!answer) - return -ENOMEM; - - if (clamp_ttl) - current = now(clock_boottime_or_monotonic()); - - LIST_FOREACH(by_key, j, first) { - _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; - - if (!j->rr) - continue; - - if (clamp_ttl) { - rr = dns_resource_record_ref(j->rr); - - r = dns_resource_record_clamp_ttl(&rr, LESS_BY(j->until, current) / USEC_PER_SEC); - if (r < 0) - return r; - } - - r = dns_answer_add(answer, rr ?: j->rr, j->ifindex, j->authenticated ? DNS_ANSWER_AUTHENTICATED : 0); - if (r < 0) - return r; - } - c->n_hit++; - *ret = answer; - *rcode = DNS_RCODE_SUCCESS; - *authenticated = have_authenticated && !have_non_authenticated; - answer = NULL; + if (ret_rcode) + *ret_rcode = DNS_RCODE_SUCCESS; + if (ret_answer) + *ret_answer = TAKE_PTR(answer); + if (ret_full_packet) + *ret_full_packet = TAKE_PTR(full_packet); + if (ret_query_flags) + *ret_query_flags = + ((have_authenticated && !have_non_authenticated) ? SD_RESOLVED_AUTHENTICATED : 0) | + ((have_confidential && !have_non_confidential) ? SD_RESOLVED_CONFIDENTIAL : 0); + if (ret_dnssec_result) + *ret_dnssec_result = dnssec_result; return n; + +miss: + if (ret_rcode) + *ret_rcode = DNS_RCODE_SUCCESS; + if (ret_answer) + *ret_answer = NULL; + if (ret_full_packet) + *ret_full_packet = NULL; + if (ret_query_flags) + *ret_query_flags = 0; + if (ret_dnssec_result) + *ret_dnssec_result = _DNSSEC_RESULT_INVALID; + + c->n_miss++; + return 0; } int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address) { diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 4ab213dc9..621b52f89 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -5,6 +5,7 @@ #include "list.h" #include "prioq.h" #include "resolve-util.h" +#include "resolved-dns-dnssec.h" #include "time-util.h" typedef struct DnsCache { @@ -22,8 +23,28 @@ typedef struct DnsCache { void dns_cache_flush(DnsCache *c); void dns_cache_prune(DnsCache *c); -int dns_cache_put(DnsCache *c, DnsCacheMode cache_mode, DnsResourceKey *key, int rcode, DnsAnswer *answer, bool authenticated, uint32_t nsec_ttl, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, bool clamp_ttl, int *rcode, DnsAnswer **answer, bool *authenticated); +int dns_cache_put( + DnsCache *c, + DnsCacheMode cache_mode, + DnsResourceKey *key, + int rcode, + DnsAnswer *answer, + DnsPacket *full_packet, + uint64_t query_flags, + DnssecResult dnssec_result, + uint32_t nsec_ttl, + int owner_family, + const union in_addr_union *owner_address); + +int dns_cache_lookup( + DnsCache *c, + DnsResourceKey *key, + uint64_t query_flags, + int *ret_rcode, + DnsAnswer **ret_answer, + DnsPacket **ret_full_packet, + uint64_t *ret_query_flags, + DnssecResult *ret_dnssec_result); int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address); diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 2f5776b5e..4b12e4835 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -490,7 +490,7 @@ static int dnssec_rrsig_prepare(DnsResourceRecord *rrsig) { assert(rrsig->key->type == DNS_TYPE_RRSIG); /* Check if this RRSIG RR is already prepared */ - if (rrsig->n_skip_labels_source != (unsigned) -1) + if (rrsig->n_skip_labels_source != UINT_MAX) return 0; if (rrsig->rrsig.inception > rrsig->rrsig.expiration) @@ -1297,10 +1297,10 @@ static int nsec3_is_good(DnsResourceRecord *rr, DnsResourceRecord *nsec3) { /* Ignore NSEC3 RRs generated from wildcards. If these NSEC3 RRs weren't correctly signed we can't make this * check (since rr->n_skip_labels_source is -1), but that's OK, as we won't trust them anyway in that case. */ - if (!IN_SET(rr->n_skip_labels_source, 0, (unsigned) -1)) + if (!IN_SET(rr->n_skip_labels_source, 0, UINT_MAX)) return 0; /* Ignore NSEC3 RRs that are located anywhere else than one label below the zone */ - if (!IN_SET(rr->n_skip_labels_signer, 1, (unsigned) -1)) + if (!IN_SET(rr->n_skip_labels_signer, 1, UINT_MAX)) return 0; if (!nsec3) diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h index 9c3c0dcfc..954bb3ef9 100644 --- a/src/resolve/resolved-dns-dnssec.h +++ b/src/resolve/resolved-dns-dnssec.h @@ -27,7 +27,7 @@ enum DnssecResult { DNSSEC_INCOMPATIBLE_SERVER, _DNSSEC_RESULT_MAX, - _DNSSEC_RESULT_INVALID = -1 + _DNSSEC_RESULT_INVALID = -EINVAL, }; enum DnssecVerdict { @@ -37,7 +37,7 @@ enum DnssecVerdict { DNSSEC_INDETERMINATE, _DNSSEC_VERDICT_MAX, - _DNSSEC_VERDICT_INVALID = -1 + _DNSSEC_VERDICT_INVALID = -EINVAL, }; #define DNSSEC_CANONICAL_HOSTNAME_MAX (DNS_HOSTNAME_MAX + 2) diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index b4eb5efae..8de407d21 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -82,8 +82,8 @@ int dns_packet_new( .rindex = DNS_PACKET_HEADER_SIZE, .allocated = a, .max_size = max_size, - .opt_start = (size_t) -1, - .opt_size = (size_t) -1, + .opt_start = SIZE_MAX, + .opt_size = SIZE_MAX, }; *ret = p; @@ -160,6 +160,38 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t min_alloc return 0; } +int dns_packet_dup(DnsPacket **ret, DnsPacket *p) { + DnsPacket *c; + int r; + + assert(ret); + assert(p); + + r = dns_packet_validate(p); + if (r < 0) + return r; + + c = malloc(ALIGN(sizeof(DnsPacket)) + p->size); + if (!c) + return -ENOMEM; + + *c = (DnsPacket) { + .n_ref = 1, + .protocol = p->protocol, + .size = p->size, + .rindex = DNS_PACKET_HEADER_SIZE, + .allocated = p->size, + .max_size = p->max_size, + .opt_start = SIZE_MAX, + .opt_size = SIZE_MAX, + }; + + memcpy(DNS_PACKET_DATA(c), DNS_PACKET_DATA(p), p->size); + + *ret = c; + return 0; +} + DnsPacket *dns_packet_ref(DnsPacket *p) { if (!p) @@ -294,13 +326,10 @@ int dns_packet_validate_query(DnsPacket *p) { break; case DNS_PROTOCOL_MDNS: - /* RFC 6762, Section 18 */ - if (DNS_PACKET_AA(p) != 0 || - DNS_PACKET_RD(p) != 0 || - DNS_PACKET_RA(p) != 0 || - DNS_PACKET_AD(p) != 0 || - DNS_PACKET_CD(p) != 0 || - DNS_PACKET_RCODE(p) != 0) + /* RFC 6762, Section 18 specifies that messages with non-zero RCODE + * must be silently ignored, and that we must ignore the values of + * AA, RD, RA, AD, and CD bits. */ + if (DNS_PACKET_RCODE(p) != 0) return -EBADMSG; break; @@ -557,15 +586,11 @@ int dns_packet_append_name( goto fail; } - r = hashmap_ensure_allocated(&p->names, &dns_name_hash_ops); + r = hashmap_ensure_put(&p->names, &dns_name_hash_ops, s, SIZE_TO_PTR(n)); if (r < 0) goto fail; - r = hashmap_put(p->names, s, SIZE_TO_PTR(n)); - if (r < 0) - goto fail; - - s = NULL; + TAKE_PTR(s); } } @@ -698,8 +723,9 @@ int dns_packet_append_opt( uint16_t max_udp_size, bool edns0_do, bool include_rfc6975, + const char *nsid, int rcode, - size_t *start) { + size_t *ret_start) { size_t saved_size; int r; @@ -710,10 +736,10 @@ int dns_packet_append_opt( assert(rcode >= 0); assert(rcode <= _DNS_RCODE_MAX); - if (p->opt_start != (size_t) -1) + if (p->opt_start != SIZE_MAX) return -EBUSY; - assert(p->opt_size == (size_t) -1); + assert(p->opt_size == SIZE_MAX); saved_size = p->size; @@ -742,7 +768,6 @@ int dns_packet_append_opt( if (r < 0) goto fail; - /* RDLENGTH */ if (edns0_do && include_rfc6975) { /* If DO is on and this is requested, also append RFC6975 Algorithm data. This is supposed to * be done on queries, not on replies, hencer callers should turn this off when finishing off @@ -777,11 +802,32 @@ int dns_packet_append_opt( NSEC3_ALGORITHM_SHA1, }; - r = dns_packet_append_uint16(p, sizeof(rfc6975), NULL); + r = dns_packet_append_uint16(p, sizeof(rfc6975), NULL); /* RDLENGTH */ if (r < 0) goto fail; - r = dns_packet_append_blob(p, rfc6975, sizeof(rfc6975), NULL); + r = dns_packet_append_blob(p, rfc6975, sizeof(rfc6975), NULL); /* the payload, as defined above */ + + } else if (nsid) { + + if (strlen(nsid) > UINT16_MAX - 4) { + r = -E2BIG; + goto fail; + } + + r = dns_packet_append_uint16(p, 4 + strlen(nsid), NULL); /* RDLENGTH */ + if (r < 0) + goto fail; + + r = dns_packet_append_uint16(p, 3, NULL); /* OPTION-CODE: NSID */ + if (r < 0) + goto fail; + + r = dns_packet_append_uint16(p, strlen(nsid), NULL); /* OPTION-LENGTH */ + if (r < 0) + goto fail; + + r = dns_packet_append_blob(p, nsid, strlen(nsid), NULL); } else r = dns_packet_append_uint16(p, 0, NULL); if (r < 0) @@ -792,8 +838,8 @@ int dns_packet_append_opt( p->opt_start = saved_size; p->opt_size = p->size - saved_size; - if (start) - *start = saved_size; + if (ret_start) + *ret_start = saved_size; return 0; @@ -805,12 +851,12 @@ fail: int dns_packet_truncate_opt(DnsPacket *p) { assert(p); - if (p->opt_start == (size_t) -1) { - assert(p->opt_size == (size_t) -1); + if (p->opt_start == SIZE_MAX) { + assert(p->opt_size == SIZE_MAX); return 0; } - assert(p->opt_size != (size_t) -1); + assert(p->opt_size != SIZE_MAX); assert(DNS_PACKET_ARCOUNT(p) > 0); if (p->opt_start + p->opt_size != p->size) @@ -818,7 +864,7 @@ int dns_packet_truncate_opt(DnsPacket *p) { dns_packet_truncate(p, p->opt_start); DNS_PACKET_HEADER(p)->arcount = htobe16(DNS_PACKET_ARCOUNT(p) - 1); - p->opt_start = p->opt_size = (size_t) -1; + p->opt_start = p->opt_size = SIZE_MAX; return 1; } @@ -1187,7 +1233,7 @@ int dns_packet_append_question(DnsPacket *p, DnsQuestion *q) { return 0; } -int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) { +int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a, unsigned *completed) { DnsResourceRecord *rr; DnsAnswerFlags flags; int r; @@ -1198,6 +1244,9 @@ int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a) { r = dns_packet_append_rr(p, rr, flags, NULL, NULL); if (r < 0) return r; + + if (completed) + (*completed)++; } return 0; @@ -1302,7 +1351,8 @@ int dns_packet_read_uint16(DnsPacket *p, uint16_t *ret, size_t *start) { if (r < 0) return r; - *ret = unaligned_read_be16(d); + if (ret) + *ret = unaligned_read_be16(d); return 0; } @@ -1388,19 +1438,19 @@ int dns_packet_read_raw_string(DnsPacket *p, const void **ret, size_t *size, siz int dns_packet_read_name( DnsPacket *p, - char **_ret, + char **ret, bool allow_compression, - size_t *start) { + size_t *ret_start) { _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; size_t after_rindex = 0, jump_barrier; - _cleanup_free_ char *ret = NULL; + _cleanup_free_ char *name = NULL; size_t n = 0, allocated = 0; bool first = true; int r; assert(p); - assert(_ret); + INIT_REWINDER(rewinder, p); jump_barrier = p->rindex; @@ -1425,15 +1475,15 @@ int dns_packet_read_name( if (r < 0) return r; - if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) + if (!GREEDY_REALLOC(name, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) return -ENOMEM; if (first) first = false; else - ret[n++] = '.'; + name[n++] = '.'; - r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX); if (r < 0) return r; @@ -1461,18 +1511,19 @@ int dns_packet_read_name( return -EBADMSG; } - if (!GREEDY_REALLOC(ret, allocated, n + 1)) + if (!GREEDY_REALLOC(name, allocated, n + 1)) return -ENOMEM; - ret[n] = 0; + name[n] = 0; if (after_rindex != 0) p->rindex= after_rindex; - *_ret = TAKE_PTR(ret); + if (ret) + *ret = TAKE_PTR(name); + if (ret_start) + *ret_start = rewinder.saved_rindex; - if (start) - *start = rewinder.saved_rindex; CANCEL_REWINDER(rewinder); return 0; @@ -1574,16 +1625,19 @@ static int dns_packet_read_type_windows(DnsPacket *p, Bitmap **types, size_t siz return 0; } -int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flush, size_t *start) { +int dns_packet_read_key( + DnsPacket *p, + DnsResourceKey **ret, + bool *ret_cache_flush, + size_t *ret_start) { + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; _cleanup_free_ char *name = NULL; bool cache_flush = false; uint16_t class, type; - DnsResourceKey *key; int r; assert(p); - assert(ret); INIT_REWINDER(rewinder, p); r = dns_packet_read_name(p, &name, true, NULL); @@ -1607,19 +1661,23 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, bool *ret_cache_flus } } - key = dns_resource_key_new_consume(class, type, name); - if (!key) - return -ENOMEM; + if (ret) { + DnsResourceKey *key; - name = NULL; - *ret = key; + key = dns_resource_key_new_consume(class, type, name); + if (!key) + return -ENOMEM; + + TAKE_PTR(name); + *ret = key; + } if (ret_cache_flush) *ret_cache_flush = cache_flush; - if (start) - *start = rewinder.saved_rindex; - CANCEL_REWINDER(rewinder); + if (ret_start) + *ret_start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; } @@ -1629,7 +1687,12 @@ static bool loc_size_ok(uint8_t size) { return m <= 9 && e <= 9 && (m > 0 || e == 0); } -int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_flush, size_t *start) { +int dns_packet_read_rr( + DnsPacket *p, + DnsResourceRecord **ret, + bool *ret_cache_flush, + size_t *ret_start) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; @@ -1639,7 +1702,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl int r; assert(p); - assert(ret); INIT_REWINDER(rewinder, p); @@ -2080,14 +2142,14 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, bool *ret_cache_fl if (p->rindex != offset + rdlength) return -EBADMSG; - *ret = TAKE_PTR(rr); - + if (ret) + *ret = TAKE_PTR(rr); if (ret_cache_flush) *ret_cache_flush = cache_flush; - if (start) - *start = rewinder.saved_rindex; - CANCEL_REWINDER(rewinder); + if (ret_start) + *ret_start = rewinder.saved_rindex; + CANCEL_REWINDER(rewinder); return 0; } @@ -2153,7 +2215,7 @@ static int dns_packet_extract_question(DnsPacket *p, DnsQuestion **ret_question) return log_oom(); r = set_reserve(keys, n * 2); /* Higher multipliers give slightly higher efficiency through - * hash collisions, but the gains quickly drop of after 2. */ + * hash collisions, but the gains quickly drop off after 2. */ if (r < 0) return r; @@ -2207,8 +2269,21 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) { for (i = 0; i < n; i++) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; bool cache_flush = false; + size_t start; - r = dns_packet_read_rr(p, &rr, &cache_flush, NULL); + if (p->rindex == p->size && p->opt) { + /* If we reached the end of the packet already, but there are still more RRs + * declared, then that's a corrupt packet. Let's accept the packet anyway, since it's + * apparently a common bug in routers. Let's however suppress OPT support in this + * case, so that we force the rest of the logic into lowest DNS baseline support. Or + * to say this differently: if the DNS server doesn't even get the RR counts right, + * it's highly unlikely it gets EDNS right. */ + log_debug("More resource records declared in packet than included, suppressing OPT."); + bad_opt = true; + break; + } + + r = dns_packet_read_rr(p, &rr, &cache_flush, &start); if (r < 0) return r; @@ -2276,28 +2351,41 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) { } p->opt = dns_resource_record_ref(rr); + p->opt_start = start; + assert(p->rindex >= start); + p->opt_size = p->rindex - start; } else { - /* According to RFC 4795, section 2.9. only the RRs from the Answer section - * shall be cached. Hence mark only those RRs as cacheable by default, but - * not the ones from the Additional or Authority sections. */ - DnsAnswerFlags flags = - (i < DNS_PACKET_ANCOUNT(p) ? DNS_ANSWER_CACHEABLE : 0) | - (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush ? DNS_ANSWER_SHARED_OWNER : 0); + DnsAnswerFlags flags = 0; - r = dns_answer_add(answer, rr, p->ifindex, flags); + if (p->protocol == DNS_PROTOCOL_MDNS && !cache_flush) + flags |= DNS_ANSWER_SHARED_OWNER; + + /* According to RFC 4795, section 2.9. only the RRs from the Answer section shall be + * cached. Hence mark only those RRs as cacheable by default, but not the ones from + * the Additional or Authority sections. */ + if (i < DNS_PACKET_ANCOUNT(p)) + flags |= DNS_ANSWER_CACHEABLE|DNS_ANSWER_SECTION_ANSWER; + else if (i < DNS_PACKET_ANCOUNT(p) + DNS_PACKET_NSCOUNT(p)) + flags |= DNS_ANSWER_SECTION_AUTHORITY; + else + flags |= DNS_ANSWER_SECTION_ADDITIONAL; + + r = dns_answer_add(answer, rr, p->ifindex, flags, NULL); if (r < 0) return r; } - /* Remember this RR, so that we potentically can merge it's ->key object with the + /* Remember this RR, so that we can potentially merge its ->key object with the * next RR. Note that we only do this if we actually decided to keep the RR around. */ dns_resource_record_unref(previous); previous = dns_resource_record_ref(rr); } - if (bad_opt) + if (bad_opt) { p->opt = dns_resource_record_unref(p->opt); + p->opt_start = p->opt_size = SIZE_MAX; + } *ret_answer = TAKE_PTR(answer); @@ -2324,6 +2412,12 @@ int dns_packet_extract(DnsPacket *p) { if (r < 0) return r; + if (p->rindex < p->size) { + log_debug("Trailing garbage in packet, suppressing OPT."); + p->opt = dns_resource_record_unref(p->opt); + p->opt_start = p->opt_size = SIZE_MAX; + } + p->question = TAKE_PTR(question); p->answer = TAKE_PTR(answer); @@ -2360,6 +2454,106 @@ int dns_packet_is_reply_for(DnsPacket *p, const DnsResourceKey *key) { return dns_resource_key_equal(p->question->keys[0], key); } +int dns_packet_patch_max_udp_size(DnsPacket *p, uint16_t max_udp_size) { + assert(p); + assert(max_udp_size >= DNS_PACKET_UNICAST_SIZE_MAX); + + if (p->opt_start == SIZE_MAX) /* No OPT section, nothing to patch */ + return 0; + + assert(p->opt_size != SIZE_MAX); + assert(p->opt_size >= 5); + + unaligned_write_be16(DNS_PACKET_DATA(p) + p->opt_start + 3, max_udp_size); + return 1; +} + +static int patch_rr(DnsPacket *p, usec_t age) { + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder; + size_t ttl_index; + uint32_t ttl; + uint16_t type, rdlength; + int r; + + INIT_REWINDER(rewinder, p); + + /* Patches the RR at the current rindex, subtracts the specified time from the TTL */ + + r = dns_packet_read_name(p, NULL, true, NULL); + if (r < 0) + return r; + + r = dns_packet_read_uint16(p, &type, NULL); + if (r < 0) + return r; + + r = dns_packet_read_uint16(p, NULL, NULL); + if (r < 0) + return r; + + r = dns_packet_read_uint32(p, &ttl, &ttl_index); + if (r < 0) + return r; + + if (type != DNS_TYPE_OPT) { /* The TTL of the OPT field is not actually a TTL, skip it */ + ttl = LESS_BY(ttl * USEC_PER_SEC, age) / USEC_PER_SEC; + unaligned_write_be32(DNS_PACKET_DATA(p) + ttl_index, ttl); + } + + r = dns_packet_read_uint16(p, &rdlength, NULL); + if (r < 0) + return r; + + r = dns_packet_read(p, rdlength, NULL, NULL); + if (r < 0) + return r; + + CANCEL_REWINDER(rewinder); + return 0; +} + +int dns_packet_patch_ttls(DnsPacket *p, usec_t timestamp) { + _cleanup_(rewind_dns_packet) DnsPacketRewinder rewinder = {}; + unsigned i, n; + usec_t k; + int r; + + assert(p); + assert(timestamp_is_set(timestamp)); + + /* Adjusts all TTLs in the packet by subtracting the time difference between now and the specified timestamp */ + + k = now(clock_boottime_or_monotonic()); + assert(k >= timestamp); + k -= timestamp; + + INIT_REWINDER(rewinder, p); + + dns_packet_rewind(p, DNS_PACKET_HEADER_SIZE); + + n = DNS_PACKET_QDCOUNT(p); + for (i = 0; i < n; i++) { + r = dns_packet_read_key(p, NULL, NULL, NULL); + if (r < 0) + return r; + } + + n = DNS_PACKET_RRCOUNT(p); + for (i = 0; i < n; i++) { + + /* DNS servers suck, hence the RR count is in many servers off. If we reached the end + * prematurely, accept that, exit early */ + if (p->rindex == p->size) + break; + + r = patch_rr(p, k); + if (r < 0) + return r; + } + + return 0; +} + static void dns_packet_hash_func(const DnsPacket *s, struct siphash *state) { assert(s); @@ -2379,6 +2573,70 @@ static int dns_packet_compare_func(const DnsPacket *x, const DnsPacket *y) { DEFINE_HASH_OPS(dns_packet_hash_ops, DnsPacket, dns_packet_hash_func, dns_packet_compare_func); +bool dns_packet_equal(const DnsPacket *a, const DnsPacket *b) { + return dns_packet_compare_func(a, b) == 0; +} + +int dns_packet_has_nsid_request(DnsPacket *p) { + bool has_nsid = false; + const uint8_t *d; + size_t l; + + assert(p); + + if (!p->opt) + return false; + + d = p->opt->opt.data; + l = p->opt->opt.data_size; + + while (l > 0) { + uint16_t code, length; + + if (l < 4U) + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), + "EDNS0 variable part has invalid size."); + + code = unaligned_read_be16(d); + length = unaligned_read_be16(d + 2); + + if (l < 4U + length) + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), + "Truncated option in EDNS0 variable part."); + + if (code == 3) { + if (has_nsid) + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), + "Duplicate NSID option in EDNS0 variable part."); + + if (length != 0) + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), + "Non-empty NSID option in DNS request."); + + has_nsid = true; + } + + d += 4U + length; + l -= 4U + length; + } + + return has_nsid; +} + +size_t dns_packet_size_unfragmented(DnsPacket *p) { + assert(p); + + if (p->fragsize == 0) /* Wasn't fragmented */ + return p->size; + + /* The fragment size (p->fragsize) covers the whole (fragmented) IP packet, while the regular packet + * size (p->size) only covers the DNS part. Thus, subtract the UDP header from the largest fragment + * size, in order to determine which size of DNS packet would have gone through without + * fragmenting. */ + + return LESS_BY(p->fragsize, udp_header_size(p->family)); +} + static const char* const dns_rcode_table[_DNS_RCODE_MAX_DEFINED] = { [DNS_RCODE_SUCCESS] = "SUCCESS", [DNS_RCODE_FORMERR] = "FORMERR", diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 7d6ee2bc4..7b2abe3e7 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -2,6 +2,7 @@ #pragma once #include +#include #include #include "hashmap.h" @@ -22,7 +23,7 @@ typedef enum DnsProtocol { DNS_PROTOCOL_MDNS, DNS_PROTOCOL_LLMNR, _DNS_PROTOCOL_MAX, - _DNS_PROTOCOL_INVALID = -1 + _DNS_PROTOCOL_INVALID = -EINVAL, } DnsProtocol; struct DnsPacketHeader { @@ -32,14 +33,19 @@ struct DnsPacketHeader { be16_t ancount; be16_t nscount; be16_t arcount; -}; +} _packed_; #define DNS_PACKET_HEADER_SIZE sizeof(DnsPacketHeader) -#define UDP_PACKET_HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr)) +#define UDP4_PACKET_HEADER_SIZE (sizeof(struct iphdr) + sizeof(struct udphdr)) +#define UDP6_PACKET_HEADER_SIZE (sizeof(struct ip6_hdr) + sizeof(struct udphdr)) -/* The various DNS protocols deviate in how large a packet can grow, - * but the TCP transport has a 16bit size field, hence that appears to - * be the absolute maximum. */ +assert_cc(sizeof(struct ip6_hdr) == 40); +assert_cc(sizeof(struct iphdr) == 20); +assert_cc(sizeof(struct udphdr) == 8); +assert_cc(sizeof(DnsPacketHeader) == 12); + +/* The various DNS protocols deviate in how large a packet can grow, but the TCP transport has a 16bit size + * field, hence that appears to be the absolute maximum. */ #define DNS_PACKET_SIZE_MAX 0xFFFFu /* The default size to use for allocation when we don't know how large @@ -55,7 +61,7 @@ struct DnsPacketHeader { struct DnsPacket { unsigned n_ref; DnsProtocol protocol; - size_t size, allocated, rindex, max_size; + size_t size, allocated, rindex, max_size, fragsize; void *_data; /* don't access directly, use DNS_PACKET_DATA()! */ Hashmap *names; /* For name compression */ size_t opt_start, opt_size; @@ -71,6 +77,7 @@ struct DnsPacket { union in_addr_union sender, destination; uint16_t sender_port, destination_port; uint32_t ttl; + usec_t timestamp; /* CLOCK_BOOTTIME (or CLOCK_MONOTONIC if the former doesn't exist) */ /* For support of truncated packets */ DnsPacket *more; @@ -81,7 +88,7 @@ struct DnsPacket { bool canonical_form:1; }; -static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { +static inline uint8_t* DNS_PACKET_DATA(const DnsPacket *p) { if (_unlikely_(!p)) return NULL; @@ -145,6 +152,14 @@ static inline bool DNS_PACKET_VERSION_SUPPORTED(DnsPacket *p) { return DNS_RESOURCE_RECORD_OPT_VERSION_SUPPORTED(p->opt); } +static inline bool DNS_PACKET_IS_FRAGMENTED(DnsPacket *p) { + assert(p); + + /* For ingress packets: was this packet fragmented according to our knowledge? */ + + return p->fragsize != 0; +} + /* LLMNR defines some bits differently */ #define DNS_PACKET_LLMNR_C(p) DNS_PACKET_AA(p) #define DNS_PACKET_LLMNR_T(p) DNS_PACKET_RD(p) @@ -175,6 +190,8 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) { int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, size_t max_size); int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t min_alloc_dsize, bool dnssec_checking_disabled); +int dns_packet_dup(DnsPacket **ret, DnsPacket *p); + void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated); DnsPacket *dns_packet_ref(DnsPacket *p); @@ -198,9 +215,12 @@ int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, bool canonica int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, bool canonical_candidate, size_t *start); int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, const DnsAnswerFlags flags, size_t *start); int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, const DnsAnswerFlags flags, size_t *start, size_t *rdata_start); -int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, bool include_rfc6975, int rcode, size_t *start); +int dns_packet_append_opt(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, bool include_rfc6975, const char *nsid, int rcode, size_t *ret_start); int dns_packet_append_question(DnsPacket *p, DnsQuestion *q); -int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a); +int dns_packet_append_answer(DnsPacket *p, DnsAnswer *a, unsigned *completed); + +int dns_packet_patch_max_udp_size(DnsPacket *p, uint16_t max_udp_size); +int dns_packet_patch_ttls(DnsPacket *p, usec_t timestamp); void dns_packet_truncate(DnsPacket *p, size_t sz); int dns_packet_truncate_opt(DnsPacket *p); @@ -221,13 +241,9 @@ void dns_packet_rewind(DnsPacket *p, size_t idx); int dns_packet_skip_question(DnsPacket *p); int dns_packet_extract(DnsPacket *p); -static inline bool DNS_PACKET_SHALL_CACHE(DnsPacket *p) { - /* Never cache data originating from localhost, under the - * assumption, that it's coming from a locally DNS forwarder - * or server, that is caching on its own. */ +bool dns_packet_equal(const DnsPacket *a, const DnsPacket *b); - return in_addr_is_localhost(p->family, &p->sender) == 0; -} +int dns_packet_has_nsid_request(DnsPacket *p); /* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-6 */ enum { @@ -269,12 +285,17 @@ DnsProtocol dns_protocol_from_string(const char *s) _pure_; extern const struct hash_ops dns_packet_hash_ops; -static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, bool authenticated) { +static inline uint64_t SD_RESOLVED_FLAGS_MAKE( + DnsProtocol protocol, + int family, + bool authenticated, + bool confidential) { uint64_t f; /* Converts a protocol + family into a flags field as used in queries and responses */ - f = authenticated ? SD_RESOLVED_AUTHENTICATED : 0; + f = (authenticated ? SD_RESOLVED_AUTHENTICATED : 0) | + (confidential ? SD_RESOLVED_CONFIDENTIAL : 0); switch (protocol) { case DNS_PROTOCOL_DNS: @@ -300,3 +321,17 @@ static inline size_t dns_packet_size_max(DnsPacket *p) { return p->max_size != 0 ? p->max_size : DNS_PACKET_SIZE_MAX; } + +static inline size_t udp_header_size(int af) { + + switch (af) { + case AF_INET: + return UDP4_PACKET_HEADER_SIZE; + case AF_INET6: + return UDP6_PACKET_HEADER_SIZE; + default: + assert_not_reached("Unexpected address family"); + } +} + +size_t dns_packet_size_unfragmented(DnsPacket *p); diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index 8ee4fd830..e960ac032 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -10,7 +10,6 @@ #include "resolved-etc-hosts.h" #include "string-util.h" -#define CNAME_MAX 8 #define QUERIES_MAX 2048 #define AUXILIARY_QUERIES_MAX 64 @@ -97,20 +96,35 @@ static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) { return 1; } -static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResourceKey *key) { +static int dns_query_candidate_add_transaction( + DnsQueryCandidate *c, + DnsResourceKey *key, + DnsPacket *bypass) { + _cleanup_(dns_transaction_gcp) DnsTransaction *t = NULL; int r; assert(c); - assert(key); - t = dns_scope_find_transaction(c->scope, key, true); - if (!t) { - r = dns_transaction_new(&t, c->scope, key); + if (key) { + /* Regular lookup with a resource key */ + assert(!bypass); + + t = dns_scope_find_transaction(c->scope, key, c->query->flags); + if (!t) { + r = dns_transaction_new(&t, c->scope, key, NULL, c->query->flags); + if (r < 0) + return r; + } else if (set_contains(c->transactions, t)) + return 0; + } else { + /* "Bypass" lookup with a query packet */ + assert(bypass); + + r = dns_transaction_new(&t, c->scope, NULL, bypass, c->query->flags); if (r < 0) return r; - } else if (set_contains(c->transactions, t)) - return 0; + } r = set_ensure_allocated(&t->notify_query_candidates_done, NULL); if (r < 0) @@ -126,7 +140,6 @@ static int dns_query_candidate_add_transaction(DnsQueryCandidate *c, DnsResource return r; } - t->clamp_ttl = c->query->clamp_ttl; TAKE_PTR(t); return 1; } @@ -214,6 +227,21 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) { dns_query_candidate_stop(c); + if (c->query->question_bypass) { + /* If this is a bypass query, then pass the original query packet along to the transaction */ + + assert(dns_question_size(c->query->question_bypass->question) == 1); + + if (!dns_scope_good_key(c->scope, c->query->question_bypass->question->keys[0])) + return 0; + + r = dns_query_candidate_add_transaction(c, NULL, c->query->question_bypass); + if (r < 0) + goto fail; + + return 1; + } + question = dns_query_question_for_protocol(c->query, c->scope->protocol); /* Create one transaction per question key */ @@ -233,7 +261,7 @@ static int dns_query_candidate_setup_transactions(DnsQueryCandidate *c) { if (!dns_scope_good_key(c->scope, qkey)) continue; - r = dns_query_candidate_add_transaction(c, qkey); + r = dns_query_candidate_add_transaction(c, qkey, NULL); if (r < 0) goto fail; @@ -297,7 +325,7 @@ static void dns_query_stop(DnsQuery *q) { assert(q); - q->timeout_event_source = sd_event_source_unref(q->timeout_event_source); + q->timeout_event_source = sd_event_source_disable_unref(q->timeout_event_source); LIST_FOREACH(candidates_by_query, c, q->candidates) dns_query_candidate_stop(c); @@ -317,10 +345,11 @@ static void dns_query_reset_answer(DnsQuery *q) { q->answer_rcode = 0; q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; q->answer_errno = 0; - q->answer_authenticated = false; + q->answer_query_flags = 0; q->answer_protocol = _DNS_PROTOCOL_INVALID; q->answer_family = AF_UNSPEC; q->answer_search_domain = dns_search_domain_unref(q->answer_search_domain); + q->answer_full_packet = dns_packet_unref(q->answer_full_packet); } DnsQuery *dns_query_free(DnsQuery *q) { @@ -340,6 +369,7 @@ DnsQuery *dns_query_free(DnsQuery *q) { dns_question_unref(q->question_idna); dns_question_unref(q->question_utf8); + dns_packet_unref(q->question_bypass); dns_query_reset_answer(q); @@ -351,13 +381,22 @@ DnsQuery *dns_query_free(DnsQuery *q) { varlink_unref(q->varlink_request); } - dns_packet_unref(q->request_dns_packet); - dns_packet_unref(q->reply_dns_packet); + if (q->request_packet) + hashmap_remove_value(q->stub_listener_extra ? + q->stub_listener_extra->queries_by_packet : + q->manager->stub_queries_by_packet, + q->request_packet, + q); - if (q->request_dns_stream) { + dns_packet_unref(q->request_packet); + dns_answer_unref(q->reply_answer); + dns_answer_unref(q->reply_authoritative); + dns_answer_unref(q->reply_additional); + + if (q->request_stream) { /* Detach the stream from our query, in case something else keeps a reference to it. */ - (void) set_remove(q->request_dns_stream->queries, q); - q->request_dns_stream = dns_stream_unref(q->request_dns_stream); + (void) set_remove(q->request_stream->queries, q); + q->request_stream = dns_stream_unref(q->request_stream); } free(q->request_address_string); @@ -375,36 +414,35 @@ int dns_query_new( DnsQuery **ret, DnsQuestion *question_utf8, DnsQuestion *question_idna, + DnsPacket *question_bypass, int ifindex, uint64_t flags) { _cleanup_(dns_query_freep) DnsQuery *q = NULL; - DnsResourceKey *key; - bool good = false; - int r; char key_str[DNS_RESOURCE_KEY_STRING_MAX]; + DnsResourceKey *key; + int r; assert(m); - if (dns_question_size(question_utf8) > 0) { - r = dns_question_is_valid_for_query(question_utf8); - if (r < 0) - return r; - if (r == 0) + if (question_bypass) { + /* It's either a "bypass" query, or a regular one, but can't be both. */ + if (question_utf8 || question_idna) return -EINVAL; - good = true; - } + } else { + bool good = false; - /* If the IDNA and UTF8 questions are the same, merge their references */ - r = dns_question_is_equal(question_idna, question_utf8); - if (r < 0) - return r; - if (r > 0) - question_idna = question_utf8; - else { - if (dns_question_size(question_idna) > 0) { - r = dns_question_is_valid_for_query(question_idna); + /* This (primarily) checks two things: + * + * 1. That the question is not empty + * 2. That all RR keys in the question objects are for the same domain + * + * Or in other words, a single DnsQuery object may be used to look up A+AAAA combination for + * the same domain name, or SRV+TXT (for DNS-SD services), but not for unrelated lookups. */ + + if (dns_question_size(question_utf8) > 0) { + r = dns_question_is_valid_for_query(question_utf8); if (r < 0) return r; if (r == 0) @@ -412,10 +450,28 @@ int dns_query_new( good = true; } - } - if (!good) /* don't allow empty queries */ - return -EINVAL; + /* If the IDNA and UTF8 questions are the same, merge their references */ + r = dns_question_is_equal(question_idna, question_utf8); + if (r < 0) + return r; + if (r > 0) + question_idna = question_utf8; + else { + if (dns_question_size(question_idna) > 0) { + r = dns_question_is_valid_for_query(question_idna); + if (r < 0) + return r; + if (r == 0) + return -EINVAL; + + good = true; + } + } + + if (!good) /* don't allow empty queries */ + return -EINVAL; + } if (m->n_dns_queries >= QUERIES_MAX) return -EBUSY; @@ -427,6 +483,7 @@ int dns_query_new( *q = (DnsQuery) { .question_utf8 = dns_question_ref(question_utf8), .question_idna = dns_question_ref(question_idna), + .question_bypass = dns_packet_ref(question_bypass), .ifindex = ifindex, .flags = flags, .answer_dnssec_result = _DNSSEC_RESULT_INVALID, @@ -434,21 +491,27 @@ int dns_query_new( .answer_family = AF_UNSPEC, }; - /* First dump UTF8 question */ - DNS_QUESTION_FOREACH(key, question_utf8) - log_debug("Looking up RR for %s.", - dns_resource_key_to_string(key, key_str, sizeof key_str)); + if (question_bypass) { + DNS_QUESTION_FOREACH(key, question_bypass->question) + log_debug("Looking up bypass packet for %s.", + dns_resource_key_to_string(key, key_str, sizeof key_str)); + } else { + /* First dump UTF8 question */ + DNS_QUESTION_FOREACH(key, question_utf8) + log_debug("Looking up RR for %s.", + dns_resource_key_to_string(key, key_str, sizeof key_str)); - /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */ - DNS_QUESTION_FOREACH(key, question_idna) { - r = dns_question_contains(question_utf8, key); - if (r < 0) - return r; - if (r > 0) - continue; + /* And then dump the IDNA question, but only what hasn't been dumped already through the UTF8 question. */ + DNS_QUESTION_FOREACH(key, question_idna) { + r = dns_question_contains(question_utf8, key); + if (r < 0) + return r; + if (r > 0) + continue; - log_debug("Looking up IDNA RR for %s.", - dns_resource_key_to_string(key, key_str, sizeof key_str)); + log_debug("Looking up IDNA RR for %s.", + dns_resource_key_to_string(key, key_str, sizeof key_str)); + } } LIST_PREPEND(queries, m->dns_queries, q); @@ -457,8 +520,8 @@ int dns_query_new( if (ret) *ret = q; - q = NULL; + TAKE_PTR(q); return 0; } @@ -559,9 +622,12 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { DNS_TRANSACTION_NOT_FOUND)) return 0; + if (FLAGS_SET(q->flags, SD_RESOLVED_NO_SYNTHESIZE)) + return 0; + r = dns_synthesize_answer( q->manager, - q->question_utf8, + q->question_bypass ? q->question_bypass->question : q->question_utf8, q->ifindex, &answer); if (r == -ENXIO) { @@ -571,7 +637,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_NXDOMAIN; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_authenticated = true; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC; *state = DNS_TRANSACTION_RCODE_FAILURE; return 0; @@ -585,7 +651,7 @@ static int dns_query_synthesize_reply(DnsQuery *q, DnsTransactionState *state) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_authenticated = true; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC; *state = DNS_TRANSACTION_SUCCESS; @@ -601,9 +667,12 @@ static int dns_query_try_etc_hosts(DnsQuery *q) { /* Looks in /etc/hosts for matching entries. Note that this is done *before* the normal lookup is * done. The data from /etc/hosts hence takes precedence over the network. */ + if (FLAGS_SET(q->flags, SD_RESOLVED_NO_SYNTHESIZE)) + return 0; + r = manager_etc_hosts_lookup( q->manager, - q->question_utf8, + q->question_bypass ? q->question_bypass->question : q->question_utf8, &answer); if (r <= 0) return r; @@ -614,7 +683,7 @@ static int dns_query_try_etc_hosts(DnsQuery *q) { q->answer_rcode = DNS_RCODE_SUCCESS; q->answer_protocol = dns_synthesize_protocol(q->flags); q->answer_family = dns_synthesize_family(q->flags); - q->answer_authenticated = true; + q->answer_query_flags = SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL|SD_RESOLVED_SYNTHETIC; return 1; } @@ -733,7 +802,7 @@ fail: static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS; - bool has_authenticated = false, has_non_authenticated = false; + bool has_authenticated = false, has_non_authenticated = false, has_confidential = false, has_non_confidential = false; DnssecResult dnssec_result_authenticated = _DNSSEC_RESULT_INVALID, dnssec_result_non_authenticated = _DNSSEC_RESULT_INVALID; DnsTransaction *t; int r; @@ -755,8 +824,9 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { q->answer = dns_answer_unref(q->answer); q->answer_rcode = 0; q->answer_dnssec_result = _DNSSEC_RESULT_INVALID; - q->answer_authenticated = false; + q->answer_query_flags = 0; q->answer_errno = c->error_code; + q->answer_full_packet = dns_packet_unref(q->answer_full_packet); } SET_FOREACH(t, c->transactions) { @@ -764,15 +834,29 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { switch (t->state) { case DNS_TRANSACTION_SUCCESS: { - /* We found a successfully reply, merge it into the answer */ - r = dns_answer_extend(&q->answer, t->answer); - if (r < 0) - goto fail; + /* We found a successful reply, merge it into the answer */ + + if (state == DNS_TRANSACTION_SUCCESS) { + r = dns_answer_extend(&q->answer, t->answer); + if (r < 0) + goto fail; + + q->answer_query_flags |= dns_transaction_source_to_query_flags(t->answer_source); + } else { + /* Override non-successful previous answers */ + dns_answer_unref(q->answer); + q->answer = dns_answer_ref(t->answer); + + q->answer_query_flags = dns_transaction_source_to_query_flags(t->answer_source); + } q->answer_rcode = t->answer_rcode; q->answer_errno = 0; - if (t->answer_authenticated) { + dns_packet_unref(q->answer_full_packet); + q->answer_full_packet = dns_packet_ref(t->received); + + if (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) { has_authenticated = true; dnssec_result_authenticated = t->answer_dnssec_result; } else { @@ -780,6 +864,11 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { dnssec_result_non_authenticated = t->answer_dnssec_result; } + if (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL)) + has_confidential = true; + else + has_non_confidential = true; + state = DNS_TRANSACTION_SUCCESS; break; } @@ -797,14 +886,18 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { continue; /* If there's already an authenticated negative reply stored, then prefer that over any unauthenticated one */ - if (q->answer_authenticated && !t->answer_authenticated) + if (FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) && + !FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) continue; - q->answer = dns_answer_unref(q->answer); + dns_answer_unref(q->answer); + q->answer = dns_answer_ref(t->answer); q->answer_rcode = t->answer_rcode; q->answer_dnssec_result = t->answer_dnssec_result; - q->answer_authenticated = t->answer_authenticated; + q->answer_query_flags = t->answer_query_flags | dns_transaction_source_to_query_flags(t->answer_source); q->answer_errno = t->answer_errno; + dns_packet_unref(q->answer_full_packet); + q->answer_full_packet = dns_packet_ref(t->received); state = t->state; break; @@ -812,8 +905,9 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) { } if (state == DNS_TRANSACTION_SUCCESS) { - q->answer_authenticated = has_authenticated && !has_non_authenticated; - q->answer_dnssec_result = q->answer_authenticated ? dnssec_result_authenticated : dnssec_result_non_authenticated; + SET_FLAG(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED, has_authenticated && !has_non_authenticated); + SET_FLAG(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, has_confidential && !has_non_confidential); + q->answer_dnssec_result = FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? dnssec_result_authenticated : dnssec_result_non_authenticated; } q->answer_protocol = c->scope->protocol; @@ -890,18 +984,18 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) assert(q); q->n_cname_redirects++; - if (q->n_cname_redirects > CNAME_MAX) + if (q->n_cname_redirects > CNAME_REDIRECT_MAX) return -ELOOP; r = dns_question_cname_redirect(q->question_idna, cname, &nq_idna); if (r < 0) return r; - else if (r > 0) + if (r > 0) log_debug("Following CNAME/DNAME %s → %s.", dns_question_first_name(q->question_idna), dns_question_first_name(nq_idna)); k = dns_question_is_equal(q->question_idna, q->question_utf8); if (k < 0) - return r; + return k; if (k > 0) { /* Same question? Shortcut new question generation */ nq_utf8 = dns_question_ref(nq_idna); @@ -910,7 +1004,7 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) k = dns_question_cname_redirect(q->question_utf8, cname, &nq_utf8); if (k < 0) return k; - else if (k > 0) + if (k > 0) log_debug("Following UTF8 CNAME/DNAME %s → %s.", dns_question_first_name(q->question_utf8), dns_question_first_name(nq_utf8)); } @@ -933,33 +1027,84 @@ static int dns_query_cname_redirect(DnsQuery *q, const DnsResourceRecord *cname) q->question_utf8 = TAKE_PTR(nq_utf8); dns_query_unref_candidates(q); - dns_query_reset_answer(q); + + /* Note that we do *not* reset the answer here, because the answer we previously got might already + * include everything we need, let's check that first */ q->state = DNS_TRANSACTION_NULL; return 0; } -int dns_query_process_cname(DnsQuery *q) { +int dns_query_process_cname_one(DnsQuery *q) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL; DnsQuestion *question; DnsResourceRecord *rr; + bool full_match = true; + DnsResourceKey *k; int r; assert(q); + /* Processes a CNAME redirect if there's one. Returns one of three values: + * + * CNAME_QUERY_MATCH → direct RR match, caller should just use the RRs in this answer (and not + * bother with any CNAME/DNAME stuff) + * + * CNAME_QUERY_NOMATCH → no match at all, neither direct nor CNAME/DNAME, caller might decide to + * restart query or take things as NODATA reply. + * + * CNAME_QUERY_CNAME → no direct RR match, but a CNAME/DNAME match that we now followed for one step. + * + * The function might also return a failure, in particular -ELOOP if we encountered too many + * CNAMEs/DNAMEs in a chain or if following CNAMEs/DNAMEs was turned off. + * + * Note that this function doesn't actually restart the query. The caller can decide to do that in + * case of CNAME_QUERY_CNAME, though. */ + if (!IN_SET(q->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_NULL)) return DNS_QUERY_NOMATCH; question = dns_query_question_for_protocol(q, q->answer_protocol); - DNS_ANSWER_FOREACH(rr, q->answer) { - r = dns_question_matches_rr(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); - if (r < 0) - return r; - if (r > 0) - return DNS_QUERY_MATCH; /* The answer matches directly, no need to follow cnames */ + /* Small reminder: our question will consist of one or more RR keys that match in name, but not in + * record type. Specifically, when we do an address lookup the question will typically consist of one + * A and one AAAA key lookup for the same domain name. When we get a response from a server we need + * to check if the answer answers all our questions to use it. Note that a response of CNAME/DNAME + * can answer both an A and the AAAA question for us, but an A/AAAA response only the relevant + * type. + * + * Hence we first check of the answers we collected are sufficient to answer all our questions + * directly. If one question wasn't answered we go on, waiting for more replies. However, if there's + * a CNAME/DNAME response we use it, and redirect to it, regardless if it was a response to the A or + * the AAAA query.*/ + DNS_QUESTION_FOREACH(k, question) { + bool match = false; + + DNS_ANSWER_FOREACH(rr, q->answer) { + r = dns_resource_key_match_rr(k, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); + if (r < 0) + return r; + if (r > 0) { + match = true; /* Yay, we found an RR that matches the key we are looking for */ + break; + } + } + + if (!match) { + /* Hmm. :-( there's no response for this key. This doesn't match. */ + full_match = false; + break; + } + } + + if (full_match) + return DNS_QUERY_MATCH; /* The answer can answer our question in full, no need to follow CNAMEs/DNAMEs */ + + /* Let's see if there is a CNAME/DNAME to match. This case is simpler: we accept the CNAME/DNAME that + * matches any of our questions. */ + DNS_ANSWER_FOREACH(rr, q->answer) { r = dns_question_matches_cname_or_dname(question, rr, DNS_SEARCH_DOMAIN_NAME(q->answer_search_domain)); if (r < 0) return r; @@ -968,36 +1113,88 @@ int dns_query_process_cname(DnsQuery *q) { } if (!cname) - return DNS_QUERY_NOMATCH; /* No match and no cname to follow */ + return DNS_QUERY_NOMATCH; /* No match and no CNAME/DNAME to follow */ if (q->flags & SD_RESOLVED_NO_CNAME) return -ELOOP; - if (!q->answer_authenticated) + if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) q->previous_redirect_unauthenticated = true; + if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL)) + q->previous_redirect_non_confidential = true; + if (!FLAGS_SET(q->answer_query_flags, SD_RESOLVED_SYNTHETIC)) + q->previous_redirect_non_synthetic = true; /* OK, let's actually follow the CNAME */ r = dns_query_cname_redirect(q, cname); if (r < 0) return r; - /* Let's see if the answer can already answer the new - * redirected question */ - r = dns_query_process_cname(q); - if (r != DNS_QUERY_NOMATCH) - return r; + return DNS_QUERY_CNAME; /* Tell caller that we did a single CNAME/DNAME redirection step */ +} - /* OK, it cannot, let's begin with the new query */ - r = dns_query_go(q); - if (r < 0) - return r; +int dns_query_process_cname_many(DnsQuery *q) { + int r; - return DNS_QUERY_RESTARTED; /* We restarted the query for a new cname */ + assert(q); + + /* Follows CNAMEs through the current packet: as long as the current packet can fulfill our + * redirected CNAME queries we keep going, and restart the query once the current packet isn't good + * enough anymore. It's a wrapper around dns_query_process_cname_one() and returns the same values, + * but with extended semantics. Specifically: + * + * DNS_QUERY_MATCH → as above + * + * DNS_QUERY_CNAME → we ran into a CNAME/DNAME redirect that we could not answer from the current + * message, and thus restarted the query to resolve it. + * + * DNS_QUERY_NOMATCH → we reached the end of CNAME/DNAME chain, and there are no direct matches nor a + * CNAME/DNAME match. i.e. this is a NODATA case. + * + * Note that this function will restart the query for the caller if needed, and that's the case + * DNS_QUERY_CNAME is returned. + */ + + r = dns_query_process_cname_one(q); + if (r != DNS_QUERY_CNAME) + return r; /* The first redirect is special: if it doesn't answer the question that's no + * reason to restart the query, we just accept this as a NODATA answer. */ + + for (;;) { + r = dns_query_process_cname_one(q); + if (r < 0 || r == DNS_QUERY_MATCH) + return r; + if (r == DNS_QUERY_NOMATCH) { + /* OK, so we followed one or more CNAME/DNAME RR but the existing packet can't answer + * this. Let's restart the query hence, with the new question. Why the different + * handling than the first chain element? Because if the server answers a direct + * question with an empty answer then this is a NODATA response. But if it responds + * with a CNAME chain that ultimately is incomplete (i.e. a non-empty but truncated + * CNAME chain) then we better follow up ourselves and ask for the rest of the + * chain. This is particular relevant since our cache will store CNAME/DNAME + * redirects that we learnt about for lookups of certain DNS types, but later on we + * can reuse this data even for other DNS types, but in that case need to follow up + * with the final lookup of the chain ourselves with the RR type we ourselves are + * interested in. */ + r = dns_query_go(q); + if (r < 0) + return r; + + return DNS_QUERY_CNAME; + } + + /* So we found a CNAME that the existing packet already answers, again via a CNAME, let's + * continue going then. */ + assert(r == DNS_QUERY_CNAME); + } } DnsQuestion* dns_query_question_for_protocol(DnsQuery *q, DnsProtocol protocol) { assert(q); + if (q->question_bypass) + return q->question_bypass->question; + switch (protocol) { case DNS_PROTOCOL_DNS: @@ -1018,6 +1215,9 @@ const char *dns_query_string(DnsQuery *q) { /* Returns a somewhat useful human-readable lookup key string for this query */ + if (q->question_bypass) + return dns_question_first_name(q->question_bypass->question); + if (q->request_address_string) return q->request_address_string; @@ -1037,5 +1237,26 @@ const char *dns_query_string(DnsQuery *q) { bool dns_query_fully_authenticated(DnsQuery *q) { assert(q); - return q->answer_authenticated && !q->previous_redirect_unauthenticated; + return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_AUTHENTICATED) && !q->previous_redirect_unauthenticated; +} + +bool dns_query_fully_confidential(DnsQuery *q) { + assert(q); + + return FLAGS_SET(q->answer_query_flags, SD_RESOLVED_CONFIDENTIAL) && !q->previous_redirect_non_confidential; +} + +bool dns_query_fully_authoritative(DnsQuery *q) { + assert(q); + + /* We are authoritative for everything synthetic (except if a previous CNAME/DNAME) wasn't + * synthetic. (Note: SD_RESOLVED_SYNTHETIC is reset on each CNAME/DNAME, hence the explicit check for + * previous synthetic DNAME/CNAME redirections.)*/ + if ((q->answer_query_flags & SD_RESOLVED_SYNTHETIC) && !q->previous_redirect_non_synthetic) + return true; + + /* We are also authoritative for everything coming only from the trust anchor and the local + * zones. (Note: the SD_RESOLVED_FROM_xyz flags we merge on each redirect, hence no need to + * explicitly check previous redirects here.)*/ + return (q->answer_query_flags & SD_RESOLVED_FROM_MASK & ~(SD_RESOLVED_FROM_TRUST_ANCHOR | SD_RESOLVED_FROM_ZONE)) == 0; } diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index 133076dbf..fa584fe3d 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -45,16 +45,24 @@ struct DnsQuery { * that even on classic DNS some labels might use UTF8 encoding. Specifically, DNS-SD service names * (in contrast to their domain suffixes) use UTF-8 encoding even on DNS. Thus, the difference * between these two fields is mostly relevant only for explicit *hostname* lookups as well as the - * domain suffixes of service lookups. */ + * domain suffixes of service lookups. + * + * Note that questions may consist of multiple RR keys at once, but they must be for the same domain + * name. This is used for A+AAAA and TXT+SRV lookups: we'll allocate a single DnsQuery object for + * them instead of two separate ones. That allows us minor optimizations with response handling: + * CNAME/DNAMEs of the first reply we get can already be used to follow the CNAME/DNAME chain for + * both, and we can take benefit of server replies that oftentimes put A responses into AAAA queries + * and vice versa (in the additional section). */ DnsQuestion *question_idna; DnsQuestion *question_utf8; + /* If this is not a question by ourselves, but a "bypass" request, we propagate the original packet + * here, and use that instead. */ + DnsPacket *question_bypass; + uint64_t flags; int ifindex; - /* If true, the RR TTLs of the answer will be clamped by their current left validity in the cache */ - bool clamp_ttl; - DnsTransactionState state; unsigned n_cname_redirects; @@ -65,12 +73,15 @@ struct DnsQuery { DnsAnswer *answer; int answer_rcode; DnssecResult answer_dnssec_result; - bool answer_authenticated; + uint64_t answer_query_flags; DnsProtocol answer_protocol; int answer_family; DnsSearchDomain *answer_search_domain; int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ bool previous_redirect_unauthenticated; + bool previous_redirect_non_confidential; + bool previous_redirect_non_synthetic; + DnsPacket *answer_full_packet; /* Bus + Varlink client information */ sd_bus_message *bus_request; @@ -82,9 +93,11 @@ struct DnsQuery { char *request_address_string; /* DNS stub information */ - DnsPacket *request_dns_packet; - DnsStream *request_dns_stream; - DnsPacket *reply_dns_packet; + DnsPacket *request_packet; + DnsStream *request_stream; + DnsAnswer *reply_answer; + DnsAnswer *reply_authoritative; + DnsAnswer *reply_additional; DnsStubListenerExtra *stub_listener_extra; /* Completion callback */ @@ -100,7 +113,7 @@ struct DnsQuery { enum { DNS_QUERY_MATCH, DNS_QUERY_NOMATCH, - DNS_QUERY_RESTARTED, + DNS_QUERY_CNAME, }; DnsQueryCandidate* dns_query_candidate_ref(DnsQueryCandidate*); @@ -109,7 +122,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQueryCandidate*, dns_query_candidate_unref); 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); +int dns_query_new(Manager *m, DnsQuery **q, DnsQuestion *question_utf8, DnsQuestion *question_idna, DnsPacket *question_bypass, int family, uint64_t flags); DnsQuery *dns_query_free(DnsQuery *q); int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for); @@ -117,7 +130,8 @@ int dns_query_make_auxiliary(DnsQuery *q, DnsQuery *auxiliary_for); int dns_query_go(DnsQuery *q); void dns_query_ready(DnsQuery *q); -int dns_query_process_cname(DnsQuery *q); +int dns_query_process_cname_one(DnsQuery *q); +int dns_query_process_cname_many(DnsQuery *q); void dns_query_complete(DnsQuery *q, DnsTransactionState state); @@ -128,3 +142,17 @@ const char *dns_query_string(DnsQuery *q); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuery*, dns_query_free); bool dns_query_fully_authenticated(DnsQuery *q); +bool dns_query_fully_confidential(DnsQuery *q); +bool dns_query_fully_authoritative(DnsQuery *q); + +static inline uint64_t dns_query_reply_flags_make(DnsQuery *q) { + assert(q); + + return SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, + q->answer_family, + dns_query_fully_authenticated(q), + dns_query_fully_confidential(q)) | + (q->answer_query_flags & (SD_RESOLVED_FROM_MASK|SD_RESOLVED_SYNTHETIC)); +} + +#define CNAME_REDIRECT_MAX 16 diff --git a/src/resolve/resolved-dns-question.c b/src/resolve/resolved-dns-question.c index 047170899..ef4093263 100644 --- a/src/resolve/resolved-dns-question.c +++ b/src/resolve/resolved-dns-question.c @@ -445,3 +445,21 @@ int dns_question_new_service( return 0; } + +/* + * This function is not used in the code base, but is useful when debugging. Do not delete. + */ +void dns_question_dump(DnsQuestion *question, FILE *f) { + DnsResourceKey *k; + + if (!f) + f = stdout; + + DNS_QUESTION_FOREACH(k, question) { + char buf[DNS_RESOURCE_KEY_STRING_MAX]; + + fputc('\t', f); + fputs(dns_resource_key_to_string(k, buf, sizeof(buf)), f); + fputc('\n', f); + } +} diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h index a6444b0ba..8f9a84c82 100644 --- a/src/resolve/resolved-dns-question.h +++ b/src/resolve/resolved-dns-question.h @@ -33,6 +33,8 @@ int dns_question_is_equal(DnsQuestion *a, DnsQuestion *b); int dns_question_cname_redirect(DnsQuestion *q, const DnsResourceRecord *cname, DnsQuestion **ret); +void dns_question_dump(DnsQuestion *q, FILE *f); + const char *dns_question_first_name(DnsQuestion *q); static inline size_t dns_question_size(DnsQuestion *q) { diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 52c76eea4..5b0e601e9 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -118,7 +118,7 @@ DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) { /* Static/const keys created with DNS_RESOURCE_KEY_CONST will * set this to -1, they should not be reffed/unreffed */ - assert(k->n_ref != (unsigned) -1); + assert(k->n_ref != UINT_MAX); assert(k->n_ref > 0); k->n_ref++; @@ -130,7 +130,7 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) { if (!k) return NULL; - assert(k->n_ref != (unsigned) -1); + assert(k->n_ref != UINT_MAX); assert(k->n_ref > 0); if (k->n_ref == 1) { @@ -244,6 +244,9 @@ int dns_resource_key_match_cname_or_dname(const DnsResourceKey *key, const DnsRe if (cname->class != key->class && key->class != DNS_CLASS_ANY) return 0; + if (!dns_type_may_redirect(key->type)) + return 0; + if (cname->type == DNS_TYPE_CNAME) r = dns_name_equal(dns_resource_key_name(key), dns_resource_key_name(cname)); else if (cname->type == DNS_TYPE_DNAME) @@ -294,21 +297,17 @@ static void dns_resource_key_hash_func(const DnsResourceKey *k, struct siphash * } static int dns_resource_key_compare_func(const DnsResourceKey *x, const DnsResourceKey *y) { - int ret; + int r; - ret = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y)); - if (ret != 0) - return ret; + r = dns_name_compare_func(dns_resource_key_name(x), dns_resource_key_name(y)); + if (r != 0) + return r; - ret = CMP(x->type, y->type); - if (ret != 0) - return ret; + r = CMP(x->type, y->type); + if (r != 0) + return r; - ret = CMP(x->class, y->class); - if (ret != 0) - return ret; - - return 0; + return CMP(x->class, y->class); } DEFINE_HASH_OPS(dns_resource_key_hash_ops, DnsResourceKey, dns_resource_key_hash_func, dns_resource_key_compare_func); @@ -346,9 +345,9 @@ bool dns_resource_key_reduce(DnsResourceKey **a, DnsResourceKey **b) { return false; /* We refuse merging const keys */ - if ((*a)->n_ref == (unsigned) -1) + if ((*a)->n_ref == UINT_MAX) return false; - if ((*b)->n_ref == (unsigned) -1) + if ((*b)->n_ref == UINT_MAX) return false; /* Already the same? */ @@ -382,8 +381,8 @@ DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key) { .n_ref = 1, .key = dns_resource_key_ref(key), .expiry = USEC_INFINITY, - .n_skip_labels_signer = (unsigned) -1, - .n_skip_labels_source = (unsigned) -1, + .n_skip_labels_signer = UINT_MAX, + .n_skip_labels_source = UINT_MAX, }; return rr; @@ -821,8 +820,8 @@ static char *format_txt(DnsTxtItem *first) { } const char *dns_resource_record_to_string(DnsResourceRecord *rr) { - _cleanup_free_ char *t = NULL; - char *s, k[DNS_RESOURCE_KEY_STRING_MAX]; + _cleanup_free_ char *s = NULL, *t = NULL; + char k[DNS_RESOURCE_KEY_STRING_MAX]; int r; assert(rr); @@ -872,18 +871,15 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return NULL; break; - case DNS_TYPE_A: { - _cleanup_free_ char *x = NULL; - - r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &x); + case DNS_TYPE_A: + r = in_addr_to_string(AF_INET, (const union in_addr_union*) &rr->a.in_addr, &t); if (r < 0) return NULL; - s = strjoin(k, " ", x); + s = strjoin(k, " ", t); if (!s) return NULL; break; - } case DNS_TYPE_AAAA: r = in_addr_to_string(AF_INET6, (const union in_addr_union*) &rr->aaaa.in6_addr, &t); @@ -966,7 +962,6 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { case DNS_TYPE_DNSKEY: { _cleanup_free_ char *alg = NULL; - char *ss; uint16_t key_tag; key_tag = dnssec_keytag(rr, true); @@ -975,7 +970,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (r < 0) return NULL; - r = asprintf(&s, "%s %u %u %s", + r = asprintf(&t, "%s %u %u %s", k, rr->dnskey.flags, rr->dnskey.protocol, @@ -983,24 +978,22 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (r < 0) return NULL; - r = base64_append(&s, r, + r = base64_append(&t, r, rr->dnskey.key, rr->dnskey.key_size, 8, columns()); if (r < 0) return NULL; - r = asprintf(&ss, "%s\n" + r = asprintf(&s, "%s\n" " -- Flags:%s%s%s\n" " -- Key tag: %u", - s, + t, rr->dnskey.flags & DNSKEY_FLAG_SEP ? " SEP" : "", rr->dnskey.flags & DNSKEY_FLAG_REVOKE ? " REVOKE" : "", rr->dnskey.flags & DNSKEY_FLAG_ZONE_KEY ? " ZONE_KEY" : "", key_tag); if (r < 0) return NULL; - free(s); - s = ss; break; } @@ -1124,18 +1117,16 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { break; } - case DNS_TYPE_CAA: { - _cleanup_free_ char *value; - - value = octescape(rr->caa.value, rr->caa.value_size); - if (!value) + case DNS_TYPE_CAA: + t = octescape(rr->caa.value, rr->caa.value_size); + if (!t) return NULL; r = asprintf(&s, "%s %u %s \"%s\"%s%s%s%.0u", k, rr->caa.flags, rr->caa.tag, - value, + t, rr->caa.flags ? "\n -- Flags:" : "", rr->caa.flags & CAA_FLAG_CRITICAL ? " critical" : "", rr->caa.flags & ~CAA_FLAG_CRITICAL ? " " : "", @@ -1144,9 +1135,8 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { return NULL; break; - } - case DNS_TYPE_OPENPGPKEY: { + case DNS_TYPE_OPENPGPKEY: r = asprintf(&s, "%s", k); if (r < 0) return NULL; @@ -1157,7 +1147,6 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { if (r < 0) return NULL; break; - } default: t = hexmem(rr->generic.data, rr->generic.data_size); @@ -1172,7 +1161,7 @@ const char *dns_resource_record_to_string(DnsResourceRecord *rr) { } rr->to_string = s; - return s; + return TAKE_PTR(s); } ssize_t dns_resource_record_payload(DnsResourceRecord *rr, void **out) { @@ -1269,7 +1258,7 @@ int dns_resource_record_signer(DnsResourceRecord *rr, const char **ret) { /* Returns the RRset's signer, if it is known. */ - if (rr->n_skip_labels_signer == (unsigned) -1) + if (rr->n_skip_labels_signer == UINT_MAX) return -ENODATA; n = dns_resource_key_name(rr->key); @@ -1292,7 +1281,7 @@ int dns_resource_record_source(DnsResourceRecord *rr, const char **ret) { /* Returns the RRset's synthesizing source, if it is known. */ - if (rr->n_skip_labels_source == (unsigned) -1) + if (rr->n_skip_labels_source == UINT_MAX) return -ENODATA; n = dns_resource_key_name(rr->key); @@ -1326,7 +1315,7 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr) { /* Returns > 0 if the RR is generated from a wildcard, and is not the asterisk name itself */ - if (rr->n_skip_labels_source == (unsigned) -1) + if (rr->n_skip_labels_source == UINT_MAX) return -ENODATA; if (rr->n_skip_labels_source == 0) @@ -1483,14 +1472,14 @@ void dns_resource_record_hash_func(const DnsResourceRecord *rr, struct siphash * } } -static int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y) { +int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y) { int r; r = dns_resource_key_compare_func(x->key, y->key); if (r != 0) return r; - if (dns_resource_record_equal(x, y)) + if (dns_resource_record_payload_equal(x, y) > 0) return 0; /* We still use CMP() here, even though don't implement proper @@ -1725,6 +1714,69 @@ int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl) { return 1; } +bool dns_resource_record_is_link_local_address(DnsResourceRecord *rr) { + assert(rr); + + if (rr->key->class != DNS_CLASS_IN) + return false; + + if (rr->key->type == DNS_TYPE_A) + return in4_addr_is_link_local(&rr->a.in_addr); + + if (rr->key->type == DNS_TYPE_AAAA) + return in6_addr_is_link_local(&rr->aaaa.in6_addr); + + return false; +} + +int dns_resource_record_get_cname_target(DnsResourceKey *key, DnsResourceRecord *cname, char **ret) { + _cleanup_free_ char *d = NULL; + int r; + + assert(key); + assert(cname); + + /* Checks if the RR `cname` is a CNAME/DNAME RR that matches the specified `key`. If so, returns the + * target domain. If not, returns -EUNATCH */ + + if (key->class != cname->key->class && key->class != DNS_CLASS_ANY) + return -EUNATCH; + + if (!dns_type_may_redirect(key->type)) /* This key type is not subject to CNAME/DNAME redirection? + * Then let's refuse right-away */ + return -EUNATCH; + + if (cname->key->type == DNS_TYPE_CNAME) { + r = dns_name_equal(dns_resource_key_name(key), + dns_resource_key_name(cname->key)); + if (r < 0) + return r; + if (r == 0) + return -EUNATCH; /* CNAME RR key doesn't actually match the original key */ + + d = strdup(cname->cname.name); + if (!d) + return -ENOMEM; + + } else if (cname->key->type == DNS_TYPE_DNAME) { + + r = dns_name_change_suffix( + dns_resource_key_name(key), + dns_resource_key_name(cname->key), + cname->dname.name, + &d); + if (r < 0) + return r; + if (r == 0) + return -EUNATCH; /* DNAME RR key doesn't actually match the original key */ + + } else + return -EUNATCH; /* Not a CNAME/DNAME RR, hence doesn't match the proposition either */ + + *ret = TAKE_PTR(d); + return 0; +} + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) { DnsTxtItem *n; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index 59b3a7017..ab48ea5f2 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -76,7 +76,7 @@ struct DnsResourceKey { * resource key object. */ #define DNS_RESOURCE_KEY_CONST(c, t, n) \ ((DnsResourceKey) { \ - .n_ref = (unsigned) -1, \ + .n_ref = UINT_MAX, \ .class = c, \ .type = t, \ ._name = (char*) n, \ @@ -324,12 +324,17 @@ int dns_resource_record_is_synthetic(DnsResourceRecord *rr); int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl); +bool dns_resource_record_is_link_local_address(DnsResourceRecord *rr); + +int dns_resource_record_get_cname_target(DnsResourceKey *key, DnsResourceRecord *cname, char **ret); + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); DnsTxtItem *dns_txt_item_copy(DnsTxtItem *i); int dns_txt_item_new_empty(DnsTxtItem **ret); void dns_resource_record_hash_func(const DnsResourceRecord *i, struct siphash *state); +int dns_resource_record_compare_func(const DnsResourceRecord *x, const DnsResourceRecord *y); extern const struct hash_ops dns_resource_key_hash_ops; extern const struct hash_ops dns_resource_record_hash_ops; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 509a2060e..67c6f54dc 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -5,6 +5,7 @@ #include "af-list.h" #include "alloc-util.h" #include "dns-domain.h" +#include "errno-util.h" #include "fd-util.h" #include "hostname-util.h" #include "missing_network.h" @@ -110,9 +111,9 @@ DnsScope* dns_scope_free(DnsScope *s) { hashmap_free(s->transactions_by_key); ordered_hashmap_free_with_destructor(s->conflict_queue, dns_resource_record_unref); - sd_event_source_unref(s->conflict_event_source); + sd_event_source_disable_unref(s->conflict_event_source); - sd_event_source_unref(s->announce_event_source); + sd_event_source_disable_unref(s->announce_event_source); dns_cache_flush(&s->cache); dns_zone_flush(&s->zone); @@ -153,16 +154,19 @@ unsigned dns_scope_get_n_dns_servers(DnsScope *s) { return n; } -void dns_scope_next_dns_server(DnsScope *s) { +void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current) { assert(s); if (s->protocol != DNS_PROTOCOL_DNS) return; + /* Changes to the next DNS server in the list. If 'if_current' is passed will do so only if the + * current DNS server still matches it. */ + if (s->link) - link_next_dns_server(s->link); + link_next_dns_server(s->link, if_current); else - manager_next_dns_server(s->manager); + manager_next_dns_server(s->manager, if_current); } void dns_scope_packet_received(DnsScope *s, usec_t rtt) { @@ -182,43 +186,73 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec) { s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC); } -static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { - union in_addr_union addr; - int ifindex = 0, r; - int family; - uint32_t mtu; +static int dns_scope_emit_one(DnsScope *s, int fd, int family, DnsPacket *p) { + int r; assert(s); assert(p); assert(p->protocol == s->protocol); - if (s->link) { - mtu = s->link->mtu; - ifindex = s->link->ifindex; - } else - mtu = manager_find_mtu(s->manager); + if (family == AF_UNSPEC) { + if (s->family == AF_UNSPEC) + return -EAFNOSUPPORT; + + family = s->family; + } switch (s->protocol) { - case DNS_PROTOCOL_DNS: + case DNS_PROTOCOL_DNS: { + size_t mtu, udp_size, min_mtu, socket_mtu = 0; + assert(fd >= 0); - if (DNS_PACKET_QDCOUNT(p) > 1) + if (DNS_PACKET_QDCOUNT(p) > 1) /* Classic DNS only allows one question per packet */ return -EOPNOTSUPP; if (p->size > DNS_PACKET_UNICAST_SIZE_MAX) return -EMSGSIZE; - if (p->size + UDP_PACKET_HEADER_SIZE > mtu) - return -EMSGSIZE; + /* Determine the local most accurate MTU */ + if (s->link) + mtu = s->link->mtu; + else + mtu = manager_find_mtu(s->manager); + + /* Acquire the socket's PMDU MTU */ + r = socket_get_mtu(fd, family, &socket_mtu); + if (r < 0 && !ERRNO_IS_DISCONNECT(r)) /* Will return ENOTCONN if no information is available yet */ + return log_debug_errno(r, "Failed to read socket MTU: %m"); + + /* Determine the appropriate UDP header size */ + udp_size = udp_header_size(family); + min_mtu = udp_size + DNS_PACKET_HEADER_SIZE; + + log_debug("Emitting UDP, link MTU is %zu, socket MTU is %zu, minimal MTU is %zu", + mtu, socket_mtu, min_mtu); + + /* Clamp by the kernel's idea of the (path) MTU */ + if (socket_mtu != 0 && socket_mtu < mtu) + mtu = socket_mtu; + + /* Put a lower limit, in case all MTU data we acquired was rubbish */ + if (mtu < min_mtu) + mtu = min_mtu; + + /* Now check our packet size against the MTU we determined */ + if (udp_size + p->size > mtu) + return -EMSGSIZE; /* This means: try TCP instead */ r = manager_write(s->manager, fd, p); if (r < 0) return r; break; + } + + case DNS_PROTOCOL_LLMNR: { + union in_addr_union addr; - case DNS_PROTOCOL_LLMNR: assert(fd < 0); if (DNS_PACKET_QDCOUNT(p) > 1) @@ -227,8 +261,6 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { if (!ratelimit_below(&s->ratelimit)) return -EBUSY; - family = s->family; - if (family == AF_INET) { addr.in = LLMNR_MULTICAST_IPV4_ADDRESS; fd = manager_llmnr_ipv4_udp_fd(s->manager); @@ -240,20 +272,20 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { if (fd < 0) return fd; - r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, NULL, p); + r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, LLMNR_PORT, NULL, p); if (r < 0) return r; break; + } - case DNS_PROTOCOL_MDNS: + case DNS_PROTOCOL_MDNS: { + union in_addr_union addr; assert(fd < 0); if (!ratelimit_below(&s->ratelimit)) return -EBUSY; - family = s->family; - if (family == AF_INET) { addr.in = MDNS_MULTICAST_IPV4_ADDRESS; fd = manager_mdns_ipv4_fd(s->manager); @@ -265,11 +297,12 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { if (fd < 0) return fd; - r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, NULL, p); + r = manager_send(s->manager, fd, s->link->ifindex, family, &addr, MDNS_PORT, NULL, p); if (r < 0) return r; break; + } default: return -EAFNOSUPPORT; @@ -278,7 +311,7 @@ static int dns_scope_emit_one(DnsScope *s, int fd, DnsPacket *p) { return 1; } -int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p) { +int dns_scope_emit_udp(DnsScope *s, int fd, int af, DnsPacket *p) { int r; assert(s); @@ -293,7 +326,7 @@ int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p) { dns_packet_set_flags(p, true, true); } - r = dns_scope_emit_one(s, fd, p); + r = dns_scope_emit_one(s, fd, af, p); if (r < 0) return r; @@ -407,14 +440,51 @@ static int dns_scope_socket( r = socket_set_recvpktinfo(fd, sa.sa.sa_family, true); if (r < 0) return r; + + /* Turn of path MTU discovery for security reasons */ + r = socket_disable_pmtud(fd, sa.sa.sa_family); + if (r < 0) + log_debug_errno(r, "Failed to disable UDP PMTUD, ignoring: %m"); + + /* Learn about fragmentation taking place */ + r = socket_set_recvfragsize(fd, sa.sa.sa_family, true); + if (r < 0) + log_debug_errno(r, "Failed to enable fragment size reception, ignoring: %m"); } if (ret_socket_address) *ret_socket_address = sa; else { + bool bound = false; + + /* Let's temporarily bind the socket to the specified ifindex. The kernel currently takes + * only the SO_BINDTODEVICE/SO_BINDTOINDEX ifindex into account when making routing decisions + * in connect() — and not IP_UNICAST_IF. We don't really want any of the other semantics of + * SO_BINDTODEVICE/SO_BINDTOINDEX, hence we immediately unbind the socket after the fact + * again. + * + * As a special exception we don't do this if we notice that the specified IP address is on + * the local host. SO_BINDTODEVICE in combination with destination addresses on the local + * host result in EHOSTUNREACH, since Linux won't send the packets out of the specified + * interface, but delivers them directly to the local socket. */ + if (s->link && + !manager_find_link_address(s->manager, sa.sa.sa_family, sockaddr_in_addr(&sa.sa))) { + r = socket_bind_to_ifindex(fd, ifindex); + if (r < 0) + return r; + + bound = true; + } + r = connect(fd, &sa.sa, salen); if (r < 0 && errno != EINPROGRESS) return -errno; + + if (bound) { + r = socket_bind_to_ifindex(fd, 0); + if (r < 0) + return r; + } } return TAKE_FD(fd); @@ -432,7 +502,7 @@ int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *add return dns_scope_socket(s, SOCK_STREAM, family, address, server, port, ret_socket_address); } -static DnsScopeMatch accept_link_local_reverse_lookups(const char *domain) { +static DnsScopeMatch match_link_local_reverse_lookups(const char *domain) { assert(domain); if (dns_name_endswith(domain, "254.169.in-addr.arpa") > 0) @@ -447,6 +517,65 @@ static DnsScopeMatch accept_link_local_reverse_lookups(const char *domain) { return _DNS_SCOPE_MATCH_INVALID; } +static DnsScopeMatch match_subnet_reverse_lookups( + DnsScope *s, + const char *domain, + bool exclude_own) { + + union in_addr_union ia; + LinkAddress *a; + int f, r; + + assert(s); + assert(domain); + + /* Checks whether the specified domain is a reverse address domain (i.e. in the .in-addr.arpa or + * .ip6.arpa area), and if so, whether the address matches any of the local subnets of the link the + * scope is associated with. If so, our scope should consider itself relevant for any lookup in the + * domain, since it apparently refers to hosts on this link's subnet. + * + * If 'exclude_own' is true this will return DNS_SCOPE_NO for any IP addresses assigned locally. This + * is useful for LLMNR/mDNS as we never want to look up our own hostname on LLMNR/mDNS but always use + * the locally synthesized one. */ + + if (!s->link) + return _DNS_SCOPE_MATCH_INVALID; /* No link, hence no local addresses to check */ + + r = dns_name_address(domain, &f, &ia); + if (r < 0) + log_debug_errno(r, "Failed to determine whether '%s' is an address domain: %m", domain); + if (r <= 0) + return _DNS_SCOPE_MATCH_INVALID; + + if (s->family != AF_UNSPEC && f != s->family) + return _DNS_SCOPE_MATCH_INVALID; /* Don't look for IPv4 addresses on LLMNR/mDNS over IPv6 and vice versa */ + + LIST_FOREACH(addresses, a, s->link->addresses) { + + if (a->family != f) + continue; + + /* Equals our own address? nah, let's not use this scope. The local synthesizer will pick it up for us. */ + if (exclude_own && + in_addr_equal(f, &a->in_addr, &ia) > 0) + return DNS_SCOPE_NO; + + if (a->prefixlen == UCHAR_MAX) /* don't know subnet mask */ + continue; + + /* Check if the address is in the local subnet */ + r = in_addr_prefix_covers(f, &a->in_addr, a->prefixlen, &ia); + if (r < 0) + log_debug_errno(r, "Failed to determine whether link address covers lookup address '%s': %m", domain); + if (r > 0) + /* Note that we only claim zero labels match. This is so that this is at the same + * priority a DNS scope with "." as routing domain is. */ + return DNS_SCOPE_YES_BASE + 0; + } + + return _DNS_SCOPE_MATCH_INVALID; +} + DnsScopeMatch dns_scope_good_domain( DnsScope *s, int ifindex, @@ -475,7 +604,7 @@ DnsScopeMatch dns_scope_good_domain( if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex)) return DNS_SCOPE_NO; - if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, 0) & flags) == 0) + if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, false, false) & flags) == 0) return DNS_SCOPE_NO; /* Never resolve any loopback hostname or IP address via DNS, LLMNR or mDNS. Instead, always rely on @@ -495,19 +624,15 @@ DnsScopeMatch dns_scope_good_domain( if (dns_name_endswith(domain, "invalid") > 0) return DNS_SCOPE_NO; - /* Never go to network for the _gateway domain, it's something special, synthesized locally. Note - * that we don't use is_gateway_hostname() here, since that has support for the legacy "gateway" - * hostname (without the prefix underscore), which we don't want to filter on all protocols. i.e. we - * don't want to filter "gateway" on classic DNS, since there might very well be such a host inside - * some search domain, and we shouldn't block that. We do filter it in LLMNR however (and on mDNS by - * side-effect, since it's a single-label name which mDNS doesn't accept anyway). */ - if (dns_name_equal(domain, "_gateway") > 0) + /* Never go to network for the _gateway domain, it's something special, synthesized locally. */ + if (is_gateway_hostname(domain)) return DNS_SCOPE_NO; switch (s->protocol) { case DNS_PROTOCOL_DNS: { bool has_search_domains = false; + DnsScopeMatch m; int n_best = -1; /* Never route things to scopes that lack DNS servers */ @@ -546,29 +671,36 @@ DnsScopeMatch dns_scope_good_domain( return DNS_SCOPE_YES_BASE + n_best; } - /* See if this scope is suitable as default route. */ + /* Exclude link-local IP ranges */ + if (match_link_local_reverse_lookups(domain) >= DNS_SCOPE_YES_BASE || + /* If networks use .local in their private setups, they are supposed to also add .local + * to their search domains, which we already checked above. Otherwise, we consider .local + * specific to mDNS and won't send such queries ordinary DNS servers. */ + dns_name_endswith(domain, "local") > 0) + return DNS_SCOPE_NO; + + /* If the IP address to look up matches the local subnet, then implicitly synthesizes + * DNS_SCOPE_YES_BASE + 0 on this interface, i.e. preferably resolve IP addresses via the DNS + * server belonging to this interface. */ + m = match_subnet_reverse_lookups(s, domain, false); + if (m >= 0) + return m; + + /* If there was no match at all, then see if this scope is suitable as default route. */ if (!dns_scope_is_default_route(s)) return DNS_SCOPE_NO; - /* Exclude link-local IP ranges */ - if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && - dns_name_endswith(domain, "8.e.f.ip6.arpa") == 0 && - dns_name_endswith(domain, "9.e.f.ip6.arpa") == 0 && - dns_name_endswith(domain, "a.e.f.ip6.arpa") == 0 && - dns_name_endswith(domain, "b.e.f.ip6.arpa") == 0 && - /* If networks use .local in their private setups, they are supposed to also add .local to their search - * domains, which we already checked above. Otherwise, we consider .local specific to mDNS and won't - * send such queries ordinary DNS servers. */ - dns_name_endswith(domain, "local") == 0) - return DNS_SCOPE_MAYBE; - - return DNS_SCOPE_NO; + return DNS_SCOPE_MAYBE; } case DNS_PROTOCOL_MDNS: { DnsScopeMatch m; - m = accept_link_local_reverse_lookups(domain); + m = match_link_local_reverse_lookups(domain); + if (m >= 0) + return m; + + m = match_subnet_reverse_lookups(s, domain, true); if (m >= 0) return m; @@ -587,7 +719,11 @@ DnsScopeMatch dns_scope_good_domain( case DNS_PROTOCOL_LLMNR: { DnsScopeMatch m; - m = accept_link_local_reverse_lookups(domain); + m = match_link_local_reverse_lookups(domain); + if (m >= 0) + return m; + + m = match_subnet_reverse_lookups(s, domain, true); if (m >= 0) return m; @@ -624,11 +760,10 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) { assert(s); assert(key); - /* Check if it makes sense to resolve the specified key on - * this scope. Note that this call assumes as fully qualified - * name, i.e. the search suffixes already appended. */ + /* Check if it makes sense to resolve the specified key on this scope. Note that this call assumes a + * fully qualified name, i.e. the search suffixes already appended. */ - if (key->class != DNS_CLASS_IN) + if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY)) return false; if (s->protocol == DNS_PROTOCOL_DNS) { @@ -650,8 +785,11 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key) { return !dns_name_is_root(name); } - /* On mDNS and LLMNR, send A and AAAA queries only on the - * respective scopes */ + /* Never route DNSSEC RR queries to LLMNR/mDNS scopes */ + if (dns_type_is_dnssec(key->type)) + return false; + + /* On mDNS and LLMNR, send A and AAAA queries only on the respective scopes */ key_family = dns_type_to_af(key->type); if (key_family < 0) @@ -743,7 +881,9 @@ int dns_scope_make_reply_packet( DnsPacket **ret) { _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + unsigned n_answer = 0, n_soa = 0; int r; + bool c_or_aa; assert(s); assert(ret); @@ -757,11 +897,14 @@ int dns_scope_make_reply_packet( if (r < 0) return r; + /* mDNS answers must have the Authoritative Answer bit set, see RFC 6762, section 18.4. */ + c_or_aa = s->protocol == DNS_PROTOCOL_MDNS; + DNS_PACKET_HEADER(p)->id = id; DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS( 1 /* qr */, 0 /* opcode */, - 0 /* c */, + c_or_aa, 0 /* tc */, tentative, 0 /* (ra) */, @@ -774,15 +917,15 @@ int dns_scope_make_reply_packet( return r; DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q)); - r = dns_packet_append_answer(p, answer); + r = dns_packet_append_answer(p, answer, &n_answer); if (r < 0) return r; - DNS_PACKET_HEADER(p)->ancount = htobe16(dns_answer_size(answer)); + DNS_PACKET_HEADER(p)->ancount = htobe16(n_answer); - r = dns_packet_append_answer(p, soa); + r = dns_packet_append_answer(p, soa, &n_soa); if (r < 0) return r; - DNS_PACKET_HEADER(p)->arcount = htobe16(dns_answer_size(soa)); + DNS_PACKET_HEADER(p)->arcount = htobe16(n_soa); *ret = TAKE_PTR(p); @@ -821,10 +964,10 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { * the LLMNR multicast addresses. See RFC 4795, * section 2.5. */ - if (p->family == AF_INET && !in_addr_equal(AF_INET, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV4_ADDRESS)) + if (p->family == AF_INET && !in4_addr_equal(&p->destination.in, &LLMNR_MULTICAST_IPV4_ADDRESS)) return; - if (p->family == AF_INET6 && !in_addr_equal(AF_INET6, &p->destination, (union in_addr_union*) &LLMNR_MULTICAST_IPV6_ADDRESS)) + if (p->family == AF_INET6 && !in6_addr_equal(&p->destination.in6, &LLMNR_MULTICAST_IPV6_ADDRESS)) return; } @@ -904,26 +1047,50 @@ void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p) { } } -DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok) { - DnsTransaction *t; +DnsTransaction *dns_scope_find_transaction( + DnsScope *scope, + DnsResourceKey *key, + uint64_t query_flags) { + + DnsTransaction *first, *t; assert(scope); assert(key); - /* Try to find an ongoing transaction that is a equal to the - * specified question */ - t = hashmap_get(scope->transactions_by_key, key); - if (!t) - return NULL; + /* Iterate through the list of transactions with a matching key */ + first = hashmap_get(scope->transactions_by_key, key); + LIST_FOREACH(transactions_by_key, t, first) { - /* Refuse reusing transactions that completed based on cached - * data instead of a real packet, if that's requested. */ - if (!cache_ok && - IN_SET(t->state, DNS_TRANSACTION_SUCCESS, DNS_TRANSACTION_RCODE_FAILURE) && - t->answer_source != DNS_TRANSACTION_NETWORK) - return NULL; + /* These four flags must match exactly: we cannot use a validated response for a + * non-validating client, and we cannot use a non-validated response for a validating + * client. Similar, if the sources don't match things aren't usable either. */ + if (((query_flags ^ t->query_flags) & + (SD_RESOLVED_NO_VALIDATE| + SD_RESOLVED_NO_ZONE| + SD_RESOLVED_NO_TRUST_ANCHOR| + SD_RESOLVED_NO_NETWORK)) != 0) + continue; - return t; + /* We can reuse a primary query if a regular one is requested, but not vice versa */ + if ((query_flags & SD_RESOLVED_REQUIRE_PRIMARY) && + !(t->query_flags & SD_RESOLVED_REQUIRE_PRIMARY)) + continue; + + /* Don't reuse a transaction that allowed caching when we got told not to use it */ + if ((query_flags & SD_RESOLVED_NO_CACHE) && + !(t->query_flags & SD_RESOLVED_NO_CACHE)) + continue; + + /* If we are asked to clamp ttls an the existing transaction doesn't do it, we can't + * reuse */ + if ((query_flags & SD_RESOLVED_CLAMP_TTL) && + !(t->query_flags & SD_RESOLVED_CLAMP_TTL)) + continue; + + return t; + } + + return NULL; } static int dns_scope_make_conflict_packet( @@ -980,7 +1147,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata assert(es); assert(scope); - scope->conflict_event_source = sd_event_source_unref(scope->conflict_event_source); + scope->conflict_event_source = sd_event_source_disable_unref(scope->conflict_event_source); for (;;) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; @@ -1000,7 +1167,7 @@ static int on_conflict_dispatch(sd_event_source *es, usec_t usec, void *userdata return 0; } - r = dns_scope_emit_udp(scope, -1, p); + r = dns_scope_emit_udp(scope, -1, AF_UNSPEC, p); if (r < 0) log_debug_errno(r, "Failed to send conflict packet: %m"); } @@ -1077,7 +1244,7 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p) { return; } - if (manager_our_packet(scope->manager, p)) + if (manager_packet_from_local_address(scope->manager, p)) return; r = dns_packet_extract(p); @@ -1191,7 +1358,7 @@ static int on_announcement_timeout(sd_event_source *s, usec_t usec, void *userda assert(s); - scope->announce_event_source = sd_event_source_unref(scope->announce_event_source); + scope->announce_event_source = sd_event_source_disable_unref(scope->announce_event_source); (void) dns_scope_announce(scope, false); return 0; @@ -1267,7 +1434,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) { else flags = goodbye ? (DNS_ANSWER_GOODBYE|DNS_ANSWER_CACHE_FLUSH) : DNS_ANSWER_CACHE_FLUSH; - r = dns_answer_add(answer, i->rr, 0 , flags); + r = dns_answer_add(answer, i->rr, 0, flags, NULL); if (r < 0) return log_debug_errno(r, "Failed to add RR to announce: %m"); } @@ -1285,7 +1452,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) { if (r < 0) log_warning_errno(r, "Failed to add DNS-SD PTR record to MDNS zone: %m"); - r = dns_answer_add(answer, rr, 0 , 0); + r = dns_answer_add(answer, rr, 0, 0, NULL); if (r < 0) return log_debug_errno(r, "Failed to add RR to announce: %m"); } @@ -1297,7 +1464,7 @@ int dns_scope_announce(DnsScope *scope, bool goodbye) { if (r < 0) return log_debug_errno(r, "Failed to build reply packet: %m"); - r = dns_scope_emit_udp(scope, -1, p); + r = dns_scope_emit_udp(scope, -1, AF_UNSPEC, p); if (r < 0) return log_debug_errno(r, "Failed to send reply packet: %m"); diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index de05c0838..f63452330 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -22,7 +22,7 @@ typedef enum DnsScopeMatch { DNS_SCOPE_YES_BASE, /* Add the number of matching labels to this */ DNS_SCOPE_YES_END = DNS_SCOPE_YES_BASE + DNS_N_LABELS_MAX, _DNS_SCOPE_MATCH_MAX, - _DNS_SCOPE_MATCH_INVALID = -1 + _DNS_SCOPE_MATCH_INVALID = -EINVAL, } DnsScopeMatch; struct DnsScope { @@ -53,14 +53,12 @@ struct DnsScope { LIST_HEAD(DnsQueryCandidate, query_candidates); - /* Note that we keep track of ongoing transactions in two - * ways: once in a hashmap, indexed by the rr key, and once in - * a linked list. We use the hashmap to quickly find - * transactions we can reuse for a key. But note that there - * might be multiple transactions for the same key (because - * the zone probing can't reuse a transaction answered from - * the zone or the cache), and the hashmap only tracks the - * most recent entry. */ + /* Note that we keep track of ongoing transactions in two ways: once in a hashmap, indexed by the rr + * key, and once in a linked list. We use the hashmap to quickly find transactions we can reuse for a + * key. But note that there might be multiple transactions for the same key (because the associated + * query flags might differ in incompatible ways: e.g. we may not reuse a non-validating transaction + * as validating. Hence we maintain a per-key list of transactions, which we iterate through to find + * one we can reuse with matching flags. */ Hashmap *transactions_by_key; LIST_HEAD(DnsTransaction, transactions); @@ -73,7 +71,7 @@ DnsScope* dns_scope_free(DnsScope *s); void dns_scope_packet_received(DnsScope *s, usec_t rtt); void dns_scope_packet_lost(DnsScope *s, usec_t usec); -int dns_scope_emit_udp(DnsScope *s, int fd, DnsPacket *p); +int dns_scope_emit_udp(DnsScope *s, int fd, int af, DnsPacket *p); int dns_scope_socket_tcp(DnsScope *s, int family, const union in_addr_union *address, DnsServer *server, uint16_t port, union sockaddr_union *ret_socket_address); int dns_scope_socket_udp(DnsScope *s, DnsServer *server); @@ -82,7 +80,7 @@ bool dns_scope_good_key(DnsScope *s, const DnsResourceKey *key); DnsServer *dns_scope_get_dns_server(DnsScope *s); unsigned dns_scope_get_n_dns_servers(DnsScope *s); -void dns_scope_next_dns_server(DnsScope *s); +void dns_scope_next_dns_server(DnsScope *s, DnsServer *if_current); int dns_scope_llmnr_membership(DnsScope *s, bool b); int dns_scope_mdns_membership(DnsScope *s, bool b); @@ -90,7 +88,7 @@ int dns_scope_mdns_membership(DnsScope *s, bool b); int dns_scope_make_reply_packet(DnsScope *s, uint16_t id, int rcode, DnsQuestion *q, DnsAnswer *answer, DnsAnswer *soa, bool tentative, DnsPacket **ret); void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p); -DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, bool cache_ok); +DnsTransaction *dns_scope_find_transaction(DnsScope *scope, DnsResourceKey *key, uint64_t query_flags); int dns_scope_notify_conflict(DnsScope *scope, DnsResourceRecord *rr); void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p); diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c index a01f3dced..94a46570f 100644 --- a/src/resolve/resolved-dns-search-domain.c +++ b/src/resolve/resolved-dns-search-domain.c @@ -151,18 +151,22 @@ void dns_search_domain_unlink_all(DnsSearchDomain *first) { dns_search_domain_unlink_all(next); } -void dns_search_domain_unlink_marked(DnsSearchDomain *first) { +bool dns_search_domain_unlink_marked(DnsSearchDomain *first) { DnsSearchDomain *next; + bool changed; if (!first) - return; + return false; next = first->domains_next; - if (first->marked) + if (first->marked) { dns_search_domain_unlink(first); + changed = true; + } else + changed = false; - dns_search_domain_unlink_marked(next); + return changed || dns_search_domain_unlink_marked(next); } void dns_search_domain_mark_all(DnsSearchDomain *first) { diff --git a/src/resolve/resolved-dns-search-domain.h b/src/resolve/resolved-dns-search-domain.h index ea91a4e2a..f0d96aca3 100644 --- a/src/resolve/resolved-dns-search-domain.h +++ b/src/resolve/resolved-dns-search-domain.h @@ -44,7 +44,7 @@ void dns_search_domain_unlink(DnsSearchDomain *d); void dns_search_domain_move_back_and_unmark(DnsSearchDomain *d); void dns_search_domain_unlink_all(DnsSearchDomain *first); -void dns_search_domain_unlink_marked(DnsSearchDomain *first); +bool dns_search_domain_unlink_marked(DnsSearchDomain *first); void dns_search_domain_mark_all(DnsSearchDomain *first); int dns_search_domain_find(DnsSearchDomain *first, const char *name, DnsSearchDomain **ret); diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c index 811237406..073489aca 100644 --- a/src/resolve/resolved-dns-server.c +++ b/src/resolve/resolved-dns-server.c @@ -240,6 +240,7 @@ static void dns_server_reset_counters(DnsServer *s) { s->n_failed_tcp = 0; s->n_failed_tls = 0; s->packet_truncated = false; + s->packet_invalid = false; s->verified_usec = 0; /* Note that we do not reset s->packet_bad_opt and s->packet_rrsig_missing here. We reset them only when the @@ -254,7 +255,7 @@ static void dns_server_reset_counters(DnsServer *s) { * incomplete. */ } -void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, size_t size) { +void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, size_t fragsize) { assert(s); if (protocol == IPPROTO_UDP) { @@ -281,33 +282,33 @@ void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLeve if (s->packet_bad_opt && level >= DNS_SERVER_FEATURE_LEVEL_EDNS0) level = DNS_SERVER_FEATURE_LEVEL_EDNS0 - 1; - /* Even if we successfully receive a reply to a request announcing support for large packets, - that does not mean we can necessarily receive large packets. */ + /* Even if we successfully receive a reply to a request announcing support for large packets, that + * does not mean we can necessarily receive large packets. */ if (level == DNS_SERVER_FEATURE_LEVEL_LARGE) level = DNS_SERVER_FEATURE_LEVEL_LARGE - 1; dns_server_verified(s, level); - /* Remember the size of the largest UDP packet we received from a server, - we know that we can always announce support for packets with at least - this size. */ - if (protocol == IPPROTO_UDP && s->received_udp_packet_max < size) - s->received_udp_packet_max = size; + /* Remember the size of the largest UDP packet fragment we received from a server, we know that we + * can always announce support for packets with at least this size. */ + if (protocol == IPPROTO_UDP && s->received_udp_fragment_max < fragsize) + s->received_udp_fragment_max = fragsize; } void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level) { assert(s); assert(s->manager); - if (s->possible_feature_level == level) { - if (protocol == IPPROTO_UDP) - s->n_failed_udp++; - else if (protocol == IPPROTO_TCP) { - if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(level)) - s->n_failed_tls++; - else - s->n_failed_tcp++; - } + if (s->possible_feature_level != level) + return; + + if (protocol == IPPROTO_UDP) + s->n_failed_udp++; + else if (protocol == IPPROTO_TCP) { + if (DNS_SERVER_FEATURE_LEVEL_IS_TLS(level)) + s->n_failed_tls++; + else + s->n_failed_tcp++; } } @@ -366,6 +367,41 @@ void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level log_debug("Downgrading transaction feature level fixed an RCODE error, downgrading server %s too.", strna(dns_server_string_full(s))); } +void dns_server_packet_invalid(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + /* Invoked whenever we got a packet we couldn't parse at all */ + + if (s->possible_feature_level != level) + return; + + s->packet_invalid = true; +} + +void dns_server_packet_do_off(DnsServer *s, DnsServerFeatureLevel level) { + assert(s); + + /* Invoked whenever the DO flag was not copied from our request to the response. */ + + if (s->possible_feature_level != level) + return; + + s->packet_do_off = true; +} + +void dns_server_packet_udp_fragmented(DnsServer *s, size_t fragsize) { + assert(s); + + /* Invoked whenever we got a fragmented UDP packet. Let's do two things: keep track of the largest + * fragment we ever received from the server, and remember this, so that we can use it to lower the + * advertised packet size in EDNS0 */ + + if (s->received_udp_fragment_max < fragsize) + s->received_udp_fragment_max = fragsize; + + s->packet_fragmented = true; +} + static bool dns_server_grace_period_expired(DnsServer *s) { usec_t ts; @@ -434,21 +470,46 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { * work. Upgrade back to UDP again. */ log_debug("Reached maximum number of failed TCP connection attempts, trying UDP again..."); s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP; + } else if (s->n_failed_tls > 0 && - DNS_SERVER_FEATURE_LEVEL_IS_TLS(s->possible_feature_level) && dns_server_get_dns_over_tls_mode(s) != DNS_OVER_TLS_YES) { + DNS_SERVER_FEATURE_LEVEL_IS_TLS(s->possible_feature_level) && + dns_server_get_dns_over_tls_mode(s) != DNS_OVER_TLS_YES) { /* We tried to connect using DNS-over-TLS, and it didn't work. Downgrade to plaintext UDP * if we don't require DNS-over-TLS */ log_debug("Server doesn't support DNS-over-TLS, downgrading protocol..."); s->possible_feature_level--; - } else if (s->packet_bad_opt && - s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_EDNS0) { - /* A reply to one of our EDNS0 queries didn't carry a valid OPT RR, then downgrade to below - * EDNS0 levels. After all, some records generate different responses with and without OPT RR - * in the request. Example: - * https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html */ + } else if (s->packet_invalid && + s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP && + s->possible_feature_level != DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN) { + + /* Downgrade from DO to EDNS0 + from EDNS0 to UDP, from TLS+DO to plain TLS. Or in + * other words, if we receive a packet we cannot parse jump to the next lower feature + * level that actually has an influence on the packet layout (and not just the + * transport). */ + + log_debug("Got invalid packet from server, downgrading protocol..."); + s->possible_feature_level = + s->possible_feature_level == DNS_SERVER_FEATURE_LEVEL_TLS_DO ? DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN : + DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level) ? DNS_SERVER_FEATURE_LEVEL_EDNS0 : + DNS_SERVER_FEATURE_LEVEL_UDP; + + } else if (s->packet_bad_opt && + DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(s->possible_feature_level) && + dns_server_get_dnssec_mode(s) != DNSSEC_YES && + dns_server_get_dns_over_tls_mode(s) != DNS_OVER_TLS_YES) { + + /* A reply to one of our EDNS0 queries didn't carry a valid OPT RR, then downgrade to + * below EDNS0 levels. After all, some servers generate different responses with and + * without OPT RR in the request. Example: + * + * https://open.nlnetlabs.nl/pipermail/dnssec-trigger/2014-November/000376.html + * + * If we are in strict DNSSEC or DoT mode, we don't do this kind of downgrade + * however, as both modes imply EDNS0 to work (DNSSEC strictly requires it, and DoT + * only in our implementation). */ log_debug("Server doesn't support EDNS(0) properly, downgrading feature level..."); s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP; @@ -457,43 +518,69 @@ DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s) { * when we can't use EDNS because the DNS server doesn't support it. */ log_level = LOG_NOTICE; - } else if (s->packet_rrsig_missing && - s->possible_feature_level >= DNS_SERVER_FEATURE_LEVEL_DO) { + } else if (s->packet_do_off && + DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level) && + dns_server_get_dnssec_mode(s) != DNSSEC_YES) { - /* RRSIG data was missing on a EDNS0 packet with DO bit set. This means the server doesn't - * augment responses with DNSSEC RRs. If so, let's better not ask the server for it anymore, - * after all some servers generate different replies depending if an OPT RR is in the query or - * not. */ + /* The server didn't copy the DO bit from request to response, thus DNSSEC is not + * correctly implemented, let's downgrade if that's allowed. */ + + log_debug("Detected server didn't copy DO flag from request to response, downgrading feature level..."); + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_IS_TLS(s->possible_feature_level) ? DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN : + DNS_SERVER_FEATURE_LEVEL_EDNS0; + + } else if (s->packet_rrsig_missing && + DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level) && + dns_server_get_dnssec_mode(s) != DNSSEC_YES) { + + /* RRSIG data was missing on a EDNS0 packet with DO bit set. This means the server + * doesn't augment responses with DNSSEC RRs. If so, let's better not ask the server + * for it anymore, after all some servers generate different replies depending if an + * OPT RR is in the query or not. If we are in strict DNSSEC mode, don't allow such + * downgrades however, since a DNSSEC feature level is a requirement for strict + * DNSSEC mode. */ log_debug("Detected server responses lack RRSIG records, downgrading feature level..."); - s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_IS_TLS(s->possible_feature_level) ? DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN : DNS_SERVER_FEATURE_LEVEL_EDNS0; + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_IS_TLS(s->possible_feature_level) ? DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN : + DNS_SERVER_FEATURE_LEVEL_EDNS0; } else if (s->n_failed_udp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && - s->possible_feature_level >= (dns_server_get_dnssec_mode(s) == DNSSEC_YES ? DNS_SERVER_FEATURE_LEVEL_LARGE : DNS_SERVER_FEATURE_LEVEL_UDP)) { + DNS_SERVER_FEATURE_LEVEL_IS_UDP(s->possible_feature_level) && + ((s->possible_feature_level != DNS_SERVER_FEATURE_LEVEL_DO) || dns_server_get_dnssec_mode(s) != DNSSEC_YES)) { - /* We lost too many UDP packets in a row, and are on a feature level of UDP or higher. If the - * packets are lost, maybe the server cannot parse them, hence downgrading sounds like a good - * idea. We might downgrade all the way down to TCP this way. + /* We lost too many UDP packets in a row, and are on an UDP feature level. If the + * packets are lost, maybe the server cannot parse them, hence downgrading sounds + * like a good idea. We might downgrade all the way down to TCP this way. * * If strict DNSSEC mode is used we won't downgrade below DO level however, as packet loss * might have many reasons, a broken DNSSEC implementation being only one reason. And if the * user is strict on DNSSEC, then let's assume that DNSSEC is not the fault here. */ log_debug("Lost too many UDP packets, downgrading feature level..."); - s->possible_feature_level--; + if (s->possible_feature_level == DNS_SERVER_FEATURE_LEVEL_DO) /* skip over TLS_PLAIN */ + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_EDNS0; + else + s->possible_feature_level--; } else if (s->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS && s->packet_truncated && - s->possible_feature_level > (dns_server_get_dnssec_mode(s) == DNSSEC_YES ? DNS_SERVER_FEATURE_LEVEL_LARGE : DNS_SERVER_FEATURE_LEVEL_UDP)) { + s->possible_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP && + DNS_SERVER_FEATURE_LEVEL_IS_UDP(s->possible_feature_level) && + (!DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level) || dns_server_get_dnssec_mode(s) != DNSSEC_YES)) { - /* We got too many TCP connection failures in a row, we had at least one truncated packet, and - * are on a feature level above UDP. By downgrading things and getting rid of DNSSEC or EDNS0 - * data we hope to make the packet smaller, so that it still works via UDP given that TCP - * appears not to be a fallback. Note that if we are already at the lowest UDP level, we don't - * go further down, since that's TCP, and TCP failed too often after all. */ + /* We got too many TCP connection failures in a row, we had at least one truncated + * packet, and are on feature level above UDP. By downgrading things and getting rid + * of DNSSEC or EDNS0 data we hope to make the packet smaller, so that it still + * works via UDP given that TCP appears not to be a fallback. Note that if we are + * already at the lowest UDP level, we don't go further down, since that's TCP, and + * TCP failed too often after all. */ log_debug("Got too many failed TCP connection failures and truncated UDP packets, downgrading feature level..."); - s->possible_feature_level--; + + if (DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(s->possible_feature_level)) + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_EDNS0; /* Go DNSSEC → EDNS0 */ + else + s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_UDP; /* Go EDNS0 → UDP */ } if (p != s->possible_feature_level) { @@ -530,12 +617,49 @@ int dns_server_adjust_opt(DnsServer *server, DnsPacket *packet, DnsServerFeature edns_do = level >= DNS_SERVER_FEATURE_LEVEL_DO; - if (level >= DNS_SERVER_FEATURE_LEVEL_LARGE) - packet_size = DNS_PACKET_UNICAST_SIZE_LARGE_MAX; - else - packet_size = server->received_udp_packet_max; + if (level == DNS_SERVER_FEATURE_LEVEL_LARGE) { + size_t udp_size; - return dns_packet_append_opt(packet, packet_size, edns_do, /* include_rfc6975 = */ true, 0, NULL); + /* In large mode, advertise the local MTU, in order to avoid fragmentation (for security + * reasons) – except if we are talking to localhost (where the security considerations don't + * matter). If we see fragmentation, lower the reported size to the largest fragment, to + * avoid it. */ + + udp_size = udp_header_size(server->family); + + if (in_addr_is_localhost(server->family, &server->address) > 0) + packet_size = 65536 - udp_size; /* force linux loopback MTU if localhost address */ + else { + /* Use the MTU pointing to the server, subtract the IP/UDP header size */ + packet_size = LESS_BY(dns_server_get_mtu(server), udp_size); + + /* On the Internet we want to avoid fragmentation for security reasons. If we saw + * fragmented packets, the above was too large, let's clamp it to the largest + * fragment we saw */ + if (server->packet_fragmented) + packet_size = MIN(server->received_udp_fragment_max, packet_size); + + /* Let's not pick ridiculously large sizes, i.e. not more than 4K. No one appears + * to ever use such large sized on the Internet IRL, hence let's not either. */ + packet_size = MIN(packet_size, 4096U); + } + + /* Strictly speaking we quite possibly can receive larger datagrams than the MTU (since the + * MTU is for egress, not for ingress), but more often than not the value is symmetric, and + * we want something that does the right thing in the majority of cases, and not just in the + * theoretical edge case. */ + } else + /* In non-large mode, let's advertise the size of the largest fragment we ever managed to accept. */ + packet_size = server->received_udp_fragment_max; + + /* Safety clamp, never advertise less than 512 or more than 65535 */ + packet_size = CLAMP(packet_size, + DNS_PACKET_UNICAST_SIZE_MAX, + DNS_PACKET_SIZE_MAX); + + log_debug("Announcing packet size %zu in egress EDNS(0) packet.", packet_size); + + return dns_packet_append_opt(packet, packet_size, edns_do, /* include_rfc6975 = */ true, NULL, 0, NULL); } int dns_server_ifindex(const DnsServer *s) { @@ -589,7 +713,10 @@ bool dns_server_dnssec_supported(DnsServer *server) { /* Returns whether the server supports DNSSEC according to what we know about it */ - if (server->possible_feature_level < DNS_SERVER_FEATURE_LEVEL_DO) + if (dns_server_get_dnssec_mode(server) == DNSSEC_YES) /* If strict DNSSEC mode is enabled, always assume DNSSEC mode is supported. */ + return true; + + if (!DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(server->possible_feature_level)) return false; if (server->packet_bad_opt) @@ -598,6 +725,9 @@ bool dns_server_dnssec_supported(DnsServer *server) { if (server->packet_rrsig_missing) return false; + if (server->packet_do_off) + return false; + /* DNSSEC servers need to support TCP properly (see RFC5966), if they don't, we assume DNSSEC is borked too */ if (server->n_failed_tcp >= DNS_SERVER_FEATURE_RETRY_ATTEMPTS) return false; @@ -620,6 +750,15 @@ void dns_server_warn_downgrade(DnsServer *server) { server->warned_downgrade = true; } +size_t dns_server_get_mtu(DnsServer *s) { + assert(s); + + if (s->link && s->link->mtu != 0) + return s->link->mtu; + + return manager_find_mtu(s->manager); +} + static void dns_server_hash_func(const DnsServer *s, struct siphash *state) { assert(s); @@ -666,18 +805,22 @@ void dns_server_unlink_all(DnsServer *first) { dns_server_unlink_all(next); } -void dns_server_unlink_marked(DnsServer *first) { +bool dns_server_unlink_marked(DnsServer *first) { DnsServer *next; + bool changed; if (!first) - return; + return false; next = first->servers_next; - if (first->marked) + if (first->marked) { + changed = true; dns_server_unlink(first); + } else + changed = false; - dns_server_unlink_marked(next); + return changed || dns_server_unlink_marked(next); } void dns_server_mark_all(DnsServer *first) { @@ -724,10 +867,11 @@ DnsServer *manager_set_dns_server(Manager *m, DnsServer *s) { if (m->current_dns_server == s) return s; + /* Let's log about the server switch, at debug level. Except if we switch from a non-fallback server + * to a fallback server or back, since that is noteworthy and possibly a configuration issue */ if (s) - log_debug("Switching to %s DNS server %s.", - dns_server_type_to_string(s->type), - strna(dns_server_string_full(s))); + log_full((s->type == DNS_SERVER_FALLBACK) != (m->current_dns_server && m->current_dns_server->type == DNS_SERVER_FALLBACK) ? LOG_NOTICE : LOG_DEBUG, + "Switching to %s DNS server %s.", dns_server_type_to_string(s->type), strna(dns_server_string_full(s))); dns_server_unref(m->current_dns_server); m->current_dns_server = dns_server_ref(s); @@ -771,23 +915,25 @@ DnsServer *manager_get_dns_server(Manager *m) { return m->current_dns_server; } -void manager_next_dns_server(Manager *m) { +void manager_next_dns_server(Manager *m, DnsServer *if_current) { assert(m); - /* If there's currently no DNS server set, then the next - * manager_get_dns_server() will find one */ + /* If the DNS server is already a different one than the one specified in 'if_current' don't do anything */ + if (if_current && m->current_dns_server != if_current) + return; + + /* If there's currently no DNS server set, then the next manager_get_dns_server() will find one */ if (!m->current_dns_server) return; - /* Change to the next one, but make sure to follow the linked - * list only if the server is still linked. */ + /* Change to the next one, but make sure to follow the linked list only if the server is still + * linked. */ if (m->current_dns_server->linked && m->current_dns_server->servers_next) { manager_set_dns_server(m, m->current_dns_server->servers_next); return; } - /* If there was no next one, then start from the beginning of - * the list */ + /* If there was no next one, then start from the beginning of the list */ if (m->current_dns_server->type == DNS_SERVER_FALLBACK) manager_set_dns_server(m, m->fallback_dns_servers); else @@ -837,10 +983,11 @@ void dns_server_reset_features(DnsServer *s) { s->verified_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; s->possible_feature_level = DNS_SERVER_FEATURE_LEVEL_BEST; - s->received_udp_packet_max = DNS_PACKET_UNICAST_SIZE_MAX; + s->received_udp_fragment_max = DNS_PACKET_UNICAST_SIZE_MAX; s->packet_bad_opt = false; s->packet_rrsig_missing = false; + s->packet_do_off = false; s->features_grace_period_usec = DNS_SERVER_FEATURE_GRACE_PERIOD_MIN_USEC; @@ -896,18 +1043,22 @@ void dns_server_dump(DnsServer *s, FILE *f) { fputc('\n', f); fprintf(f, - "\tMaximum UDP packet size received: %zu\n" + "\tMaximum UDP fragment size received: %zu\n" "\tFailed UDP attempts: %u\n" "\tFailed TCP attempts: %u\n" "\tSeen truncated packet: %s\n" "\tSeen OPT RR getting lost: %s\n" - "\tSeen RRSIG RR missing: %s\n", - s->received_udp_packet_max, + "\tSeen RRSIG RR missing: %s\n" + "\tSeen invalid packet: %s\n" + "\tServer dropped DO flag: %s\n", + s->received_udp_fragment_max, s->n_failed_udp, s->n_failed_tcp, yes_no(s->packet_truncated), yes_no(s->packet_bad_opt), - yes_no(s->packet_rrsig_missing)); + yes_no(s->packet_rrsig_missing), + yes_no(s->packet_invalid), + yes_no(s->packet_do_off)); } void dns_server_unref_stream(DnsServer *s) { diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 20afee74a..fe0eaee49 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -20,7 +20,7 @@ typedef enum DnsServerType { DNS_SERVER_FALLBACK, DNS_SERVER_LINK, _DNS_SERVER_TYPE_MAX, - _DNS_SERVER_TYPE_INVALID = -1 + _DNS_SERVER_TYPE_INVALID = -EINVAL, } DnsServerType; const char* dns_server_type_to_string(DnsServerType i) _const_; @@ -35,12 +35,15 @@ typedef enum DnsServerFeatureLevel { DNS_SERVER_FEATURE_LEVEL_LARGE, DNS_SERVER_FEATURE_LEVEL_TLS_DO, _DNS_SERVER_FEATURE_LEVEL_MAX, - _DNS_SERVER_FEATURE_LEVEL_INVALID = -1 + _DNS_SERVER_FEATURE_LEVEL_INVALID = -EINVAL, } DnsServerFeatureLevel; #define DNS_SERVER_FEATURE_LEVEL_WORST 0 #define DNS_SERVER_FEATURE_LEVEL_BEST (_DNS_SERVER_FEATURE_LEVEL_MAX - 1) +#define DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_EDNS0) #define DNS_SERVER_FEATURE_LEVEL_IS_TLS(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN, DNS_SERVER_FEATURE_LEVEL_TLS_DO) +#define DNS_SERVER_FEATURE_LEVEL_IS_DNSSEC(x) ((x) >= DNS_SERVER_FEATURE_LEVEL_DO) +#define DNS_SERVER_FEATURE_LEVEL_IS_UDP(x) IN_SET(x, DNS_SERVER_FEATURE_LEVEL_UDP, DNS_SERVER_FEATURE_LEVEL_EDNS0, DNS_SERVER_FEATURE_LEVEL_DO, DNS_SERVER_FEATURE_LEVEL_LARGE) const char* dns_server_feature_level_to_string(int i) _const_; int dns_server_feature_level_from_string(const char *s) _pure_; @@ -72,15 +75,18 @@ struct DnsServer { DnsServerFeatureLevel verified_feature_level; DnsServerFeatureLevel possible_feature_level; - size_t received_udp_packet_max; + size_t received_udp_fragment_max; /* largest packet or fragment (without IP/UDP header) we saw so far */ unsigned n_failed_udp; unsigned n_failed_tcp; unsigned n_failed_tls; - bool packet_truncated:1; - bool packet_bad_opt:1; - bool packet_rrsig_missing:1; + bool packet_truncated:1; /* Set when TC bit was set on reply */ + bool packet_bad_opt:1; /* Set when OPT was missing or otherwise bad on reply */ + bool packet_rrsig_missing:1; /* Set when RRSIG was missing */ + bool packet_invalid:1; /* Set when we failed to parse a reply */ + bool packet_do_off:1; /* Set when the server didn't copy DNSSEC DO flag from request to response */ + bool packet_fragmented:1; /* Set when we ever saw a fragmented packet */ usec_t verified_usec; usec_t features_grace_period_usec; @@ -113,12 +119,15 @@ DnsServer* dns_server_unref(DnsServer *s); void dns_server_unlink(DnsServer *s); void dns_server_move_back_and_unmark(DnsServer *s); -void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, size_t size); +void dns_server_packet_received(DnsServer *s, int protocol, DnsServerFeatureLevel level, size_t fragsize); void dns_server_packet_lost(DnsServer *s, int protocol, DnsServerFeatureLevel level); void dns_server_packet_truncated(DnsServer *s, DnsServerFeatureLevel level); void dns_server_packet_rrsig_missing(DnsServer *s, DnsServerFeatureLevel level); void dns_server_packet_bad_opt(DnsServer *s, DnsServerFeatureLevel level); void dns_server_packet_rcode_downgrade(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_invalid(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_do_off(DnsServer *s, DnsServerFeatureLevel level); +void dns_server_packet_udp_fragmented(DnsServer *s, size_t fragsize); DnsServerFeatureLevel dns_server_possible_feature_level(DnsServer *s); @@ -136,18 +145,20 @@ void dns_server_warn_downgrade(DnsServer *server); DnsServer *dns_server_find(DnsServer *first, int family, const union in_addr_union *in_addr, uint16_t port, int ifindex, const char *name); void dns_server_unlink_all(DnsServer *first); -void dns_server_unlink_marked(DnsServer *first); +bool dns_server_unlink_marked(DnsServer *first); void dns_server_mark_all(DnsServer *first); DnsServer *manager_get_first_dns_server(Manager *m, DnsServerType t); DnsServer *manager_set_dns_server(Manager *m, DnsServer *s); DnsServer *manager_get_dns_server(Manager *m); -void manager_next_dns_server(Manager *m); +void manager_next_dns_server(Manager *m, DnsServer *if_current); DnssecMode dns_server_get_dnssec_mode(DnsServer *s); DnsOverTlsMode dns_server_get_dns_over_tls_mode(DnsServer *s); +size_t dns_server_get_mtu(DnsServer *s); + DEFINE_TRIVIAL_CLEANUP_FUNC(DnsServer*, dns_server_unref); extern const struct hash_ops dns_server_hash_ops; diff --git a/src/resolve/resolved-dns-stream.c b/src/resolve/resolved-dns-stream.c index 1aab08993..10641f6ac 100644 --- a/src/resolve/resolved-dns-stream.c +++ b/src/resolve/resolved-dns-stream.c @@ -18,8 +18,8 @@ static void dns_stream_stop(DnsStream *s) { assert(s); - s->io_event_source = sd_event_source_unref(s->io_event_source); - s->timeout_event_source = sd_event_source_unref(s->timeout_event_source); + s->io_event_source = sd_event_source_disable_unref(s->io_event_source); + s->timeout_event_source = sd_event_source_disable_unref(s->timeout_event_source); s->fd = safe_close(s->fd); /* Disconnect us from the server object if we are now not usable anymore */ @@ -187,7 +187,7 @@ static int dns_stream_identify(DnsStream *s) { /* If we don't know the interface index still, we look for the * first local interface with a matching address. Yuck! */ if (s->ifindex <= 0) - s->ifindex = manager_find_ifindex(s->manager, s->local.sa.sa_family, s->local.sa.sa_family == AF_INET ? (union in_addr_union*) &s->local.in.sin_addr : (union in_addr_union*) &s->local.in6.sin6_addr); + s->ifindex = manager_find_ifindex(s->manager, s->local.sa.sa_family, sockaddr_in_addr(&s->local.sa)); if (s->protocol == DNS_PROTOCOL_LLMNR && s->ifindex > 0) { /* Make sure all packets for this connection are sent on the same interface */ @@ -377,6 +377,7 @@ static int on_stream_io(sd_event_source *es, int fd, uint32_t revents, void *use s->read_packet->family = s->peer.sa.sa_family; s->read_packet->ttl = s->ttl; s->read_packet->ifindex = s->ifindex; + s->read_packet->timestamp = now(clock_boottime_or_monotonic()); if (s->read_packet->family == AF_INET) { s->read_packet->sender.in = s->peer.in.sin_addr; diff --git a/src/resolve/resolved-dns-stream.h b/src/resolve/resolved-dns-stream.h index dba06447c..470d446dd 100644 --- a/src/resolve/resolved-dns-stream.h +++ b/src/resolve/resolved-dns-stream.h @@ -21,7 +21,7 @@ typedef enum DnsStreamType { DNS_STREAM_LLMNR_RECV, /* Incoming LLMNR TCP lookup */ DNS_STREAM_STUB, /* Incoming DNS stub connection */ _DNS_STREAM_TYPE_MAX, - _DNS_STREAM_TYPE_INVALID = -1, + _DNS_STREAM_TYPE_INVALID = -EINVAL, } DnsStreamType; #define DNS_STREAM_WRITE_TLS_DATA 1 diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 6a3dc9901..602720bf5 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "errno-util.h" #include "fd-util.h" @@ -9,6 +10,7 @@ #include "resolved-dns-stub.h" #include "socket-netlink.h" #include "socket-util.h" +#include "stdio-util.h" #include "string-table.h" /* The MTU of the loopback device is 64K on Linux, advertise that as maximum datagram size, but subtract the Ethernet, @@ -79,123 +81,402 @@ DnsStubListenerExtra *dns_stub_listener_extra_free(DnsStubListenerExtra *p) { if (!p) return NULL; - p->udp_event_source = sd_event_source_unref(p->udp_event_source); - p->tcp_event_source = sd_event_source_unref(p->tcp_event_source); + p->udp_event_source = sd_event_source_disable_unref(p->udp_event_source); + p->tcp_event_source = sd_event_source_disable_unref(p->tcp_event_source); + + hashmap_free(p->queries_by_packet); return mfree(p); } +static void stub_packet_hash_func(const DnsPacket *p, struct siphash *state) { + assert(p); + + siphash24_compress(&p->protocol, sizeof(p->protocol), state); + siphash24_compress(&p->family, sizeof(p->family), state); + siphash24_compress(&p->sender, sizeof(p->sender), state); + siphash24_compress(&p->ipproto, sizeof(p->ipproto), state); + siphash24_compress(&p->sender_port, sizeof(p->sender_port), state); + siphash24_compress(DNS_PACKET_HEADER(p), sizeof(DnsPacketHeader), state); + + /* We don't bother hashing the full packet here, just the header */ +} + +static int stub_packet_compare_func(const DnsPacket *x, const DnsPacket *y) { + int r; + + r = CMP(x->protocol, y->protocol); + if (r != 0) + return r; + + r = CMP(x->family, y->family); + if (r != 0) + return r; + + r = memcmp(&x->sender, &y->sender, sizeof(x->sender)); + if (r != 0) + return r; + + r = CMP(x->ipproto, y->ipproto); + if (r != 0) + return r; + + r = CMP(x->sender_port, y->sender_port); + if (r != 0) + return r; + + return memcmp(DNS_PACKET_HEADER(x), DNS_PACKET_HEADER(y), sizeof(DnsPacketHeader)); +} + +DEFINE_HASH_OPS(stub_packet_hash_ops, DnsPacket, stub_packet_hash_func, stub_packet_compare_func); + +static int reply_add_with_rrsig( + DnsAnswer **reply, + DnsResourceRecord *rr, + int ifindex, + DnsAnswerFlags flags, + DnsResourceRecord *rrsig, + bool with_rrsig) { + int r; + + assert(reply); + assert(rr); + + r = dns_answer_add_extend(reply, rr, ifindex, flags, rrsig); + if (r < 0) + return r; + + if (with_rrsig && rrsig) { + r = dns_answer_add_extend(reply, rrsig, ifindex, flags, NULL); + if (r < 0) + return r; + } + + return 0; +} + +static int dns_stub_collect_answer_by_question( + DnsAnswer **reply, + DnsAnswer *answer, + DnsQuestion *question, + bool with_rrsig) { /* Add RRSIG RR matching each RR */ + + DnsAnswerItem *item; + int r; + + assert(reply); + + /* Copies all RRs from 'answer' into 'reply', if they match 'question'. */ + + DNS_ANSWER_FOREACH_ITEM(item, answer) { + + /* We have a question, let's see if this RR matches it */ + r = dns_question_matches_rr(question, item->rr, NULL); + if (r < 0) + return r; + if (!r) { + /* Maybe there's a CNAME/DNAME in here? If so, that's an answer too */ + r = dns_question_matches_cname_or_dname(question, item->rr, NULL); + if (r < 0) + return r; + if (!r) + continue; + } + + /* Mask the section info, we want the primary answers to always go without section + * info, so that it is added to the answer section when we synthesize a reply. */ + + r = reply_add_with_rrsig( + reply, + item->rr, + item->ifindex, + item->flags & ~DNS_ANSWER_MASK_SECTIONS, + item->rrsig, + with_rrsig); + if (r < 0) + return r; + } + + return 0; +} + +static int dns_stub_collect_answer_by_section( + DnsAnswer **reply, + DnsAnswer *answer, + DnsAnswerFlags section, + DnsAnswer *exclude1, + DnsAnswer *exclude2, + bool with_dnssec) { /* Include DNSSEC RRs. RRSIG, NSEC, … */ + + DnsAnswerItem *item; + int r; + + assert(reply); + + /* Copies all RRs from 'answer' into 'reply', if they originate from the specified section. Also, + * avoid any RRs listed in 'exclude'. */ + + DNS_ANSWER_FOREACH_ITEM(item, answer) { + + if (dns_answer_contains(exclude1, item->rr) || + dns_answer_contains(exclude2, item->rr)) + continue; + + if (!with_dnssec && + dns_type_is_dnssec(item->rr->key->type)) + continue; + + if (((item->flags ^ section) & DNS_ANSWER_MASK_SECTIONS) != 0) + continue; + + r = reply_add_with_rrsig( + reply, + item->rr, + item->ifindex, + item->flags, + item->rrsig, + with_dnssec); + if (r < 0) + return r; + } + + return 0; +} + +static int dns_stub_assign_sections( + DnsQuery *q, + DnsQuestion *question, + bool edns0_do) { + + int r; + + assert(q); + assert(question); + + /* Let's assign the 'answer' RRs we collected to their respective sections in the reply datagram. We + * try to reproduce a section assignment similar to what the upstream DNS server responded to us. We + * use the DNS_ANSWER_SECTION_xyz flags to match things up, which is where the original upstream's + * packet section assignment is stored in the DnsAnswer object. Not all RRs in the 'answer' objects + * come with section information though (for example, because they were synthesized locally, and not + * from a DNS packet). To deal with that we extend the assignment logic a bit: anything from the + * 'answer' object that directly matches the original question is always put in the ANSWER section, + * regardless if it carries section info, or what that section info says. Then, anything from the + * 'answer' objects that is from the ANSWER or AUTHORITY sections, and wasn't already added to the + * ANSWER section is placed in the AUTHORITY section. Everything else from either object is added to + * the ADDITIONAL section. */ + + /* Include all RRs that directly answer the question in the answer section */ + r = dns_stub_collect_answer_by_question( + &q->reply_answer, + q->answer, + question, + edns0_do); + if (r < 0) + return r; + + /* Include all RRs that originate from the authority sections, and aren't already listed in the + * answer section, in the authority section */ + r = dns_stub_collect_answer_by_section( + &q->reply_authoritative, + q->answer, + DNS_ANSWER_SECTION_AUTHORITY, + q->reply_answer, NULL, + edns0_do); + if (r < 0) + return r; + + /* Include all RRs that originate from the answer or additional sections in the additional section + * (except if already listed in the other two sections). Also add all RRs with no section marking. */ + r = dns_stub_collect_answer_by_section( + &q->reply_additional, + q->answer, + DNS_ANSWER_SECTION_ANSWER, + q->reply_answer, q->reply_authoritative, + edns0_do); + if (r < 0) + return r; + r = dns_stub_collect_answer_by_section( + &q->reply_additional, + q->answer, + DNS_ANSWER_SECTION_ADDITIONAL, + q->reply_answer, q->reply_authoritative, + edns0_do); + if (r < 0) + return r; + r = dns_stub_collect_answer_by_section( + &q->reply_additional, + q->answer, + 0, + q->reply_answer, q->reply_authoritative, + edns0_do); + if (r < 0) + return r; + + return 0; +} + static int dns_stub_make_reply_packet( - DnsPacket **p, + DnsPacket **ret, size_t max_size, DnsQuestion *q, - DnsAnswer *answer, bool *ret_truncated) { - bool truncated = false; - DnsResourceRecord *rr; - unsigned c = 0; + _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; + bool tc = false; + int r; + + assert(ret); + + r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0, max_size); + if (r < 0) + return r; + + r = dns_packet_append_question(p, q); + if (r == -EMSGSIZE) + tc = true; + else if (r < 0) + return r; + + if (ret_truncated) + *ret_truncated = tc; + else if (tc) + return -EMSGSIZE; + + DNS_PACKET_HEADER(p)->qdcount = htobe16(dns_question_size(q)); + + *ret = TAKE_PTR(p); + return 0; +} + +static int dns_stub_add_reply_packet_body( + DnsPacket *p, + DnsAnswer *answer, + DnsAnswer *authoritative, + DnsAnswer *additional, + bool edns0_do, /* Client expects DNSSEC RRs? */ + bool *truncated) { + + unsigned n_answer = 0, n_authoritative = 0, n_additional = 0; + bool tc = false; int r; assert(p); - /* Note that we don't bother with any additional RRs, as this is stub is for local lookups only, and hence - * roundtrips aren't expensive. */ + /* Add the three sections to the packet. If the answer section doesn't fit we'll signal that as + * truncation. If the authoritative section doesn't fit and we are in DNSSEC mode, also signal + * truncation. In all other cases where things don't fit don't signal truncation, as for those cases + * the dropped RRs should not be essential. */ - if (!*p) { - r = dns_packet_new(p, DNS_PROTOCOL_DNS, 0, max_size); - if (r < 0) - return r; - - r = dns_packet_append_question(*p, q); - if (r < 0) - return r; - - DNS_PACKET_HEADER(*p)->qdcount = htobe16(dns_question_size(q)); - } - - DNS_ANSWER_FOREACH(rr, answer) { - - r = dns_question_matches_rr(q, rr, NULL); - if (r < 0) - return r; - if (r > 0) - goto add; - - r = dns_question_matches_cname_or_dname(q, rr, NULL); - if (r < 0) - return r; - if (r > 0) - goto add; - - continue; - add: - r = dns_packet_append_rr(*p, rr, 0, NULL, NULL); + r = dns_packet_append_answer(p, answer, &n_answer); + if (r == -EMSGSIZE) + tc = true; + else if (r < 0) + return r; + else { + r = dns_packet_append_answer(p, authoritative, &n_authoritative); if (r == -EMSGSIZE) { - truncated = true; - break; - } - if (r < 0) + if (edns0_do) + tc = true; + } else if (r < 0) return r; - - c++; + else { + r = dns_packet_append_answer(p, additional, &n_additional); + if (r < 0 && r != -EMSGSIZE) + return r; + } } - if (ret_truncated) - *ret_truncated = truncated; - else if (truncated) - return -EMSGSIZE; + if (tc) { + if (!truncated) + return -EMSGSIZE; - DNS_PACKET_HEADER(*p)->ancount = htobe16(be16toh(DNS_PACKET_HEADER(*p)->ancount) + c); + *truncated = true; + } + DNS_PACKET_HEADER(p)->ancount = htobe16(n_answer); + DNS_PACKET_HEADER(p)->nscount = htobe16(n_authoritative); + DNS_PACKET_HEADER(p)->arcount = htobe16(n_additional); return 0; } +static const char *nsid_string(void) { + static char buffer[SD_ID128_STRING_MAX + STRLEN(".resolved.systemd.io")] = ""; + sd_id128_t id; + int r; + + /* Let's generate a string that we can use as RFC5001 NSID identifier. The string shall identify us + * as systemd-resolved, and return a different string for each resolved instance without leaking host + * identity. Hence let's use a fixed suffix that identifies resolved, and a prefix generated from the + * machine ID but from which the machine ID cannot be determined. + * + * Clients can use this to determine whether an answer is originating locally or is proxied from + * upstream. */ + + if (!isempty(buffer)) + return buffer; + + r = sd_id128_get_machine_app_specific( + SD_ID128_MAKE(ed,d3,12,5d,16,b9,41,f9,a1,49,5f,ab,15,62,ab,27), + &id); + if (r < 0) { + log_debug_errno(r, "Failed to determine machine ID, ignoring: %m"); + return NULL; + } + + xsprintf(buffer, SD_ID128_FORMAT_STR ".resolved.systemd.io", SD_ID128_FORMAT_VAL(id)); + return buffer; +} + static int dns_stub_finish_reply_packet( DnsPacket *p, uint16_t id, int rcode, bool tc, /* set the Truncated bit? */ + bool aa, /* set the Authoritative Answer bit? */ bool add_opt, /* add an OPT RR to this packet? */ bool edns0_do, /* set the EDNS0 DNSSEC OK bit? */ bool ad, /* set the DNSSEC authenticated data bit? */ - uint16_t max_udp_size) { /* The maximum UDP datagram size to advertise to clients */ + bool cd, /* set the DNSSEC checking disabled bit? */ + uint16_t max_udp_size, /* The maximum UDP datagram size to advertise to clients */ + bool nsid) { /* whether to add NSID */ int r; assert(p); if (add_opt) { - r = dns_packet_append_opt(p, max_udp_size, edns0_do, /* include_rfc6975 = */ false, rcode, NULL); + r = dns_packet_append_opt(p, max_udp_size, edns0_do, /* include_rfc6975 = */ false, nsid ? nsid_string() : NULL, rcode, NULL); if (r == -EMSGSIZE) /* Hit the size limit? then indicate truncation */ tc = true; else if (r < 0) return r; - } else { /* If the client can't to EDNS0, don't do DO either */ edns0_do = false; - /* If the client didn't do EDNS, clamp the rcode to 4 bit */ + /* If we don't do EDNS, clamp the rcode to 4 bit */ if (rcode > 0xF) rcode = DNS_RCODE_SERVFAIL; } - /* Don't set the AD bit unless DO is on, too */ + /* Don't set the CD bit unless DO is on, too */ if (!edns0_do) - ad = false; + cd = false; + + /* Note that we allow the AD bit to be set even if client didn't signal DO, as per RFC 6840, section + * 5.7 */ DNS_PACKET_HEADER(p)->id = id; DNS_PACKET_HEADER(p)->flags = htobe16(DNS_PACKET_MAKE_FLAGS( 1 /* qr */, 0 /* opcode */, - 0 /* aa */, + aa /* aa */, tc /* tc */, 1 /* rd */, 1 /* ra */, ad /* ad */, - 0 /* cd */, + cd /* cd */, rcode)); return 0; @@ -231,6 +512,87 @@ static int dns_stub_send( return 0; } +static int dns_stub_reply_with_edns0_do(DnsQuery *q) { + assert(q); + + /* Reply with DNSSEC DO set? Only if client supports it; and we did any DNSSEC verification + * ourselves, or consider the data fully authenticated because we generated it locally, or the client + * set cd */ + + return DNS_PACKET_DO(q->request_packet) && + (q->answer_dnssec_result >= 0 || /* we did proper DNSSEC validation … */ + dns_query_fully_authenticated(q) || /* … or we considered it authentic otherwise … */ + DNS_PACKET_CD(q->request_packet)); /* … or client set CD */ +} + +static void dns_stub_suppress_duplicate_section_rrs(DnsQuery *q) { + /* If we follow a CNAME/DNAME chain we might end up populating our sections with redundant RRs + * because we built up the sections from multiple reply packets (one from each CNAME/DNAME chain + * element). E.g. it could be that an RR that was included in the first reply's additional section + * ends up being relevant as main answer in a subsequent reply in the chain. Let's clean this up, and + * remove everything in the "higher priority" sections from the "lower priority" sections. + * + * Note that this removal matches by RR keys instead of the full RRs. This is because RRsets should + * always end up in one section fully or not at all, but never be split among sections. + * + * Specifically: we remove ANSWER section RRs from the AUTHORITATIVE and ADDITIONAL sections, as well + * as AUTHORITATIVE section RRs from the ADDITIONAL section. */ + + dns_answer_remove_by_answer_keys(&q->reply_authoritative, q->reply_answer); + dns_answer_remove_by_answer_keys(&q->reply_additional, q->reply_answer); + dns_answer_remove_by_answer_keys(&q->reply_additional, q->reply_authoritative); +} + +static int dns_stub_send_reply( + DnsQuery *q, + int rcode) { + + _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + bool truncated, edns0_do; + int r; + + assert(q); + + edns0_do = dns_stub_reply_with_edns0_do(q); /* let's check if we shall reply with EDNS0 DO? */ + + r = dns_stub_make_reply_packet( + &reply, + DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_packet), + q->request_packet->question, + &truncated); + if (r < 0) + return log_debug_errno(r, "Failed to build reply packet: %m"); + + dns_stub_suppress_duplicate_section_rrs(q); + + r = dns_stub_add_reply_packet_body( + reply, + q->reply_answer, + q->reply_authoritative, + q->reply_additional, + edns0_do, + &truncated); + if (r < 0) + return log_debug_errno(r, "Failed to append reply packet body: %m"); + + r = dns_stub_finish_reply_packet( + reply, + DNS_PACKET_ID(q->request_packet), + rcode, + truncated, + dns_query_fully_authoritative(q), + !!q->request_packet->opt, + edns0_do, + DNS_PACKET_AD(q->request_packet) && dns_query_fully_authenticated(q), + DNS_PACKET_CD(q->request_packet), + q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX, + dns_packet_has_nsid_request(q->request_packet) > 0 && !q->stub_listener_extra); + if (r < 0) + return log_debug_errno(r, "Failed to build failure packet: %m"); + + return dns_stub_send(q->manager, q->stub_listener_extra, q->request_stream, q->request_packet, reply); +} + static int dns_stub_send_failure( Manager *m, DnsStubListenerExtra *l, @@ -240,12 +602,17 @@ static int dns_stub_send_failure( bool authenticated) { _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + bool truncated; int r; assert(m); assert(p); - r = dns_stub_make_reply_packet(&reply, DNS_PACKET_PAYLOAD_SIZE_MAX(p), p->question, NULL, NULL); + r = dns_stub_make_reply_packet( + &reply, + DNS_PACKET_PAYLOAD_SIZE_MAX(p), + p->question, + &truncated); if (r < 0) return log_debug_errno(r, "Failed to make failure packet: %m"); @@ -253,72 +620,172 @@ static int dns_stub_send_failure( reply, DNS_PACKET_ID(p), rcode, - /* truncated = */ false, + truncated, + false, !!p->opt, DNS_PACKET_DO(p), - authenticated, - l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX); + DNS_PACKET_AD(p) && authenticated, + DNS_PACKET_CD(p), + l ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX, + dns_packet_has_nsid_request(p) > 0 && !l); if (r < 0) return log_debug_errno(r, "Failed to build failure packet: %m"); return dns_stub_send(m, l, s, p, reply); } +static int dns_stub_patch_bypass_reply_packet( + DnsPacket **ret, /* Where to place the patched packet */ + DnsPacket *original, /* The packet to patch */ + DnsPacket *request) { /* The packet the patched packet shall look like a reply to */ + _cleanup_(dns_packet_unrefp) DnsPacket *c = NULL; + int r; + + assert(ret); + assert(original); + assert(request); + + r = dns_packet_dup(&c, original); + if (r < 0) + return r; + + /* Extract the packet, so that we know where the OPT field is */ + r = dns_packet_extract(c); + if (r < 0) + return r; + + /* Copy over the original client request ID, so that we can make the upstream query look like our own reply. */ + DNS_PACKET_HEADER(c)->id = DNS_PACKET_HEADER(request)->id; + + /* Patch in our own maximum datagram size, if EDNS0 was on */ + r = dns_packet_patch_max_udp_size(c, ADVERTISE_DATAGRAM_SIZE_MAX); + if (r < 0) + return r; + + /* Lower all TTLs by the time passed since we received the datagram. */ + if (timestamp_is_set(original->timestamp)) { + r = dns_packet_patch_ttls(c, original->timestamp); + if (r < 0) + return r; + } + + /* Our upstream connection might have supported larger DNS requests than our downstream one, hence + * set the TC bit if our reply is larger than what the client supports, and truncate. */ + if (c->size > DNS_PACKET_PAYLOAD_SIZE_MAX(request)) { + log_debug("Artificially truncating stub response, as advertised size of client is smaller than upstream one."); + dns_packet_truncate(c, DNS_PACKET_PAYLOAD_SIZE_MAX(request)); + DNS_PACKET_HEADER(c)->flags = htobe16(be16toh(DNS_PACKET_HEADER(c)->flags) | DNS_PACKET_FLAG_TC); + } + + *ret = TAKE_PTR(c); + return 0; +} + static void dns_stub_query_complete(DnsQuery *q) { int r; assert(q); - assert(q->request_dns_packet); + assert(q->request_packet); + + if (q->question_bypass) { + /* This is a bypass reply. If so, let's propagate the upstream packet, if we have it and it + * is regular DNS. (We can't do this if the upstream packet is LLMNR or mDNS, since the + * packets are not 100% compatible.) */ + + if (q->answer_full_packet && + q->answer_full_packet->protocol == DNS_PROTOCOL_DNS) { + _cleanup_(dns_packet_unrefp) DnsPacket *reply = NULL; + + r = dns_stub_patch_bypass_reply_packet(&reply, q->answer_full_packet, q->request_packet); + if (r < 0) + log_debug_errno(r, "Failed to patch bypass reply packet: %m"); + else + (void) dns_stub_send(q->manager, q->stub_listener_extra, q->request_stream, q->request_packet, reply); + + dns_query_free(q); + return; + } + } + + /* Take all data from the current reply, and merge it into the three reply sections we are building + * up. We do this before processing CNAME redirects, so that we gradually build up our sections, and + * and keep adding all RRs in the CNAME chain. */ + r = dns_stub_assign_sections( + q, + dns_query_question_for_protocol(q, DNS_PROTOCOL_DNS), + dns_stub_reply_with_edns0_do(q)); + if (r < 0) { + log_debug_errno(r, "Failed to assign sections: %m"); + dns_query_free(q); + return; + } switch (q->state) { case DNS_TRANSACTION_SUCCESS: { - bool truncated; + bool first = true; - r = dns_stub_make_reply_packet(&q->reply_dns_packet, DNS_PACKET_PAYLOAD_SIZE_MAX(q->request_dns_packet), q->question_idna, q->answer, &truncated); - if (r < 0) { - log_debug_errno(r, "Failed to build reply packet: %m"); - break; - } + for (;;) { + int cname_result; - if (!truncated) { - r = dns_query_process_cname(q); - if (r == -ELOOP) { - (void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false); + cname_result = dns_query_process_cname_one(q); + if (cname_result == -ELOOP) { /* CNAME loop, let's send what we already have */ + log_debug_errno(r, "Detected CNAME loop, returning what we already have."); + (void) dns_stub_send_reply(q, q->answer_rcode); break; } - if (r < 0) { - log_debug_errno(r, "Failed to process CNAME: %m"); + if (cname_result < 0) { + log_debug_errno(cname_result, "Failed to process CNAME: %m"); break; } - if (r == DNS_QUERY_RESTARTED) + + if (cname_result == DNS_QUERY_NOMATCH) { + /* This answer doesn't contain any RR that would answer our question + * positively, i.e. neither directly nor via CNAME. */ + + if (first) /* We never followed a CNAME and the answer doesn't match our + * question at all? Then this is final, the empty answer is the + * answer. */ + break; + + /* Otherwise, we already followed a CNAME once within this packet, and the + * packet doesn't answer our question. In that case let's restart the query, + * now with the redirected question. We'll */ + r = dns_query_go(q); + if (r < 0) + log_debug_errno(r, "Failed to restart query: %m"); + return; + } + + r = dns_stub_assign_sections( + q, + dns_query_question_for_protocol(q, DNS_PROTOCOL_DNS), + dns_stub_reply_with_edns0_do(q)); + if (r < 0) { + log_debug_errno(r, "Failed to assign sections: %m"); + dns_query_free(q); + return; + } + + if (cname_result == DNS_QUERY_MATCH) /* A match? Then we are done, let's return what we got */ + break; + + /* We followed a CNAME. and collected the RRs that answer the redirected question + * successfully. Let's not try to do this again. */ + assert(cname_result == DNS_QUERY_CNAME); + first = false; } - r = dns_stub_finish_reply_packet( - q->reply_dns_packet, - DNS_PACKET_ID(q->request_dns_packet), - q->answer_rcode, - truncated, - !!q->request_dns_packet->opt, - DNS_PACKET_DO(q->request_dns_packet), - dns_query_fully_authenticated(q), - q->stub_listener_extra ? ADVERTISE_EXTRA_DATAGRAM_SIZE_MAX : ADVERTISE_DATAGRAM_SIZE_MAX); - if (r < 0) { - log_debug_errno(r, "Failed to finish reply packet: %m"); - break; - } - - (void) dns_stub_send(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, q->reply_dns_packet); - break; + _fallthrough_; } case DNS_TRANSACTION_RCODE_FAILURE: - (void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, q->answer_rcode, dns_query_fully_authenticated(q)); + (void) dns_stub_send_reply(q, q->answer_rcode); break; case DNS_TRANSACTION_NOT_FOUND: - (void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_NXDOMAIN, dns_query_fully_authenticated(q)); + (void) dns_stub_send_reply(q, DNS_RCODE_NXDOMAIN); break; case DNS_TRANSACTION_TIMEOUT: @@ -334,7 +801,9 @@ static void dns_stub_query_complete(DnsQuery *q) { case DNS_TRANSACTION_NO_TRUST_ANCHOR: case DNS_TRANSACTION_RR_TYPE_UNSUPPORTED: case DNS_TRANSACTION_NETWORK_DOWN: - (void) dns_stub_send_failure(q->manager, q->stub_listener_extra, q->request_dns_stream, q->request_dns_packet, DNS_RCODE_SERVFAIL, false); + case DNS_TRANSACTION_NO_SOURCE: + case DNS_TRANSACTION_STUB_LOOP: + (void) dns_stub_send_reply(q, DNS_RCODE_SERVFAIL); break; case DNS_TRANSACTION_NULL: @@ -370,6 +839,8 @@ static int dns_stub_stream_complete(DnsStream *s, int error) { static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStream *s, DnsPacket *p) { _cleanup_(dns_query_freep) DnsQuery *q = NULL; + Hashmap **queries_by_packet; + DnsQuery *existing; int r; assert(m); @@ -383,6 +854,18 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea return; } + if (manager_packet_from_our_transaction(m, p)) { + log_debug("Got our own packet looped back, ignoring."); + return; + } + + queries_by_packet = l ? &l->queries_by_packet : &m->stub_queries_by_packet; + existing = hashmap_get(*queries_by_packet, p); + if (existing && dns_packet_equal(existing->request_packet, p)) { + log_debug("Got repeat packet from client, ignoring."); + return; + } + r = dns_packet_extract(p); if (r < 0) { log_debug_errno(r, "Failed to extract resources from incoming packet, ignoring packet: %m"); @@ -398,13 +881,13 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea if (dns_type_is_obsolete(p->question->keys[0]->type)) { log_debug("Got message with obsolete key type, refusing."); - dns_stub_send_failure(m, l, s, p, DNS_RCODE_NOTIMP, false); + dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false); return; } if (dns_type_is_zone_transer(p->question->keys[0]->type)) { log_debug("Got request for zone transfer, refusing."); - dns_stub_send_failure(m, l, s, p, DNS_RCODE_NOTIMP, false); + dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false); return; } @@ -415,24 +898,36 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea return; } - if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) { - log_debug("Got request with DNSSEC CD bit set, refusing."); - dns_stub_send_failure(m, l, s, p, DNS_RCODE_NOTIMP, false); + r = hashmap_ensure_allocated(queries_by_packet, &stub_packet_hash_ops); + if (r < 0) { + log_oom(); return; } - r = dns_query_new(m, &q, p->question, p->question, 0, SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_SEARCH); + if (DNS_PACKET_DO(p) && DNS_PACKET_CD(p)) { + log_debug("Got request with DNSSEC checking disabled, enabling bypass logic."); + + r = dns_query_new(m, &q, NULL, NULL, p, 0, + SD_RESOLVED_PROTOCOLS_ALL| + SD_RESOLVED_NO_CNAME| + SD_RESOLVED_NO_SEARCH| + SD_RESOLVED_NO_VALIDATE| + SD_RESOLVED_REQUIRE_PRIMARY| + SD_RESOLVED_CLAMP_TTL); + } else + r = dns_query_new(m, &q, p->question, p->question, NULL, 0, + SD_RESOLVED_PROTOCOLS_ALL| + SD_RESOLVED_NO_SEARCH| + (DNS_PACKET_DO(p) ? SD_RESOLVED_REQUIRE_PRIMARY : 0)| + SD_RESOLVED_CLAMP_TTL); if (r < 0) { log_error_errno(r, "Failed to generate query object: %m"); dns_stub_send_failure(m, l, s, p, DNS_RCODE_SERVFAIL, false); return; } - /* Request that the TTL is corrected by the cached time for this lookup, so that we return vaguely useful TTLs */ - q->clamp_ttl = true; - - q->request_dns_packet = dns_packet_ref(p); - q->request_dns_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */ + q->request_packet = dns_packet_ref(p); + q->request_stream = dns_stream_ref(s); /* make sure the stream stays around until we can send a reply through it */ q->stub_listener_extra = l; q->complete = dns_stub_query_complete; @@ -448,6 +943,11 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea assert(r > 0); } + /* Add the query to the hash table we use to determine repeat packets now. We don't care about + * failures here, since in the worst case we'll not recognize duplicate incoming requests, which + * isn't particularly bad. */ + (void) hashmap_put(*queries_by_packet, q->request_packet, q); + r = dns_query_go(q); if (r < 0) { log_error_errno(r, "Failed to start query: %m"); @@ -566,6 +1066,22 @@ static int set_dns_stub_common_socket_options(int fd, int family) { return 0; } +static int set_dns_stub_common_tcp_socket_options(int fd) { + int r; + + assert(fd >= 0); + + r = setsockopt_int(fd, IPPROTO_TCP, TCP_FASTOPEN, 5); /* Everybody appears to pick qlen=5, let's do the same here. */ + if (r < 0) + log_debug_errno(r, "Failed to enable TCP_FASTOPEN on TCP listening socket, ignoring: %m"); + + r = setsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY, true); + if (r < 0) + log_debug_errno(r, "Failed to enable TCP_NODELAY mode, ignoring: %m"); + + return 0; +} + static int manager_dns_stub_fd(Manager *m, int type) { union sockaddr_union sa = { .in.sin_family = AF_INET, @@ -589,6 +1105,12 @@ static int manager_dns_stub_fd(Manager *m, int type) { if (r < 0) return r; + if (type == SOCK_STREAM) { + r = set_dns_stub_common_tcp_socket_options(fd); + if (r < 0) + return r; + } + /* Make sure no traffic from outside the local host can leak to onto this socket */ r = socket_bind_to_ifindex(fd, LOOPBACK_IFINDEX); if (r < 0) @@ -640,13 +1162,13 @@ static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int ty if (l->family == AF_INET) sa = (union sockaddr_union) { .in.sin_family = l->family, - .in.sin_port = htobe16(l->port != 0 ? l->port : 53U), + .in.sin_port = htobe16(dns_stub_listener_extra_port(l)), .in.sin_addr = l->address.in, }; else sa = (union sockaddr_union) { .in6.sin6_family = l->family, - .in6.sin6_port = htobe16(l->port != 0 ? l->port : 53U), + .in6.sin6_port = htobe16(dns_stub_listener_extra_port(l)), .in6.sin6_addr = l->address.in6, }; @@ -660,6 +1182,12 @@ static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int ty if (r < 0) goto fail; + if (type == SOCK_STREAM) { + r = set_dns_stub_common_tcp_socket_options(fd); + if (r < 0) + goto fail; + } + /* Do not set IP_TTL for extra DNS stub listeners, as the address may not be local and in that case * people may want ttl > 1. */ @@ -667,6 +1195,16 @@ static int manager_dns_stub_fd_extra(Manager *m, DnsStubListenerExtra *l, int ty if (r < 0) goto fail; + if (type == SOCK_DGRAM) { + r = socket_disable_pmtud(fd, l->family); + if (r < 0) + log_debug_errno(r, "Failed to disable UDP PMTUD, ignoring: %m"); + + r = socket_set_recvfragsize(fd, l->family, true); + if (r < 0) + log_debug_errno(r, "Failed to enable fragment size reception, ignoring: %m"); + } + if (bind(fd, &sa.sa, SOCKADDR_LEN(sa)) < 0) { r = -errno; goto fail; @@ -763,12 +1301,12 @@ int manager_dns_stub_start(Manager *m) { void manager_dns_stub_stop(Manager *m) { assert(m); - m->dns_stub_udp_event_source = sd_event_source_unref(m->dns_stub_udp_event_source); - m->dns_stub_tcp_event_source = sd_event_source_unref(m->dns_stub_tcp_event_source); + m->dns_stub_udp_event_source = sd_event_source_disable_unref(m->dns_stub_udp_event_source); + m->dns_stub_tcp_event_source = sd_event_source_disable_unref(m->dns_stub_tcp_event_source); } static const char* const dns_stub_listener_mode_table[_DNS_STUB_LISTENER_MODE_MAX] = { - [DNS_STUB_LISTENER_NO] = "no", + [DNS_STUB_LISTENER_NO] = "no", [DNS_STUB_LISTENER_UDP] = "udp", [DNS_STUB_LISTENER_TCP] = "tcp", [DNS_STUB_LISTENER_YES] = "yes", diff --git a/src/resolve/resolved-dns-stub.h b/src/resolve/resolved-dns-stub.h index 072f2130e..3b9bf65b2 100644 --- a/src/resolve/resolved-dns-stub.h +++ b/src/resolve/resolved-dns-stub.h @@ -11,7 +11,7 @@ typedef enum DnsStubListenerMode { DNS_STUB_LISTENER_TCP = 1 << 1, DNS_STUB_LISTENER_YES = DNS_STUB_LISTENER_UDP | DNS_STUB_LISTENER_TCP, _DNS_STUB_LISTENER_MODE_MAX, - _DNS_STUB_LISTENER_MODE_INVALID = -1 + _DNS_STUB_LISTENER_MODE_INVALID = -EINVAL, } DnsStubListenerMode; #include "resolved-manager.h" @@ -27,12 +27,19 @@ struct DnsStubListenerExtra { sd_event_source *udp_event_source; sd_event_source *tcp_event_source; + + Hashmap *queries_by_packet; }; extern const struct hash_ops dns_stub_listener_extra_hash_ops; int dns_stub_listener_extra_new(Manager *m, DnsStubListenerExtra **ret); DnsStubListenerExtra *dns_stub_listener_extra_free(DnsStubListenerExtra *p); +static inline uint16_t dns_stub_listener_extra_port(DnsStubListenerExtra *p) { + assert(p); + + return p->port > 0 ? p->port : 53; +} void manager_dns_stub_stop(Manager *m); int manager_dns_stub_start(Manager *m); diff --git a/src/resolve/resolved-dns-synthesize.c b/src/resolve/resolved-dns-synthesize.c index f08d62116..d4a4be71b 100644 --- a/src/resolve/resolved-dns-synthesize.c +++ b/src/resolve/resolved-dns-synthesize.c @@ -76,12 +76,12 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if rr->a.in_addr.s_addr = htobe32(INADDR_LOOPBACK); - r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; } - if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY)) { + if (IN_SET(key->type, DNS_TYPE_AAAA, DNS_TYPE_ANY) && socket_ipv6_is_enabled()) { _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_AAAA, dns_resource_key_name(key)); @@ -90,7 +90,7 @@ static int synthesize_localhost_rr(Manager *m, const DnsResourceKey *key, int if rr->aaaa.in6_addr = in6addr_loopback; - r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, dns_synthesize_ifindex(ifindex), DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; } @@ -109,7 +109,7 @@ static int answer_add_ptr(DnsAnswer **answer, const char *from, const char *to, if (!rr->ptr.name) return -ENOMEM; - return dns_answer_add(*answer, rr, ifindex, flags); + return dns_answer_add(*answer, rr, ifindex, flags, NULL); } static int synthesize_localhost_ptr(Manager *m, const DnsResourceKey *key, int ifindex, DnsAnswer **answer) { @@ -155,7 +155,7 @@ static int answer_add_addresses_rr( if (r < 0) return r; - r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; } @@ -197,7 +197,7 @@ static int answer_add_addresses_ptr( if (r < 0) return r; - r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, addresses[j].ifindex, DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; @@ -234,7 +234,7 @@ static int synthesize_system_hostname_rr(Manager *m, const DnsResourceKey *key, .address.in.s_addr = htobe32(0x7F000002), }; - if (IN_SET(af, AF_INET6, AF_UNSPEC)) + if (IN_SET(af, AF_INET6, AF_UNSPEC) && socket_ipv6_is_enabled()) buffer[n++] = (struct local_address) { .family = AF_INET6, .ifindex = dns_synthesize_ifindex(ifindex), diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 37f0ddde6..6eac7e9c5 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -29,8 +29,8 @@ static void dns_transaction_reset_answer(DnsTransaction *t) { t->answer_rcode = 0; t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; - t->answer_authenticated = false; - t->answer_nsec_ttl = (uint32_t) -1; + t->answer_query_flags = 0; + t->answer_nsec_ttl = UINT32_MAX; t->answer_errno = 0; } @@ -46,7 +46,14 @@ static void dns_transaction_flush_dnssec_transactions(DnsTransaction *t) { } } -static void dns_transaction_close_connection(DnsTransaction *t) { +static void dns_transaction_close_connection( + DnsTransaction *t, + bool use_graveyard) { /* Set use_graveyard = false when you know the connection is already + * dead, for example because you got a connection error back from the + * kernel. In that case there's no point in keeping the fd around, + * hence don't. */ + int r; + assert(t); if (t->stream) { @@ -59,14 +66,28 @@ static void dns_transaction_close_connection(DnsTransaction *t) { t->stream = dns_stream_unref(t->stream); } - t->dns_udp_event_source = sd_event_source_unref(t->dns_udp_event_source); + t->dns_udp_event_source = sd_event_source_disable_unref(t->dns_udp_event_source); + + /* If we have an UDP socket where we sent a packet, but never received one, then add it to the socket + * graveyard, instead of closing it right away. That way it will stick around for a moment longer, + * and the reply we might still get from the server will be eaten up instead of resulting in an ICMP + * port unreachable error message. */ + + if (use_graveyard && t->dns_udp_fd >= 0 && t->sent && !t->received) { + r = manager_add_socket_to_graveyard(t->scope->manager, t->dns_udp_fd); + if (r < 0) + log_debug_errno(r, "Failed to add UDP socket to graveyard, closing immediately: %m"); + else + TAKE_FD(t->dns_udp_fd); + } + t->dns_udp_fd = safe_close(t->dns_udp_fd); } static void dns_transaction_stop_timeout(DnsTransaction *t) { assert(t); - t->timeout_event_source = sd_event_source_unref(t->timeout_event_source); + t->timeout_event_source = sd_event_source_disable_unref(t->timeout_event_source); } DnsTransaction* dns_transaction_free(DnsTransaction *t) { @@ -79,7 +100,7 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { log_debug("Freeing transaction %" PRIu16 ".", t->id); - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); dns_transaction_stop_timeout(t); dns_packet_unref(t->sent); @@ -88,7 +109,17 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_server_unref(t->server); if (t->scope) { - hashmap_remove_value(t->scope->transactions_by_key, t->key, t); + if (t->key) { + DnsTransaction *first; + + first = hashmap_get(t->scope->transactions_by_key, t->key); + LIST_REMOVE(transactions_by_key, first, t); + if (first) + hashmap_replace(t->scope->transactions_by_key, first->key, first); + else + hashmap_remove(t->scope->transactions_by_key, t->key); + } + LIST_REMOVE(transactions_by_scope, t->scope->transactions, t); if (t->id != 0) @@ -124,29 +155,30 @@ DnsTransaction* dns_transaction_free(DnsTransaction *t) { dns_answer_unref(t->validated_keys); dns_resource_key_unref(t->key); + dns_packet_unref(t->bypass); return mfree(t); } DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_free); -bool dns_transaction_gc(DnsTransaction *t) { +DnsTransaction* dns_transaction_gc(DnsTransaction *t) { assert(t); + /* Returns !NULL if we can't gc yet. */ + if (t->block_gc > 0) - return true; + return t; if (set_isempty(t->notify_query_candidates) && set_isempty(t->notify_query_candidates_done) && set_isempty(t->notify_zone_items) && set_isempty(t->notify_zone_items_done) && set_isempty(t->notify_transactions) && - set_isempty(t->notify_transactions_done)) { - dns_transaction_free(t); - return false; - } + set_isempty(t->notify_transactions_done)) + return dns_transaction_free(t); - return true; + return t; } static uint16_t pick_new_id(Manager *m) { @@ -165,13 +197,9 @@ static uint16_t pick_new_id(Manager *m) { return new_id; } -int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) { - _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL; - int r; - - assert(ret); - assert(s); - assert(key); +static int key_ok( + DnsScope *scope, + DnsResourceKey *key) { /* Don't allow looking up invalid or pseudo RRs */ if (!dns_type_is_valid_query(key->type)) @@ -183,6 +211,49 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) if (!IN_SET(key->class, DNS_CLASS_IN, DNS_CLASS_ANY)) return -EOPNOTSUPP; + /* Don't allows DNSSEC RRs to be looked up via LLMNR/mDNS. They don't really make sense + * there, and it speeds up our queries if we refuse this early */ + if (scope->protocol != DNS_PROTOCOL_DNS && + dns_type_is_dnssec(key->type)) + return -EOPNOTSUPP; + + return 0; +} + +int dns_transaction_new( + DnsTransaction **ret, + DnsScope *s, + DnsResourceKey *key, + DnsPacket *bypass, + uint64_t query_flags) { + + _cleanup_(dns_transaction_freep) DnsTransaction *t = NULL; + int r; + + assert(ret); + assert(s); + + if (key) { + assert(!bypass); + + r = key_ok(s, key); + if (r < 0) + return r; + } else { + DnsResourceKey *qk; + assert(bypass); + + r = dns_packet_validate_query(bypass); + if (r < 0) + return r; + + DNS_QUESTION_FOREACH(qk, bypass->question) { + r = key_ok(s, qk); + if (r < 0) + return r; + } + } + if (hashmap_size(s->manager->dns_transactions) >= TRANSACTIONS_MAX) return -EBUSY; @@ -190,9 +261,11 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) if (r < 0) return r; - r = hashmap_ensure_allocated(&s->transactions_by_key, &dns_resource_key_hash_ops); - if (r < 0) - return r; + if (key) { + r = hashmap_ensure_allocated(&s->transactions_by_key, &dns_resource_key_hash_ops); + if (r < 0) + return r; + } t = new(DnsTransaction, 1); if (!t) @@ -202,10 +275,13 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) .dns_udp_fd = -1, .answer_source = _DNS_TRANSACTION_SOURCE_INVALID, .answer_dnssec_result = _DNSSEC_RESULT_INVALID, - .answer_nsec_ttl = (uint32_t) -1, + .answer_nsec_ttl = UINT32_MAX, .key = dns_resource_key_ref(key), + .query_flags = query_flags, + .bypass = dns_packet_ref(bypass), .current_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID, - .clamp_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID, + .clamp_feature_level_servfail = _DNS_SERVER_FEATURE_LEVEL_INVALID, + .clamp_feature_level_nxdomain = _DNS_SERVER_FEATURE_LEVEL_INVALID, .id = pick_new_id(s->manager), }; @@ -215,10 +291,17 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) return r; } - r = hashmap_replace(s->transactions_by_key, t->key, t); - if (r < 0) { - hashmap_remove(s->manager->dns_transactions, UINT_TO_PTR(t->id)); - return r; + if (t->key) { + DnsTransaction *first; + + first = hashmap_get(s->transactions_by_key, t->key); + LIST_PREPEND(transactions_by_key, first, t); + + r = hashmap_replace(s->transactions_by_key, first->key, first); + if (r < 0) { + LIST_REMOVE(transactions_by_key, first, t); + return r; + } } LIST_PREPEND(transactions_by_scope, s->transactions, t); @@ -229,8 +312,7 @@ int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key) if (ret) *ret = t; - t = NULL; - + TAKE_PTR(t); return 0; } @@ -257,15 +339,16 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) { assert(t); assert(p); + assert(t->scope->protocol == DNS_PROTOCOL_LLMNR); - if (manager_our_packet(t->scope->manager, p) != 0) + if (manager_packet_from_local_address(t->scope->manager, p) != 0) return; (void) in_addr_to_string(p->family, &p->sender, &pretty); log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s got tentative packet from %s.", t->id, - dns_resource_key_to_string(t->key, key_str, sizeof key_str), + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->ifname : "*", af_to_name_short(t->scope->family), @@ -307,7 +390,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { assert(!DNS_TRANSACTION_IS_LIVE(state)); if (state == DNS_TRANSACTION_DNSSEC_FAILED) { - dns_resource_key_to_string(t->key, key_str, sizeof key_str); + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str); log_struct(LOG_NOTICE, "MESSAGE_ID=" SD_MESSAGE_DNSSEC_FAILURE_STR, @@ -328,19 +411,22 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) { else st = dns_transaction_state_to_string(state); - log_debug("Transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s).", + log_debug("%s transaction %" PRIu16 " for <%s> on scope %s on %s/%s now complete with <%s> from %s (%s; %s).", + t->bypass ? "Bypass" : "Regular", t->id, - dns_resource_key_to_string(t->key, key_str, sizeof key_str), + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->ifname : "*", af_to_name_short(t->scope->family), st, t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source), - t->answer_authenticated ? "authenticated" : "unsigned"); + FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) ? "not validated" : + (FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED) ? "authenticated" : "unsigned"), + FLAGS_SET(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL) ? "confidential" : "non-confidential"); t->state = state; - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); dns_transaction_stop_timeout(t); /* Notify all queries that are interested, but make sure the @@ -387,15 +473,20 @@ static int dns_transaction_pick_server(DnsTransaction *t) { /* If we changed the server invalidate the feature level clamping, as the new server might have completely * different properties. */ - if (server != t->server) - t->clamp_feature_level = _DNS_SERVER_FEATURE_LEVEL_INVALID; + if (server != t->server) { + t->clamp_feature_level_servfail = _DNS_SERVER_FEATURE_LEVEL_INVALID; + t->clamp_feature_level_nxdomain = _DNS_SERVER_FEATURE_LEVEL_INVALID; + } t->current_feature_level = dns_server_possible_feature_level(server); /* Clamp the feature level if that is requested. */ - if (t->clamp_feature_level != _DNS_SERVER_FEATURE_LEVEL_INVALID && - t->current_feature_level > t->clamp_feature_level) - t->current_feature_level = t->clamp_feature_level; + if (t->clamp_feature_level_servfail != _DNS_SERVER_FEATURE_LEVEL_INVALID && + t->current_feature_level > t->clamp_feature_level_servfail) + t->current_feature_level = t->clamp_feature_level_servfail; + if (t->clamp_feature_level_nxdomain != _DNS_SERVER_FEATURE_LEVEL_INVALID && + t->current_feature_level > t->clamp_feature_level_nxdomain) + t->current_feature_level = t->clamp_feature_level_nxdomain; log_debug("Using feature level %s for transaction %u.", dns_server_feature_level_to_string(t->current_feature_level), t->id); @@ -417,23 +508,41 @@ static void dns_transaction_retry(DnsTransaction *t, bool next_server) { assert(t); - log_debug("Retrying transaction %" PRIu16 ".", t->id); + /* Retries the transaction as it is, possibly on a different server */ + + if (next_server) + log_debug("Retrying transaction %" PRIu16 ", after switching servers.", t->id); + else + log_debug("Retrying transaction %" PRIu16 ".", t->id); /* Before we try again, switch to a new server. */ if (next_server) - dns_scope_next_dns_server(t->scope); + dns_scope_next_dns_server(t->scope, t->server); r = dns_transaction_go(t); if (r < 0) dns_transaction_complete_errno(t, r); } +static bool dns_transaction_limited_retry(DnsTransaction *t) { + assert(t); + + /* If we haven't tried all different servers yet, let's try again with a different server */ + + if (t->n_picked_servers >= dns_scope_get_n_dns_servers(t->scope)) + return false; + + dns_transaction_retry(t, /* next_server= */ true); + return true; +} + static int dns_transaction_maybe_restart(DnsTransaction *t) { int r; assert(t); - /* Returns > 0 if the transaction was restarted, 0 if not */ + /* Restarts the transaction, under a new ID if the feature level of the server changed since we first + * tried, without changing DNS server. Returns > 0 if the transaction was restarted, 0 if not. */ if (!t->server) return 0; @@ -460,7 +569,7 @@ static int dns_transaction_maybe_restart(DnsTransaction *t) { static void on_transaction_stream_error(DnsTransaction *t, int error) { assert(t); - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); if (ERRNO_IS_DISCONNECT(error)) { if (t->scope->protocol == DNS_PROTOCOL_LLMNR) { @@ -477,11 +586,16 @@ static void on_transaction_stream_error(DnsTransaction *t, int error) { dns_transaction_complete_errno(t, error); } -static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) { +static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsStream *s, DnsPacket *p) { + bool encrypted; + assert(t); + assert(s); assert(p); - dns_transaction_close_connection(t); + encrypted = s->encrypted; + + dns_transaction_close_connection(t, true); if (dns_packet_validate_reply(p) <= 0) { log_debug("Invalid TCP reply packet."); @@ -492,7 +606,7 @@ static int dns_transaction_on_stream_packet(DnsTransaction *t, DnsPacket *p) { dns_scope_check_conflicts(t->scope, p); t->block_gc++; - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, encrypted); t->block_gc--; /* If the response wasn't useful, then complete the transition @@ -537,12 +651,12 @@ static int on_stream_packet(DnsStream *s) { assert(s); /* Take ownership of packet to be able to receive new packets */ - p = dns_stream_take_read_packet(s); - assert(p); + assert_se(p = dns_stream_take_read_packet(s)); t = hashmap_get(s->manager->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); - if (t) - return dns_transaction_on_stream_packet(t, p); + if (t && t->stream == s) /* Validate that the stream we got this on actually is the stream the + * transaction was using. */ + return dns_transaction_on_stream_packet(t, s, p); /* Ignore incorrect transaction id as an old transaction can have been canceled. */ log_debug("Received unexpected TCP reply packet with id %" PRIu16 ", ignoring.", DNS_PACKET_ID(p)); @@ -550,8 +664,11 @@ static int on_stream_packet(DnsStream *s) { } static uint16_t dns_transaction_port(DnsTransaction *t) { + assert(t); + if (t->server->port > 0) return t->server->port; + return DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) ? 853 : 53; } @@ -563,8 +680,9 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { int r; assert(t); + assert(t->sent); - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); switch (t->scope->protocol) { @@ -573,12 +691,17 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { if (r < 0) return r; - if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type)) - return -EOPNOTSUPP; + if (manager_server_is_stub(t->scope->manager, t->server)) + return -ELOOP; - r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); - if (r < 0) - return r; + if (!t->bypass) { + if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(dns_transaction_key(t)->type)) + return -EOPNOTSUPP; + + r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); + if (r < 0) + return r; + } if (t->server->stream && (DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level) == t->server->stream->encrypted)) s = dns_stream_ref(t->server->stream); @@ -600,7 +723,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { * the IP address, in case this is a reverse * PTR lookup */ - r = dns_name_address(dns_resource_key_name(t->key), &family, &address); + r = dns_name_address(dns_resource_key_name(dns_transaction_key(t)), &family, &address); if (r < 0) return r; if (r == 0) @@ -659,7 +782,7 @@ static int dns_transaction_emit_tcp(DnsTransaction *t) { r = dns_stream_write_packet(t->stream, t->sent); if (r < 0) { - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, /* use_graveyard= */ false); return r; } @@ -682,21 +805,27 @@ static void dns_transaction_cache_answer(DnsTransaction *t) { if (t->scope->manager->enable_cache == DNS_CACHE_MODE_NO) return; - /* We never cache if this packet is from the local host, under - * the assumption that a locally running DNS server would - * cache this anyway, and probably knows better when to flush - * the cache then we could. */ - if (!DNS_PACKET_SHALL_CACHE(t->received)) + /* If validation is turned off for this transaction, but DNSSEC is on, then let's not cache this */ + if (FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) && t->scope->dnssec_mode != DNSSEC_NO) + return; + + /* Packet from localhost? */ + if (!t->scope->manager->cache_from_localhost && + in_addr_is_localhost(t->received->family, &t->received->sender) != 0) return; dns_cache_put(&t->scope->cache, t->scope->manager->enable_cache, - t->key, + dns_transaction_key(t), t->answer_rcode, t->answer, - t->answer_authenticated, + DNS_PACKET_CD(t->received) ? t->received : NULL, /* only cache full packets with CD on, + * since our usecase for caching them + * is "bypass" mode which is only + * enabled for CD packets. */ + t->answer_query_flags, + t->answer_dnssec_result, t->answer_nsec_ttl, - 0, t->received->family, &t->received->sender); } @@ -715,6 +844,7 @@ static bool dns_transaction_dnssec_is_live(DnsTransaction *t) { static int dns_transaction_dnssec_ready(DnsTransaction *t) { DnsTransaction *dt; + int r; assert(t); @@ -748,7 +878,7 @@ static int dns_transaction_dnssec_ready(DnsTransaction *t) { case DNS_TRANSACTION_DNSSEC_FAILED: /* We handle DNSSEC failures different from other errors, as we care about the DNSSEC - * validationr result */ + * validation result */ log_debug("Auxiliary DNSSEC RR query failed validation: %s", dnssec_result_to_string(dt->answer_dnssec_result)); t->answer_dnssec_result = dt->answer_dnssec_result; /* Copy error code over */ @@ -765,6 +895,18 @@ static int dns_transaction_dnssec_ready(DnsTransaction *t) { return 1; fail: + /* Some auxiliary DNSSEC transaction failed for some reason. Maybe we learned something about the + * server due to this failure, and the feature level is now different? Let's see and restart the + * transaction if so. If not, let's propagate the auxiliary failure. + * + * This is particularly relevant if an auxiliary request figured out that DNSSEC doesn't work, and we + * are in permissive DNSSEC mode, and thus should restart things without DNSSEC magic. */ + r = dns_transaction_maybe_restart(t); + if (r < 0) + return r; + if (r > 0) + return 0; /* don't validate just yet, we restarted things */ + t->answer_dnssec_result = DNSSEC_FAILED_AUXILIARY; dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); return 0; @@ -806,11 +948,8 @@ static void dns_transaction_process_dnssec(DnsTransaction *t) { /* We are not in automatic downgrade mode, and the server is bad. Let's try a different server, maybe * that works. */ - if (t->n_picked_servers < dns_scope_get_n_dns_servers(t->scope)) { - /* We tried fewer servers on this transaction than we know, let's try another one then */ - dns_transaction_retry(t, true); + if (dns_transaction_limited_retry(t)) return; - } /* OK, let's give up, apparently all servers we tried didn't work. */ dns_transaction_complete(t, DNS_TRANSACTION_DNSSEC_FAILED); @@ -850,11 +989,11 @@ static int dns_transaction_has_positive_answer(DnsTransaction *t, DnsAnswerFlags /* Checks whether the answer is positive, i.e. either a direct * answer to the question, or a CNAME/DNAME for it */ - r = dns_answer_match_key(t->answer, t->key, flags); + r = dns_answer_match_key(t->answer, dns_transaction_key(t), flags); if (r != 0) return r; - r = dns_answer_find_cname_or_dname(t->answer, t->key, NULL, flags); + r = dns_answer_find_cname_or_dname(t->answer, dns_transaction_key(t), NULL, flags); if (r != 0) return r; @@ -891,8 +1030,8 @@ static int dns_transaction_fix_rcode(DnsTransaction *t) { return 0; } -void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { - usec_t ts; +void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypted) { + bool retry_with_tcp = false; int r; assert(t); @@ -907,7 +1046,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { * should hence not attempt to access the query or transaction * after calling this function. */ - log_debug("Processing incoming packet on transaction %" PRIu16" (rcode=%s).", + log_debug("Processing incoming packet of size %zu on transaction %" PRIu16" (rcode=%s).", + p->size, t->id, dns_rcode_to_string(DNS_PACKET_RCODE(p))); switch (t->scope->protocol) { @@ -975,14 +1115,13 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } } - assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); - switch (t->scope->protocol) { case DNS_PROTOCOL_DNS: assert(t->server); - if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) { + if (!t->bypass && + IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_FORMERR, DNS_RCODE_SERVFAIL, DNS_RCODE_NOTIMP)) { /* Request failed, immediately try again with reduced features */ @@ -995,11 +1134,8 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { * packet loss, but is not going to give us better rcodes should we actually have * managed to get them already at UDP level. */ - if (t->n_picked_servers < dns_scope_get_n_dns_servers(t->scope)) { - /* We tried fewer servers on this transaction than we know, let's try another one then */ - dns_transaction_retry(t, true); + if (dns_transaction_limited_retry(t)) return; - } /* Give up, accept the rcode */ log_debug("Server returned error: %s", dns_rcode_to_string(DNS_PACKET_RCODE(p))); @@ -1009,19 +1145,19 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* Reduce this feature level by one and try again. */ switch (t->current_feature_level) { case DNS_SERVER_FEATURE_LEVEL_TLS_DO: - t->clamp_feature_level = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN; + t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN; break; case DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN + 1: /* Skip plain TLS when TLS is not supported */ - t->clamp_feature_level = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN - 1; + t->clamp_feature_level_servfail = DNS_SERVER_FEATURE_LEVEL_TLS_PLAIN - 1; break; default: - t->clamp_feature_level = t->current_feature_level - 1; + t->clamp_feature_level_servfail = t->current_feature_level - 1; } log_debug("Server returned error %s, retrying transaction with reduced feature level %s.", dns_rcode_to_string(DNS_PACKET_RCODE(p)), - dns_server_feature_level_to_string(t->clamp_feature_level)); + dns_server_feature_level_to_string(t->clamp_feature_level_servfail)); dns_transaction_retry(t, false /* use the same server */); return; @@ -1030,8 +1166,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { if (DNS_PACKET_RCODE(p) == DNS_RCODE_REFUSED) { /* This server refused our request? If so, try again, use a different server */ log_debug("Server returned REFUSED, switching servers, and retrying."); - dns_transaction_retry(t, true /* pick a new server */); - return; + + if (dns_transaction_limited_retry(t)) + return; + + break; } if (DNS_PACKET_TC(p)) @@ -1041,7 +1180,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { case DNS_PROTOCOL_LLMNR: case DNS_PROTOCOL_MDNS: - dns_scope_packet_received(t->scope, ts - t->start_usec); + dns_scope_packet_received(t->scope, p->timestamp - t->start_usec); break; default: @@ -1056,9 +1195,30 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { return; } - log_debug("Reply truncated, retrying via TCP."); - /* Response was truncated, let's try again with good old TCP */ + log_debug("Reply truncated, retrying via TCP."); + retry_with_tcp = true; + + } else if (t->scope->protocol == DNS_PROTOCOL_DNS && + DNS_PACKET_IS_FRAGMENTED(p)) { + + /* Report the fragment size, so that we downgrade from LARGE to regular EDNS0 if needed */ + if (t->server) + dns_server_packet_udp_fragmented(t->server, dns_packet_size_unfragmented(p)); + + if (t->current_feature_level > DNS_SERVER_FEATURE_LEVEL_UDP) { + /* Packet was fragmented. Let's retry with TCP to avoid fragmentation attack + * issues. (We don't do that on the lowest feature level however, since crappy DNS + * servers often do not implement TCP, hence falling back to TCP on fragmentation is + * counter-productive there.) */ + + log_debug("Reply fragmented, retrying via TCP. (Largest fragment size: %zu; Datagram size: %zu)", + p->fragsize, p->size); + retry_with_tcp = true; + } + } + + if (retry_with_tcp) { r = dns_transaction_emit_tcp(t); if (r == -ESRCH) { /* No servers found? Damn! */ @@ -1077,7 +1237,11 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { goto fail; /* On DNS, couldn't send? Try immediately again, with a new server */ - dns_transaction_retry(t, true); + if (dns_transaction_limited_retry(t)) + return; + + /* No new server to try, give up */ + dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED); } return; @@ -1086,24 +1250,79 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { /* After the superficial checks, actually parse the message. */ r = dns_packet_extract(p); if (r < 0) { + if (t->server) { + dns_server_packet_invalid(t->server, t->current_feature_level); + + r = dns_transaction_maybe_restart(t); + if (r < 0) + goto fail; + if (r > 0) /* Transaction got restarted... */ + return; + } + dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); return; } + if (t->scope->protocol == DNS_PROTOCOL_DNS && + !t->bypass && + DNS_PACKET_RCODE(p) == DNS_RCODE_NXDOMAIN && + p->opt && !DNS_PACKET_DO(p) && + DNS_SERVER_FEATURE_LEVEL_IS_EDNS0(t->current_feature_level) && + DNS_SERVER_FEATURE_LEVEL_IS_UDP(t->current_feature_level) && + t->scope->dnssec_mode != DNSSEC_YES) { + + /* Some captive portals are special in that the Aruba/Datavalet hardware will miss + * replacing the packets with the local server IP to point to the authenticated side + * of the network if EDNS0 is enabled. Instead they return NXDOMAIN, with DO bit set + * to zero... nothing to see here, yet respond with the captive portal IP, when using + * the more simple UDP level. + * + * Common portal names that fail like so are: + * secure.datavalet.io + * securelogin.arubanetworks.com + * securelogin.networks.mycompany.com + * + * Thus retry NXDOMAIN RCODES with a lower feature level. + * + * Do not lower the server's tracked feature level, as the captive portal should not + * be lying for the wider internet (e.g. _other_ queries were observed fine with + * EDNS0 on these networks, post auth), i.e. let's just lower the level transaction's + * feature level. + * + * This is reported as https://github.com/dns-violations/dns-violations/blob/master/2018/DVE-2018-0001.md + */ + + t->clamp_feature_level_nxdomain = DNS_SERVER_FEATURE_LEVEL_UDP; + + log_debug("Server returned error %s in EDNS0 mode, retrying transaction with reduced feature level %s (DVE-2018-0001 mitigation)", + dns_rcode_to_string(DNS_PACKET_RCODE(p)), + dns_server_feature_level_to_string(t->clamp_feature_level_nxdomain)); + + dns_transaction_retry(t, false /* use the same server */); + return; + } + if (t->server) { /* Report that we successfully received a valid packet with a good rcode after we initially got a bad * rcode and subsequently downgraded the protocol */ if (IN_SET(DNS_PACKET_RCODE(p), DNS_RCODE_SUCCESS, DNS_RCODE_NXDOMAIN) && - t->clamp_feature_level != _DNS_SERVER_FEATURE_LEVEL_INVALID) - dns_server_packet_rcode_downgrade(t->server, t->clamp_feature_level); + t->clamp_feature_level_servfail != _DNS_SERVER_FEATURE_LEVEL_INVALID) + dns_server_packet_rcode_downgrade(t->server, t->clamp_feature_level_servfail); /* Report that the OPT RR was missing */ if (!p->opt) dns_server_packet_bad_opt(t->server, t->current_feature_level); - /* Report that we successfully received a packet */ - dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, p->size); + /* Report that the server didn't copy our query DO bit from request to response */ + if (DNS_PACKET_DO(t->sent) && !DNS_PACKET_DO(t->received)) + dns_server_packet_do_off(t->server, t->current_feature_level); + + /* Report that we successfully received a packet. We keep track of the largest packet + * size/fragment size we got. Which is useful for announcing the EDNS(0) packet size we can + * receive to our server. */ + dns_server_packet_received(t->server, p->ipproto, t->current_feature_level, dns_packet_size_unfragmented(p)); } /* See if we know things we didn't know before that indicate we better restart the lookup immediately. */ @@ -1117,7 +1336,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { * to the request. For mDNS this check doesn't make sense, because the section 6 of RFC6762 states * that "Multicast DNS responses MUST NOT contain any questions in the Question Section". */ if (t->scope->protocol != DNS_PROTOCOL_MDNS) { - r = dns_packet_is_reply_for(p, t->key); + r = dns_packet_is_reply_for(p, dns_transaction_key(t)); if (r < 0) goto fail; if (r == 0) { @@ -1126,12 +1345,16 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { } } - /* Install the answer as answer to the transaction */ + /* Install the answer as answer to the transaction. We ref the answer twice here: the main `answer` + * field is later replaced by the DNSSEC validated subset. The 'answer_auxiliary' field carries the + * original complete record set, including RRSIG and friends. We use this when passing data to + * clients that ask for DNSSEC metadata. */ dns_answer_unref(t->answer); t->answer = dns_answer_ref(p->answer); t->answer_rcode = DNS_PACKET_RCODE(p); t->answer_dnssec_result = _DNSSEC_RESULT_INVALID; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, encrypted); r = dns_transaction_fix_rcode(t); if (r < 0) @@ -1156,7 +1379,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) { if (r > 0) { /* There are DNSSEC transactions pending now. Update the state accordingly. */ t->state = DNS_TRANSACTION_VALIDATING; - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); dns_transaction_stop_timeout(t); return; } @@ -1187,7 +1410,12 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &usec) >= 0); dns_server_packet_lost(t->server, IPPROTO_UDP, t->current_feature_level); - dns_transaction_retry(t, true); + dns_transaction_close_connection(t, /* use_graveyard = */ false); + + if (dns_transaction_limited_retry(t)) /* Try a different server */ + return 0; + + dns_transaction_complete_errno(t, r); return 0; } if (r < 0) { @@ -1213,7 +1441,7 @@ static int on_dns_packet(sd_event_source *s, int fd, uint32_t revents, void *use return 0; } - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); return 0; } @@ -1228,16 +1456,22 @@ static int dns_transaction_emit_udp(DnsTransaction *t) { if (r < 0) return r; + if (manager_server_is_stub(t->scope->manager, t->server)) + return -ELOOP; + if (t->current_feature_level < DNS_SERVER_FEATURE_LEVEL_UDP || DNS_SERVER_FEATURE_LEVEL_IS_TLS(t->current_feature_level)) return -EAGAIN; /* Sorry, can't do UDP, try TCP! */ - if (!dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(t->key->type)) + if (!t->bypass && !dns_server_dnssec_supported(t->server) && dns_type_is_dnssec(dns_transaction_key(t)->type)) return -EOPNOTSUPP; if (r > 0 || t->dns_udp_fd < 0) { /* Server changed, or no connection yet. */ int fd; - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); + + /* Before we allocate a new UDP socket, let's process the graveyard a bit to free some fds */ + manager_socket_graveyard_process(t->scope->manager); fd = dns_scope_socket_udp(t->scope, t->server); if (fd < 0) @@ -1253,13 +1487,15 @@ static int dns_transaction_emit_udp(DnsTransaction *t) { t->dns_udp_fd = fd; } - r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); - if (r < 0) - return r; + if (!t->bypass) { + r = dns_server_adjust_opt(t->server, t->sent, t->current_feature_level); + if (r < 0) + return r; + } } else - dns_transaction_close_connection(t); + dns_transaction_close_connection(t, true); - r = dns_scope_emit_udp(t->scope, t->dns_udp_fd, t->sent); + r = dns_scope_emit_udp(t->scope, t->dns_udp_fd, t->server ? t->server->family : AF_UNSPEC, t->sent); if (r < 0) return r; @@ -1298,7 +1534,8 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat log_debug("Timeout reached on transaction %" PRIu16 ".", t->id); - dns_transaction_retry(t, true); + dns_transaction_retry(t, true); /* try a different server, but given this means packet loss, let's do + * so even if we already tried a bunch */ return 0; } @@ -1333,6 +1570,30 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) { } } +static void dns_transaction_randomize_answer(DnsTransaction *t) { + int r; + + assert(t); + + /* Randomizes the order of the answer array. This is done for all cached responses, so that we return + * a different order each time. We do this only for DNS traffic, in order to do some minimal, crappy + * load balancing. We don't do this for LLMNR or mDNS, since the order (preferring link-local + * addresses, and such like) might have meaning there, and load balancing is pointless. */ + + if (t->scope->protocol != DNS_PROTOCOL_DNS) + return; + + /* No point in randomizing, if there's just one RR */ + if (dns_answer_size(t->answer) <= 1) + return; + + r = dns_answer_reserve_or_clone(&t->answer, 0); + if (r < 0) /* If this fails, just don't randomize, this is non-essential stuff after all */ + return (void) log_debug_errno(r, "Failed to clone answer record, not randomizing RR order of answer: %m"); + + dns_answer_randomize(t->answer); +} + static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { int r; @@ -1377,94 +1638,105 @@ static int dns_transaction_prepare(DnsTransaction *t, usec_t ts) { dns_transaction_flush_dnssec_transactions(t); /* Check the trust anchor. Do so only on classic DNS, since DNSSEC does not apply otherwise. */ - if (t->scope->protocol == DNS_PROTOCOL_DNS) { - r = dns_trust_anchor_lookup_positive(&t->scope->manager->trust_anchor, t->key, &t->answer); + if (t->scope->protocol == DNS_PROTOCOL_DNS && + !FLAGS_SET(t->query_flags, SD_RESOLVED_NO_TRUST_ANCHOR)) { + r = dns_trust_anchor_lookup_positive(&t->scope->manager->trust_anchor, dns_transaction_key(t), &t->answer); if (r < 0) return r; if (r > 0) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); return 0; } - if (dns_name_is_root(dns_resource_key_name(t->key)) && - t->key->type == DNS_TYPE_DS) { + if (dns_name_is_root(dns_resource_key_name(dns_transaction_key(t))) && + dns_transaction_key(t)->type == DNS_TYPE_DS) { - /* Hmm, this is a request for the root DS? A - * DS RR doesn't exist in the root zone, and - * if our trust anchor didn't know it either, - * this means we cannot do any DNSSEC logic - * anymore. */ + /* Hmm, this is a request for the root DS? A DS RR doesn't exist in the root zone, + * and if our trust anchor didn't know it either, this means we cannot do any DNSSEC + * logic anymore. */ if (t->scope->dnssec_mode == DNSSEC_ALLOW_DOWNGRADE) { - /* We are in downgrade mode. In this - * case, synthesize an unsigned empty - * response, so that the any lookup - * depending on this one can continue - * assuming there was no DS, and hence - * the root zone was unsigned. */ + /* We are in downgrade mode. In this case, synthesize an unsigned empty + * response, so that the any lookup depending on this one can continue + * assuming there was no DS, and hence the root zone was unsigned. */ t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_CONFIDENTIAL, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); } else - /* If we are not in downgrade mode, - * then fail the lookup, because we - * cannot reasonably answer it. There - * might be DS RRs, but we don't know - * them, and the DNS server won't tell - * them to us (and even if it would, - * we couldn't validate and trust them. */ + /* If we are not in downgrade mode, then fail the lookup, because we cannot + * reasonably answer it. There might be DS RRs, but we don't know them, and + * the DNS server won't tell them to us (and even if it would, we couldn't + * validate and trust them. */ dns_transaction_complete(t, DNS_TRANSACTION_NO_TRUST_ANCHOR); return 0; } } - /* Check the zone, but only if this transaction is not used - * for probing or verifying a zone item. */ - if (set_isempty(t->notify_zone_items)) { - - r = dns_zone_lookup(&t->scope->zone, t->key, dns_scope_ifindex(t->scope), &t->answer, NULL, NULL); + /* Check the zone. */ + if (!FLAGS_SET(t->query_flags, SD_RESOLVED_NO_ZONE)) { + r = dns_zone_lookup(&t->scope->zone, dns_transaction_key(t), dns_scope_ifindex(t->scope), &t->answer, NULL, NULL); if (r < 0) return r; if (r > 0) { t->answer_rcode = DNS_RCODE_SUCCESS; t->answer_source = DNS_TRANSACTION_ZONE; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED|SD_RESOLVED_CONFIDENTIAL, true); dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); return 0; } } - /* Check the cache, but only if this transaction is not used - * for probing or verifying a zone item. */ - if (set_isempty(t->notify_zone_items)) { + /* Check the cache. */ + if (!FLAGS_SET(t->query_flags, SD_RESOLVED_NO_CACHE)) { - /* Before trying the cache, let's make sure we figured out a - * server to use. Should this cause a change of server this - * might flush the cache. */ + /* Before trying the cache, let's make sure we figured out a server to use. Should this cause + * a change of server this might flush the cache. */ (void) dns_scope_get_dns_server(t->scope); /* Let's then prune all outdated entries */ dns_cache_prune(&t->scope->cache); - r = dns_cache_lookup(&t->scope->cache, t->key, t->clamp_ttl, &t->answer_rcode, &t->answer, &t->answer_authenticated); + r = dns_cache_lookup( + &t->scope->cache, + dns_transaction_key(t), + t->query_flags, + &t->answer_rcode, + &t->answer, + &t->received, + &t->answer_query_flags, + &t->answer_dnssec_result); if (r < 0) return r; if (r > 0) { - t->answer_source = DNS_TRANSACTION_CACHE; - if (t->answer_rcode == DNS_RCODE_SUCCESS) - dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); - else - dns_transaction_complete(t, DNS_TRANSACTION_RCODE_FAILURE); - return 0; + dns_transaction_randomize_answer(t); + + if (t->bypass && t->scope->protocol == DNS_PROTOCOL_DNS && !t->received) + /* When bypass mode is on, do not use cached data unless it came with a full + * packet. */ + dns_transaction_reset_answer(t); + else { + t->answer_source = DNS_TRANSACTION_CACHE; + if (t->answer_rcode == DNS_RCODE_SUCCESS) + dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); + else + dns_transaction_complete(t, DNS_TRANSACTION_RCODE_FAILURE); + return 0; + } } } + if (FLAGS_SET(t->query_flags, SD_RESOLVED_NO_NETWORK)) { + dns_transaction_complete(t, DNS_TRANSACTION_NO_SOURCE); + return 0; + } + return 1; } @@ -1489,17 +1761,17 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { if (r < 0) return r; - r = dns_packet_append_key(p, t->key, 0, NULL); + r = dns_packet_append_key(p, dns_transaction_key(t), 0, NULL); if (r < 0) return r; qdcount = 1; - if (dns_key_is_shared(t->key)) + if (dns_key_is_shared(dns_transaction_key(t))) add_known_answers = true; - if (t->key->type == DNS_TYPE_ANY) { - r = set_ensure_put(&keys, &dns_resource_key_hash_ops, t->key); + if (dns_transaction_key(t)->type == DNS_TYPE_ANY) { + r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(t)); if (r < 0) return r; } @@ -1527,7 +1799,7 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { if (qdcount >= UINT16_MAX) break; - r = dns_packet_append_key(p, other->key, 0, NULL); + r = dns_packet_append_key(p, dns_transaction_key(other), 0, NULL); /* * If we can't stuff more questions into the packet, just give up. @@ -1561,11 +1833,11 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { qdcount++; - if (dns_key_is_shared(other->key)) + if (dns_key_is_shared(dns_transaction_key(other))) add_known_answers = true; - if (other->key->type == DNS_TYPE_ANY) { - r = set_ensure_put(&keys, &dns_resource_key_hash_ops, other->key); + if (dns_transaction_key(other)->type == DNS_TYPE_ANY) { + r = set_ensure_put(&keys, &dns_resource_key_hash_ops, dns_transaction_key(other)); if (r < 0) return r; } @@ -1588,11 +1860,9 @@ static int dns_transaction_make_packet_mdns(DnsTransaction *t) { if (r < 0) return r; - r = dns_packet_append_answer(p, answer); + r = dns_packet_append_answer(p, answer, &nscount); if (r < 0) return r; - - nscount += dns_answer_size(answer); } DNS_PACKET_HEADER(p)->nscount = htobe16(nscount); @@ -1613,19 +1883,31 @@ static int dns_transaction_make_packet(DnsTransaction *t) { if (t->sent) return 0; - r = dns_packet_new_query(&p, t->scope->protocol, 0, t->scope->dnssec_mode != DNSSEC_NO); - if (r < 0) - return r; + if (t->bypass && t->bypass->protocol == t->scope->protocol) { + /* If bypass logic is enabled and the protocol if the original packet and our scope match, + * take the original packet, copy it, and patch in our new ID */ + r = dns_packet_dup(&p, t->bypass); + if (r < 0) + return r; + } else { + r = dns_packet_new_query( + &p, t->scope->protocol, + /* min_alloc_dsize = */ 0, + /* dnssec_cd = */ !FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) && + t->scope->dnssec_mode != DNSSEC_NO); + if (r < 0) + return r; - r = dns_packet_append_key(p, t->key, 0, NULL); - if (r < 0) - return r; + r = dns_packet_append_key(p, dns_transaction_key(t), 0, NULL); + if (r < 0) + return r; + + DNS_PACKET_HEADER(p)->qdcount = htobe16(1); + } - DNS_PACKET_HEADER(p)->qdcount = htobe16(1); DNS_PACKET_HEADER(p)->id = t->id; t->sent = TAKE_PTR(p); - return 0; } @@ -1646,12 +1928,14 @@ int dns_transaction_go(DnsTransaction *t) { if (r <= 0) return r; - log_debug("Transaction %" PRIu16 " for <%s> scope %s on %s/%s.", + log_debug("%s transaction %" PRIu16 " for <%s> scope %s on %s/%s (validate=%s).", + t->bypass ? "Bypass" : "Regular", t->id, - dns_resource_key_to_string(t->key, key_str, sizeof key_str), + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str), dns_protocol_to_string(t->scope->protocol), t->scope->link ? t->scope->link->ifname : "*", - af_to_name_short(t->scope->family)); + af_to_name_short(t->scope->family), + yes_no(!FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE))); if (!t->initial_jitter_scheduled && IN_SET(t->scope->protocol, DNS_PROTOCOL_LLMNR, DNS_PROTOCOL_MDNS)) { @@ -1705,8 +1989,8 @@ int dns_transaction_go(DnsTransaction *t) { return r; if (t->scope->protocol == DNS_PROTOCOL_LLMNR && - (dns_name_endswith(dns_resource_key_name(t->key), "in-addr.arpa") > 0 || - dns_name_endswith(dns_resource_key_name(t->key), "ip6.arpa") > 0)) { + (dns_name_endswith(dns_resource_key_name(dns_transaction_key(t)), "in-addr.arpa") > 0 || + dns_name_endswith(dns_resource_key_name(dns_transaction_key(t)), "ip6.arpa") > 0)) { /* RFC 4795, Section 2.4. says reverse lookups shall * always be made via TCP on LLMNR */ @@ -1722,7 +2006,23 @@ int dns_transaction_go(DnsTransaction *t) { if (IN_SET(r, -EMSGSIZE, -EAGAIN)) r = dns_transaction_emit_tcp(t); } + if (r == -ELOOP) { + if (t->scope->protocol != DNS_PROTOCOL_DNS) + return r; + /* One of our own stub listeners */ + log_debug_errno(r, "Detected that specified DNS server is our own extra listener, switching DNS servers."); + + dns_scope_next_dns_server(t->scope, t->server); + + if (dns_scope_get_dns_server(t->scope) == t->server) { + log_debug_errno(r, "Still pointing to extra listener after switching DNS servers, refusing operation."); + dns_transaction_complete(t, DNS_TRANSACTION_STUB_LOOP); + return 0; + } + + return dns_transaction_go(t); + } if (r == -ESRCH) { /* No servers to send this to? */ dns_transaction_complete(t, DNS_TRANSACTION_NO_SERVERS); @@ -1744,7 +2044,7 @@ int dns_transaction_go(DnsTransaction *t) { return r; /* Couldn't send? Try immediately again, with a new server */ - dns_scope_next_dns_server(t->scope); + dns_scope_next_dns_server(t->scope, t->server); return dns_transaction_go(t); } @@ -1797,9 +2097,9 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource assert(ret); assert(key); - aux = dns_scope_find_transaction(t->scope, key, true); + aux = dns_scope_find_transaction(t->scope, key, t->query_flags); if (!aux) { - r = dns_transaction_new(&aux, t->scope, key); + r = dns_transaction_new(&aux, t->scope, key, NULL, t->query_flags); if (r < 0) return r; } else { @@ -1817,9 +2117,9 @@ static int dns_transaction_add_dnssec_transaction(DnsTransaction *t, DnsResource return log_debug_errno(SYNTHETIC_ERRNO(ELOOP), "Potential cyclic dependency, refusing to add transaction %" PRIu16 " (%s) as dependency for %" PRIu16 " (%s).", aux->id, - dns_resource_key_to_string(t->key, s, sizeof s), + dns_resource_key_to_string(dns_transaction_key(t), s, sizeof s), t->id, - dns_resource_key_to_string(aux->key, saux, sizeof saux)); + dns_resource_key_to_string(dns_transaction_key(aux), saux, sizeof saux)); } } @@ -1912,7 +2212,7 @@ static int dns_transaction_has_unsigned_negative_answer(DnsTransaction *t) { /* Is this key explicitly listed as a negative trust anchor? * If so, it's nothing we need to care about */ - r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(dns_transaction_key(t))); if (r < 0) return r; if (r > 0) @@ -1941,11 +2241,11 @@ static int dns_transaction_is_primary_response(DnsTransaction *t, DnsResourceRec * i.e. either matches the question precisely or is a * CNAME/DNAME for it. */ - r = dns_resource_key_match_rr(t->key, rr, NULL); + r = dns_resource_key_match_rr(dns_transaction_key(t), rr, NULL); if (r != 0) return r; - return dns_resource_key_match_cname_or_dname(t->key, rr->key, NULL); + return dns_resource_key_match_cname_or_dname(dns_transaction_key(t), rr->key, NULL); } static bool dns_transaction_dnssec_supported(DnsTransaction *t) { @@ -2009,7 +2309,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * - For other queries with no matching response RRs, and no NSEC/NSEC3, the SOA RR */ - if (t->scope->dnssec_mode == DNSSEC_NO) + if (FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) || t->scope->dnssec_mode == DNSSEC_NO) return 0; if (t->answer_source != DNS_TRANSACTION_NETWORK) return 0; /* We only need to validate stuff from the network */ @@ -2057,7 +2357,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * in another transaction whose additional RRs * point back to the original transaction, and * we deadlock. */ - r = dns_name_endswith(dns_resource_key_name(t->key), rr->rrsig.signer); + r = dns_name_endswith(dns_resource_key_name(dns_transaction_key(t)), rr->rrsig.signer); if (r < 0) return r; if (r == 0) @@ -2086,7 +2386,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * up in request loops, and want to keep * additional traffic down. */ - r = dns_name_endswith(dns_resource_key_name(t->key), dns_resource_key_name(rr->key)); + r = dns_name_endswith(dns_resource_key_name(dns_transaction_key(t)), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) @@ -2116,7 +2416,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * this RR matches our original question, * however. */ - r = dns_resource_key_match_rr(t->key, rr, NULL); + r = dns_resource_key_match_rr(dns_transaction_key(t), rr, NULL); if (r < 0) return r; if (r == 0) { @@ -2124,7 +2424,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * a negative reply, and we need the SOA RR's TTL in order to cache a negative entry? * If so, we need to validate it, too. */ - r = dns_answer_match_key(t->answer, t->key, NULL); + r = dns_answer_match_key(t->answer, dns_transaction_key(t), NULL); if (r < 0) return r; if (r > 0) /* positive reply, we won't need the SOA and hence don't need to validate @@ -2133,7 +2433,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { /* Only bother with this if the SOA/NS RR we are looking at is actually a parent of * what we are looking for, otherwise there's no value in it for us. */ - r = dns_name_endswith(dns_resource_key_name(t->key), dns_resource_key_name(rr->key)); + r = dns_name_endswith(dns_resource_key_name(dns_transaction_key(t)), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) @@ -2259,7 +2559,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { const char *name; uint16_t type = 0; - name = dns_resource_key_name(t->key); + name = dns_resource_key_name(dns_transaction_key(t)); /* If this was a SOA or NS request, then check if there's a DS RR for the same domain. Note that this * could also be used as indication that we are not at a zone apex, but in real world setups there are @@ -2268,16 +2568,16 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { * is signed, hence ask the parent SOA in that case. If this was any other RR then ask for the SOA RR, * to see if that is signed. */ - if (t->key->type == DNS_TYPE_DS) { + if (dns_transaction_key(t)->type == DNS_TYPE_DS) { r = dns_name_parent(&name); if (r > 0) { type = DNS_TYPE_SOA; log_debug("Requesting parent SOA (→ %s) to validate transaction %" PRIu16 " (%s, unsigned empty DS response).", - name, t->id, dns_resource_key_name(t->key)); + name, t->id, dns_resource_key_name(dns_transaction_key(t))); } else name = NULL; - } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) { + } else if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_SOA, DNS_TYPE_NS)) { type = DNS_TYPE_DS; log_debug("Requesting DS (→ %s) to validate transaction %" PRIu16 " (%s, unsigned empty SOA/NS response).", @@ -2292,7 +2592,7 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) { if (name) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *soa = NULL; - soa = dns_resource_key_new(t->key->class, type, name); + soa = dns_resource_key_new(dns_transaction_key(t)->class, type, name); if (!soa) return -ENOMEM; @@ -2318,8 +2618,8 @@ void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source) { } static int dns_transaction_validate_dnskey_by_ds(DnsTransaction *t) { - DnsResourceRecord *rr; - int ifindex, r; + DnsAnswerItem *item; + int r; assert(t); @@ -2327,16 +2627,16 @@ static int dns_transaction_validate_dnskey_by_ds(DnsTransaction *t) { * RRs from the list of validated keys to the list of * validated keys. */ - DNS_ANSWER_FOREACH_IFINDEX(rr, ifindex, t->answer) { + DNS_ANSWER_FOREACH_ITEM(item, t->answer) { - r = dnssec_verify_dnskey_by_ds_search(rr, t->validated_keys); + r = dnssec_verify_dnskey_by_ds_search(item->rr, t->validated_keys); if (r < 0) return r; if (r == 0) continue; /* If so, the DNSKEY is validated too. */ - r = dns_answer_add_extend(&t->validated_keys, rr, ifindex, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add_extend(&t->validated_keys, item->rr, item->ifindex, item->flags|DNS_ANSWER_AUTHENTICATED, item->rrsig); if (r < 0) return r; } @@ -2379,12 +2679,12 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * SET_FOREACH(dt, t->dnssec_transactions) { - if (dt->key->class != rr->key->class) + if (dns_transaction_key(dt)->class != rr->key->class) continue; - if (dt->key->type != DNS_TYPE_DS) + if (dns_transaction_key(dt)->type != DNS_TYPE_DS) continue; - r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key)); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) @@ -2394,10 +2694,10 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * * RRs we are looking at. If it discovered signed DS * RRs, then we need to be signed, too. */ - if (!dt->answer_authenticated) + if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) return false; - return dns_answer_match_key(dt->answer, dt->key, NULL); + return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL); } /* We found nothing that proves this is safe to leave @@ -2420,9 +2720,9 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * SET_FOREACH(dt, t->dnssec_transactions) { - if (dt->key->class != rr->key->class) + if (dns_transaction_key(dt)->class != rr->key->class) continue; - if (dt->key->type != DNS_TYPE_SOA) + if (dns_transaction_key(dt)->type != DNS_TYPE_SOA) continue; if (!parent) { @@ -2440,13 +2740,13 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * } } - r = dns_name_equal(dns_resource_key_name(dt->key), parent); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), parent); if (r < 0) return r; if (r == 0) continue; - return t->answer_authenticated; + return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED); } return true; @@ -2459,23 +2759,21 @@ static int dns_transaction_requires_rrsig(DnsTransaction *t, DnsResourceRecord * SET_FOREACH(dt, t->dnssec_transactions) { - if (dt->key->class != rr->key->class) + if (dns_transaction_key(dt)->class != rr->key->class) continue; - if (dt->key->type != DNS_TYPE_SOA) + if (dns_transaction_key(dt)->type != DNS_TYPE_SOA) continue; - r = dns_name_equal(dns_resource_key_name(dt->key), dns_resource_key_name(rr->key)); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), dns_resource_key_name(rr->key)); if (r < 0) return r; if (r == 0) continue; - /* We found the transaction that was supposed to find - * the SOA RR for us. It was successful, but found no - * RR for us. This means we are not at a zone cut. In - * this case, we require authentication if the SOA - * lookup was authenticated too. */ - return t->answer_authenticated; + /* We found the transaction that was supposed to find the SOA RR for us. It was + * successful, but found no RR for us. This means we are not at a zone cut. In this + * case, we require authentication if the SOA lookup was authenticated too. */ + return FLAGS_SET(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED); } return true; @@ -2522,10 +2820,10 @@ static int dns_transaction_in_private_tld(DnsTransaction *t, const DnsResourceKe SET_FOREACH(dt, t->dnssec_transactions) { - if (dt->key->class != key->class) + if (dns_transaction_key(dt)->class != key->class) continue; - r = dns_name_equal(dns_resource_key_name(dt->key), tld); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), tld); if (r < 0) return r; if (r == 0) @@ -2556,16 +2854,16 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { if (t->scope->dnssec_mode == DNSSEC_NO) return false; - if (dns_type_is_pseudo(t->key->type)) + if (dns_type_is_pseudo(dns_transaction_key(t)->type)) return -EINVAL; - r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(t->key)); + r = dns_transaction_negative_trust_anchor_lookup(t, dns_resource_key_name(dns_transaction_key(t))); if (r < 0) return r; if (r > 0) return false; - r = dns_transaction_in_private_tld(t, t->key); + r = dns_transaction_in_private_tld(t, dns_transaction_key(t)); if (r < 0) return r; if (r > 0) { @@ -2574,13 +2872,13 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { * that fact that we didn't get any NSEC RRs. */ log_info("Detected a negative query %s in a private DNS zone, permitting unsigned response.", - dns_resource_key_to_string(t->key, key_str, sizeof key_str)); + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str)); return false; } - name = dns_resource_key_name(t->key); + name = dns_resource_key_name(dns_transaction_key(t)); - if (t->key->type == DNS_TYPE_DS) { + if (dns_transaction_key(t)->type == DNS_TYPE_DS) { /* We got a negative reply for this DS lookup? DS RRs are signed when their parent zone is signed, * hence check the parent SOA in this case. */ @@ -2593,7 +2891,7 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { type = DNS_TYPE_SOA; - } else if (IN_SET(t->key->type, DNS_TYPE_SOA, DNS_TYPE_NS)) + } else if (IN_SET(dns_transaction_key(t)->type, DNS_TYPE_SOA, DNS_TYPE_NS)) /* We got a negative reply for this SOA/NS lookup? If so, check if there's a DS RR for this */ type = DNS_TYPE_DS; else @@ -2605,18 +2903,18 @@ static int dns_transaction_requires_nsec(DnsTransaction *t) { SET_FOREACH(dt, t->dnssec_transactions) { - if (dt->key->class != t->key->class) + if (dns_transaction_key(dt)->class != dns_transaction_key(t)->class) continue; - if (dt->key->type != type) + if (dns_transaction_key(dt)->type != type) continue; - r = dns_name_equal(dns_resource_key_name(dt->key), name); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), name); if (r < 0) return r; if (r == 0) continue; - return dt->answer_authenticated; + return FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED); } /* If in doubt, require NSEC/NSEC3 */ @@ -2649,43 +2947,40 @@ static int dns_transaction_dnskey_authenticated(DnsTransaction *t, DnsResourceRe SET_FOREACH(dt, t->dnssec_transactions) { - if (dt->key->class != rr->key->class) + if (dns_transaction_key(dt)->class != rr->key->class) continue; - if (dt->key->type == DNS_TYPE_DNSKEY) { + if (dns_transaction_key(dt)->type == DNS_TYPE_DNSKEY) { - r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), rrsig->rrsig.signer); if (r < 0) return r; if (r == 0) continue; - /* OK, we found an auxiliary DNSKEY - * lookup. If that lookup is - * authenticated, report this. */ + /* OK, we found an auxiliary DNSKEY lookup. If that lookup is authenticated, + * report this. */ - if (dt->answer_authenticated) + if (FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) return true; found = true; - } else if (dt->key->type == DNS_TYPE_DS) { + } else if (dns_transaction_key(dt)->type == DNS_TYPE_DS) { - r = dns_name_equal(dns_resource_key_name(dt->key), rrsig->rrsig.signer); + r = dns_name_equal(dns_resource_key_name(dns_transaction_key(dt)), rrsig->rrsig.signer); if (r < 0) return r; if (r == 0) continue; - /* OK, we found an auxiliary DS - * lookup. If that lookup is - * authenticated and non-zero, we - * won! */ + /* OK, we found an auxiliary DS lookup. If that lookup is authenticated and + * non-zero, we won! */ - if (!dt->answer_authenticated) + if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) return false; - return dns_answer_match_key(dt->answer, dt->key, NULL); + return dns_answer_match_key(dt->answer, dns_transaction_key(dt), NULL); } } } @@ -2770,7 +3065,7 @@ static int dns_transaction_copy_validated(DnsTransaction *t) { if (DNS_TRANSACTION_IS_LIVE(dt->state)) continue; - if (!dt->answer_authenticated) + if (!FLAGS_SET(dt->answer_query_flags, SD_RESOLVED_AUTHENTICATED)) continue; r = dns_answer_extend(&t->validated_keys, dt->answer); @@ -2827,19 +3122,26 @@ static int dnssec_validate_records( continue; } - r = dnssec_verify_rrset_search(t->answer, rr->key, t->validated_keys, USEC_INFINITY, &result, &rrsig); + r = dnssec_verify_rrset_search( + t->answer, + rr->key, + t->validated_keys, + USEC_INFINITY, + &result, + &rrsig); if (r < 0) return r; log_debug("Looking at %s: %s", strna(dns_resource_record_to_string(rr)), dnssec_result_to_string(result)); if (result == DNSSEC_VALIDATED) { + assert(rrsig); if (rr->key->type == DNS_TYPE_DNSKEY) { /* If we just validated a DNSKEY RRset, then let's add these keys to * the set of validated keys for this transaction. */ - r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_copy_by_key(&t->validated_keys, t->answer, rr->key, DNS_ANSWER_AUTHENTICATED, rrsig); if (r < 0) return r; @@ -2850,10 +3152,9 @@ static int dnssec_validate_records( return r; } - /* Add the validated RRset to the new list of validated - * RRsets, and remove it from the unvalidated RRsets. - * We mark the RRset as authenticated and cacheable. */ - r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE); + /* Add the validated RRset to the new list of validated RRsets, and remove it from + * the unvalidated RRsets. We mark the RRset as authenticated and cacheable. */ + r = dns_answer_move_by_key(validated, &t->answer, rr->key, DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE, rrsig); if (r < 0) return r; @@ -2873,6 +3174,8 @@ static int dnssec_validate_records( bool authenticated = false; const char *source; + assert(rrsig); + /* This RRset validated, but as a wildcard. This means we need * to prove via NSEC/NSEC3 that no matching non-wildcard RR exists. */ @@ -2891,8 +3194,12 @@ static int dnssec_validate_records( if (r == 0) result = DNSSEC_INVALID; else { - r = dns_answer_move_by_key(validated, &t->answer, rr->key, - authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0); + r = dns_answer_move_by_key( + validated, + &t->answer, + rr->key, + authenticated ? (DNS_ANSWER_AUTHENTICATED|DNS_ANSWER_CACHEABLE) : 0, + rrsig); if (r < 0) return r; @@ -2910,7 +3217,12 @@ static int dnssec_validate_records( if (r == 0) { /* Data does not require signing. In that case, just copy it over, * but remember that this is by no means authenticated. */ - r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); + r = dns_answer_move_by_key( + validated, + &t->answer, + rr->key, + 0, + NULL); if (r < 0) return r; @@ -2931,7 +3243,7 @@ static int dnssec_validate_records( /* Downgrading is OK? If so, just consider the information unsigned */ - r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL); if (r < 0) return r; @@ -2956,7 +3268,7 @@ static int dnssec_validate_records( log_info("Detected RRset %s is in a private DNS zone, permitting unsigned RRs.", dns_resource_key_to_string(rr->key, s, sizeof s)); - r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL); if (r < 0) return r; @@ -2977,7 +3289,7 @@ static int dnssec_validate_records( /* The DNSKEY transaction was not authenticated, this means there's * no DS for this, which means it's OK if no keys are found for this signature. */ - r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0); + r = dns_answer_move_by_key(validated, &t->answer, rr->key, 0, NULL); if (r < 0) return r; @@ -3042,11 +3354,10 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { assert(t); - /* We have now collected all DS and DNSKEY RRs in - * t->validated_keys, let's see which RRs we can now + /* We have now collected all DS and DNSKEY RRs in t->validated_keys, let's see which RRs we can now * authenticate with that. */ - if (t->scope->dnssec_mode == DNSSEC_NO) + if (FLAGS_SET(t->query_flags, SD_RESOLVED_NO_VALIDATE) || t->scope->dnssec_mode == DNSSEC_NO) return 0; /* Already validated */ @@ -3056,7 +3367,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { /* Our own stuff needs no validation */ if (IN_SET(t->answer_source, DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR)) { t->answer_dnssec_result = DNSSEC_VALIDATED; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); return 0; } @@ -3073,7 +3384,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { log_debug("Validating response from transaction %" PRIu16 " (%s).", t->id, - dns_resource_key_to_string(t->key, key_str, sizeof key_str)); + dns_resource_key_to_string(dns_transaction_key(t), key_str, sizeof key_str)); /* First, see if this response contains any revoked trust * anchors we care about */ @@ -3144,11 +3455,11 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { /* The answer is fully authenticated, yay. */ t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_SUCCESS; - t->answer_authenticated = true; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, true); } else { /* The answer is not fully authenticated. */ t->answer_dnssec_result = DNSSEC_UNSIGNED; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); } } else if (r == 0) { @@ -3156,7 +3467,7 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { bool authenticated = false; /* Bummer! Let's check NSEC/NSEC3 */ - r = dnssec_nsec_test(t->answer, t->key, &nr, &authenticated, &t->answer_nsec_ttl); + r = dnssec_nsec_test(t->answer, dns_transaction_key(t), &nr, &authenticated, &t->answer_nsec_ttl); if (r < 0) return r; @@ -3167,9 +3478,9 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { log_debug("Proved NXDOMAIN via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_NXDOMAIN; - t->answer_authenticated = authenticated; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, authenticated); - manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, t->key); + manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, dns_transaction_key(t)); break; case DNSSEC_NSEC_NODATA: @@ -3177,18 +3488,18 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { log_debug("Proved NODATA via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_VALIDATED; t->answer_rcode = DNS_RCODE_SUCCESS; - t->answer_authenticated = authenticated; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, authenticated); - manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, t->key); + manager_dnssec_verdict(t->scope->manager, authenticated ? DNSSEC_SECURE : DNSSEC_INSECURE, dns_transaction_key(t)); break; case DNSSEC_NSEC_OPTOUT: /* NSEC3 says the data might not be signed */ log_debug("Data is NSEC3 opt-out via NSEC/NSEC3 for transaction %u (%s)", t->id, key_str); t->answer_dnssec_result = DNSSEC_UNSIGNED; - t->answer_authenticated = false; + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); - manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, t->key); + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, dns_transaction_key(t)); break; case DNSSEC_NSEC_NO_RR: @@ -3199,11 +3510,11 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { return r; if (r > 0) { t->answer_dnssec_result = DNSSEC_NO_SIGNATURE; - manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, t->key); + manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, dns_transaction_key(t)); } else { t->answer_dnssec_result = DNSSEC_UNSIGNED; - t->answer_authenticated = false; - manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, t->key); + SET_FLAG(t->answer_query_flags, SD_RESOLVED_AUTHENTICATED, false); + manager_dnssec_verdict(t->scope->manager, DNSSEC_INSECURE, dns_transaction_key(t)); } break; @@ -3211,14 +3522,14 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) { case DNSSEC_NSEC_UNSUPPORTED_ALGORITHM: /* We don't know the NSEC3 algorithm used? */ t->answer_dnssec_result = DNSSEC_UNSUPPORTED_ALGORITHM; - manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, t->key); + manager_dnssec_verdict(t->scope->manager, DNSSEC_INDETERMINATE, dns_transaction_key(t)); break; case DNSSEC_NSEC_FOUND: case DNSSEC_NSEC_CNAME: /* NSEC says it needs to be there, but we couldn't find it? Bummer! */ t->answer_dnssec_result = DNSSEC_NSEC_MISMATCH; - manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, t->key); + manager_dnssec_verdict(t->scope->manager, DNSSEC_BOGUS, dns_transaction_key(t)); break; default: @@ -3246,6 +3557,8 @@ static const char* const dns_transaction_state_table[_DNS_TRANSACTION_STATE_MAX] [DNS_TRANSACTION_RR_TYPE_UNSUPPORTED] = "rr-type-unsupported", [DNS_TRANSACTION_NETWORK_DOWN] = "network-down", [DNS_TRANSACTION_NOT_FOUND] = "not-found", + [DNS_TRANSACTION_NO_SOURCE] = "no-source", + [DNS_TRANSACTION_STUB_LOOP] = "stub-loop", }; DEFINE_STRING_TABLE_LOOKUP(dns_transaction_state, DnsTransactionState); diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 88b0d8eab..a8ec6e18d 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -2,8 +2,10 @@ #pragma once #include "sd-event.h" +#include "in-addr-util.h" typedef struct DnsTransaction DnsTransaction; +typedef struct DnsTransactionFinder DnsTransactionFinder; typedef enum DnsTransactionState DnsTransactionState; typedef enum DnsTransactionSource DnsTransactionSource; @@ -30,8 +32,10 @@ enum DnsTransactionState { DNS_TRANSACTION_RR_TYPE_UNSUPPORTED, DNS_TRANSACTION_NETWORK_DOWN, DNS_TRANSACTION_NOT_FOUND, /* like NXDOMAIN, but when LLMNR/TCP connections fail */ + DNS_TRANSACTION_NO_SOURCE, /* All suitable DnsTransactionSource turned off */ + DNS_TRANSACTION_STUB_LOOP, _DNS_TRANSACTION_STATE_MAX, - _DNS_TRANSACTION_STATE_INVALID = -1 + _DNS_TRANSACTION_STATE_INVALID = -EINVAL, }; #define DNS_TRANSACTION_IS_LIVE(state) IN_SET((state), DNS_TRANSACTION_NULL, DNS_TRANSACTION_PENDING, DNS_TRANSACTION_VALIDATING) @@ -42,13 +46,16 @@ enum DnsTransactionSource { DNS_TRANSACTION_ZONE, DNS_TRANSACTION_TRUST_ANCHOR, _DNS_TRANSACTION_SOURCE_MAX, - _DNS_TRANSACTION_SOURCE_INVALID = -1 + _DNS_TRANSACTION_SOURCE_INVALID = -EINVAL, }; struct DnsTransaction { DnsScope *scope; - DnsResourceKey *key; + DnsResourceKey *key; /* For regular lookups the RR key to look for */ + DnsPacket *bypass; /* For bypass lookups the full original request packet */ + + uint64_t query_flags; DnsTransactionState state; @@ -59,8 +66,6 @@ struct DnsTransaction { bool initial_jitter_scheduled:1; bool initial_jitter_elapsed:1; - bool clamp_ttl:1; - bool probing:1; DnsPacket *sent, *received; @@ -72,15 +77,12 @@ struct DnsTransaction { uint32_t answer_nsec_ttl; int answer_errno; /* if state is DNS_TRANSACTION_ERRNO */ - /* Indicates whether the primary answer is authenticated, - * i.e. whether the RRs from answer which directly match the - * question are authenticated, or, if there are none, whether - * the NODATA or NXDOMAIN case is. It says nothing about - * additional RRs listed in the answer, however they have - * their own DNS_ANSWER_AUTHORIZED FLAGS. Note that this bit - * is defined different than the AD bit in DNS packets, as - * that covers more than just the actual primary answer. */ - bool answer_authenticated; + /* SD_RESOLVED_AUTHENTICATED here indicates whether the primary answer is authenticated, i.e. whether + * the RRs from answer which directly match the question are authenticated, or, if there are none, + * whether the NODATA or NXDOMAIN case is. It says nothing about additional RRs listed in the answer, + * however they have their own DNS_ANSWER_AUTHORIZED FLAGS. Note that this bit is defined different + * than the AD bit in DNS packets, as that covers more than just the actual primary answer. */ + uint64_t answer_query_flags; /* Contains DNSKEY, DS, SOA RRs we already verified and need * to authenticate this reply */ @@ -106,8 +108,11 @@ struct DnsTransaction { /* The features of the DNS server at time of transaction start */ DnsServerFeatureLevel current_feature_level; - /* If we got SERVFAIL back, we retry the lookup, using a lower feature level than we used before. */ - DnsServerFeatureLevel clamp_feature_level; + /* If we got SERVFAIL back, we retry the lookup, using a lower feature level than we used + * before. Similar, if we get NXDOMAIN in pure EDNS0 mode, we check in EDNS0-less mode before giving + * up (as mitigation for DVE-2018-0001). */ + DnsServerFeatureLevel clamp_feature_level_servfail; + DnsServerFeatureLevel clamp_feature_level_nxdomain; /* Query candidates this transaction is referenced by and that * shall be notified about this specific transaction @@ -132,23 +137,62 @@ struct DnsTransaction { LIST_FIELDS(DnsTransaction, transactions_by_scope); LIST_FIELDS(DnsTransaction, transactions_by_stream); + LIST_FIELDS(DnsTransaction, transactions_by_key); }; -int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key); +int dns_transaction_new(DnsTransaction **ret, DnsScope *s, DnsResourceKey *key, DnsPacket *bypass, uint64_t flags); DnsTransaction* dns_transaction_free(DnsTransaction *t); -bool dns_transaction_gc(DnsTransaction *t); +DnsTransaction* dns_transaction_gc(DnsTransaction *t); DEFINE_TRIVIAL_CLEANUP_FUNC(DnsTransaction*, dns_transaction_gc); int dns_transaction_go(DnsTransaction *t); -void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p); +void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p, bool encrypted); void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state); void dns_transaction_notify(DnsTransaction *t, DnsTransaction *source); int dns_transaction_validate_dnssec(DnsTransaction *t); int dns_transaction_request_dnssec_keys(DnsTransaction *t); +static inline DnsResourceKey *dns_transaction_key(DnsTransaction *t) { + assert(t); + + /* Return the lookup key of this transaction. Either takes the lookup key from the bypass packet if + * we are a bypass transaction. Or take the configured key for regular transactions. */ + + if (t->key) + return t->key; + + assert(t->bypass); + + if (dns_question_isempty(t->bypass->question)) + return NULL; + + return t->bypass->question->keys[0]; +} + +static inline uint64_t dns_transaction_source_to_query_flags(DnsTransactionSource s) { + + switch (s) { + + case DNS_TRANSACTION_NETWORK: + return SD_RESOLVED_FROM_NETWORK; + + case DNS_TRANSACTION_CACHE: + return SD_RESOLVED_FROM_CACHE; + + case DNS_TRANSACTION_ZONE: + return SD_RESOLVED_FROM_ZONE; + + case DNS_TRANSACTION_TRUST_ANCHOR: + return SD_RESOLVED_FROM_TRUST_ANCHOR; + + default: + return 0; + } +} + const char* dns_transaction_state_to_string(DnsTransactionState p) _const_; DnsTransactionState dns_transaction_state_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c index 3e5d25586..8ba459b3e 100644 --- a/src/resolve/resolved-dns-trust-anchor.c +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -60,7 +60,7 @@ static int add_root_ksk( if (!rr->ds.digest) return -ENOMEM; - r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; @@ -354,7 +354,7 @@ static int dns_trust_anchor_load_positive(DnsTrustAnchor *d, const char *path, u old_answer = hashmap_get(d->positive_by_key, rr->key); answer = dns_answer_ref(old_answer); - r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add_extend(&answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return log_error_errno(r, "Failed to add trust anchor RR: %m"); diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 00eb6725f..6f15c5395 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -26,16 +26,15 @@ void dns_zone_item_probe_stop(DnsZoneItem *i) { dns_transaction_gc(t); } -static void dns_zone_item_free(DnsZoneItem *i) { +static DnsZoneItem* dns_zone_item_free(DnsZoneItem *i) { if (!i) - return; + return NULL; dns_zone_item_probe_stop(i); dns_resource_record_unref(i->rr); - free(i); + return mfree(i); } - DEFINE_TRIVIAL_CLEANUP_FUNC(DnsZoneItem*, dns_zone_item_free); static void dns_zone_item_remove_and_free(DnsZone *z, DnsZoneItem *i) { @@ -170,7 +169,10 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (i->probe_transaction) return 0; - t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), false); + t = dns_scope_find_transaction( + i->scope, + &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(i->rr->key)), + SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); if (!t) { _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; @@ -178,7 +180,7 @@ static int dns_zone_item_probe_start(DnsZoneItem *i) { if (!key) return -ENOMEM; - r = dns_transaction_new(&t, i->scope, key); + r = dns_transaction_new(&t, i->scope, key, NULL, SD_RESOLVED_NO_CACHE|SD_RESOLVED_NO_ZONE); if (r < 0) return r; } @@ -296,7 +298,7 @@ static int dns_zone_add_authenticated_answer(DnsAnswer *a, DnsZoneItem *i, int i else flags = DNS_ANSWER_AUTHENTICATED; - return dns_answer_add(a, i->rr, ifindex, flags); + return dns_answer_add(a, i->rr, ifindex, flags, NULL); } int dns_zone_lookup(DnsZone *z, DnsResourceKey *key, int ifindex, DnsAnswer **ret_answer, DnsAnswer **ret_soa, bool *ret_tentative) { diff --git a/src/resolve/resolved-dnssd-gperf.gperf b/src/resolve/resolved-dnssd-gperf.gperf index 2780b856b..f10eae3ce 100644 --- a/src/resolve/resolved-dnssd-gperf.gperf +++ b/src/resolve/resolved-dnssd-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #include #include "conf-parser.h" diff --git a/src/resolve/resolved-dnssd.c b/src/resolve/resolved-dnssd.c index 8b4063972..33d695a9c 100644 --- a/src/resolve/resolved-dnssd.c +++ b/src/resolve/resolved-dnssd.c @@ -88,7 +88,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) { dropin_dirname = strjoina(service->name, ".dnssd.d"); r = config_parse_many( - filename, DNSSD_SERVICE_DIRS, dropin_dirname, + STRV_MAKE_CONST(filename), DNSSD_SERVICE_DIRS, dropin_dirname, "Service\0", config_item_perf_lookup, resolved_dnssd_gperf_lookup, CONFIG_PARSE_WARN, @@ -117,14 +117,10 @@ static int dnssd_service_load(Manager *manager, const char *filename) { return r; LIST_PREPEND(items, service->txt_data_items, txt_data); - txt_data = NULL; + TAKE_PTR(txt_data); } - r = hashmap_ensure_allocated(&manager->dnssd_services, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(manager->dnssd_services, service->name, service); + r = hashmap_ensure_put(&manager->dnssd_services, &string_hash_ops, service->name, service); if (r < 0) return r; @@ -134,7 +130,7 @@ static int dnssd_service_load(Manager *manager, const char *filename) { if (r < 0) return r; - service = NULL; + TAKE_PTR(service); return 0; } diff --git a/src/resolve/resolved-dnstls-gnutls.c b/src/resolve/resolved-dnstls-gnutls.c index d3edd350b..e7ccba934 100644 --- a/src/resolve/resolved-dnstls-gnutls.c +++ b/src/resolve/resolved-dnstls-gnutls.c @@ -11,7 +11,7 @@ #include "resolved-manager.h" #define TLS_PROTOCOL_PRIORITY "NORMAL:-VERS-ALL:+VERS-TLS1.3:+VERS-TLS1.2" -DEFINE_TRIVIAL_CLEANUP_FUNC(gnutls_session_t, gnutls_deinit); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gnutls_session_t, gnutls_deinit, NULL); static ssize_t dnstls_stream_writev(gnutls_transport_ptr_t p, const giovec_t *iov, int iovcnt) { int r; diff --git a/src/resolve/resolved-dnstls-openssl.c b/src/resolve/resolved-dnstls-openssl.c index defddb523..17af90d4c 100644 --- a/src/resolve/resolved-dnstls-openssl.c +++ b/src/resolve/resolved-dnstls-openssl.c @@ -13,8 +13,8 @@ #include "resolved-dnstls.h" #include "resolved-manager.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(SSL*, SSL_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(BIO*, BIO_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(SSL*, SSL_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(BIO*, BIO_free, NULL); static int dnstls_flush_write_buffer(DnsStream *stream) { ssize_t ss; diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c index e784213e9..65b815c43 100644 --- a/src/resolve/resolved-etc-hosts.c +++ b/src/resolve/resolved-etc-hosts.c @@ -10,6 +10,7 @@ #include "resolved-dns-synthesize.h" #include "resolved-etc-hosts.h" #include "socket-netlink.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" @@ -36,9 +37,7 @@ void etc_hosts_free(EtcHosts *hosts) { void manager_etc_hosts_flush(Manager *m) { etc_hosts_free(&m->etc_hosts); - m->etc_hosts_mtime = USEC_INFINITY; - m->etc_hosts_ino = 0; - m->etc_hosts_dev = 0; + m->etc_hosts_stat = (struct stat) {}; } static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) { @@ -62,7 +61,7 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) { return 0; } - r = in_addr_is_null(address.family, &address.address); + r = in_addr_data_is_null(&address); if (r < 0) { log_warning_errno(r, "/etc/hosts:%u: address '%s' is invalid, ignoring: %m", nr, address_str); return 0; @@ -114,10 +113,6 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) { continue; } - if (is_localhost(name)) - /* Suppress the "localhost" line that is often seen */ - continue; - if (!item) { /* Optimize the case where we don't need to store any addresses, by storing * only the name in a dedicated Set instead of the hashmap */ @@ -164,6 +159,95 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) { return 0; } +static void strip_localhost(EtcHosts *hosts) { + static const struct in_addr_data local_in_addrs[] = { + { + .family = AF_INET, +#if __BYTE_ORDER == __LITTLE_ENDIAN + /* We want constant expressions here, that's why we don't use htole32() here */ + .address.in.s_addr = UINT32_C(0x0100007F), +#else + .address.in.s_addr = UINT32_C(0x7F000001), +#endif + }, + { + .family = AF_INET6, + .address.in6 = IN6ADDR_LOOPBACK_INIT, + }, + }; + + EtcHostsItem *item; + + assert(hosts); + + /* Removes the 'localhost' entry from what we loaded. But only if the mapping is exclusively between + * 127.0.0.1 and localhost (or aliases to that we recognize). If there's any other name assigned to + * it, we leave the entry in. + * + * This way our regular synthesizing can take over, but only if it would result in the exact same + * mappings. */ + + for (size_t j = 0; j < ELEMENTSOF(local_in_addrs); j++) { + bool all_localhost, in_order; + char **i; + + item = hashmap_get(hosts->by_address, local_in_addrs + j); + if (!item) + continue; + + /* Check whether all hostnames the loopback address points to are localhost ones */ + all_localhost = true; + STRV_FOREACH(i, item->names) + if (!is_localhost(*i)) { + all_localhost = false; + break; + } + + if (!all_localhost) /* Not all names are localhost, hence keep the entries for this address. */ + continue; + + /* Now check if the names listed for this address actually all point back just to this + * address (or the other loopback address). If not, let's stay away from this too. */ + in_order = true; + STRV_FOREACH(i, item->names) { + EtcHostsItemByName *n; + bool all_local_address; + + n = hashmap_get(hosts->by_name, *i); + if (!n) /* No reverse entry? Then almost certainly the entry already got deleted from + * the previous iteration of this loop, i.e. via the other protocol */ + break; + + /* Now check if the addresses of this item are all localhost addresses */ + all_local_address = true; + for (size_t m = 0; m < n->n_addresses; m++) + if (!in_addr_is_localhost(n->addresses[m]->family, &n->addresses[m]->address)) { + all_local_address = false; + break; + } + + if (!all_local_address) { + in_order = false; + break; + } + } + + if (!in_order) + continue; + + STRV_FOREACH(i, item->names) { + EtcHostsItemByName *n; + + n = hashmap_remove(hosts->by_name, *i); + if (n) + etc_hosts_item_by_name_free(n); + } + + assert_se(hashmap_remove(hosts->by_address, local_in_addrs + j) == item); + etc_hosts_item_free(item); + } +} + int etc_hosts_parse(EtcHosts *hosts, FILE *f) { _cleanup_(etc_hosts_free) EtcHosts t = {}; unsigned nr = 0; @@ -194,6 +278,8 @@ int etc_hosts_parse(EtcHosts *hosts, FILE *f) { return r; } + strip_localhost(&t); + etc_hosts_free(hosts); *hosts = t; t = (EtcHosts) {}; /* prevent cleanup */ @@ -214,7 +300,7 @@ static int manager_etc_hosts_read(Manager *m) { m->etc_hosts_last = ts; - if (m->etc_hosts_mtime != USEC_INFINITY) { + if (m->etc_hosts_stat.st_mode != 0) { if (stat("/etc/hosts", &st) < 0) { if (errno != ENOENT) return log_error_errno(errno, "Failed to stat /etc/hosts: %m"); @@ -224,8 +310,7 @@ static int manager_etc_hosts_read(Manager *m) { } /* Did the mtime or ino/dev change? If not, there's no point in re-reading the file. */ - if (timespec_load(&st.st_mtim) == m->etc_hosts_mtime && - st.st_ino == m->etc_hosts_ino && st.st_dev == m->etc_hosts_dev) + if (stat_inode_unmodified(&m->etc_hosts_stat, &st)) return 0; } @@ -248,9 +333,7 @@ static int manager_etc_hosts_read(Manager *m) { if (r < 0) return r; - m->etc_hosts_mtime = timespec_load(&st.st_mtim); - m->etc_hosts_ino = st.st_ino; - m->etc_hosts_dev = st.st_dev; + m->etc_hosts_stat = st; m->etc_hosts_last = ts; return 1; @@ -323,7 +406,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { if (!rr->ptr.name) return -ENOMEM; - r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; } @@ -375,7 +458,7 @@ int manager_etc_hosts_lookup(Manager *m, DnsQuestion* q, DnsAnswer **answer) { if (r < 0) return r; - r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED); + r = dns_answer_add(*answer, rr, 0, DNS_ANSWER_AUTHENTICATED, NULL); if (r < 0) return r; } diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index b54fa1ba9..eab4c7ee1 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -30,3 +31,4 @@ Resolve.DNSStubListener, config_parse_dns_stub_listener_mode, 0, Resolve.ReadEtcHosts, config_parse_bool, 0, offsetof(Manager, read_etc_hosts) Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0, offsetof(Manager, resolve_unicast_single_label) Resolve.DNSStubListenerExtra, config_parse_dns_stub_listener_extra, 0, offsetof(Manager, dns_extra_stub_listeners) +Resolve.CacheFromLocalhost, config_parse_bool, 0, offsetof(Manager, cache_from_localhost) diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c index 6a693ffe7..d56d5de4d 100644 --- a/src/resolve/resolved-link-bus.c +++ b/src/resolve/resolved-link-bus.c @@ -9,6 +9,7 @@ #include "bus-get-properties.h" #include "bus-message-util.h" #include "bus-polkit.h" +#include "log-link.h" #include "parse-util.h" #include "resolve-util.h" #include "resolved-bus.h" @@ -252,7 +253,9 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) { } static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) { + _cleanup_free_ char *j = NULL; struct in_addr_full **dns; + bool changed = false; Link *l = userdata; size_t n; int r; @@ -279,6 +282,23 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi goto finalize; } + for (size_t i = 0; i < n; i++) { + const char *s; + + s = in_addr_full_to_string(dns[i]); + if (!s) { + r = -ENOMEM; + goto finalize; + } + + if (!strextend_with_separator(&j, ", ", s)) { + r = -ENOMEM; + goto finalize; + } + } + + bus_client_log(message, "DNS server change"); + dns_server_mark_all(l->dns_servers); for (size_t i = 0; i < n; i++) { @@ -293,16 +313,26 @@ static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, voi dns_server_unlink_all(l->dns_servers); goto finalize; } + + changed = true; } } - dns_server_unlink_marked(l->dns_servers); - link_allocate_scopes(l); + changed = dns_server_unlink_marked(l->dns_servers) || changed; - (void) link_save_user(l); - (void) manager_write_resolv_conf(l->manager); - (void) manager_send_changed(l->manager, "DNS"); + if (changed) { + link_allocate_scopes(l); + + (void) link_save_user(l); + (void) manager_write_resolv_conf(l->manager); + (void) manager_send_changed(l->manager, "DNS"); + + if (j) + log_link_info(l, "Bus client set DNS server list to: %s", j); + else + log_link_info(l, "Bus client reset DNS server list."); + } r = sd_bus_reply_method_return(message, NULL); @@ -323,7 +353,9 @@ int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, } int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) { + _cleanup_free_ char *j = NULL; Link *l = userdata; + bool changed = false; int r; assert(message); @@ -338,6 +370,7 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ return r; for (;;) { + _cleanup_free_ char *prefixed = NULL; const char *name; int route_only; @@ -354,6 +387,17 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name); if (!route_only && dns_name_is_root(name)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain"); + + if (route_only) { + prefixed = strjoin("~", name); + if (!prefixed) + return -ENOMEM; + + name = prefixed; + } + + if (!strextend_with_separator(&j, ", ", name)) + return -ENOMEM; } r = sd_bus_message_rewind(message, false); @@ -369,6 +413,8 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ if (r == 0) return 1; /* Polkit will call us back */ + bus_client_log(message, "dns domains change"); + dns_search_domain_mark_all(l->search_domains); for (;;) { @@ -392,6 +438,8 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name); if (r < 0) goto clear; + + changed = true; } d->route_only = route_only; @@ -401,10 +449,17 @@ int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_ if (r < 0) goto clear; - dns_search_domain_unlink_marked(l->search_domains); + changed = dns_search_domain_unlink_marked(l->search_domains) || changed; - (void) link_save_user(l); - (void) manager_write_resolv_conf(l->manager); + if (changed) { + (void) link_save_user(l); + (void) manager_write_resolv_conf(l->manager); + + if (j) + log_link_info(l, "Bus client set search domain list to: %s", j); + else + log_link_info(l, "Bus client reset search domain list."); + } return sd_bus_reply_method_return(message, NULL); @@ -437,11 +492,15 @@ int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, s if (r == 0) return 1; /* Polkit will call us back */ + bus_client_log(message, "dns default route change"); + if (l->default_route != b) { l->default_route = b; (void) link_save_user(l); (void) manager_write_resolv_conf(l->manager); + + log_link_info(l, "Bus client set default route setting: %s", yes_no(b)); } return sd_bus_reply_method_return(message, NULL); @@ -481,11 +540,17 @@ int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_er if (r == 0) return 1; /* Polkit will call us back */ - l->llmnr_support = mode; - link_allocate_scopes(l); - link_add_rrs(l, false); + bus_client_log(message, "LLMNR change"); - (void) link_save_user(l); + if (l->llmnr_support != mode) { + l->llmnr_support = mode; + link_allocate_scopes(l); + link_add_rrs(l, false); + + (void) link_save_user(l); + + log_link_info(l, "Bus client set LLMNR setting: %s", resolve_support_to_string(mode)); + } return sd_bus_reply_method_return(message, NULL); } @@ -524,11 +589,17 @@ int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_err if (r == 0) return 1; /* Polkit will call us back */ - l->mdns_support = mode; - link_allocate_scopes(l); - link_add_rrs(l, false); + bus_client_log(message, "mDNS change"); - (void) link_save_user(l); + if (l->mdns_support != mode) { + l->mdns_support = mode; + link_allocate_scopes(l); + link_add_rrs(l, false); + + (void) link_save_user(l); + + log_link_info(l, "Bus client set MulticastDNS setting: %s", resolve_support_to_string(mode)); + } return sd_bus_reply_method_return(message, NULL); } @@ -567,9 +638,16 @@ int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd if (r == 0) return 1; /* Polkit will call us back */ - link_set_dns_over_tls_mode(l, mode); + bus_client_log(message, "D-o-T change"); - (void) link_save_user(l); + if (l->dns_over_tls_mode != mode) { + link_set_dns_over_tls_mode(l, mode); + + (void) link_save_user(l); + + log_link_info(l, "Bus client set DNSOverTLS setting: %s", + mode < 0 ? "default" : dns_over_tls_mode_to_string(mode)); + } return sd_bus_reply_method_return(message, NULL); } @@ -608,9 +686,16 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e if (r == 0) return 1; /* Polkit will call us back */ - link_set_dnssec_mode(l, mode); + bus_client_log(message, "DNSSEC change"); - (void) link_save_user(l); + if (l->dnssec_mode != mode) { + link_set_dnssec_mode(l, mode); + + (void) link_save_user(l); + + log_link_info(l, "Bus client set DNSSEC setting: %s", + mode < 0 ? "default" : dnssec_mode_to_string(mode)); + } return sd_bus_reply_method_return(message, NULL); } @@ -618,6 +703,7 @@ int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_e int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_set_free_free_ Set *ns = NULL; _cleanup_strv_free_ char **ntas = NULL; + _cleanup_free_ char *j = NULL; Link *l = userdata; int r; char **i; @@ -648,6 +734,9 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v r = set_put_strdup(&ns, *i); if (r < 0) return r; + + if (!strextend_with_separator(&j, ", ", *i)) + return -ENOMEM; } r = bus_verify_polkit_async(message, CAP_NET_ADMIN, @@ -659,10 +748,19 @@ int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, v if (r == 0) return 1; /* Polkit will call us back */ - set_free_free(l->dnssec_negative_trust_anchors); - l->dnssec_negative_trust_anchors = TAKE_PTR(ns); + bus_client_log(message, "DNSSEC NTA change"); - (void) link_save_user(l); + if (!set_equal(ns, l->dnssec_negative_trust_anchors)) { + set_free_free(l->dnssec_negative_trust_anchors); + l->dnssec_negative_trust_anchors = TAKE_PTR(ns); + + (void) link_save_user(l); + + if (j) + log_link_info(l, "Bus client set NTA list to: %s", j); + else + log_link_info(l, "Bus client reset NTA list."); + } return sd_bus_reply_method_return(message, NULL); } @@ -687,6 +785,8 @@ int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error if (r == 0) return 1; /* Polkit will call us back */ + bus_client_log(message, "revert"); + link_flush_settings(l); link_allocate_scopes(l); link_add_rrs(l, false); diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index 4fa4451ab..18dc3d29e 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -27,10 +27,6 @@ int link_new(Manager *m, Link **ret, int ifindex) { assert(m); assert(ifindex > 0); - r = hashmap_ensure_allocated(&m->links, NULL); - if (r < 0) - return r; - l = new(Link, 1); if (!l) return -ENOMEM; @@ -48,7 +44,7 @@ int link_new(Manager *m, Link **ret, int ifindex) { if (asprintf(&l->state_file, "/run/systemd/resolve/netif/%i", ifindex) < 0) return -ENOMEM; - r = hashmap_put(m->links, INT_TO_PTR(ifindex), l); + r = hashmap_ensure_put(&m->links, NULL, INT_TO_PTR(ifindex), l); if (r < 0) return r; @@ -56,7 +52,7 @@ int link_new(Manager *m, Link **ret, int ifindex) { if (ret) *ret = l; - l = NULL; + TAKE_PTR(l); return 0; } @@ -341,25 +337,20 @@ static int link_update_llmnr_support(Link *l) { assert(l); + l->llmnr_support = RESOLVE_SUPPORT_YES; /* yes, yes, we set it twice which is ugly */ + r = sd_network_link_get_llmnr(l->ifindex, &b); - if (r == -ENODATA) { - r = 0; - goto clear; - } + if (r == -ENODATA) + return 0; if (r < 0) - goto clear; + return r; - l->llmnr_support = resolve_support_from_string(b); - if (l->llmnr_support < 0) { - r = -EINVAL; - goto clear; - } + r = resolve_support_from_string(b); + if (r < 0) + return r; + l->llmnr_support = r; return 0; - -clear: - l->llmnr_support = RESOLVE_SUPPORT_YES; - return r; } static int link_update_mdns_support(Link *l) { @@ -368,25 +359,20 @@ static int link_update_mdns_support(Link *l) { assert(l); - r = sd_network_link_get_mdns(l->ifindex, &b); - if (r == -ENODATA) { - r = 0; - goto clear; - } - if (r < 0) - goto clear; - - l->mdns_support = resolve_support_from_string(b); - if (l->mdns_support < 0) { - r = -EINVAL; - goto clear; - } - - return 0; - -clear: l->mdns_support = RESOLVE_SUPPORT_NO; - return r; + + r = sd_network_link_get_mdns(l->ifindex, &b); + if (r == -ENODATA) + return 0; + if (r < 0) + return r; + + r = resolve_support_from_string(b); + if (r < 0) + return r; + + l->mdns_support = r; + return 0; } void link_set_dns_over_tls_mode(Link *l, DnsOverTlsMode mode) { @@ -408,25 +394,20 @@ static int link_update_dns_over_tls_mode(Link *l) { assert(l); - r = sd_network_link_get_dns_over_tls(l->ifindex, &b); - if (r == -ENODATA) { - r = 0; - goto clear; - } - if (r < 0) - goto clear; - - l->dns_over_tls_mode = dns_over_tls_mode_from_string(b); - if (l->dns_over_tls_mode < 0) { - r = -EINVAL; - goto clear; - } - - return 0; - -clear: l->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID; - return r; + + r = sd_network_link_get_dns_over_tls(l->ifindex, &b); + if (r == -ENODATA) + return 0; + if (r < 0) + return r; + + r = dns_over_tls_mode_from_string(b); + if (r < 0) + return r; + + l->dns_over_tls_mode = r; + return 0; } void link_set_dnssec_mode(Link *l, DnssecMode mode) { @@ -462,27 +443,20 @@ static int link_update_dnssec_mode(Link *l) { assert(l); + l->dnssec_mode = _DNSSEC_MODE_INVALID; + r = sd_network_link_get_dnssec(l->ifindex, &m); - if (r == -ENODATA) { - r = 0; - goto clear; - } + if (r == -ENODATA) + return 0; if (r < 0) - goto clear; + return r; mode = dnssec_mode_from_string(m); - if (mode < 0) { - r = -EINVAL; - goto clear; - } + if (mode < 0) + return mode; link_set_dnssec_mode(l, mode); - return 0; - -clear: - l->dnssec_mode = _DNSSEC_MODE_INVALID; - return r; } static int link_update_dnssec_negative_trust_anchors(Link *l) { @@ -492,13 +466,13 @@ static int link_update_dnssec_negative_trust_anchors(Link *l) { assert(l); + l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors); + r = sd_network_link_get_dnssec_negative_trust_anchors(l->ifindex, &ntas); - if (r == -ENODATA) { - r = 0; - goto clear; - } + if (r == -ENODATA) + return r; if (r < 0) - goto clear; + return r; ns = set_new(&dns_name_hash_ops); if (!ns) @@ -508,14 +482,8 @@ static int link_update_dnssec_negative_trust_anchors(Link *l) { if (r < 0) return r; - set_free_free(l->dnssec_negative_trust_anchors); l->dnssec_negative_trust_anchors = TAKE_PTR(ns); - return 0; - -clear: - l->dnssec_negative_trust_anchors = set_free_free(l->dnssec_negative_trust_anchors); - return r; } static int link_update_search_domain_one(Link *l, const char *name, bool route_only) { @@ -729,6 +697,12 @@ LinkAddress *link_find_address(Link *l, int family, const union in_addr_union *i assert(l); + if (!IN_SET(family, AF_INET, AF_INET6)) + return NULL; + + if (!in_addr) + return NULL; + LIST_FOREACH(addresses, a, l->addresses) if (a->family == family && in_addr_equal(family, &a->in_addr, in_addr)) return a; @@ -763,19 +737,27 @@ DnsServer *link_get_dns_server(Link *l) { return l->current_dns_server; } -void link_next_dns_server(Link *l) { +void link_next_dns_server(Link *l, DnsServer *if_current) { assert(l); + /* If the current server of the transaction is specified, and we already are at a different one, + * don't do anything */ + if (if_current && l->current_dns_server != if_current) + return; + + /* If currently have no DNS server, then don't do anything, we'll pick it lazily the next time a DNS + * server is needed. */ if (!l->current_dns_server) return; - /* Change to the next one, but make sure to follow the linked - * list only if this server is actually still linked. */ + /* Change to the next one, but make sure to follow the linked list only if this server is actually + * still linked. */ if (l->current_dns_server->linked && l->current_dns_server->servers_next) { link_set_dns_server(l, l->current_dns_server->servers_next); return; } + /* Pick the first one again, after we reached the end */ link_set_dns_server(l, l->dns_servers); } @@ -826,6 +808,7 @@ int link_address_new(Link *l, LinkAddress **ret, int family, const union in_addr .family = family, .in_addr = *in_addr, .link = l, + .prefixlen = UCHAR_MAX, }; LIST_PREPEND(addresses, l->addresses, a); @@ -1118,6 +1101,7 @@ fail: int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) { int r; + assert(a); assert(m); @@ -1125,7 +1109,8 @@ int link_address_update_rtnl(LinkAddress *a, sd_netlink_message *m) { if (r < 0) return r; - sd_rtnl_message_addr_get_scope(m, &a->scope); + (void) sd_rtnl_message_addr_get_prefixlen(m, &a->prefixlen); + (void) sd_rtnl_message_addr_get_scope(m, &a->scope); link_allocate_scopes(a->link); link_add_rrs(a->link, false); diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index 26b0d1312..3c364866f 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -23,6 +23,7 @@ struct LinkAddress { int family; union in_addr_union in_addr; + unsigned char prefixlen; unsigned char flags, scope; @@ -91,7 +92,7 @@ void link_allocate_scopes(Link *l); DnsServer* link_set_dns_server(Link *l, DnsServer *s); DnsServer* link_get_dns_server(Link *l); -void link_next_dns_server(Link *l); +void link_next_dns_server(Link *l, DnsServer *if_current); DnssecMode link_get_dnssec_mode(Link *l); bool link_dnssec_supported(Link *l); diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 2ddf08815..ce2db7d4b 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include "errno-util.h" @@ -11,16 +12,16 @@ void manager_llmnr_stop(Manager *m) { assert(m); - m->llmnr_ipv4_udp_event_source = sd_event_source_unref(m->llmnr_ipv4_udp_event_source); + m->llmnr_ipv4_udp_event_source = sd_event_source_disable_unref(m->llmnr_ipv4_udp_event_source); m->llmnr_ipv4_udp_fd = safe_close(m->llmnr_ipv4_udp_fd); - m->llmnr_ipv6_udp_event_source = sd_event_source_unref(m->llmnr_ipv6_udp_event_source); + m->llmnr_ipv6_udp_event_source = sd_event_source_disable_unref(m->llmnr_ipv6_udp_event_source); m->llmnr_ipv6_udp_fd = safe_close(m->llmnr_ipv6_udp_fd); - m->llmnr_ipv4_tcp_event_source = sd_event_source_unref(m->llmnr_ipv4_tcp_event_source); + m->llmnr_ipv4_tcp_event_source = sd_event_source_disable_unref(m->llmnr_ipv4_tcp_event_source); m->llmnr_ipv4_tcp_fd = safe_close(m->llmnr_ipv4_tcp_fd); - m->llmnr_ipv6_tcp_event_source = sd_event_source_unref(m->llmnr_ipv6_tcp_event_source); + m->llmnr_ipv6_tcp_event_source = sd_event_source_disable_unref(m->llmnr_ipv6_tcp_event_source); m->llmnr_ipv6_tcp_fd = safe_close(m->llmnr_ipv6_tcp_fd); } @@ -83,7 +84,7 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u if (r <= 0) return r; - if (manager_our_packet(m, p)) + if (manager_packet_from_local_address(m, p)) return 0; scope = manager_find_scope(m, p); @@ -99,7 +100,7 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); if (t) - dns_transaction_process_reply(t, p); + dns_transaction_process_reply(t, p, false); } else if (dns_packet_validate_query(p) > 0) { log_debug("Got LLMNR UDP query packet for id %u", DNS_PACKET_ID(p)); @@ -111,6 +112,31 @@ static int on_llmnr_packet(sd_event_source *s, int fd, uint32_t revents, void *u return 0; } +static int set_llmnr_common_socket_options(int fd, int family) { + int r; + + r = socket_set_recvpktinfo(fd, family, true); + if (r < 0) + return r; + + r = socket_set_recvttl(fd, family, true); + if (r < 0) + return r; + + return 0; +} + +static int set_llmnr_common_udp_socket_options(int fd, int family) { + int r; + + /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ + r = socket_set_ttl(fd, family, 255); + if (r < 0) + return r; + + return 0; +} + int manager_llmnr_ipv4_udp_fd(Manager *m) { union sockaddr_union sa = { .in.sin_family = AF_INET, @@ -128,10 +154,13 @@ int manager_llmnr_ipv4_udp_fd(Manager *m) { if (s < 0) return log_error_errno(errno, "LLMNR-IPv4(UDP): Failed to create socket: %m"); - /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ - r = setsockopt_int(s, IPPROTO_IP, IP_TTL, 255); + r = set_llmnr_common_socket_options(s, AF_INET); if (r < 0) - return log_error_errno(r, "LLMNR-IPv4(UDP): Failed to set IP_TTL: %m"); + return log_error_errno(r, "LLMNR-IPv4(UDP): Failed to set common socket options: %m"); + + r = set_llmnr_common_udp_socket_options(s, AF_INET); + if (r < 0) + return log_error_errno(r, "LLMNR-IPv4(UDP): Failed to set common UDP socket options: %m"); r = setsockopt_int(s, IPPROTO_IP, IP_MULTICAST_TTL, 255); if (r < 0) @@ -141,14 +170,6 @@ int manager_llmnr_ipv4_udp_fd(Manager *m) { if (r < 0) return log_error_errno(r, "LLMNR-IPv4(UDP): Failed to set IP_MULTICAST_LOOP: %m"); - r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true); - if (r < 0) - return log_error_errno(r, "LLMNR-IPv4(UDP): Failed to set IP_PKTINFO: %m"); - - r = setsockopt_int(s, IPPROTO_IP, IP_RECVTTL, true); - if (r < 0) - return log_error_errno(r, "LLMNR-IPv4(UDP): Failed to set IP_RECVTTL: %m"); - /* Disable Don't-Fragment bit in the IP header */ r = setsockopt_int(s, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DONT); if (r < 0) @@ -203,9 +224,13 @@ int manager_llmnr_ipv6_udp_fd(Manager *m) { if (s < 0) return log_error_errno(errno, "LLMNR-IPv6(UDP): Failed to create socket: %m"); - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 255); + r = set_llmnr_common_socket_options(s, AF_INET6); if (r < 0) - return log_error_errno(r, "LLMNR-IPv6(UDP): Failed to set IPV6_UNICAST_HOPS: %m"); + return log_error_errno(r, "LLMNR-IPv6(UDP): Failed to set common socket options: %m"); + + r = set_llmnr_common_udp_socket_options(s, AF_INET6); + if (r < 0) + return log_error_errno(r, "LLMNR-IPv6(UDP): Failed to set common UDP socket options: %m"); /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ r = setsockopt_int(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, 255); @@ -220,14 +245,6 @@ int manager_llmnr_ipv6_udp_fd(Manager *m) { if (r < 0) return log_error_errno(r, "LLMNR-IPv6(UDP): Failed to set IPV6_V6ONLY: %m"); - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, true); - if (r < 0) - return log_error_errno(r, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVPKTINFO: %m"); - - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, true); - if (r < 0) - return log_error_errno(r, "LLMNR-IPv6(UDP): Failed to set IPV6_RECVHOPLIMIT: %m"); - /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */ r = bind(s, &sa.sa, sizeof(sa.in6)); if (r < 0) { @@ -308,6 +325,25 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u return 0; } +static int set_llmnr_common_tcp_socket_options(int fd, int family) { + int r; + + /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ + r = socket_set_ttl(fd, family, 1); + if (r < 0) + return r; + + r = setsockopt_int(fd, IPPROTO_TCP, TCP_FASTOPEN, 5); /* Everybody appears to pick qlen=5, let's do the same here. */ + if (r < 0) + log_debug_errno(r, "Failed to enable TCP_FASTOPEN on TCP listening socket, ignoring: %m"); + + r = setsockopt_int(fd, IPPROTO_TCP, TCP_NODELAY, true); + if (r < 0) + log_debug_errno(r, "Failed to enable TCP_NODELAY mode, ignoring: %m"); + + return 0; +} + int manager_llmnr_ipv4_tcp_fd(Manager *m) { union sockaddr_union sa = { .in.sin_family = AF_INET, @@ -325,18 +361,13 @@ int manager_llmnr_ipv4_tcp_fd(Manager *m) { if (s < 0) return log_error_errno(errno, "LLMNR-IPv4(TCP): Failed to create socket: %m"); - /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ - r = setsockopt_int(s, IPPROTO_IP, IP_TTL, 1); + r = set_llmnr_common_socket_options(s, AF_INET); if (r < 0) - return log_error_errno(r, "LLMNR-IPv4(TCP): Failed to set IP_TTL: %m"); + return log_error_errno(r, "LLMNR-IPv4(TCP): Failed to set common socket options: %m"); - r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true); + r = set_llmnr_common_tcp_socket_options(s, AF_INET); if (r < 0) - return log_error_errno(r, "LLMNR-IPv4(TCP): Failed to set IP_PKTINFO: %m"); - - r = setsockopt_int(s, IPPROTO_IP, IP_RECVTTL, true); - if (r < 0) - return log_error_errno(r, "LLMNR-IPv4(TCP): Failed to set IP_RECVTTL: %m"); + return log_error_errno(r, "LLMNR-IPv4(TCP): Failed to set common TCP socket options: %m"); /* Disable Don't-Fragment bit in the IP header */ r = setsockopt_int(s, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_DONT); @@ -396,22 +427,17 @@ int manager_llmnr_ipv6_tcp_fd(Manager *m) { if (s < 0) return log_error_errno(errno, "LLMNR-IPv6(TCP): Failed to create socket: %m"); - /* RFC 4795, section 2.5. requires setting the TTL of TCP streams to 1 */ - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS, 1); - if (r < 0) - return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set IPV6_UNICAST_HOPS: %m"); - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_V6ONLY, true); if (r < 0) return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set IPV6_V6ONLY: %m"); - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, true); + r = set_llmnr_common_socket_options(s, AF_INET6); if (r < 0) - return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVPKTINFO: %m"); + return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set common socket options: %m"); - r = setsockopt_int(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, true); + r = set_llmnr_common_tcp_socket_options(s, AF_INET6); if (r < 0) - return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set IPV6_RECVHOPLIMIT: %m"); + return log_error_errno(r, "LLMNR-IPv6(TCP): Failed to set common TCP socket options: %m"); /* first try to bind without SO_REUSEADDR to detect another LLMNR responder */ r = bind(s, &sa.sa, sizeof(sa.in6)); diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 7690eac8c..21154a7f8 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -19,8 +19,8 @@ #include "idn-util.h" #include "io-util.h" #include "missing_network.h" +#include "missing_socket.h" #include "netlink-util.h" -#include "network-internal.h" #include "ordered-set.h" #include "parse-util.h" #include "random-util.h" @@ -33,6 +33,7 @@ #include "resolved-manager.h" #include "resolved-mdns.h" #include "resolved-resolv-conf.h" +#include "resolved-util.h" #include "resolved-varlink.h" #include "socket-util.h" #include "string-table.h" @@ -314,75 +315,65 @@ static int manager_network_monitor_listen(Manager *m) { return 0; } -static int determine_hostname(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) { +static int manager_clock_change_listen(Manager *m); + +static int on_clock_change(sd_event_source *source, int fd, uint32_t revents, void *userdata) { + Manager *m = userdata; + + assert(m); + + /* The clock has changed, let's flush all caches. Why that? That's because DNSSEC validation takes + * the system clock into consideration, and if the clock changes the old validations might have been + * wrong. Let's redo all validation with the new, correct time. + * + * (Also, this is triggered after system suspend, which is also a good reason to drop caches, since + * we might be connected to a different network now without this being visible in a dropped link + * carrier or so.) */ + + log_info("Clock change detected. Flushing caches."); + manager_flush_caches(m, LOG_DEBUG /* downgrade the functions own log message, since we already logged here at LOG_INFO level */); + + /* The clock change timerfd is unusable after it triggered once, create a new one. */ + return manager_clock_change_listen(m); +} + +static int manager_clock_change_listen(Manager *m) { + _cleanup_close_ int fd = -1; + int r; + + assert(m); + + m->clock_change_event_source = sd_event_source_disable_unref(m->clock_change_event_source); + + fd = time_change_fd(); + if (fd < 0) + return log_error_errno(fd, "Failed to allocate clock change timer fd: %m"); + + r = sd_event_add_io(m->event, &m->clock_change_event_source, fd, EPOLLIN, on_clock_change, m); + if (r < 0) + return log_error_errno(r, "Failed to create clock change event source: %m"); + + r = sd_event_source_set_io_fd_own(m->clock_change_event_source, true); + if (r < 0) + return log_error_errno(r, "Failed to pass ownership of clock fd to event source: %m"); + TAKE_FD(fd); + + (void) sd_event_source_set_description(m->clock_change_event_source, "clock-change"); + + return 0; +} + +static int determine_hostnames(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) { _cleanup_free_ char *h = NULL, *n = NULL; -#if HAVE_LIBIDN2 - _cleanup_free_ char *utf8 = NULL; -#elif HAVE_LIBIDN - int k; -#endif - char label[DNS_LABEL_MAX]; - const char *p, *decoded; int r; assert(full_hostname); assert(llmnr_hostname); assert(mdns_hostname); - /* Extract and normalize the first label of the locally configured hostname, and check it's not "localhost". */ - - r = gethostname_strict(&h); + r = resolve_system_hostname(&h, &n); if (r < 0) - return log_debug_errno(r, "Can't determine system hostname: %m"); - - p = h; - r = dns_label_unescape(&p, label, sizeof label, 0); - if (r < 0) - return log_error_errno(r, "Failed to unescape hostname: %m"); - if (r == 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Couldn't find a single label in hostname."); - -#if HAVE_LIBIDN || HAVE_LIBIDN2 - r = dlopen_idn(); - if (r < 0) { - log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m"); - decoded = label; /* no decoding */ - } else -#endif - { -#if HAVE_LIBIDN2 - r = sym_idn2_to_unicode_8z8z(label, &utf8, 0); - if (r != IDN2_OK) - return log_error_errno(SYNTHETIC_ERRNO(EUCLEAN), - "Failed to undo IDNA: %s", sym_idn2_strerror(r)); - assert(utf8_is_valid(utf8)); - - r = strlen(utf8); - decoded = utf8; -#elif HAVE_LIBIDN - k = dns_label_undo_idna(label, r, label, sizeof label); - if (k < 0) - return log_error_errno(k, "Failed to undo IDNA: %m"); - if (k > 0) - r = k; - - if (!utf8_is_valid(label)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "System hostname is not UTF-8 clean."); - decoded = label; -#else - decoded = label; /* no decoding */ -#endif - } - - r = dns_label_escape_new(decoded, r, &n); - if (r < 0) - return log_error_errno(r, "Failed to escape hostname: %m"); - - if (is_localhost(n)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "System hostname is 'localhost', ignoring."); + return r; r = dns_name_concat(n, "local", 0, mdns_hostname); if (r < 0) @@ -394,20 +385,25 @@ static int determine_hostname(char **full_hostname, char **llmnr_hostname, char return 0; } -static const char *fallback_hostname(void) { +static char* fallback_hostname(void) { - /* Determine the fall back hostname. For exposing this system to the outside world, we cannot have it to be - * "localhost" even if that's the compiled in hostname. In this case, let's revert to "linux" instead. */ + /* Determine the fall back hostname. For exposing this system to the outside world, we cannot have it + * to be "localhost" even if that's the default hostname. In this case, let's revert to "linux" + * instead. */ - if (is_localhost(FALLBACK_HOSTNAME)) - return "linux"; + _cleanup_free_ char *n = get_default_hostname(); + if (!n) + return NULL; - return FALLBACK_HOSTNAME; + if (is_localhost(n)) + return strdup("linux"); + + return TAKE_PTR(n); } static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname, char **mdns_hostname) { - _cleanup_free_ char *n = NULL, *m = NULL; - char label[DNS_LABEL_MAX], *h; + _cleanup_free_ char *h = NULL, *n = NULL, *m = NULL; + char label[DNS_LABEL_MAX]; const char *p; int r; @@ -415,7 +411,10 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname, assert(llmnr_hostname); assert(mdns_hostname); - p = fallback_hostname(); + p = h = fallback_hostname(); + if (!h) + return log_oom(); + r = dns_label_unescape(&p, label, sizeof label, 0); if (r < 0) return log_error_errno(r, "Failed to unescape fallback hostname: %m"); @@ -430,14 +429,9 @@ static int make_fallback_hostnames(char **full_hostname, char **llmnr_hostname, if (r < 0) return log_error_errno(r, "Failed to concatenate mDNS hostname: %m"); - h = strdup(fallback_hostname()); - if (!h) - return log_oom(); - *llmnr_hostname = TAKE_PTR(n); *mdns_hostname = TAKE_PTR(m); - - *full_hostname = h; + *full_hostname = TAKE_PTR(h); return 0; } @@ -450,9 +444,11 @@ static int on_hostname_change(sd_event_source *es, int fd, uint32_t revents, voi assert(m); - r = determine_hostname(&full_hostname, &llmnr_hostname, &mdns_hostname); - if (r < 0) + r = determine_hostnames(&full_hostname, &llmnr_hostname, &mdns_hostname); + if (r < 0) { + log_warning_errno(r, "Failed to determine the local hostname and LLMNR/mDNS names, ignoring: %m"); return 0; /* ignore invalid hostnames */ + } llmnr_hostname_changed = !streq(llmnr_hostname, m->llmnr_hostname); if (streq(full_hostname, m->full_hostname) && @@ -495,9 +491,15 @@ static int manager_watch_hostname(Manager *m) { (void) sd_event_source_set_description(m->hostname_event_source, "hostname"); - r = determine_hostname(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); + r = determine_hostnames(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); if (r < 0) { - log_info("Defaulting to hostname '%s'.", fallback_hostname()); + _cleanup_free_ char *d = NULL; + + d = fallback_hostname(); + if (!d) + return log_oom(); + + log_info("Defaulting to hostname '%s'.", d); r = make_fallback_hostnames(&m->full_hostname, &m->llmnr_hostname, &m->mdns_hostname); if (r < 0) @@ -550,7 +552,7 @@ static int manager_sigusr2(sd_event_source *s, const struct signalfd_siginfo *si assert(si); assert(m); - manager_flush_caches(m); + manager_flush_caches(m, LOG_INFO); return 0; } @@ -594,9 +596,6 @@ int manager_new(Manager **ret) { .read_resolv_conf = true, .need_builtin_fallbacks = true, .etc_hosts_last = USEC_INFINITY, - .etc_hosts_mtime = USEC_INFINITY, - .etc_hosts_ino = 0, - .etc_hosts_dev = 0, .read_etc_hosts = true, }; @@ -643,6 +642,10 @@ int manager_new(Manager **ret) { if (r < 0) return r; + r = manager_clock_change_listen(m); + if (r < 0) + return r; + r = manager_connect_bus(m); if (r < 0) return r; @@ -691,6 +694,8 @@ Manager *manager_free(Manager *m) { while (m->dns_queries) dns_query_free(m->dns_queries); + m->stub_queries_by_packet = hashmap_free(m->stub_queries_by_packet); + dns_scope_free(m->unicast_scope); /* At this point only orphaned streams should remain. All others should have been freed already by their @@ -710,12 +715,15 @@ Manager *manager_free(Manager *m) { sd_netlink_unref(m->rtnl); sd_event_source_unref(m->rtnl_event_source); + sd_event_source_unref(m->clock_change_event_source); manager_llmnr_stop(m); manager_mdns_stop(m); manager_dns_stub_stop(m); manager_varlink_done(m); + manager_socket_graveyard_clear(m); + ordered_set_free(m->dns_extra_stub_listeners); bus_verify_polkit_async_registry_free(m->polkit_registry); @@ -726,8 +734,6 @@ Manager *manager_free(Manager *m) { sd_event_source_unref(m->sigusr2_event_source); sd_event_source_unref(m->sigrtmin1_event_source); - sd_event_unref(m->event); - dns_resource_key_unref(m->llmnr_host_ipv4_key); dns_resource_key_unref(m->llmnr_host_ipv6_key); dns_resource_key_unref(m->mdns_host_ipv4_key); @@ -736,6 +742,8 @@ Manager *manager_free(Manager *m) { sd_event_source_unref(m->hostname_event_source); safe_close(m->hostname_fd); + sd_event_unref(m->event); + free(m->full_hostname); free(m->llmnr_hostname); free(m->mdns_hostname); @@ -805,6 +813,8 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { } else return -EAFNOSUPPORT; + p->timestamp = now(clock_boottime_or_monotonic()); + CMSG_FOREACH(cmsg, &mh) { if (cmsg->cmsg_level == IPPROTO_IPV6) { @@ -826,6 +836,9 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { p->ttl = *(int *) CMSG_DATA(cmsg); break; + case IPV6_RECVFRAGSIZE: + p->fragsize = *(int *) CMSG_DATA(cmsg); + break; } } else if (cmsg->cmsg_level == IPPROTO_IP) { assert(p->family == AF_INET); @@ -845,6 +858,10 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { case IP_TTL: p->ttl = *(int *) CMSG_DATA(cmsg); break; + + case IP_RECVFRAGSIZE: + p->fragsize = *(int *) CMSG_DATA(cmsg); + break; } } } @@ -863,8 +880,10 @@ int manager_recv(Manager *m, int fd, DnsProtocol protocol, DnsPacket **ret) { p->ifindex = manager_find_ifindex(m, p->family, &p->destination); } - *ret = TAKE_PTR(p); + log_debug("Received %s UDP packet of size %zu, ifindex=%i, ttl=%i, fragsize=%zu", + dns_protocol_to_string(protocol), p->size, p->ifindex, p->ttl, p->fragsize); + *ret = TAKE_PTR(p); return 1; } @@ -1098,6 +1117,12 @@ int manager_find_ifindex(Manager *m, int family, const union in_addr_union *in_a assert(m); + if (!IN_SET(family, AF_INET, AF_INET6)) + return 0; + + if (!in_addr) + return 0; + a = manager_find_link_address(m, family, in_addr); if (a) return a->link->ifindex; @@ -1193,6 +1218,12 @@ LinkAddress* manager_find_link_address(Manager *m, int family, const union in_ad assert(m); + if (!IN_SET(family, AF_INET, AF_INET6)) + return NULL; + + if (!in_addr) + return NULL; + HASHMAP_FOREACH(l, m->links) { LinkAddress *a; @@ -1204,13 +1235,31 @@ LinkAddress* manager_find_link_address(Manager *m, int family, const union in_ad return NULL; } -bool manager_our_packet(Manager *m, DnsPacket *p) { +bool manager_packet_from_local_address(Manager *m, DnsPacket *p) { assert(m); assert(p); + /* Let's see if this packet comes from an IP address we have on any local interface */ + return !!manager_find_link_address(m, p->family, &p->sender); } +bool manager_packet_from_our_transaction(Manager *m, DnsPacket *p) { + DnsTransaction *t; + + assert(m); + assert(p); + + /* Let's see if we have a transaction with a query message with the exact same binary contents as the + * one we just got. If so, it's almost definitely a packet loop of some kind. */ + + t = hashmap_get(m->dns_transactions, UINT_TO_PTR(DNS_PACKET_ID(p))); + if (!t) + return false; + + return t->sent && dns_packet_equal(t->sent, p); +} + DnsScope* manager_find_scope(Manager *m, DnsPacket *p) { Link *l; @@ -1441,7 +1490,7 @@ bool manager_routable(Manager *m) { return false; } -void manager_flush_caches(Manager *m) { +void manager_flush_caches(Manager *m, int log_level) { DnsScope *scope; assert(m); @@ -1449,7 +1498,7 @@ void manager_flush_caches(Manager *m) { LIST_FOREACH(scopes, scope, m->dns_scopes) dns_cache_flush(&scope->cache); - log_info("Flushed all caches."); + log_full(log_level, "Flushed all caches."); } void manager_reset_server_features(Manager *m) { @@ -1549,3 +1598,87 @@ bool manager_next_dnssd_names(Manager *m) { return tried; } + +bool manager_server_is_stub(Manager *m, DnsServer *s) { + DnsStubListenerExtra *l; + + assert(m); + assert(s); + + /* Safety check: we generally already skip the main stub when parsing configuration. But let's be + * extra careful, and check here again */ + if (s->family == AF_INET && + s->address.in.s_addr == htobe32(INADDR_DNS_STUB) && + dns_server_port(s) == 53) + return true; + + /* Main reason to call this is to check server data against the extra listeners, and filter things + * out. */ + ORDERED_SET_FOREACH(l, m->dns_extra_stub_listeners) + if (s->family == l->family && + in_addr_equal(s->family, &s->address, &l->address) && + dns_server_port(s) == dns_stub_listener_extra_port(l)) + return true; + + return false; +} + +int socket_disable_pmtud(int fd, int af) { + int r; + + assert(fd >= 0); + + if (af == AF_UNSPEC) { + r = socket_get_family(fd, &af); + if (r < 0) + return r; + } + + switch (af) { + + case AF_INET: { + /* Turn off path MTU discovery, let's rather fragment on the way than to open us up against + * PMTU forgery vulnerabilities. + * + * There appears to be no documentation about IP_PMTUDISC_OMIT, but it has the effect that + * the "Don't Fragment" bit in the IPv4 header is turned off, thus enforcing fragmentation if + * our datagram size exceeds the MTU of a router in the path, and turning off path MTU + * discovery. + * + * This helps mitigating the PMTUD vulnerability described here: + * + * https://blog.apnic.net/2019/07/12/its-time-to-consider-avoiding-ip-fragmentation-in-the-dns/ + * + * Similar logic is in place in most DNS servers. + * + * There are multiple conflicting goals: we want to allow the largest datagrams possible (for + * efficiency reasons), but not have fragmentation (for security reasons), nor use PMTUD (for + * security reasons, too). Our strategy to deal with this is: use large packets, turn off + * PMTUD, but watch fragmentation taking place, and then size our packets to the max of the + * fragments seen — and if we need larger packets always go to TCP. + */ + + r = setsockopt_int(fd, IPPROTO_IP, IP_MTU_DISCOVER, IP_PMTUDISC_OMIT); + if (r < 0) + return r; + + return 0; + } + + case AF_INET6: { + /* On IPv6 fragmentation only is done by the sender — never by routers on the path. PMTUD is + * mandatory. If we want to turn off PMTUD, the only way is by sending with minimal MTU only, + * so that we apply maximum fragmentation locally already, and thus PMTUD doesn't happen + * because there's nothing that could be fragmented further anymore. */ + + r = setsockopt_int(fd, IPPROTO_IPV6, IPV6_MTU, IPV6_MIN_MTU); + if (r < 0) + return r; + + return 0; + } + + default: + return -EAFNOSUPPORT; + } +} diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index 20afab05f..1371c41b9 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -21,6 +21,7 @@ typedef struct Manager Manager; #include "resolved-dns-stub.h" #include "resolved-dns-trust-anchor.h" #include "resolved-link.h" +#include "resolved-socket-graveyard.h" #define MANAGER_SEARCH_DOMAINS_MAX 256 #define MANAGER_DNS_SERVERS_MAX 256 @@ -39,6 +40,7 @@ struct Manager { DnssecMode dnssec_mode; DnsOverTlsMode dns_over_tls_mode; DnsCacheMode enable_cache; + bool cache_from_localhost; DnsStubListenerMode dns_stub_listener_mode; #if ENABLE_DNS_OVER_TLS @@ -58,6 +60,7 @@ struct Manager { Hashmap *dns_transactions; LIST_HEAD(DnsQuery, dns_queries); unsigned n_dns_queries; + Hashmap *stub_queries_by_packet; LIST_HEAD(DnsStream, dns_streams); unsigned n_dns_streams[_DNS_STREAM_TYPE_MAX]; @@ -96,13 +99,12 @@ struct Manager { /* mDNS */ int mdns_ipv4_fd; int mdns_ipv6_fd; + sd_event_source *mdns_ipv4_event_source; + sd_event_source *mdns_ipv6_event_source; /* DNS-SD */ Hashmap *dnssd_services; - sd_event_source *mdns_ipv4_event_source; - sd_event_source *mdns_ipv6_event_source; - /* dbus */ sd_bus *bus; @@ -128,9 +130,8 @@ struct Manager { /* Data from /etc/hosts */ EtcHosts etc_hosts; - usec_t etc_hosts_last, etc_hosts_mtime; - ino_t etc_hosts_ino; - dev_t etc_hosts_dev; + usec_t etc_hosts_last; + struct stat etc_hosts_stat; bool read_etc_hosts; OrderedSet *dns_extra_stub_listeners; @@ -142,6 +143,12 @@ struct Manager { Hashmap *polkit_registry; VarlinkServer *varlink_server; + + sd_event_source *clock_change_event_source; + + LIST_HEAD(SocketGraveyard, socket_graveyard); + SocketGraveyard *socket_graveyard_oldest; + size_t n_socket_graveyard; }; /* Manager */ @@ -163,7 +170,9 @@ LinkAddress* manager_find_link_address(Manager *m, int family, const union in_ad void manager_refresh_rrs(Manager *m); int manager_next_hostname(Manager *m); -bool manager_our_packet(Manager *m, DnsPacket *p); +bool manager_packet_from_local_address(Manager *m, DnsPacket *p); +bool manager_packet_from_our_transaction(Manager *m, DnsPacket *p); + DnsScope* manager_find_scope(Manager *m, DnsPacket *p); void manager_verify_all(Manager *m); @@ -187,9 +196,13 @@ void manager_dnssec_verdict(Manager *m, DnssecVerdict verdict, const DnsResource bool manager_routable(Manager *m); -void manager_flush_caches(Manager *m); +void manager_flush_caches(Manager *m, int log_level); void manager_reset_server_features(Manager *m); void manager_cleanup_saved_user(Manager *m); bool manager_next_dnssd_names(Manager *m); + +bool manager_server_is_stub(Manager *m, DnsServer *s); + +int socket_disable_pmtud(int fd, int af); diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c index a09374719..2857b58e8 100644 --- a/src/resolve/resolved-mdns.c +++ b/src/resolve/resolved-mdns.c @@ -15,10 +15,10 @@ void manager_mdns_stop(Manager *m) { assert(m); - m->mdns_ipv4_event_source = sd_event_source_unref(m->mdns_ipv4_event_source); + m->mdns_ipv4_event_source = sd_event_source_disable_unref(m->mdns_ipv4_event_source); m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); - m->mdns_ipv6_event_source = sd_event_source_unref(m->mdns_ipv6_event_source); + m->mdns_ipv6_event_source = sd_event_source_disable_unref(m->mdns_ipv6_event_source); m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); } @@ -237,7 +237,7 @@ static int mdns_scope_process_query(DnsScope *s, DnsPacket *p) { if (!ratelimit_below(&s->ratelimit)) return 0; - r = dns_scope_emit_udp(s, -1, reply); + r = dns_scope_emit_udp(s, -1, AF_UNSPEC, reply); if (r < 0) return log_debug_errno(r, "Failed to send reply packet: %m"); @@ -254,7 +254,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us if (r <= 0) return r; - if (manager_our_packet(m, p)) + if (manager_packet_from_local_address(m, p)) return 0; scope = manager_find_scope(m, p); @@ -265,6 +265,7 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us if (dns_packet_validate_reply(p) > 0) { DnsResourceRecord *rr; + DnsTransaction *t; log_debug("Got mDNS reply packet"); @@ -286,12 +287,15 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us dns_scope_check_conflicts(scope, p); DNS_ANSWER_FOREACH(rr, p->answer) { - const char *name = dns_resource_key_name(rr->key); - DnsTransaction *t; + const char *name; - /* If the received reply packet contains ANY record that is not .local or .in-addr.arpa, - * we assume someone's playing tricks on us and discard the packet completely. */ + name = dns_resource_key_name(rr->key); + + /* If the received reply packet contains ANY record that is not .local + * or .in-addr.arpa or .ip6.arpa, we assume someone's playing tricks on + * us and discard the packet completely. */ if (!(dns_name_endswith(name, "in-addr.arpa") > 0 || + dns_name_endswith(name, "ip6.arpa") > 0 || dns_name_endswith(name, "local") > 0)) return 0; @@ -300,26 +304,17 @@ static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *us /* See the section 10.1 of RFC6762 */ rr->ttl = 1; } - - t = dns_scope_find_transaction(scope, rr->key, false); - if (t) - dns_transaction_process_reply(t, p); - - /* Also look for the various types of ANY transactions */ - t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(rr->key->class, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), false); - if (t) - dns_transaction_process_reply(t, p); - - t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, rr->key->type, dns_resource_key_name(rr->key)), false); - if (t) - dns_transaction_process_reply(t, p); - - t = dns_scope_find_transaction(scope, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_ANY, DNS_TYPE_ANY, dns_resource_key_name(rr->key)), false); - if (t) - dns_transaction_process_reply(t, p); } - dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, false, (uint32_t) -1, 0, p->family, &p->sender); + LIST_FOREACH(transactions_by_scope, t, scope->transactions) { + r = dns_answer_match_key(p->answer, t->key, NULL); + if (r < 0) + log_debug_errno(r, "Failed to match resource key, ignoring: %m"); + else if (r > 0) /* This packet matches the transaction, let's pass it on as reply */ + dns_transaction_process_reply(t, p, false); + } + + dns_cache_put(&scope->cache, scope->manager->enable_cache, NULL, DNS_PACKET_RCODE(p), p->answer, NULL, false, _DNSSEC_RESULT_INVALID, UINT32_MAX, p->family, &p->sender); } else if (dns_packet_validate_query(p) > 0) { log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p)); diff --git a/src/resolve/resolved-resolv-conf.c b/src/resolve/resolved-resolv-conf.c index fce5c9b03..dd02d368e 100644 --- a/src/resolve/resolved-resolv-conf.c +++ b/src/resolve/resolved-resolv-conf.c @@ -252,7 +252,11 @@ static void write_resolv_conf_search( static int write_uplink_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) { - fputs("# This file is managed by man:systemd-resolved(8). Do not edit.\n" + fputs("# This is "PRIVATE_UPLINK_RESOLV_CONF" managed by man:systemd-resolved(8).\n" + "# Do not edit.\n" + "#\n" + "# This file might be symlinked as /etc/resolv.conf. If you're looking at\n" + "# /etc/resolv.conf and seeing this text, you have followed the symlink.\n" "#\n" "# This is a dynamic resolv.conf file for connecting local clients directly to\n" "# all known uplink DNS servers. This file lists all configured search domains.\n" @@ -285,7 +289,11 @@ static int write_uplink_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSe } static int write_stub_resolv_conf_contents(FILE *f, OrderedSet *dns, OrderedSet *domains) { - fputs("# This file is managed by man:systemd-resolved(8). Do not edit.\n" + fputs("# This is "PRIVATE_STUB_RESOLV_CONF" managed by man:systemd-resolved(8).\n" + "# Do not edit.\n" + "#\n" + "# This file might be symlinked as /etc/resolv.conf. If you're looking at\n" + "# /etc/resolv.conf and seeing this text, you have followed the symlink.\n" "#\n" "# This is a dynamic resolv.conf file for connecting local clients to the\n" "# internal DNS stub resolver of systemd-resolved. This file lists all\n" @@ -360,8 +368,9 @@ int manager_write_resolv_conf(Manager *m) { goto fail; } - if (rename(temp_path_stub, PRIVATE_STUB_RESOLV_CONF) < 0) - r = log_error_errno(errno, "Failed to move new %s into place: %m", PRIVATE_STUB_RESOLV_CONF); + r = conservative_rename(temp_path_stub, PRIVATE_STUB_RESOLV_CONF); + if (r < 0) + log_error_errno(r, "Failed to move new %s into place: %m", PRIVATE_STUB_RESOLV_CONF); } else { r = symlink_atomic_label(basename(PRIVATE_UPLINK_RESOLV_CONF), PRIVATE_STUB_RESOLV_CONF); @@ -369,8 +378,9 @@ int manager_write_resolv_conf(Manager *m) { log_error_errno(r, "Failed to symlink %s: %m", PRIVATE_STUB_RESOLV_CONF); } - if (rename(temp_path_uplink, PRIVATE_UPLINK_RESOLV_CONF) < 0) - r = log_error_errno(errno, "Failed to move new %s into place: %m", PRIVATE_UPLINK_RESOLV_CONF); + r = conservative_rename(temp_path_uplink, PRIVATE_UPLINK_RESOLV_CONF); + if (r < 0) + log_error_errno(r, "Failed to move new %s into place: %m", PRIVATE_UPLINK_RESOLV_CONF); fail: if (r < 0) { diff --git a/src/resolve/resolved-resolv-conf.h b/src/resolve/resolved-resolv-conf.h index 3734e28a9..8c0dee876 100644 --- a/src/resolve/resolved-resolv-conf.h +++ b/src/resolve/resolved-resolv-conf.h @@ -14,7 +14,7 @@ typedef enum ResolvConfMode { RESOLV_CONF_FOREIGN, RESOLV_CONF_MISSING, _RESOLV_CONF_MODE_MAX, - _RESOLV_CONF_MODE_INVALID = -1, + _RESOLV_CONF_MODE_INVALID = -EINVAL, } ResolvConfMode; int resolv_conf_mode(void); diff --git a/src/resolve/resolved-socket-graveyard.c b/src/resolve/resolved-socket-graveyard.c new file mode 100644 index 000000000..471fe1d57 --- /dev/null +++ b/src/resolve/resolved-socket-graveyard.c @@ -0,0 +1,133 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ + +#include "resolved-socket-graveyard.h" + +#define SOCKET_GRAVEYARD_USEC (5 * USEC_PER_SEC) +#define SOCKET_GRAVEYARD_MAX 100 + +/* This implements a socket "graveyard" for UDP sockets. If a socket fd is added to the graveyard it is kept + * open for a couple of more seconds, expecting one reply. Once the reply is received the fd is closed + * immediately, or if none is received it is closed after the timeout. Why all this? So that if we contact a + * DNS server, and it doesn't reply instantly, and we lose interest in the response and thus close the fd, we + * don't end up sending back an ICMP error once the server responds but we aren't listening anymore. (See + * https://github.com/systemd/systemd/issues/17421 for further information.) + * + * Note that we don't allocate any timer event source to clear up the graveyard once the socket's timeout is + * reached. Instead we operate lazily: we close old entries when adding a new fd to the graveyard, or + * whenever any code runs manager_socket_graveyard_process() — which the DNS transaction code does right + * before allocating a new UDP socket. */ + +static SocketGraveyard* socket_graveyard_free(SocketGraveyard *g) { + if (!g) + return NULL; + + if (g->manager) { + assert(g->manager->n_socket_graveyard > 0); + g->manager->n_socket_graveyard--; + + if (g->manager->socket_graveyard_oldest == g) + g->manager->socket_graveyard_oldest = g->graveyard_prev; + + LIST_REMOVE(graveyard, g->manager->socket_graveyard, g); + + assert((g->manager->n_socket_graveyard > 0) == !!g->manager->socket_graveyard); + assert((g->manager->n_socket_graveyard > 0) == !!g->manager->socket_graveyard_oldest); + } + + if (g->io_event_source) { + log_debug("Closing graveyard socket fd %i", sd_event_source_get_io_fd(g->io_event_source)); + sd_event_source_disable_unref(g->io_event_source); + } + + return mfree(g); +} + +DEFINE_TRIVIAL_CLEANUP_FUNC(SocketGraveyard*, socket_graveyard_free); + +void manager_socket_graveyard_process(Manager *m) { + usec_t n = USEC_INFINITY; + + assert(m); + + while (m->socket_graveyard_oldest) { + SocketGraveyard *g = m->socket_graveyard_oldest; + + if (n == USEC_INFINITY) + assert_se(sd_event_now(m->event, clock_boottime_or_monotonic(), &n) >= 0); + + if (g->deadline > n) + break; + + socket_graveyard_free(g); + } +} + +void manager_socket_graveyard_clear(Manager *m) { + assert(m); + + while (m->socket_graveyard) + socket_graveyard_free(m->socket_graveyard); +} + +static int on_io_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) { + SocketGraveyard *g = userdata; + + assert(g); + + /* An IO event happened on the graveyard fd. We don't actually care which event that is, and we don't + * read any incoming packet off the socket. We just close the fd, that's enough to not trigger the + * ICMP unreachable port event */ + + socket_graveyard_free(g); + return 0; +} + +static void manager_socket_graveyard_make_room(Manager *m) { + assert(m); + + while (m->n_socket_graveyard >= SOCKET_GRAVEYARD_MAX) + socket_graveyard_free(m->socket_graveyard_oldest); +} + +int manager_add_socket_to_graveyard(Manager *m, int fd) { + _cleanup_(socket_graveyard_freep) SocketGraveyard *g = NULL; + int r; + + assert(m); + assert(fd >= 0); + + manager_socket_graveyard_process(m); + manager_socket_graveyard_make_room(m); + + g = new(SocketGraveyard, 1); + if (!g) + return log_oom(); + + *g = (SocketGraveyard) { + .manager = m, + }; + + LIST_PREPEND(graveyard, m->socket_graveyard, g); + if (!m->socket_graveyard_oldest) + m->socket_graveyard_oldest = g; + + m->n_socket_graveyard++; + + assert_se(sd_event_now(m->event, clock_boottime_or_monotonic(), &g->deadline) >= 0); + g->deadline += SOCKET_GRAVEYARD_USEC; + + r = sd_event_add_io(m->event, &g->io_event_source, fd, EPOLLIN, on_io_event, g); + if (r < 0) + return log_error_errno(r, "Failed to create graveyard IO source: %m"); + + r = sd_event_source_set_io_fd_own(g->io_event_source, true); + if (r < 0) + return log_error_errno(r, "Failed to enable graveyard IO source fd ownership: %m"); + + (void) sd_event_source_set_description(g->io_event_source, "graveyard"); + + log_debug("Added socket %i to graveyard", fd); + + TAKE_PTR(g); + return 0; +} diff --git a/src/resolve/resolved-socket-graveyard.h b/src/resolve/resolved-socket-graveyard.h new file mode 100644 index 000000000..9b13bb048 --- /dev/null +++ b/src/resolve/resolved-socket-graveyard.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: LGPL-2.1+ */ +#pragma once + +typedef struct SocketGraveyard SocketGraveyard; + +#include "resolved-manager.h" + +struct SocketGraveyard { + Manager *manager; + usec_t deadline; + sd_event_source *io_event_source; + LIST_FIELDS(SocketGraveyard, graveyard); +}; + +void manager_socket_graveyard_process(Manager *m); +void manager_socket_graveyard_clear(Manager *m); + +int manager_add_socket_to_graveyard(Manager *m, int fd); diff --git a/src/resolve/resolved-util.c b/src/resolve/resolved-util.c new file mode 100644 index 000000000..00abada42 --- /dev/null +++ b/src/resolve/resolved-util.c @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "dns-def.h" +#include "dns-domain.h" +#include "hostname-util.h" +#include "idn-util.h" +#include "resolved-util.h" +#include "utf8.h" + +int resolve_system_hostname(char **full_hostname, char **first_label) { + _cleanup_free_ char *h = NULL, *n = NULL; +#if HAVE_LIBIDN2 + _cleanup_free_ char *utf8 = NULL; +#elif HAVE_LIBIDN + int k; +#endif + char label[DNS_LABEL_MAX]; + const char *p, *decoded; + int r; + + /* Return the full hostname in *full_hostname, if nonnull. + * + * Extract and normalize the first label of the locally configured hostname, check it's not + * "localhost", and return it in *first_label, if nonnull. */ + + r = gethostname_strict(&h); + if (r < 0) + return log_debug_errno(r, "Can't determine system hostname: %m"); + + p = h; + r = dns_label_unescape(&p, label, sizeof label, 0); + if (r < 0) + return log_debug_errno(r, "Failed to unescape hostname: %m"); + if (r == 0) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "Couldn't find a single label in hostname."); + +#if HAVE_LIBIDN || HAVE_LIBIDN2 + r = dlopen_idn(); + if (r < 0) { + log_debug_errno(r, "Failed to initialize IDN support, ignoring: %m"); + decoded = label; /* no decoding */ + } else +#endif + { +#if HAVE_LIBIDN2 + r = sym_idn2_to_unicode_8z8z(label, &utf8, 0); + if (r != IDN2_OK) + return log_debug_errno(SYNTHETIC_ERRNO(EUCLEAN), + "Failed to undo IDNA: %s", sym_idn2_strerror(r)); + assert(utf8_is_valid(utf8)); + + r = strlen(utf8); + decoded = utf8; +#elif HAVE_LIBIDN + k = dns_label_undo_idna(label, r, label, sizeof label); + if (k < 0) + return log_debug_errno(k, "Failed to undo IDNA: %m"); + if (k > 0) + r = k; + + if (!utf8_is_valid(label)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "System hostname is not UTF-8 clean."); + decoded = label; +#else + decoded = label; /* no decoding */ +#endif + } + + r = dns_label_escape_new(decoded, r, &n); + if (r < 0) + return log_debug_errno(r, "Failed to escape hostname: %m"); + + if (is_localhost(n)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "System hostname is 'localhost', ignoring."); + + if (full_hostname) + *full_hostname = TAKE_PTR(h); + if (first_label) + *first_label = TAKE_PTR(n); + return 0; +} diff --git a/src/resolve/resolved-util.h b/src/resolve/resolved-util.h new file mode 100644 index 000000000..446b7c9f1 --- /dev/null +++ b/src/resolve/resolved-util.h @@ -0,0 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +int resolve_system_hostname(char **full_hostname, char **first_label); diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c index 70d6f9056..27d8c8967 100644 --- a/src/resolve/resolved-varlink.c +++ b/src/resolve/resolved-varlink.c @@ -57,6 +57,12 @@ static int reply_query_state(DnsQuery *q) { case DNS_TRANSACTION_NETWORK_DOWN: return varlink_error(q->varlink_request, "io.systemd.Resolve.NetworkDown", NULL); + case DNS_TRANSACTION_NO_SOURCE: + return varlink_error(q->varlink_request, "io.systemd.Resolve.NoSource", NULL); + + case DNS_TRANSACTION_STUB_LOOP: + return varlink_error(q->varlink_request, "io.systemd.Resolve.StubLoop", NULL); + case DNS_TRANSACTION_NOT_FOUND: /* We return this as NXDOMAIN. This is only generated when a host doesn't implement LLMNR/TCP, and we * thus quickly know that we cannot resolve an in-addr.arpa or ip6.arpa address. */ @@ -103,7 +109,7 @@ static bool validate_and_mangle_flags( /* This checks that the specified client-provided flags parameter actually makes sense, and mangles * it slightly. Specifically: * - * 1. We check that only the protocol flags and the NO_CNAME flag are on at most, plus the + * 1. We check that only the protocol flags and a bunch of NO_XYZ flags are on at most, plus the * method-specific flags specified in 'ok'. * * 2. If no protocols are enabled we automatically convert that to "all protocols are enabled". @@ -114,7 +120,15 @@ static bool validate_and_mangle_flags( * "everything". */ - if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL|SD_RESOLVED_NO_CNAME|ok)) + if (*flags & ~(SD_RESOLVED_PROTOCOLS_ALL| + SD_RESOLVED_NO_CNAME| + SD_RESOLVED_NO_VALIDATE| + SD_RESOLVED_NO_SYNTHESIZE| + SD_RESOLVED_NO_CACHE| + SD_RESOLVED_NO_ZONE| + SD_RESOLVED_NO_TRUST_ANCHOR| + SD_RESOLVED_NO_NETWORK| + ok)) return false; if ((*flags & SD_RESOLVED_PROTOCOLS_ALL) == 0) /* If no protocol is enabled, enable all */ @@ -144,14 +158,14 @@ static void vl_method_resolve_hostname_complete(DnsQuery *q) { goto finish; } - r = dns_query_process_cname(q); + r = dns_query_process_cname_many(q); if (r == -ELOOP) { r = varlink_error(q->varlink_request, "io.systemd.Resolve.CNAMELoop", NULL); goto finish; } if (r < 0) goto finish; - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; question = dns_query_question_for_protocol(q, q->answer_protocol); @@ -180,7 +194,7 @@ static void vl_method_resolve_hostname_complete(DnsQuery *q) { r = json_build(&entry, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("ifindex", JSON_BUILD_INTEGER(ifindex)), + JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", JSON_BUILD_INTEGER(ifindex)), JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(family)), JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(p, FAMILY_ADDRESS_SIZE(family))))); if (r < 0) @@ -208,7 +222,7 @@ static void vl_method_resolve_hostname_complete(DnsQuery *q) { JSON_BUILD_OBJECT( JSON_BUILD_PAIR("addresses", JSON_BUILD_VARIANT(array)), JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(dns_query_reply_flags_make(q))))); finish: if (r < 0) { log_error_errno(r, "Failed to send hostname reply: %m"); @@ -253,7 +267,8 @@ static int parse_as_address(Varlink *link, LookupParameters *p) { JSON_BUILD_PAIR("family", JSON_BUILD_INTEGER(ff)), JSON_BUILD_PAIR("address", JSON_BUILD_BYTE_ARRAY(&parsed, FAMILY_ADDRESS_SIZE(ff)))))), JSON_BUILD_PAIR("name", JSON_BUILD_STRING(canonical)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(dns_synthesize_protocol(p->flags), ff, true, true)| + SD_RESOLVED_SYNTHETIC)))); } static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) { @@ -269,11 +284,13 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va _cleanup_(lookup_parameters_destroy) LookupParameters p = { .family = AF_UNSPEC, }; - Manager *m = userdata; DnsQuery *q; + Manager *m; int r; assert(link); + + m = varlink_server_get_userdata(varlink_get_server(link)); assert(m); if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) @@ -310,7 +327,7 @@ static int vl_method_resolve_hostname(Varlink *link, JsonVariant *parameters, Va if (r < 0 && r != -EALREADY) return r; - r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, p.ifindex, p.flags); + r = dns_query_new(m, &q, question_utf8, question_idna ?: question_utf8, NULL, p.ifindex, p.flags); if (r < 0) return r; @@ -378,14 +395,14 @@ static void vl_method_resolve_address_complete(DnsQuery *q) { goto finish; } - r = dns_query_process_cname(q); + r = dns_query_process_cname_many(q); if (r == -ELOOP) { r = varlink_error(q->varlink_request, "io.systemd.Resolve.CNAMELoop", NULL); goto finish; } if (r < 0) goto finish; - if (r == DNS_QUERY_RESTARTED) /* This was a cname, and the query was restarted. */ + if (r == DNS_QUERY_CNAME) /* This was a cname, and the query was restarted. */ return; question = dns_query_question_for_protocol(q, q->answer_protocol); @@ -406,7 +423,7 @@ static void vl_method_resolve_address_complete(DnsQuery *q) { r = json_build(&entry, JSON_BUILD_OBJECT( - JSON_BUILD_PAIR("ifindex", JSON_BUILD_INTEGER(ifindex)), + JSON_BUILD_PAIR_CONDITION(ifindex > 0, "ifindex", JSON_BUILD_INTEGER(ifindex)), JSON_BUILD_PAIR("name", JSON_BUILD_STRING(normalized)))); if (r < 0) goto finish; @@ -424,7 +441,7 @@ static void vl_method_resolve_address_complete(DnsQuery *q) { r = varlink_replyb(q->varlink_request, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("names", JSON_BUILD_VARIANT(array)), - JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, dns_query_fully_authenticated(q)))))); + JSON_BUILD_PAIR("flags", JSON_BUILD_INTEGER(dns_query_reply_flags_make(q))))); finish: if (r < 0) { log_error_errno(r, "Failed to send address reply: %m"); @@ -447,11 +464,13 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var _cleanup_(lookup_parameters_destroy) LookupParameters p = { .family = AF_UNSPEC, }; - Manager *m = userdata; DnsQuery *q; + Manager *m; int r; assert(link); + + m = varlink_server_get_userdata(varlink_get_server(link)); assert(m); if (FLAGS_SET(flags, VARLINK_METHOD_ONEWAY)) @@ -477,7 +496,7 @@ static int vl_method_resolve_address(Varlink *link, JsonVariant *parameters, Var if (r < 0) return r; - r = dns_query_new(m, &q, question, question, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH); + r = dns_query_new(m, &q, question, question, NULL, p.ifindex, p.flags|SD_RESOLVED_NO_SEARCH); if (r < 0) return r; diff --git a/src/resolve/resolved.c b/src/resolve/resolved.c index fd9be30dc..aabaa266e 100644 --- a/src/resolve/resolved.c +++ b/src/resolve/resolved.c @@ -26,7 +26,7 @@ static int run(int argc, char *argv[]) { _cleanup_(notify_on_cleanup) const char *notify_stop = NULL; int r; - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-resolved.service", "Provide name resolution with caching using DNS, mDNS, LLMNR.", @@ -58,7 +58,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Could not create runtime directory: %m"); - /* Drop privileges, but keep three caps. Note that we drop those too, later on (see below) */ + /* Drop privileges, but keep three caps. Note that we drop two of those too, later on (see below) */ r = drop_privileges(uid, gid, (UINT64_C(1) << CAP_NET_RAW)| /* needed for SO_BINDTODEVICE */ (UINT64_C(1) << CAP_NET_BIND_SERVICE)| /* needed to bind on port 53 */ @@ -83,7 +83,7 @@ static int run(int argc, char *argv[]) { (void) manager_check_resolv_conf(m); /* Let's drop the remaining caps now */ - r = capability_bounding_set_drop(0, true); + r = capability_bounding_set_drop((UINT64_C(1) << CAP_NET_RAW), true); if (r < 0) return log_error_errno(r, "Failed to drop remaining caps: %m"); diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index 93279b3df..f88a4e97c 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -1,15 +1,18 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See resolved.conf(5) for details +# Use 'systemd-analyze cat-config systemd/resolved.conf' to display the full config. +# +# See resolved.conf(5) for details. [Resolve] # Some examples of DNS servers which may be used for DNS= and FallbackDNS=: @@ -24,6 +27,7 @@ #MulticastDNS=@DEFAULT_MDNS_MODE@ #LLMNR=@DEFAULT_LLMNR_MODE@ #Cache=yes +#CacheFromLocalhost=no #DNSStubListener=yes #DNSStubListenerExtra= #ReadEtcHosts=yes diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 47c7d671c..01f15ca88 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -90,8 +90,41 @@ static void test_packet_from_file(const char* filename, bool canonical) { } } +static void test_dns_resource_record_get_cname_target(void) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL, *dname = NULL; + _cleanup_free_ char *target = NULL; + + assert_se(cname = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "quux.foobar")); + assert_se(cname->cname.name = strdup("wuff.wuff")); + + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "waldo"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "foobar"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, ""), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "."), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "nope.quux.foobar"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux.foobar"), cname, &target) == 0); + assert_se(streq(target, "wuff.wuff")); + target = mfree(target); + + assert_se(dname = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNAME, "quux.foobar")); + assert_se(dname->dname.name = strdup("wuff.wuff")); + + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "waldo"), dname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "foobar"), dname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux"), dname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, ""), dname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "."), dname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "yupp.quux.foobar"), dname, &target) == 0); + assert_se(streq(target, "yupp.wuff.wuff")); + target = mfree(target); + + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux.foobar"), cname, &target) == 0); + assert_se(streq(target, "wuff.wuff")); +} + int main(int argc, char **argv) { - int i, N; + int N; _cleanup_globfree_ glob_t g = {}; char **fnames; @@ -108,7 +141,7 @@ int main(int argc, char **argv) { fnames = g.gl_pathv; } - for (i = 0; i < N; i++) { + for (int i = 0; i < N; i++) { test_packet_from_file(fnames[i], false); puts(""); test_packet_from_file(fnames[i], true); @@ -116,5 +149,7 @@ int main(int argc, char **argv) { puts(""); } + test_dns_resource_record_get_cname_target(); + return EXIT_SUCCESS; } diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c index 0275d0eb9..b0763694d 100644 --- a/src/resolve/test-dnssec.c +++ b/src/resolve/test-dnssec.c @@ -170,7 +170,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example1(void) { answer = dns_answer_new(1); assert_se(answer); - assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey, rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0); @@ -262,7 +262,7 @@ static void test_dnssec_verify_rfc8080_ed25519_example2(void) { answer = dns_answer_new(1); assert_se(answer); - assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + assert_se(dns_answer_add(answer, mx, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); assert_se(dnssec_verify_rrset(answer, mx->key, rrsig, dnskey, rrsig->rrsig.inception * USEC_PER_SEC, &result) >= 0); @@ -344,7 +344,7 @@ static void test_dnssec_verify_rrset(void) { answer = dns_answer_new(1); assert_se(answer); - assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + assert_se(dns_answer_add(answer, a, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); /* Validate the RR as it if was 2015-12-2 today */ assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC, &result) >= 0); @@ -436,7 +436,7 @@ static void test_dnssec_verify_rrset2(void) { answer = dns_answer_new(1); assert_se(answer); - assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + assert_se(dns_answer_add(answer, nsec, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); /* Validate the RR as it if was 2015-12-11 today */ assert_se(dnssec_verify_rrset(answer, nsec->key, rrsig, dnskey, 1449849318*USEC_PER_SEC, &result) >= 0); @@ -563,10 +563,10 @@ static void test_dnssec_verify_rrset3(void) { answer = dns_answer_new(4); assert_se(answer); - assert_se(dns_answer_add(answer, mx1, 0, DNS_ANSWER_AUTHENTICATED) >= 0); - assert_se(dns_answer_add(answer, mx2, 0, DNS_ANSWER_AUTHENTICATED) >= 0); - assert_se(dns_answer_add(answer, mx3, 0, DNS_ANSWER_AUTHENTICATED) >= 0); - assert_se(dns_answer_add(answer, mx4, 0, DNS_ANSWER_AUTHENTICATED) >= 0); + assert_se(dns_answer_add(answer, mx1, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); + assert_se(dns_answer_add(answer, mx2, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); + assert_se(dns_answer_add(answer, mx3, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); + assert_se(dns_answer_add(answer, mx4, 0, DNS_ANSWER_AUTHENTICATED, NULL) >= 0); /* Validate the RR as it if was 2020-02-24 today */ assert_se(dnssec_verify_rrset(answer, mx1->key, rrsig, dnskey, 1582534685*USEC_PER_SEC, &result) >= 0); diff --git a/src/rfkill/rfkill.c b/src/rfkill/rfkill.c index c38716842..e2d1a1be5 100644 --- a/src/rfkill/rfkill.c +++ b/src/rfkill/rfkill.c @@ -135,8 +135,6 @@ static int determine_state_file( static int load_state(Context *c, const struct rfkill_event *event) { _cleanup_free_ char *state_file = NULL, *value = NULL; - struct rfkill_event we; - ssize_t l; int b, r; assert(c); @@ -168,18 +166,22 @@ static int load_state(Context *c, const struct rfkill_event *event) { if (b < 0) return log_error_errno(b, "Failed to parse state file %s: %m", state_file); - we = (struct rfkill_event) { - .op = RFKILL_OP_CHANGE, + struct rfkill_event we = { .idx = event->idx, + .op = RFKILL_OP_CHANGE, .soft = b, }; + assert_cc(offsetof(struct rfkill_event, op) < RFKILL_EVENT_SIZE_V1); + assert_cc(offsetof(struct rfkill_event, soft) < RFKILL_EVENT_SIZE_V1); - l = write(c->rfkill_fd, &we, sizeof(we)); + ssize_t l = write(c->rfkill_fd, &we, sizeof we); if (l < 0) return log_error_errno(errno, "Failed to restore rfkill state for %i: %m", event->idx); - if (l != sizeof(we)) + if (l < RFKILL_EVENT_SIZE_V1) return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Couldn't write rfkill event structure, too short."); + "Couldn't write rfkill event structure, too short (wrote %zd of %zu bytes).", + l, sizeof we); + log_debug("Writing struct rfkill_event successful (%zd of %zu bytes).", l, sizeof we); log_debug("Loaded state '%s' from %s.", one_zero(b), state_file); return 0; @@ -276,7 +278,7 @@ static int run(int argc, char *argv[]) { if (argc > 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires no arguments."); - log_setup_service(); + log_setup(); umask(0022); @@ -305,44 +307,45 @@ static int run(int argc, char *argv[]) { } for (;;) { - struct rfkill_event event; - const char *type; - ssize_t l; + struct rfkill_event event = {}; - l = read(c.rfkill_fd, &event, sizeof(event)); + ssize_t l = read(c.rfkill_fd, &event, sizeof event); if (l < 0) { - if (errno == EAGAIN) { + if (errno != EAGAIN) + return log_error_errno(errno, "Failed to read from /dev/rfkill: %m"); - if (!ready) { - /* Notify manager that we are - * now finished with - * processing whatever was - * queued */ - (void) sd_notify(false, "READY=1"); - ready = true; - } - - /* Hang around for a bit, maybe there's more coming */ - - r = fd_wait_for_event(c.rfkill_fd, POLLIN, EXIT_USEC); - if (r == -EINTR) - continue; - if (r < 0) - return log_error_errno(r, "Failed to poll() on device: %m"); - if (r > 0) - continue; - - log_debug("All events read and idle, exiting."); - break; + if (!ready) { + /* Notify manager that we are now finished with processing whatever was + * queued */ + (void) sd_notify(false, "READY=1"); + ready = true; } - log_error_errno(errno, "Failed to read from /dev/rfkill: %m"); + /* Hang around for a bit, maybe there's more coming */ + + r = fd_wait_for_event(c.rfkill_fd, POLLIN, EXIT_USEC); + if (r == -EINTR) + continue; + if (r < 0) + return log_error_errno(r, "Failed to poll() on device: %m"); + if (r > 0) + continue; + + log_debug("All events read and idle, exiting."); + break; } - if (l != RFKILL_EVENT_SIZE_V1) - return log_error_errno(SYNTHETIC_ERRNO(EIO), "Read event structure of invalid size."); + if (l < RFKILL_EVENT_SIZE_V1) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Short read of struct rfkill_event: (%zd < %d)", + l, RFKILL_EVENT_SIZE_V1); + log_debug("Reading struct rfkill_event: got %zd bytes.", l); - type = rfkill_type_to_string(event.type); + /* The event structure has more fields. We only care about the first few, so it's OK if we + * don't read the full structure. */ + assert_cc(offsetof(struct rfkill_event, op) < RFKILL_EVENT_SIZE_V1); + assert_cc(offsetof(struct rfkill_event, type) < RFKILL_EVENT_SIZE_V1); + + const char *type = rfkill_type_to_string(event.type); if (!type) { log_debug("An rfkill device of unknown type %i discovered, ignoring.", event.type); continue; diff --git a/src/core/macros.systemd.in b/src/rpm/macros.systemd.in similarity index 97% rename from src/core/macros.systemd.in rename to src/rpm/macros.systemd.in index 1c40328db..24996de10 100644 --- a/src/core/macros.systemd.in +++ b/src/rpm/macros.systemd.in @@ -82,7 +82,9 @@ fi \ %{expand:%%{?__systemd_someargs_%#:%%__systemd_someargs_%# systemd_postun_with_restart}} \ if [ $1 -ge 1 ] && [ -x @bindir@/systemctl ]; then \ # Package upgrade, not uninstall \ - @bindir@/systemctl try-restart %{?*} || : \ + for unit in %{?*}; do \ + @bindir@/systemctl set-property $unit Markers=+needs-restart || : \ + done \ fi \ %{nil} diff --git a/src/rpm/meson.build b/src/rpm/meson.build new file mode 100644 index 000000000..d299b1801 --- /dev/null +++ b/src/rpm/meson.build @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +configure_file( + input : 'macros.systemd.in', + output : 'macros.systemd', + configuration : substs, + install_dir : rpmmacrosdir == 'no' ? '' : rpmmacrosdir) + +# Those doesn't get installed anywhere, one of them needs to included in the +# rpm spec file definition. +configure_file( + input : 'triggers.systemd.in', + output : 'triggers.systemd', + configuration : substs) +configure_file( + input : 'triggers.systemd.sh.in', + output : 'triggers.systemd.sh', + configuration : substs) diff --git a/src/core/triggers.systemd.in b/src/rpm/triggers.systemd.in similarity index 73% rename from src/core/triggers.systemd.in rename to src/rpm/triggers.systemd.in index 2d25db369..3a89f9169 100644 --- a/src/core/triggers.systemd.in +++ b/src/rpm/triggers.systemd.in @@ -6,14 +6,35 @@ # The contents of this are an example to be copied into systemd.spec. # -# Minimum rpm version supported: 4.13.0 +# Minimum rpm version supported: 4.14.0 %transfiletriggerin -P 900900 -p -- @systemunitdir@ /etc/systemd/system -- This script will run after any package is initially installed or -- upgraded. We care about the case where a package is initially -- installed, because other cases are covered by the *un scriptlets, -- so sometimes we will reload needlessly. +if posix.access("/run/systemd/system") then + pid = posix.fork() + if pid == 0 then + assert(posix.exec("%{_bindir}/systemctl", "daemon-reload")) + elseif pid > 0 then + posix.wait(pid) + end + pid = posix.fork() + if pid == 0 then + assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked")) + elseif pid > 0 then + posix.wait(pid) + end +end + +%transfiletriggerpostun -P 1000100 -p -- @systemunitdir@ /etc/systemd/system +-- On removal, we need to run daemon-reload after any units have been +-- removed. +-- On upgrade, we need to run daemon-reload after any new unit files +-- have been installed, but before %postun scripts in packages get +-- executed. if posix.access("/run/systemd/system") then pid = posix.fork() if pid == 0 then @@ -23,34 +44,12 @@ if posix.access("/run/systemd/system") then end end -%transfiletriggerun -p -- @systemunitdir@ /etc/systemd/system --- On removal, we need to run daemon-reload after any units have been --- removed. %transfiletriggerpostun would be ideal, but it does not get --- executed for some reason. --- On upgrade, we need to run daemon-reload after any new unit files --- have been installed, but before %postun scripts in packages get --- executed. %transfiletriggerun gets the right list of files --- but it is invoked too early (before changes happen). --- %filetriggerpostun happens at the right time, but it fires for --- every package. --- To execute the reload at the right time, we create a state --- file in %transfiletriggerun and execute the daemon-reload in --- the first %filetriggerpostun. - +%transfiletriggerpostun -P 10000 -p -- @systemunitdir@ /etc/systemd/system +-- We restart remaining services that should be restarted here. if posix.access("/run/systemd/system") then - posix.mkdir("%{_localstatedir}/lib") - posix.mkdir("%{_localstatedir}/lib/rpm-state") - posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd") - io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w") -end - -%filetriggerpostun -P 1000100 -p -- @systemunitdir@ /etc/systemd/system -if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then - posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") - posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd") pid = posix.fork() if pid == 0 then - assert(posix.exec("%{_bindir}/systemctl", "daemon-reload")) + assert(posix.exec("%{_bindir}/systemctl", "reload-or-restart", "--marked")) elseif pid > 0 then posix.wait(pid) end @@ -69,7 +68,43 @@ if posix.access("/run/systemd/system") then end end -%transfiletriggerin -P 100500 -p -- @tmpfilesdir@ +%transfiletriggerin -P 1000700 udev -p -- @udevhwdbdir@ +-- This script will automatically invoke hwdb update if files have been +-- installed or updated in @udevhwdbdir@. +if posix.access("/run/systemd/system") then + pid = posix.fork() + if pid == 0 then + assert(posix.exec("%{_bindir}/systemd-hwdb", "update")) + elseif pid > 0 then + posix.wait(pid) + end +end + +%transfiletriggerin -P 1000700 -p -- @catalogdir@ +-- This script will automatically invoke journal catalog update if files +-- have been installed or updated in @catalogdir@. +if posix.access("/run/systemd/system") then + pid = posix.fork() + if pid == 0 then + assert(posix.exec("%{_bindir}/journalctl", "--update-catalog")) + elseif pid > 0 then + posix.wait(pid) + end +end + +%transfiletriggerin -P 1000700 -p -- @binfmtdir@ +-- This script will automatically apply binfmt rules if files have been +-- installed or updated in @binfmtdir@. +if posix.access("/run/systemd/system") then + pid = posix.fork() + if pid == 0 then + assert(posix.exec("@rootlibexecdir@/systemd-binfmt")) + elseif pid > 0 then + posix.wait(pid) + end +end + +%transfiletriggerin -P 1000600 -p -- @tmpfilesdir@ -- This script will process files installed in @tmpfilesdir@ to create -- tmpfiles automatically. The priority is set such that it will run -- after the sysusers file trigger, but before any other triggers. @@ -82,31 +117,7 @@ if posix.access("/run/systemd/system") then end end -%transfiletriggerin -p -- @udevhwdbdir@ --- This script will automatically invoke hwdb update if files have been --- installed or updated in @udevhwdbdir@. -if posix.access("/run/systemd/system") then - pid = posix.fork() - if pid == 0 then - assert(posix.exec("%{_bindir}/systemd-hwdb", "update")) - elseif pid > 0 then - posix.wait(pid) - end -end - -%transfiletriggerin -p -- @catalogdir@ --- This script will automatically invoke journal catalog update if files --- have been installed or updated in @catalogdir@. -if posix.access("/run/systemd/system") then - pid = posix.fork() - if pid == 0 then - assert(posix.exec("%{_bindir}/journalctl", "--update-catalog")) - elseif pid > 0 then - posix.wait(pid) - end -end - -%transfiletriggerin -p -- @udevrulesdir@ +%transfiletriggerin -P 1000600 udev -p -- @udevrulesdir@ -- This script will automatically update udev with new rules if files -- have been installed or updated in @udevrulesdir@. if posix.access("/run/systemd/system") then @@ -118,7 +129,7 @@ if posix.access("/run/systemd/system") then end end -%transfiletriggerin -p -- @sysctldir@ +%transfiletriggerin -P 1000500 -p -- @sysctldir@ -- This script will automatically apply sysctl rules if files have been -- installed or updated in @sysctldir@. if posix.access("/run/systemd/system") then @@ -129,15 +140,3 @@ if posix.access("/run/systemd/system") then posix.wait(pid) end end - -%transfiletriggerin -p -- @binfmtdir@ --- This script will automatically apply binfmt rules if files have been --- installed or updated in @binfmtdir@. -if posix.access("/run/systemd/system") then - pid = posix.fork() - if pid == 0 then - assert(posix.exec("@rootlibexecdir@/systemd-binfmt")) - elseif pid > 0 then - posix.wait(pid) - end -end diff --git a/src/rpm/triggers.systemd.sh.in b/src/rpm/triggers.systemd.sh.in new file mode 100644 index 000000000..0080040de --- /dev/null +++ b/src/rpm/triggers.systemd.sh.in @@ -0,0 +1,89 @@ +# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# Copyright 2018 Neal Gompa + +# The contents of this are an example to be copied into systemd.spec. +# +# Minimum rpm version supported: 4.14.0 + +%transfiletriggerin -P 900900 -- @systemunitdir@ /etc/systemd/system +# This script will run after any package is initially installed or +# upgraded. We care about the case where a package is initially +# installed, because other cases are covered by the *un scriptlets, +# so sometimes we will reload needlessly. +if test -d "/run/systemd/system"; then + %{_bindir}/systemctl daemon-reload || : + %{_bindir}/systemctl reload-or-restart --marked || : +fi + +%transfiletriggerpostun -P 1000100 -- @systemunitdir@ /etc/systemd/system +# On removal, we need to run daemon-reload after any units have been +# removed. +# On upgrade, we need to run daemon-reload after any new unit files +# have been installed, but before %postun scripts in packages get +# executed. +if test -d "/run/systemd/system"; then + %{_bindir}/systemctl daemon-reload || : +fi + +%transfiletriggerpostun -P 10000 -- @systemunitdir@ /etc/systemd/system +# We restart remaining services that should be restarted here. +if test -d "/run/systemd/system"; then + %{_bindir}/systemctl reload-or-restart --marked || : +fi + +%transfiletriggerin -P 1000700 -- @sysusersdir@ +# This script will process files installed in @sysusersdir@ to create +# specified users automatically. The priority is set such that it +# will run before the tmpfiles file trigger. +if test -d "/run/systemd/system"; then + %{_bindir}/systemd-sysusers || : +fi + +%transfiletriggerin -P 1000700 udev -- @udevhwdbdir@ +# This script will automatically invoke hwdb update if files have been +# installed or updated in @udevhwdbdir@. +if test -d "/run/systemd/system"; then + %{_bindir}/systemd-hwdb update || : +fi + +%transfiletriggerin -P 1000700 -- @catalogdir@ +# This script will automatically invoke journal catalog update if files +# have been installed or updated in @catalogdir@. +if test -d "/run/systemd/system"; then + %{_bindir}/journalctl --update-catalog || : +fi + +%transfiletriggerin -P 1000700 -- @binfmtdir@ +# This script will automatically apply binfmt rules if files have been +# installed or updated in @binfmtdir@. +if test -d "/run/systemd/system"; then + # systemd-binfmt might fail if binfmt_misc kernel module is not loaded + # during install + @rootlibexecdir@/systemd-binfmt || : +fi + +%transfiletriggerin -P 1000600 -- @tmpfilesdir@ +# This script will process files installed in @tmpfilesdir@ to create +# tmpfiles automatically. The priority is set such that it will run +# after the sysusers file trigger, but before any other triggers. +if test -d "/run/systemd/system"; then + %{_bindir}/systemd-tmpfiles --create || : +fi + +%transfiletriggerin -P 1000600 udev -- @udevrulesdir@ +# This script will automatically update udev with new rules if files +# have been installed or updated in @udevrulesdir@. +if test -e /run/udev/control; then + %{_bindir}/udevadm control --reload || : +fi + +%transfiletriggerin -P 1000500 -- @sysctldir@ +# This script will automatically apply sysctl rules if files have been +# installed or updated in @sysctldir@. +if test -d "/run/systemd/system"; then + @rootlibexecdir@/systemd-sysctl || : +fi diff --git a/src/run-generator/run-generator.c b/src/run-generator/run-generator.c index 11e7d9e83..1cf14e71f 100644 --- a/src/run-generator/run-generator.c +++ b/src/run-generator/run-generator.c @@ -39,16 +39,14 @@ static int parse(const char *key, const char *value, void *data) { if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_success_action, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_success_action, value); } else if (proc_cmdline_key_streq(key, "systemd.run_failure_action")) { if (proc_cmdline_value_missing(key, value)) return 0; - if (free_and_strdup(&arg_failure_action, value) < 0) - return log_oom(); + return free_and_strdup_warn(&arg_failure_action, value); } return 0; @@ -101,7 +99,7 @@ static int generate(void) { if (r < 0) return log_error_errno(r, "Failed to write unit file %s: %m", p); - /* Let's create a a target we can link "default.target" to */ + /* Let's create a target we can link "default.target" to */ p = strjoina(arg_dest, "/kernel-command-line.target"); r = write_string_file( p, diff --git a/src/run/run.c b/src/run/run.c index b4cc6fe7f..ac405d39d 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -21,6 +21,7 @@ #include "fd-util.h" #include "format-util.h" #include "main-func.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" @@ -131,11 +132,11 @@ static int help(void) { " --on-timezone-change Run when the timezone changes\n" " --on-clock-change Run when the realtime clock jumps\n" " --timer-property=NAME=VALUE Set timer unit property\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -470,7 +471,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_WORKING_DIRECTORY: - r = parse_path_argument_and_warn(optarg, true, &arg_working_directory); + r = parse_path_argument(optarg, true, &arg_working_directory); if (r < 0) return r; @@ -955,10 +956,12 @@ static int make_unit_name(sd_bus *bus, UnitType t, char **ret) { return 0; } - /* We managed to get the unique name, then let's use that to - * name our transient units. */ + /* We managed to get the unique name, then let's use that to name our transient units. */ - id = startswith(unique, ":1."); + id = startswith(unique, ":1."); /* let' strip the usual prefix */ + if (!id) + id = startswith(unique, ":"); /* the spec only requires things to start with a colon, hence + * let's add a generic fallback for that. */ if (!id) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unique name %s has unexpected format.", diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 837e8699e..03595c665 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -21,13 +21,13 @@ int fd_add_uid_acl_permission(int fd, uid_t uid, unsigned mask); /* acl_free takes multiple argument types. * Multiple cleanup functions are necessary. */ -DEFINE_TRIVIAL_CLEANUP_FUNC(acl_t, acl_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(acl_t, acl_free, NULL); #define acl_free_charp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC(char*, acl_free_charp); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(char*, acl_free_charp, NULL); #define acl_free_uid_tp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC(uid_t*, acl_free_uid_tp); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(uid_t*, acl_free_uid_tp, NULL); #define acl_free_gid_tp acl_free -DEFINE_TRIVIAL_CLEANUP_FUNC(gid_t*, acl_free_gid_tp); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(gid_t*, acl_free_gid_tp, NULL); #else #define ACL_READ 0x04 diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 112445379..cccea2f72 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -72,7 +72,7 @@ int acpi_get_boot_usec(usec_t *loader_start, usec_t *loader_exit) { struct acpi_fpdt_boot_header hbrec; struct acpi_fpdt_boot brec; - r = read_full_file("/sys/firmware/acpi/tables/FPDT", &buf, &l); + r = read_full_virtual_file("/sys/firmware/acpi/tables/FPDT", &buf, &l); if (r < 0) return r; diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index 8d66f9ffa..729aa1fb0 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -205,7 +204,7 @@ static int backspace_string(int ttyfd, const char *str) { return 0; size_t m = utf8_n_codepoints(str); - if (m == (size_t) -1) + if (m == SIZE_MAX) m = strlen(str); /* Not a valid UTF-8 string? If so, let's backspace the number of bytes * output. Most likely this happened because we are not in an UTF-8 locale, * and in that case that is the correct thing to do. And even if it's not, @@ -276,44 +275,28 @@ int ask_password_plymouth( pollfd[POLL_INOTIFY].events = POLLIN; for (;;) { - int sleep_for = -1, j; + usec_t timeout; - if (until > 0) { - usec_t y; - - y = now(CLOCK_MONOTONIC); - - if (y > until) { - r = -ETIME; - goto finish; - } - - sleep_for = (int) ((until - y) / USEC_PER_MSEC); - } + if (until > 0) + timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC)); + else + timeout = USEC_INFINITY; if (flag_file && access(flag_file, F_OK) < 0) { r = -errno; goto finish; } - j = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); - if (j < 0) { - if (errno == EINTR) - continue; - - r = -errno; + r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout); + if (r == -EINTR) + continue; + if (r < 0) goto finish; - } else if (j == 0) { + if (r == 0) { r = -ETIME; goto finish; } - if (pollfd[POLL_SOCKET].revents & POLLNVAL || - (notify >= 0 && pollfd[POLL_INOTIFY].revents & POLLNVAL)) { - r = -EBADF; - goto finish; - } - if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0) (void) flush_fd(notify); @@ -481,7 +464,7 @@ int ask_password_tty( if (!(flags & ASK_PASSWORD_SILENT) && !(flags & ASK_PASSWORD_ECHO)) { if (use_color) - (void) loop_write(ttyfd, ANSI_GREY, STRLEN(ANSI_GREY), false); + (void) loop_write(ttyfd, ansi_grey(), strlen(ansi_grey()), false); (void) loop_write(ttyfd, PRESS_TAB, strlen(PRESS_TAB), false); press_tab_visible = true; } @@ -513,21 +496,13 @@ int ask_password_tty( for (;;) { _cleanup_(erase_char) char c; - int sleep_for = -1, k; + usec_t timeout; ssize_t n; - if (until > 0) { - usec_t y; - - y = now(CLOCK_MONOTONIC); - - if (y > until) { - r = -ETIME; - goto finish; - } - - sleep_for = (int) DIV_ROUND_UP(until - y, USEC_PER_MSEC); - } + if (until > 0) + timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC)); + else + timeout = USEC_INFINITY; if (flag_file) if (access(flag_file, F_OK) < 0) { @@ -535,24 +510,16 @@ int ask_password_tty( goto finish; } - k = poll(pollfd, notify >= 0 ? 2 : 1, sleep_for); - if (k < 0) { - if (errno == EINTR) - continue; - - r = -errno; + r = ppoll_usec(pollfd, notify >= 0 ? 2 : 1, timeout); + if (r == -EINTR) + continue; + if (r < 0) goto finish; - } else if (k == 0) { + if (r == 0) { r = -ETIME; goto finish; } - if ((pollfd[POLL_TTY].revents & POLLNVAL) || - (notify >= 0 && (pollfd[POLL_INOTIFY].revents & POLLNVAL))) { - r = -EBADF; - goto finish; - } - if (notify >= 0 && pollfd[POLL_INOTIFY].revents != 0 && keyname) { (void) flush_fd(notify); @@ -614,11 +581,11 @@ int ask_password_tty( * last one begins */ q = 0; for (;;) { - size_t z; + int z; - z = utf8_encoded_valid_unichar(passphrase + q, (size_t) -1); - if (z == 0) { - q = (size_t) -1; /* Invalid UTF8! */ + z = utf8_encoded_valid_unichar(passphrase + q, SIZE_MAX); + if (z <= 0) { + q = SIZE_MAX; /* Invalid UTF8! */ break; } @@ -628,7 +595,7 @@ int ask_password_tty( q += z; } - p = codepoint = q == (size_t) -1 ? p - 1 : q; + p = codepoint = q == SIZE_MAX ? p - 1 : q; explicit_bzero_safe(passphrase + p, sizeof(passphrase) - p); } else if (!dirty && !(flags & ASK_PASSWORD_SILENT)) { @@ -665,7 +632,7 @@ int ask_password_tty( if (!(flags & ASK_PASSWORD_SILENT) && ttyfd >= 0) { /* Check if we got a complete UTF-8 character now. If so, let's output one '*'. */ - n = utf8_encoded_valid_unichar(passphrase + codepoint, (size_t) -1); + n = utf8_encoded_valid_unichar(passphrase + codepoint, SIZE_MAX); if (n >= 0) { if (flags & ASK_PASSWORD_ECHO) (void) loop_write(ttyfd, passphrase + codepoint, n, false); @@ -875,38 +842,24 @@ int ask_password_agent( char passphrase[LINE_MAX+1]; struct iovec iovec; struct ucred *ucred; + usec_t timeout; ssize_t n; - int k; - usec_t t; - t = now(CLOCK_MONOTONIC); + if (until > 0) + timeout = usec_sub_unsigned(until, now(CLOCK_MONOTONIC)); + else + timeout = USEC_INFINITY; - if (until > 0 && until <= t) { + r = ppoll_usec(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, timeout); + if (r == -EINTR) + continue; + if (r < 0) + goto finish; + if (r == 0) { r = -ETIME; goto finish; } - k = poll(pollfd, notify >= 0 ? _FD_MAX : _FD_MAX - 1, until > 0 ? (int) ((until-t)/USEC_PER_MSEC) : -1); - if (k < 0) { - if (errno == EINTR) - continue; - - r = -errno; - goto finish; - } - - if (k <= 0) { - r = -ETIME; - goto finish; - } - - if (pollfd[FD_SOCKET].revents & POLLNVAL || - pollfd[FD_SIGNAL].revents & POLLNVAL || - (notify >= 0 && pollfd[FD_INOTIFY].revents & POLLNVAL)) { - r = -EBADF; - goto finish; - } - if (pollfd[FD_SIGNAL].revents & POLLIN) { r = -EINTR; goto finish; diff --git a/src/shared/barrier.c b/src/shared/barrier.c index 9c93d61a3..2864c1b8f 100644 --- a/src/shared/barrier.c +++ b/src/shared/barrier.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -12,6 +11,7 @@ #include "barrier.h" #include "fd-util.h" +#include "io-util.h" #include "macro.h" /** @@ -123,14 +123,15 @@ int barrier_create(Barrier *b) { * * If @b is NULL, this is a no-op. */ -void barrier_destroy(Barrier *b) { +Barrier* barrier_destroy(Barrier *b) { if (!b) - return; + return NULL; b->me = safe_close(b->me); b->them = safe_close(b->them); safe_close_pair(b->pipe); b->barriers = 0; + return NULL; } /** @@ -218,14 +219,10 @@ static bool barrier_read(Barrier *b, int64_t comp) { uint64_t buf; int r; - r = poll(pfd, ELEMENTSOF(pfd), -1); - if (r < 0) { - if (IN_SET(errno, EAGAIN, EINTR)) - continue; - goto error; - } - if (pfd[0].revents & POLLNVAL || - pfd[1].revents & POLLNVAL) + r = ppoll_usec(pfd, ELEMENTSOF(pfd), USEC_INFINITY); + if (r == -EINTR) + continue; + if (r < 0) goto error; if (pfd[1].revents) { diff --git a/src/shared/barrier.h b/src/shared/barrier.h index b11dce4fc..b9fc92d75 100644 --- a/src/shared/barrier.h +++ b/src/shared/barrier.h @@ -37,7 +37,7 @@ struct Barrier { #define BARRIER_NULL {-1, -1, {-1, -1}, 0} int barrier_create(Barrier *obj); -void barrier_destroy(Barrier *b); +Barrier* barrier_destroy(Barrier *b); DEFINE_TRIVIAL_CLEANUP_FUNC(Barrier*, barrier_destroy); diff --git a/src/shared/bitmap.c b/src/shared/bitmap.c index 5d450c883..dcf67fbbd 100644 --- a/src/shared/bitmap.c +++ b/src/shared/bitmap.c @@ -18,17 +18,17 @@ #define BITMAPS_MAX_ENTRY 0xffff /* This indicates that we reached the end of the bitmap */ -#define BITMAP_END ((unsigned) -1) +#define BITMAP_END (UINT_MAX) #define BITMAP_NUM_TO_OFFSET(n) ((n) / (sizeof(uint64_t) * 8)) #define BITMAP_NUM_TO_REM(n) ((n) % (sizeof(uint64_t) * 8)) #define BITMAP_OFFSET_TO_NUM(offset, rem) ((offset) * sizeof(uint64_t) * 8 + (rem)) -Bitmap *bitmap_new(void) { +Bitmap* bitmap_new(void) { return new0(Bitmap, 1); } -Bitmap *bitmap_copy(Bitmap *b) { +Bitmap* bitmap_copy(Bitmap *b) { Bitmap *ret; ret = bitmap_new(); @@ -43,12 +43,12 @@ Bitmap *bitmap_copy(Bitmap *b) { return ret; } -void bitmap_free(Bitmap *b) { +Bitmap* bitmap_free(Bitmap *b) { if (!b) - return; + return NULL; free(b->bitmaps); - free(b); + return mfree(b); } int bitmap_ensure_allocated(Bitmap **b) { diff --git a/src/shared/bitmap.h b/src/shared/bitmap.h index 1c305a2c4..5c7651c68 100644 --- a/src/shared/bitmap.h +++ b/src/shared/bitmap.h @@ -12,10 +12,10 @@ typedef struct Bitmap { size_t bitmaps_allocated; } Bitmap; -Bitmap *bitmap_new(void); -Bitmap *bitmap_copy(Bitmap *b); +Bitmap* bitmap_new(void); +Bitmap* bitmap_copy(Bitmap *b); int bitmap_ensure_allocated(Bitmap **b); -void bitmap_free(Bitmap *b); +Bitmap* bitmap_free(Bitmap *b); int bitmap_set(Bitmap *b, unsigned n); void bitmap_unset(Bitmap *b, unsigned n); diff --git a/src/shared/blkid-util.h b/src/shared/blkid-util.h index 3f38e9b30..aa444990f 100644 --- a/src/shared/blkid-util.h +++ b/src/shared/blkid-util.h @@ -6,5 +6,5 @@ # include "macro.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(blkid_probe, blkid_free_probe); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(blkid_probe, blkid_free_probe, NULL); #endif diff --git a/src/shared/bond-util.h b/src/shared/bond-util.h index a8f9ecb45..9e693b16a 100644 --- a/src/shared/bond-util.h +++ b/src/shared/bond-util.h @@ -21,7 +21,7 @@ typedef enum BondMode { NETDEV_BOND_MODE_BALANCE_TLB = BOND_MODE_TLB, NETDEV_BOND_MODE_BALANCE_ALB = BOND_MODE_ALB, _NETDEV_BOND_MODE_MAX, - _NETDEV_BOND_MODE_INVALID = -1 + _NETDEV_BOND_MODE_INVALID = -EINVAL, } BondMode; typedef enum BondXmitHashPolicy { @@ -31,14 +31,14 @@ typedef enum BondXmitHashPolicy { NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23 = BOND_XMIT_POLICY_ENCAP23, NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34 = BOND_XMIT_POLICY_ENCAP34, _NETDEV_BOND_XMIT_HASH_POLICY_MAX, - _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1 + _NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -EINVAL, } BondXmitHashPolicy; typedef enum BondLacpRate { NETDEV_BOND_LACP_RATE_SLOW, NETDEV_BOND_LACP_RATE_FAST, _NETDEV_BOND_LACP_RATE_MAX, - _NETDEV_BOND_LACP_RATE_INVALID = -1, + _NETDEV_BOND_LACP_RATE_INVALID = -EINVAL, } BondLacpRate; typedef enum BondAdSelect { @@ -46,7 +46,7 @@ typedef enum BondAdSelect { NETDEV_BOND_AD_SELECT_BANDWIDTH, NETDEV_BOND_AD_SELECT_COUNT, _NETDEV_BOND_AD_SELECT_MAX, - _NETDEV_BOND_AD_SELECT_INVALID = -1, + _NETDEV_BOND_AD_SELECT_INVALID = -EINVAL, } BondAdSelect; typedef enum BondFailOverMac { @@ -54,7 +54,7 @@ typedef enum BondFailOverMac { NETDEV_BOND_FAIL_OVER_MAC_ACTIVE, NETDEV_BOND_FAIL_OVER_MAC_FOLLOW, _NETDEV_BOND_FAIL_OVER_MAC_MAX, - _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -1, + _NETDEV_BOND_FAIL_OVER_MAC_INVALID = -EINVAL, } BondFailOverMac; typedef enum BondArpValidate { @@ -63,14 +63,14 @@ typedef enum BondArpValidate { NETDEV_BOND_ARP_VALIDATE_BACKUP, NETDEV_BOND_ARP_VALIDATE_ALL, _NETDEV_BOND_ARP_VALIDATE_MAX, - _NETDEV_BOND_ARP_VALIDATE_INVALID = -1, + _NETDEV_BOND_ARP_VALIDATE_INVALID = -EINVAL, } BondArpValidate; typedef enum BondArpAllTargets { NETDEV_BOND_ARP_ALL_TARGETS_ANY, NETDEV_BOND_ARP_ALL_TARGETS_ALL, _NETDEV_BOND_ARP_ALL_TARGETS_MAX, - _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -1, + _NETDEV_BOND_ARP_ALL_TARGETS_INVALID = -EINVAL, } BondArpAllTargets; typedef enum BondPrimaryReselect { @@ -78,7 +78,7 @@ typedef enum BondPrimaryReselect { NETDEV_BOND_PRIMARY_RESELECT_BETTER, NETDEV_BOND_PRIMARY_RESELECT_FAILURE, _NETDEV_BOND_PRIMARY_RESELECT_MAX, - _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1, + _NETDEV_BOND_PRIMARY_RESELECT_INVALID = -EINVAL, } BondPrimaryReselect; const char *bond_mode_to_string(BondMode d) _const_; diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c index e50408ab5..17c28c6e0 100644 --- a/src/shared/bootspec.c +++ b/src/shared/bootspec.c @@ -244,7 +244,7 @@ static int boot_loader_read_conf(const char *path, BootConfig *config) { } static int boot_entry_compare(const BootEntry *a, const BootEntry *b) { - return str_verscmp(a->id, b->id); + return strverscmp_improved(a->id, b->id); } static int boot_entries_find( @@ -1033,6 +1033,16 @@ static int verify_fsroot_dir( SYNTHETIC_ERRNO(searching ? EADDRNOTAVAIL : ENODEV), "Block device node of \"%s\" is invalid.", path); + if (path_equal(path, "/")) { + /* Let's assume that the root directory of the OS is always the root of its file system + * (which technically doesn't have to be the case, but it's close enough, and it's not easy + * to be fully correct for it, since we can't look further up than the root dir easily.) */ + if (ret_dev) + *ret_dev = st.st_dev; + + return 0; + } + t2 = strjoina(path, "/.."); if (stat(t2, &st2) < 0) { if (errno != EACCES) @@ -1048,10 +1058,7 @@ static int verify_fsroot_dir( if (!parent) return log_oom(); - if (stat(parent, &st2) < 0) - r = -errno; - else - r = 0; + r = stat(parent, &st2) < 0 ? -errno : 0; } if (r < 0) diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h index 1557bd068..c7b4a2ee0 100644 --- a/src/shared/bootspec.h +++ b/src/shared/bootspec.h @@ -15,7 +15,7 @@ typedef enum BootEntryType { BOOT_ENTRY_UNIFIED, /* Type #2 entries: *.efi files */ BOOT_ENTRY_LOADER, /* Additional entries augmented from LoaderEntries EFI var */ _BOOT_ENTRY_MAX, - _BOOT_ENTRY_INVALID = -1, + _BOOT_ENTRY_INVALID = -EINVAL, } BootEntryType; typedef struct BootEntry { diff --git a/src/shared/bridge-util.h b/src/shared/bridge-util.h index c9b02d822..a60891c8f 100644 --- a/src/shared/bridge-util.h +++ b/src/shared/bridge-util.h @@ -13,7 +13,7 @@ typedef enum BridgeState { NETDEV_BRIDGE_STATE_FORWARDING = BR_STATE_FORWARDING, NETDEV_BRIDGE_STATE_BLOCKING = BR_STATE_BLOCKING, _NETDEV_BRIDGE_STATE_MAX, - _NETDEV_BRIDGE_STATE_INVALID = -1, + _NETDEV_BRIDGE_STATE_INVALID = -EINVAL, } BridgeState; const char *bridge_state_to_string(BridgeState d) _const_; diff --git a/src/shared/bus-get-properties.c b/src/shared/bus-get-properties.c index 32f68d5e6..feb6d3807 100644 --- a/src/shared/bus-get-properties.c +++ b/src/shared/bus-get-properties.c @@ -55,23 +55,6 @@ int bus_property_get_id128( return sd_bus_message_append_array(reply, 'y', id->bytes, 16); } -int bus_property_get_percent( - sd_bus *bus, - const char *path, - const char *interface, - const char *property, - sd_bus_message *reply, - void *userdata, - sd_bus_error *error) { - - char pstr[DECIMAL_STR_MAX(int) + 2]; - int p = *(int*) userdata; - - xsprintf(pstr, "%d%%", p); - - return sd_bus_message_append_basic(reply, 's', pstr); -} - #if __SIZEOF_SIZE_T__ != 8 int bus_property_get_size( sd_bus *bus, @@ -159,9 +142,9 @@ int bus_property_get_rlimit( x = is_soft ? buf.rlim_cur : buf.rlim_max; } - /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on all + /* rlim_t might have different sizes, let's map RLIMIT_INFINITY to UINT64_MAX, so that it is the same on all * archs */ - u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x; + u = x == RLIM_INFINITY ? UINT64_MAX : (uint64_t) x; return sd_bus_message_append(reply, "t", u); } diff --git a/src/shared/bus-get-properties.h b/src/shared/bus-get-properties.h index 9832c0d06..26f3e8588 100644 --- a/src/shared/bus-get-properties.h +++ b/src/shared/bus-get-properties.h @@ -8,7 +8,6 @@ int bus_property_get_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); int bus_property_set_bool(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error); int bus_property_get_id128(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); -int bus_property_get_percent(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error); #define bus_property_get_usec ((sd_bus_property_get_t) NULL) #define bus_property_set_usec ((sd_bus_property_set_t) NULL) diff --git a/src/shared/bus-print-properties.c b/src/shared/bus-print-properties.c index 4cea25073..2a712be73 100644 --- a/src/shared/bus-print-properties.c +++ b/src/shared/bus-print-properties.c @@ -180,18 +180,18 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b } else if ((STR_IN_SET(name, "CPUWeight", "StartupCPUWeight", "IOWeight", "StartupIOWeight") && u == CGROUP_WEIGHT_INVALID) || (STR_IN_SET(name, "CPUShares", "StartupCPUShares") && u == CGROUP_CPU_SHARES_INVALID) || (STR_IN_SET(name, "BlockIOWeight", "StartupBlockIOWeight") && u == CGROUP_BLKIO_WEIGHT_INVALID) || - (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == (uint64_t) -1) || - (endswith(name, "NSec") && u == (uint64_t) -1)) + (STR_IN_SET(name, "MemoryCurrent", "TasksCurrent") && u == UINT64_MAX) || + (endswith(name, "NSec") && u == UINT64_MAX)) bus_print_property_value(name, expected_value, value, "[not set]"); else if ((STR_IN_SET(name, "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) || - (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) || - (startswith(name, "Limit") && u == (uint64_t) -1) || - (startswith(name, "DefaultLimit") && u == (uint64_t) -1)) + (STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == UINT64_MAX) || + (startswith(name, "Limit") && u == UINT64_MAX) || + (startswith(name, "DefaultLimit") && u == UINT64_MAX)) bus_print_property_value(name, expected_value, value, "infinity"); - else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == (uint64_t) -1) + else if (STR_IN_SET(name, "IPIngressBytes", "IPIngressPackets", "IPEgressBytes", "IPEgressPackets") && u == UINT64_MAX) bus_print_property_value(name, expected_value, value, "[no data]"); else bus_print_property_valuef(name, expected_value, value, "%"PRIu64, u); diff --git a/src/shared/bus-unit-procs.c b/src/shared/bus-unit-procs.c index 3e97be967..b76125e55 100644 --- a/src/shared/bus-unit-procs.c +++ b/src/shared/bus-unit-procs.c @@ -104,11 +104,7 @@ static int add_process( if (r < 0) return r; - r = hashmap_ensure_allocated(&cg->pids, &trivial_hash_ops); - if (r < 0) - return r; - - return hashmap_put(cg->pids, PID_TO_PTR(pid), (void*) name); + return hashmap_ensure_put(&cg->pids, &trivial_hash_ops, PID_TO_PTR(pid), (void*) name); } static void remove_cgroup(Hashmap *cgroups, struct CGroupInfo *cg) { diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c index 2bab2299f..a75178068 100644 --- a/src/shared/bus-unit-util.c +++ b/src/shared/bus-unit-util.c @@ -28,6 +28,7 @@ #include "numa-util.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "process-util.h" #include "rlimit-util.h" #if HAVE_SECCOMP @@ -436,9 +437,22 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons "Slice", "ManagedOOMSwap", "ManagedOOMMemoryPressure", - "ManagedOOMMemoryPressureLimitPercent")) + "ManagedOOMPreference")) return bus_append_string(m, field, eq); + if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) { + r = parse_permyriad(eq); + if (r < 0) + return log_error_errno(r, "Failed to parse %s value: %s", field, eq); + + /* Pass around scaled to 2^32-1 == 100% */ + r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + if (STR_IN_SET(field, "CPUAccounting", "MemoryAccounting", "IOAccounting", @@ -523,7 +537,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons return 1; } - r = parse_permille(eq); + r = parse_permyriad(eq); if (r >= 0) { char *n; @@ -532,7 +546,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons * size can be determined server-side. */ n = strjoina(field, "Scale"); - r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U)); + r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r)); if (r < 0) return bus_log_create_error(r); @@ -549,14 +563,14 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons if (isempty(eq)) r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY); else { - r = parse_permille_unbounded(eq); + r = parse_permyriad_unbounded(eq); if (r == 0) return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small."); if (r < 0) return log_error_errno(r, "CPU quota '%s' invalid.", eq); - r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U)); + r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U)); } if (r < 0) @@ -868,6 +882,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "ProtectProc", "ProcSubset", "NetworkNamespacePath", + "IPCNamespacePath", "LogNamespace")) return bus_append_string(m, field, eq); @@ -880,6 +895,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "PrivateNetwork", "PrivateUsers", "PrivateMounts", + "PrivateIPC", "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", @@ -904,6 +920,8 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths", + "ExecPaths", + "NoExecPaths", "RuntimeDirectory", "StateDirectory", "CacheDirectory", @@ -1144,6 +1162,9 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con } else if ((n = startswith(eq, "append:"))) { appended = strjoina(field, "FileToAppend"); r = sd_bus_message_append(m, "(sv)", appended, "s", n); + } else if ((n = startswith(eq, "truncate:"))) { + appended = strjoina(field, "FileToTruncate"); + r = sd_bus_message_append(m, "(sv)", appended, "s", n); } else r = sd_bus_message_append(m, "(sv)", field, "s", eq); if (r < 0) @@ -1159,7 +1180,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con if (r < 0) return log_error_errno(r, "Failed to unescape text '%s': %m", eq); - if (!strextend(&unescaped, "\n", NULL)) + if (!strextend(&unescaped, "\n")) return log_oom(); /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic @@ -1172,7 +1193,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con _cleanup_free_ void *decoded = NULL; size_t sz; - r = unbase64mem(eq, (size_t) -1, &decoded, &sz); + r = unbase64mem(eq, SIZE_MAX, &decoded, &sz); if (r < 0) return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq); @@ -1612,10 +1633,6 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con return log_error_errno(r, "Failed to parse argument: %m"); STRV_FOREACH_PAIR(first, second, l) { - /* Format is either 'root:foo' or 'foo' (root is implied) */ - if (!isempty(*second) && partition_designator_from_string(*first) < 0) - return bus_log_create_error(-EINVAL); - r = sd_bus_message_append(m, "(ss)", !isempty(*second) ? *first : "root", !isempty(*second) ? *second : *first); @@ -1664,14 +1681,14 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); if (r < 0) - return r; + return log_error_errno(r, "Failed to parse MountImages= property: %s", eq); if (r == 0) break; q = tuple; r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL); if (r < 0) - return r; + return log_error_errno(r, "Failed to parse MountImages= property: %s", eq); if (r == 0) continue; @@ -1703,7 +1720,7 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL); if (r < 0) - return r; + return log_error_errno(r, "Failed to parse MountImages= property: %s", eq); if (r == 0) break; /* Single set of options, applying to the root partition/single filesystem */ @@ -1715,8 +1732,106 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con break; } - if (partition_designator_from_string(partition) < 0) - return bus_log_create_error(-EINVAL); + r = sd_bus_message_append(m, "(ss)", partition, mount_options); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + return 1; + } + + if (streq(field, "ExtensionImages")) { + const char *p = eq; + + r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'v', "a(sba(ss))"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(sba(ss))"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *source = NULL, *tuple = NULL; + const char *q = NULL, *s = NULL; + bool permissive = false; + + r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r < 0) + return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq); + if (r == 0) + break; + + q = tuple; + r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq); + if (r == 0) + continue; + + s = source; + if (s[0] == '-') { + permissive = true; + s++; + } + + r = sd_bus_message_open_container(m, 'r', "sba(ss)"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append(m, "sb", s, permissive); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + if (r < 0) + return bus_log_create_error(r); + + for (;;) { + _cleanup_free_ char *partition = NULL, *mount_options = NULL; + + r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL); + if (r < 0) + return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq); + if (r == 0) + break; + /* Single set of options, applying to the root partition/single filesystem */ + if (r == 1) { + r = sd_bus_message_append(m, "(ss)", "root", partition); + if (r < 0) + return bus_log_create_error(r); + + break; + } r = sd_bus_message_append(m, "(ss)", partition, mount_options); if (r < 0) @@ -2171,7 +2286,8 @@ static int bus_append_unit_property(sd_bus_message *m, const char *field, const if (unit_dependency_from_string(field) >= 0 || STR_IN_SET(field, "Documentation", - "RequiresMountsFor")) + "RequiresMountsFor", + "Markers")) return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE); t = condition_type_from_string(field); @@ -2366,10 +2482,10 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) { /* We expect only "success" changes to be sent over the bus. Hence, reject anything negative. */ - UnitFileChangeType ch = unit_file_change_type_from_string(type); - + int ch = unit_file_change_type_from_string(type); if (ch < 0) { - log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path); + log_notice_errno(ch, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", + type, path); continue; } diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index fbda218b3..64ca67993 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -101,7 +101,7 @@ int bus_event_loop_with_idle( else idle = true; - r = sd_event_run(e, exiting || !idle ? (uint64_t) -1 : timeout); + r = sd_event_run(e, exiting || !idle ? UINT64_MAX : timeout); if (r < 0) return r; @@ -249,7 +249,12 @@ int bus_connect_user_systemd(sd_bus **_bus) { return 0; } -int bus_connect_transport(BusTransport transport, const char *host, bool user, sd_bus **ret) { +int bus_connect_transport( + BusTransport transport, + const char *host, + bool user, + sd_bus **ret) { + _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL; int r; @@ -258,7 +263,7 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s assert(ret); assert_return((transport == BUS_TRANSPORT_LOCAL) == !host, -EINVAL); - assert_return(transport == BUS_TRANSPORT_LOCAL || !user, -EOPNOTSUPP); + assert_return(transport != BUS_TRANSPORT_REMOTE || !user, -EOPNOTSUPP); switch (transport) { @@ -279,7 +284,10 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s break; case BUS_TRANSPORT_MACHINE: - r = sd_bus_open_system_machine(&bus, host); + if (user) + r = sd_bus_open_user_machine(&bus, host); + else + r = sd_bus_open_system_machine(&bus, host); break; default: @@ -293,7 +301,6 @@ int bus_connect_transport(BusTransport transport, const char *host, bool user, s return r; *ret = TAKE_PTR(bus); - return 0; } diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index 27dd6c19c..e0d4d5d91 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -19,7 +19,7 @@ typedef enum BusTransport { BUS_TRANSPORT_REMOTE, BUS_TRANSPORT_MACHINE, _BUS_TRANSPORT_MAX, - _BUS_TRANSPORT_INVALID = -1 + _BUS_TRANSPORT_INVALID = -EINVAL, } BusTransport; int bus_async_unregister_and_exit(sd_event *e, sd_bus *bus, const char *name); diff --git a/src/shared/bus-wait-for-jobs.c b/src/shared/bus-wait-for-jobs.c index b2a9e031c..51b71ecc2 100644 --- a/src/shared/bus-wait-for-jobs.c +++ b/src/shared/bus-wait-for-jobs.c @@ -61,9 +61,9 @@ static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *er return 0; } -void bus_wait_for_jobs_free(BusWaitForJobs *d) { +BusWaitForJobs* bus_wait_for_jobs_free(BusWaitForJobs *d) { if (!d) - return; + return NULL; set_free(d->jobs); @@ -75,7 +75,7 @@ void bus_wait_for_jobs_free(BusWaitForJobs *d) { free(d->name); free(d->result); - free(d); + return mfree(d); } int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret) { @@ -133,7 +133,7 @@ static int bus_process_wait(sd_bus *bus) { if (r > 0) return 0; - r = sd_bus_wait(bus, (uint64_t) -1); + r = sd_bus_wait(bus, UINT64_MAX); if (r < 0) return r; } @@ -200,22 +200,24 @@ static void log_job_error_with_service_result(const char* service, const char *r if (i < ELEMENTSOF(explanations)) { log_error("Job for %s failed because %s.\n" - "See \"%s status %s\" and \"%s -xe\" for details.\n", + "See \"%s status %s\" and \"%s -xeu %s\" for details.\n", service, explanations[i].explanation, systemctl, service_shell_quoted ?: "", - journalctl); + journalctl, + service_shell_quoted ?: ""); goto finish; } } log_error("Job for %s failed.\n" - "See \"%s status %s\" and \"%s -xe\" for details.\n", + "See \"%s status %s\" and \"%s -xeu %s\" for details.\n", service, systemctl, service_shell_quoted ?: "", - journalctl); + journalctl, + service_shell_quoted ?: ""); finish: /* For some results maybe additional explanation is required */ diff --git a/src/shared/bus-wait-for-jobs.h b/src/shared/bus-wait-for-jobs.h index 015588745..68c9d604a 100644 --- a/src/shared/bus-wait-for-jobs.h +++ b/src/shared/bus-wait-for-jobs.h @@ -8,7 +8,7 @@ typedef struct BusWaitForJobs BusWaitForJobs; int bus_wait_for_jobs_new(sd_bus *bus, BusWaitForJobs **ret); -void bus_wait_for_jobs_free(BusWaitForJobs *d); +BusWaitForJobs* bus_wait_for_jobs_free(BusWaitForJobs *d); int bus_wait_for_jobs_add(BusWaitForJobs *d, const char *path); int bus_wait_for_jobs(BusWaitForJobs *d, bool quiet, const char* const* extra_args); int bus_wait_for_jobs_one(BusWaitForJobs *d, const char *path, bool quiet); diff --git a/src/shared/bus-wait-for-units.c b/src/shared/bus-wait-for-units.c index 4f1c505bd..29620e0d1 100644 --- a/src/shared/bus-wait-for-units.c +++ b/src/shared/bus-wait-for-units.c @@ -414,7 +414,7 @@ int bus_wait_for_units_run(BusWaitForUnits *d) { if (r > 0) continue; - r = sd_bus_wait(d->bus, (uint64_t) -1); + r = sd_bus_wait(d->bus, UINT64_MAX); if (r < 0) return r; } diff --git a/src/shared/bus-wait-for-units.h b/src/shared/bus-wait-for-units.h index f7ab666f1..2623e72ce 100644 --- a/src/shared/bus-wait-for-units.h +++ b/src/shared/bus-wait-for-units.h @@ -11,7 +11,7 @@ typedef enum BusWaitForUnitsState { BUS_WAIT_FAILURE, /* dito, but something failed */ BUS_WAIT_RUNNING, /* Still something to wait for */ _BUS_WAIT_FOR_UNITS_STATE_MAX, - _BUS_WAIT_FOR_UNITS_STATE_INVALID = -1, + _BUS_WAIT_FOR_UNITS_STATE_INVALID = -EINVAL, } BusWaitForUnitsState; typedef enum BusWaitForUnitsFlags { diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 7162592fb..bf24d8d5b 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -27,20 +27,19 @@ /* An arbitrary limit on the length of the chains of components. We don't want to * build a very long linked list, which would be slow to iterate over and might cause * our stack to overflow. It's unlikely that legitimate uses require more than a few - * linked compenents anyway. */ + * linked components anyway. */ #define CALENDARSPEC_COMPONENTS_MAX 240 /* Let's make sure that the microsecond component is safe to be stored in an 'int' */ assert_cc(INT_MAX >= USEC_PER_SEC); -static void chain_free(CalendarComponent *c) { - CalendarComponent *n; - +static CalendarComponent* chain_free(CalendarComponent *c) { while (c) { - n = c->next; + CalendarComponent *n = c->next; free(c); c = n; } + return NULL; } DEFINE_TRIVIAL_CLEANUP_FUNC(CalendarComponent*, chain_free); @@ -1102,7 +1101,7 @@ int calendar_spec_from_string(const char *p, CalendarSpec **spec) { return 0; } -static int find_end_of_month(struct tm *tm, bool utc, int day) { +static int find_end_of_month(const struct tm *tm, bool utc, int day) { struct tm t = *tm; t.tm_mon++; @@ -1115,28 +1114,39 @@ static int find_end_of_month(struct tm *tm, bool utc, int day) { return t.tm_mday; } -static int find_matching_component(const CalendarSpec *spec, const CalendarComponent *c, - struct tm *tm, int *val) { - const CalendarComponent *p = c; - int start, stop, d = -1; +static int find_matching_component( + const CalendarSpec *spec, + const CalendarComponent *c, + const struct tm *tm, /* tm is only used for end-of-month calculations */ + int *val) { + + int d = -1, r; bool d_set = false; - int r; assert(val); + /* Finds the *earliest* matching time specified by one of the CalendarCompoment items in chain c. + * If no matches can be found, returns -ENOENT. + * Otherwise, updates *val to the matching time. 1 is returned if *val was changed, 0 otherwise. + */ + if (!c) return 0; - while (c) { - start = c->start; - stop = c->stop; + bool end_of_month = spec->end_of_month && c == spec->day; - if (spec->end_of_month && p == spec->day) { - start = find_end_of_month(tm, spec->utc, start); - stop = find_end_of_month(tm, spec->utc, stop); + while (c) { + int start, stop; + + if (end_of_month) { + start = find_end_of_month(tm, spec->utc, c->start); + stop = find_end_of_month(tm, spec->utc, c->stop); if (stop > 0) SWAP_TWO(start, stop); + } else { + start = c->start; + stop = c->stop; } if (start >= *val) { @@ -1185,15 +1195,18 @@ static int tm_within_bounds(struct tm *tm, bool utc) { return negative_errno(); /* Did any normalization take place? If so, it was out of bounds before */ - bool good = t.tm_year == tm->tm_year && - t.tm_mon == tm->tm_mon && - t.tm_mday == tm->tm_mday && - t.tm_hour == tm->tm_hour && - t.tm_min == tm->tm_min && - t.tm_sec == tm->tm_sec; - if (!good) + int cmp = CMP(t.tm_year, tm->tm_year) ?: + CMP(t.tm_mon, tm->tm_mon) ?: + CMP(t.tm_mday, tm->tm_mday) ?: + CMP(t.tm_hour, tm->tm_hour) ?: + CMP(t.tm_min, tm->tm_min) ?: + CMP(t.tm_sec, tm->tm_sec); + + if (cmp < 0) + return -EDEADLK; /* Refuse to go backward */ + if (cmp > 0) *tm = t; - return good; + return cmp == 0; } static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { @@ -1211,6 +1224,10 @@ static bool matches_weekday(int weekdays_bits, const struct tm *tm, bool utc) { return (weekdays_bits & (1 << k)); } +/* A safety valve: if we get stuck in the calculation, return an error. + * C.f. https://bugzilla.redhat.com/show_bug.cgi?id=1941335. */ +#define MAX_CALENDAR_ITERATIONS 1000 + static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { struct tm c; int tm_usec; @@ -1224,7 +1241,7 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { c = *tm; tm_usec = *usec; - for (;;) { + for (unsigned iteration = 0; iteration < MAX_CALENDAR_ITERATIONS; iteration++) { /* Normalize the current date */ (void) mktime_or_timegm(&c, spec->utc); c.tm_isdst = spec->dst; @@ -1321,6 +1338,14 @@ static int find_next(const CalendarSpec *spec, struct tm *tm, usec_t *usec) { *usec = tm_usec; return 0; } + + /* It seems we entered an infinite loop. Let's gracefully return an error instead of hanging or + * aborting. This code is also exercised when timers.target is brought up during early boot, so + * aborting here is problematic and hard to diagnose for users. */ + _cleanup_free_ char *s = NULL; + (void) calendar_spec_to_string(spec, &s); + return log_warning_errno(SYNTHETIC_ERRNO(EDEADLK), + "Infinite loop in calendar calculation: %s", strna(s)); } static int calendar_spec_next_usec_impl(const CalendarSpec *spec, usec_t usec, usec_t *ret_next) { diff --git a/src/shared/clock-util.c b/src/shared/clock-util.c index 2caa70fa5..ec67b054b 100644 --- a/src/shared/clock-util.c +++ b/src/shared/clock-util.c @@ -96,8 +96,7 @@ int clock_is_localtime(const char* adjtime_path) { return false; } -int clock_set_timezone(int *min) { - const struct timeval *tv_null = NULL; +int clock_set_timezone(int *ret_minutesdelta) { struct timespec ts; struct tm tm; int minutesdelta; @@ -107,36 +106,32 @@ int clock_set_timezone(int *min) { assert_se(localtime_r(&ts.tv_sec, &tm)); minutesdelta = tm.tm_gmtoff / 60; - tz.tz_minuteswest = -minutesdelta; - tz.tz_dsttime = 0; /* DST_NONE */ + tz = (struct timezone) { + .tz_minuteswest = -minutesdelta, + .tz_dsttime = 0, /* DST_NONE */ + }; - /* - * If the RTC does not run in UTC but in local time, the very first - * call to settimeofday() will set the kernel's timezone and will warp the - * system clock, so that it runs in UTC instead of the local time we - * have read from the RTC. - */ - if (settimeofday(tv_null, &tz) < 0) - return negative_errno(); + /* If the RTC does not run in UTC but in local time, the very first call to settimeofday() will set + * the kernel's timezone and will warp the system clock, so that it runs in UTC instead of the local + * time we have read from the RTC. */ + if (settimeofday(NULL, &tz) < 0) + return -errno; + + if (ret_minutesdelta) + *ret_minutesdelta = minutesdelta; - if (min) - *min = minutesdelta; return 0; } int clock_reset_timewarp(void) { - const struct timeval *tv_null = NULL; - struct timezone tz; + static const struct timezone tz = { + .tz_minuteswest = 0, + .tz_dsttime = 0, /* DST_NONE */ + }; - tz.tz_minuteswest = 0; - tz.tz_dsttime = 0; /* DST_NONE */ - - /* - * The very first call to settimeofday() does time warp magic. Do a - * dummy call here, so the time warping is sealed and all later calls - * behave as expected. - */ - if (settimeofday(tv_null, &tz) < 0) + /* The very first call to settimeofday() does time warp magic. Do a dummy call here, so the time + * warping is sealed and all later calls behave as expected. */ + if (settimeofday(NULL, &tz) < 0) return -errno; return 0; diff --git a/src/shared/clock-util.h b/src/shared/clock-util.h index 3f1ae7abf..9e96d50d9 100644 --- a/src/shared/clock-util.h +++ b/src/shared/clock-util.h @@ -4,7 +4,7 @@ #include int clock_is_localtime(const char* adjtime_path); -int clock_set_timezone(int *min); +int clock_set_timezone(int *ret_minutesdelta); int clock_reset_timewarp(void); int clock_get_hwclock(struct tm *tm); int clock_set_hwclock(const struct tm *tm); diff --git a/src/shared/condition.c b/src/shared/condition.c index b2ec690bc..d84377c26 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -146,7 +146,7 @@ typedef enum { ORDER_EQUAL, ORDER_UNEQUAL, _ORDER_MAX, - _ORDER_INVALID = -1 + _ORDER_INVALID = -EINVAL, } OrderOperator; static OrderOperator parse_order(const char **s) { @@ -247,7 +247,7 @@ static int condition_test_kernel_version(Condition *c, char **env) { return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unexpected end of expression: %s", p); } - r = test_order(str_verscmp(u.release, s), order); + r = test_order(strverscmp_improved(u.release, s), order); } else /* No prefix? Then treat as glob string */ r = fnmatch(s, u.release, 0) == 0; @@ -354,6 +354,15 @@ static int condition_test_control_group_controller(Condition *c, char **env) { assert(c->parameter); assert(c->type == CONDITION_CONTROL_GROUP_CONTROLLER); + if (streq(c->parameter, "v2")) + return cg_all_unified(); + if (streq(c->parameter, "v1")) { + r = cg_all_unified(); + if (r < 0) + return r; + return !r; + } + r = cg_mask_supported(&system_mask); if (r < 0) return log_debug_errno(r, "Failed to determine supported controllers: %m"); @@ -480,6 +489,32 @@ static int condition_test_ac_power(Condition *c, char **env) { return (on_ac_power() != 0) == !!r; } +static int has_tpm2(void) { + int r; + + /* Checks whether the system has at least one TPM2 resource manager device, i.e. at least one "tpmrm" + * class device */ + + r = dir_is_empty("/sys/class/tpmrm"); + if (r == 0) + return true; /* nice! we have a device */ + + /* Hmm, so Linux doesn't know of the TPM2 device (or we couldn't check for it), most likely because + * the driver wasn't loaded yet. Let's see if the firmware knows about a TPM2 device, in this + * case. This way we can answer the TPM2 question already during early boot (where we most likely + * need it) */ + if (efi_has_tpm2()) + return true; + + /* OK, this didn't work either, in this case propagate the original errors */ + if (r == -ENOENT) + return false; + if (r < 0) + return log_debug_errno(r, "Failed to determine whether system has TPM2 support: %m"); + + return !r; +} + static int condition_test_security(Condition *c, char **env) { assert(c); assert(c->parameter); @@ -499,6 +534,8 @@ static int condition_test_security(Condition *c, char **env) { return mac_tomoyo_use(); if (streq(c->parameter, "uefi-secureboot")) return is_efi_secure_boot(); + if (streq(c->parameter, "tpm2")) + return has_tpm2(); return false; } @@ -728,6 +765,14 @@ static int condition_test_path_is_read_write(Condition *c, char **env) { return path_is_read_only_fs(c->parameter) <= 0; } +static int condition_test_cpufeature(Condition *c, char **env) { + assert(c); + assert(c->parameter); + assert(c->type == CONDITION_CPU_FEATURE); + + return has_cpu_with_flag(ascii_strlower(c->parameter)); +} + static int condition_test_path_is_encrypted(Condition *c, char **env) { int r; @@ -806,6 +851,7 @@ int condition_test(Condition *c, char **env) { [CONDITION_CPUS] = condition_test_cpus, [CONDITION_MEMORY] = condition_test_memory, [CONDITION_ENVIRONMENT] = condition_test_environment, + [CONDITION_CPU_FEATURE] = condition_test_cpufeature, }; int r, b; @@ -928,6 +974,7 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_CPUS] = "ConditionCPUs", [CONDITION_MEMORY] = "ConditionMemory", [CONDITION_ENVIRONMENT] = "ConditionEnvironment", + [CONDITION_CPU_FEATURE] = "ConditionCPUFeature", }; DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType); @@ -959,6 +1006,7 @@ static const char* const assert_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_CPUS] = "AssertCPUs", [CONDITION_MEMORY] = "AssertMemory", [CONDITION_ENVIRONMENT] = "AssertEnvironment", + [CONDITION_CPU_FEATURE] = "AssertCPUFeature", }; DEFINE_STRING_TABLE_LOOKUP(assert_type, ConditionType); diff --git a/src/shared/condition.h b/src/shared/condition.h index 0d9754eb8..75c430e9e 100644 --- a/src/shared/condition.h +++ b/src/shared/condition.h @@ -19,6 +19,7 @@ typedef enum ConditionType { CONDITION_MEMORY, CONDITION_CPUS, CONDITION_ENVIRONMENT, + CONDITION_CPU_FEATURE, CONDITION_NEEDS_UPDATE, CONDITION_FIRST_BOOT, @@ -40,7 +41,7 @@ typedef enum ConditionType { CONDITION_CONTROL_GROUP_CONTROLLER, _CONDITION_TYPE_MAX, - _CONDITION_TYPE_INVALID = -1 + _CONDITION_TYPE_INVALID = -EINVAL, } ConditionType; typedef enum ConditionResult { @@ -49,7 +50,7 @@ typedef enum ConditionResult { CONDITION_FAILED, CONDITION_ERROR, _CONDITION_RESULT_MAX, - _CONDITION_RESULT_INVALID = -1 + _CONDITION_RESULT_INVALID = -EINVAL, } ConditionResult; typedef struct Condition { diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 35d301d9d..9dfa19075 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -11,6 +11,7 @@ #include "conf-files.h" #include "conf-parser.h" #include "def.h" +#include "ether-addr-util.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" @@ -21,9 +22,11 @@ #include "nulstr-util.h" #include "parse-util.h" #include "path-util.h" +#include "percent-util.h" #include "process-util.h" #include "rlimit-util.h" #include "sd-id128.h" +#include "set.h" #include "signal-util.h" #include "socket-util.h" #include "string-util.h" @@ -251,15 +254,16 @@ static int parse_line( } /* Go through the file and parse each line */ -int config_parse(const char *unit, - const char *filename, - FILE *f, - const char *sections, - ConfigItemLookup lookup, - const void *table, - ConfigParseFlags flags, - void *userdata, - usec_t *ret_mtime) { +int config_parse( + const char *unit, + const char *filename, + FILE *f, + const char *sections, + ConfigItemLookup lookup, + const void *table, + ConfigParseFlags flags, + void *userdata, + usec_t *latest_mtime) { _cleanup_free_ char *section = NULL, *continuation = NULL; _cleanup_fclose_ FILE *ours = NULL; @@ -271,6 +275,9 @@ int config_parse(const char *unit, assert(filename); assert(lookup); + /* latest_mtime is an input-output parameter: it will be updated if the mtime of the file we're + * looking at is later than the current *latest_mtime value. */ + if (!f) { f = ours = fopen(filename, "re"); if (!f) { @@ -340,7 +347,7 @@ int config_parse(const char *unit, return -ENOBUFS; } - if (!strextend(&continuation, l, NULL)) { + if (!strextend(&continuation, l)) { if (flags & CONFIG_PARSE_WARN) log_oom(); return -ENOMEM; @@ -413,14 +420,14 @@ int config_parse(const char *unit, } } - if (ret_mtime) - *ret_mtime = mtime; + if (latest_mtime) + *latest_mtime = MAX(*latest_mtime, mtime); - return 0; + return 1; } static int config_parse_many_files( - const char *conf_file, + const char* const* conf_files, char **files, const char *sections, ConfigItemLookup lookup, @@ -433,20 +440,20 @@ static int config_parse_many_files( char **fn; int r; - if (conf_file) { - r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata, &mtime); + /* First read the first found main config file. */ + STRV_FOREACH(fn, (char**) conf_files) { + r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &mtime); if (r < 0) return r; + if (r > 0) + break; } + /* Then read all the drop-ins. */ STRV_FOREACH(fn, files) { - usec_t t; - - r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &t); + r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata, &mtime); if (r < 0) return r; - if (t > mtime) /* Find the newest */ - mtime = t; } if (ret_mtime) @@ -473,12 +480,14 @@ int config_parse_many_nulstr( if (r < 0) return r; - return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime); + return config_parse_many_files(STRV_MAKE_CONST(conf_file), + files, sections, lookup, table, flags, userdata, + ret_mtime); } /* Parse each config file in the directories specified as strv. */ int config_parse_many( - const char *conf_file, + const char* const* conf_files, const char* const* conf_file_dirs, const char *dropin_dirname, const char *sections, @@ -502,7 +511,7 @@ int config_parse_many( if (r < 0) return r; - return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata, ret_mtime); + return config_parse_many_files(conf_files, files, sections, lookup, table, flags, userdata, ret_mtime); } #define DEFINE_PARSER(type, vartype, conv_func) \ @@ -522,16 +531,17 @@ DEFINE_PARSER(sec, usec_t, parse_sec); DEFINE_PARSER(sec_def_infinity, usec_t, parse_sec_def_infinity); DEFINE_PARSER(mode, mode_t, parse_mode); -int config_parse_iec_size(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_iec_size( + 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) { size_t *sz = data; uint64_t v; @@ -608,16 +618,17 @@ int config_parse_iec_uint64( return 0; } -int config_parse_bool(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_bool( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { int k; bool *b = data; @@ -726,10 +737,7 @@ int config_parse_string( assert(rvalue); assert(data); - if (free_and_strdup(s, empty_to_null(rvalue)) < 0) - return log_oom(); - - return 0; + return free_and_strdup_warn(s, empty_to_null(rvalue)); } int config_parse_path( @@ -869,7 +877,7 @@ int config_parse_log_facility( x = log_facility_unshifted_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse log facility, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log facility, ignoring: %s", rvalue); return 0; } @@ -899,7 +907,7 @@ int config_parse_log_level( x = log_level_from_string(rvalue); if (x < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse log level, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, x, "Failed to parse log level, ignoring: %s", rvalue); return 0; } @@ -932,7 +940,7 @@ int config_parse_signal( r = signal_from_string(rvalue); if (r <= 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Failed to parse signal name, ignoring: %s", rvalue); + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse signal name, ignoring: %s", rvalue); return 0; } @@ -1181,16 +1189,17 @@ int config_parse_rlimit( return 0; } -int config_parse_permille(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_permille( + 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) { unsigned *permille = data; int r; @@ -1212,17 +1221,20 @@ int config_parse_permille(const char* unit, return 0; } -int config_parse_vlanprotocol(const char* unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { +int config_parse_vlanprotocol( + const char* unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + int *vlan_protocol = data; + assert(filename); assert(lvalue); @@ -1244,4 +1256,107 @@ int config_parse_vlanprotocol(const char* unit, return 0; } +int config_parse_hwaddr( + 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_ struct ether_addr *n = NULL; + struct ether_addr **hwaddr = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *hwaddr = mfree(*hwaddr); + return 0; + } + + n = new0(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = ether_addr_from_string(rvalue, n); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Not a valid MAC address, ignoring assignment: %s", rvalue); + return 0; + } + + free_and_replace(*hwaddr, n); + + return 0; +} + +int config_parse_hwaddrs( + 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) { + + Set **hwaddrs = data; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + /* Empty assignment resets the list */ + *hwaddrs = set_free_free(*hwaddrs); + return 0; + } + + for (const char *p = rvalue;;) { + _cleanup_free_ char *word = NULL; + _cleanup_free_ struct ether_addr *n = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + n = new(struct ether_addr, 1); + if (!n) + return log_oom(); + + r = ether_addr_from_string(word, n); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Not a valid MAC address, ignoring: %s", word); + continue; + } + + r = set_ensure_put(hwaddrs, ðer_addr_hash_ops, n); + if (r < 0) + return log_oom(); + if (r > 0) + TAKE_PTR(n); /* avoid cleanup */ + } +} + DEFINE_CONFIG_PARSE(config_parse_percent, parse_percent, "Failed to parse percent value"); +DEFINE_CONFIG_PARSE(config_parse_permyriad, parse_permyriad, "Failed to parse permyriad value"); diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index f115cb23a..c4b989142 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -89,7 +89,7 @@ int config_parse( const void *table, ConfigParseFlags flags, void *userdata, - usec_t *ret_mtime); /* possibly NULL */ + usec_t *latest_mtime); /* input/output, possibly NULL */ int config_parse_many_nulstr( const char *conf_file, /* possibly NULL */ @@ -102,7 +102,7 @@ int config_parse_many_nulstr( usec_t *ret_mtime); /* possibly NULL */ int config_parse_many( - const char *conf_file, /* possibly NULL */ + const char* const* conf_files, /* possibly empty */ const char* const* conf_file_dirs, const char *dropin_dirname, const char *sections, /* nulstr */ @@ -147,7 +147,10 @@ CONFIG_PARSER_PROTOTYPE(config_parse_ip_port); CONFIG_PARSER_PROTOTYPE(config_parse_mtu); CONFIG_PARSER_PROTOTYPE(config_parse_rlimit); CONFIG_PARSER_PROTOTYPE(config_parse_vlanprotocol); +CONFIG_PARSER_PROTOTYPE(config_parse_hwaddr); +CONFIG_PARSER_PROTOTYPE(config_parse_hwaddrs); CONFIG_PARSER_PROTOTYPE(config_parse_percent); +CONFIG_PARSER_PROTOTYPE(config_parse_permyriad); typedef enum Disabled { DISABLED_CONFIGURATION, @@ -204,7 +207,7 @@ typedef enum Disabled { \ x = from_string(rvalue); \ if (x < 0) { \ - log_syntax(unit, LOG_WARNING, filename, line, 0, \ + log_syntax(unit, LOG_WARNING, filename, line, x, \ msg ", ignoring: %s", rvalue); \ return 0; \ } \ @@ -232,7 +235,7 @@ typedef enum Disabled { \ x = name##_from_string(rvalue); \ if (x < 0) { \ - log_syntax(unit, LOG_WARNING, filename, line, 0, \ + log_syntax(unit, LOG_WARNING, filename, line, x, \ msg ", ignoring: %s", rvalue); \ return 0; \ } \ @@ -266,14 +269,17 @@ typedef enum Disabled { r = extract_first_word(&p, &en, NULL, 0); \ if (r == -ENOMEM) \ return log_oom(); \ - if (r < 0) \ - return log_syntax(unit, LOG_ERR, filename, line, 0, \ - msg ": %s", en); \ + if (r < 0) { \ + log_syntax(unit, LOG_WARNING, filename, line, r, \ + msg ", ignoring: %s", en); \ + return 0; \ + } \ if (r == 0) \ break; \ \ - if ((x = name##_from_string(en)) < 0) { \ - log_syntax(unit, LOG_WARNING, filename, line, 0, \ + x = name##_from_string(en); \ + if (x < 0) { \ + log_syntax(unit, LOG_WARNING, filename, line, x, \ msg ", ignoring: %s", en); \ continue; \ } \ diff --git a/src/shared/coredump-util.h b/src/shared/coredump-util.h index a7f3c0e86..09e7ed443 100644 --- a/src/shared/coredump-util.h +++ b/src/shared/coredump-util.h @@ -14,7 +14,7 @@ typedef enum CoredumpFilter { COREDUMP_FILTER_PRIVATE_DAX, COREDUMP_FILTER_SHARED_DAX, _COREDUMP_FILTER_MAX, - _COREDUMP_FILTER_INVALID = -1, + _COREDUMP_FILTER_INVALID = -EINVAL, } CoredumpFilter; #define COREDUMP_FILTER_MASK_DEFAULT (1u << COREDUMP_FILTER_PRIVATE_ANONYMOUS | \ diff --git a/src/shared/cryptsetup-util.c b/src/shared/cryptsetup-util.c index 34a078e7e..c1ba9f6ab 100644 --- a/src/shared/cryptsetup-util.c +++ b/src/shared/cryptsetup-util.c @@ -5,6 +5,7 @@ #include "cryptsetup-util.h" #include "dlfcn-util.h" #include "log.h" +#include "parse-util.h" static void *cryptsetup_dl = NULL; @@ -26,7 +27,13 @@ int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64_t new_ int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device); void (*sym_crypt_set_debug_level)(int level); void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr); +int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf) = NULL; +int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json) = NULL; +int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json) = NULL; int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size); +#if HAVE_CRYPT_TOKEN_MAX +int (*sym_crypt_token_max)(const char *type); +#endif int dlopen_cryptsetup(void) { _cleanup_(dlclosep) void *dl = NULL; @@ -43,25 +50,31 @@ int dlopen_cryptsetup(void) { r = dlsym_many_and_warn( dl, LOG_DEBUG, - &sym_crypt_activate_by_passphrase, "crypt_activate_by_passphrase", + DLSYM_ARG(crypt_activate_by_passphrase), #if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY - &sym_crypt_activate_by_signed_key, "crypt_activate_by_signed_key", + DLSYM_ARG(crypt_activate_by_signed_key), +#endif + DLSYM_ARG(crypt_activate_by_volume_key), + DLSYM_ARG(crypt_deactivate_by_name), + DLSYM_ARG(crypt_format), + DLSYM_ARG(crypt_free), + DLSYM_ARG(crypt_get_dir), + DLSYM_ARG(crypt_get_verity_info), + DLSYM_ARG(crypt_init), + DLSYM_ARG(crypt_init_by_name), + DLSYM_ARG(crypt_keyslot_add_by_volume_key), + DLSYM_ARG(crypt_load), + DLSYM_ARG(crypt_resize), + DLSYM_ARG(crypt_set_data_device), + DLSYM_ARG(crypt_set_debug_level), + DLSYM_ARG(crypt_set_log_callback), + DLSYM_ARG(crypt_set_pbkdf_type), + DLSYM_ARG(crypt_token_json_get), + DLSYM_ARG(crypt_token_json_set), + DLSYM_ARG(crypt_volume_key_get), +#if HAVE_CRYPT_TOKEN_MAX + DLSYM_ARG(crypt_token_max), #endif - &sym_crypt_activate_by_volume_key, "crypt_activate_by_volume_key", - &sym_crypt_deactivate_by_name, "crypt_deactivate_by_name", - &sym_crypt_format, "crypt_format", - &sym_crypt_free, "crypt_free", - &sym_crypt_get_dir, "crypt_get_dir", - &sym_crypt_get_verity_info, "crypt_get_verity_info", - &sym_crypt_init, "crypt_init", - &sym_crypt_init_by_name, "crypt_init_by_name", - &sym_crypt_keyslot_add_by_volume_key, "crypt_keyslot_add_by_volume_key", - &sym_crypt_load, "crypt_load", - &sym_crypt_resize, "crypt_resize", - &sym_crypt_set_data_device, "crypt_set_data_device", - &sym_crypt_set_debug_level, "crypt_set_debug_level", - &sym_crypt_set_log_callback, "crypt_set_log_callback", - &sym_crypt_volume_key_get, "crypt_volume_key_get", NULL); if (r < 0) return r; @@ -108,4 +121,126 @@ void cryptsetup_enable_logging(struct crypt_device *cd) { sym_crypt_set_debug_level(DEBUG_LOGGING ? CRYPT_DEBUG_ALL : CRYPT_DEBUG_NONE); } +int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd) { + + static const struct crypt_pbkdf_type minimal_pbkdf = { + .hash = "sha512", + .type = CRYPT_KDF_PBKDF2, + .iterations = 1, + .time_ms = 1, + }; + + int r; + + /* Sets a minimal PKBDF in case we already have a high entropy key. */ + + r = dlopen_cryptsetup(); + if (r < 0) + return r; + + r = sym_crypt_set_pbkdf_type(cd, &minimal_pbkdf); + if (r < 0) + return r; + + return 0; +} + +int cryptsetup_get_token_as_json( + struct crypt_device *cd, + int idx, + const char *verify_type, + JsonVariant **ret) { + + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL; + const char *text; + int r; + + assert(cd); + + /* Extracts and parses the LUKS2 JSON token data from a LUKS2 device. Optionally verifies the type of + * the token. Returns: + * + * -EINVAL → token index out of range or "type" field missing + * -ENOENT → token doesn't exist + * -EMEDIUMTYPE → "verify_type" specified and doesn't match token's type + */ + + r = dlopen_cryptsetup(); + if (r < 0) + return r; + + r = sym_crypt_token_json_get(cd, idx, &text); + if (r < 0) + return r; + + r = json_parse(text, 0, &v, NULL, NULL); + if (r < 0) + return r; + + if (verify_type) { + JsonVariant *w; + + w = json_variant_by_key(v, "type"); + if (!w) + return -EINVAL; + + if (!streq_ptr(json_variant_string(w), verify_type)) + return -EMEDIUMTYPE; + } + + if (ret) + *ret = TAKE_PTR(v); + + return 0; +} + +int cryptsetup_get_keyslot_from_token(JsonVariant *v) { + int keyslot, r; + JsonVariant *w; + + /* Parses the "keyslots" field of a LUKS2 token object. The field can be an array, but here we assume + * that it contains a single element only, since that's the only way we ever generate it + * ourselves. */ + + w = json_variant_by_key(v, "keyslots"); + if (!w) + return -ENOENT; + if (!json_variant_is_array(w) || json_variant_elements(w) != 1) + return -EMEDIUMTYPE; + + w = json_variant_by_index(w, 0); + if (!w) + return -ENOENT; + if (!json_variant_is_string(w)) + return -EMEDIUMTYPE; + + r = safe_atoi(json_variant_string(w), &keyslot); + if (r < 0) + return r; + if (keyslot < 0) + return -EINVAL; + + return keyslot; +} + +int cryptsetup_add_token_json(struct crypt_device *cd, JsonVariant *v) { + _cleanup_free_ char *text = NULL; + int r; + + r = dlopen_cryptsetup(); + if (r < 0) + return r; + + r = json_variant_format(v, 0, &text); + if (r < 0) + return log_debug_errno(r, "Failed to format token data for LUKS: %m"); + + log_debug("Adding token text <%s>", text); + + r = sym_crypt_token_json_set(cd, CRYPT_ANY_TOKEN, text); + if (r < 0) + return log_debug_errno(r, "Failed to write token data to LUKS: %m"); + + return 0; +} #endif diff --git a/src/shared/cryptsetup-util.h b/src/shared/cryptsetup-util.h index e7d885d2a..5ebb0ac57 100644 --- a/src/shared/cryptsetup-util.h +++ b/src/shared/cryptsetup-util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "json.h" #include "macro.h" #if HAVE_LIBCRYPTSETUP @@ -32,13 +33,32 @@ extern int (*sym_crypt_resize)(struct crypt_device *cd, const char *name, uint64 extern int (*sym_crypt_set_data_device)(struct crypt_device *cd, const char *device); extern void (*sym_crypt_set_debug_level)(int level); extern void (*sym_crypt_set_log_callback)(struct crypt_device *cd, void (*log)(int level, const char *msg, void *usrptr), void *usrptr); +extern int (*sym_crypt_set_pbkdf_type)(struct crypt_device *cd, const struct crypt_pbkdf_type *pbkdf); +extern int (*sym_crypt_token_json_get)(struct crypt_device *cd, int token, const char **json); +extern int (*sym_crypt_token_json_set)(struct crypt_device *cd, int token, const char *json); extern int (*sym_crypt_volume_key_get)(struct crypt_device *cd, int keyslot, char *volume_key, size_t *volume_key_size, const char *passphrase, size_t passphrase_size); +#if HAVE_CRYPT_TOKEN_MAX +extern int (*sym_crypt_token_max)(const char *type); +#else +/* As a fallback, use the same hard-coded value libcryptsetup uses internally. */ +static inline int sym_crypt_token_max(_unused_ const char *type) { + assert(streq(type, CRYPT_LUKS2)); + + return 32; +} +#endif int dlopen_cryptsetup(void); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, crypt_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct crypt_device *, sym_crypt_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, crypt_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct crypt_device *, sym_crypt_free, NULL); void cryptsetup_enable_logging(struct crypt_device *cd); +int cryptsetup_set_minimal_pbkdf(struct crypt_device *cd); + +int cryptsetup_get_token_as_json(struct crypt_device *cd, int idx, const char *verify_type, JsonVariant **ret); +int cryptsetup_get_keyslot_from_token(JsonVariant *v); +int cryptsetup_add_token_json(struct crypt_device *cd, JsonVariant *v); + #endif diff --git a/src/login/logind-acl.c b/src/shared/devnode-acl.c similarity index 99% rename from src/login/logind-acl.c rename to src/shared/devnode-acl.c index ed615e23f..07e29e101 100644 --- a/src/login/logind-acl.c +++ b/src/shared/devnode-acl.c @@ -7,11 +7,11 @@ #include "acl-util.h" #include "alloc-util.h" #include "device-util.h" +#include "devnode-acl.h" #include "dirent-util.h" #include "escape.h" #include "fd-util.h" #include "format-util.h" -#include "logind-acl.h" #include "set.h" #include "string-util.h" #include "util.h" diff --git a/src/login/logind-acl.h b/src/shared/devnode-acl.h similarity index 100% rename from src/login/logind-acl.h rename to src/shared/devnode-acl.h diff --git a/src/shared/machine-image.c b/src/shared/discover-image.c similarity index 87% rename from src/shared/machine-image.c rename to src/shared/discover-image.c index 671a56b9e..79c4c70a4 100644 --- a/src/shared/machine-image.c +++ b/src/shared/discover-image.c @@ -16,18 +16,18 @@ #include "chattr-util.h" #include "copy.h" #include "dirent-util.h" +#include "discover-image.h" #include "dissect-image.h" #include "env-file.h" #include "env-util.h" #include "fd-util.h" #include "fs-util.h" #include "hashmap.h" -#include "hostname-util.h" +#include "hostname-setup.h" #include "id128-util.h" #include "lockfile-util.h" #include "log.h" #include "loop-util.h" -#include "machine-image.h" #include "macro.h" #include "mkdir.h" #include "nulstr-util.h" @@ -42,18 +42,24 @@ #include "xattr-util.h" static const char* const image_search_path[_IMAGE_CLASS_MAX] = { - [IMAGE_MACHINE] = "/etc/machines\0" /* only place symlinks here */ - "/run/machines\0" /* and here too */ - "/var/lib/machines\0" /* the main place for images */ - "/var/lib/container\0" /* legacy */ - "/usr/local/lib/machines\0" - "/usr/lib/machines\0", + [IMAGE_MACHINE] = "/etc/machines\0" /* only place symlinks here */ + "/run/machines\0" /* and here too */ + "/var/lib/machines\0" /* the main place for images */ + "/var/lib/container\0" /* legacy */ + "/usr/local/lib/machines\0" + "/usr/lib/machines\0", - [IMAGE_PORTABLE] = "/etc/portables\0" /* only place symlinks here */ - "/run/portables\0" /* and here too */ - "/var/lib/portables\0" /* the main place for images */ - "/usr/local/lib/portables\0" - "/usr/lib/portables\0", + [IMAGE_PORTABLE] = "/etc/portables\0" /* only place symlinks here */ + "/run/portables\0" /* and here too */ + "/var/lib/portables\0" /* the main place for images */ + "/usr/local/lib/portables\0" + "/usr/lib/portables\0", + + [IMAGE_EXTENSION] = "/etc/extensions\0" /* only place symlinks here */ + "/run/extensions\0" /* and here too */ + "/var/lib/extensions\0" /* the main place for images */ + "/usr/local/lib/extensions\0" + "/usr/lib/extensions\0", }; static Image *image_free(Image *i) { @@ -65,6 +71,7 @@ static Image *image_free(Image *i) { free(i->hostname); strv_free(i->machine_info); strv_free(i->os_release); + strv_free(i->extension_release); return mfree(i); } @@ -129,17 +136,21 @@ static int image_new( assert(filename); assert(ret); - i = new0(Image, 1); + i = new(Image, 1); if (!i) return -ENOMEM; - i->n_ref = 1; - i->type = t; - i->read_only = read_only; - i->crtime = crtime; - i->mtime = mtime; - i->usage = i->usage_exclusive = (uint64_t) -1; - i->limit = i->limit_exclusive = (uint64_t) -1; + *i = (Image) { + .n_ref = 1, + .type = t, + .read_only = read_only, + .crtime = crtime, + .mtime = mtime, + .usage = UINT64_MAX, + .usage_exclusive = UINT64_MAX, + .limit = UINT64_MAX, + .limit_exclusive = UINT64_MAX, + }; i->name = strdup(pretty); if (!i->name) @@ -232,6 +243,7 @@ static int image_make( if (S_ISDIR(st->st_mode)) { _cleanup_close_ int fd = -1; unsigned file_attr = 0; + usec_t crtime = 0; if (!ret) return 0; @@ -248,8 +260,7 @@ static int image_make( if (fd < 0) return -errno; - /* btrfs subvolumes have inode 256 */ - if (st->st_ino == 256) { + if (btrfs_might_be_subvol(st)) { r = btrfs_is_filesystem(fd); if (r < 0) @@ -291,8 +302,10 @@ static int image_make( } } - /* If the IMMUTABLE bit is set, we consider the - * directory read-only. Since the ioctl is not + /* Get directory creation time (not available everywhere, but that's OK */ + (void) fd_getcrtime(dfd, &crtime); + + /* If the IMMUTABLE bit is set, we consider the directory read-only. Since the ioctl is not * supported everywhere we ignore failures. */ (void) read_attr_fd(fd, &file_attr); @@ -302,8 +315,8 @@ static int image_make( path, filename, read_only || (file_attr & FS_IMMUTABLE_FL), - 0, - 0, + crtime, + 0, /* we don't use mtime of stat() here, since it's not the time of last change of the tree, but only of the top-level dir */ ret); if (r < 0) return r; @@ -408,7 +421,11 @@ static int image_make( return -EMEDIUMTYPE; } -int image_find(ImageClass class, const char *name, Image **ret) { +int image_find(ImageClass class, + const char *name, + const char *root, + Image **ret) { + const char *path; int r; @@ -421,20 +438,22 @@ int image_find(ImageClass class, const char *name, Image **ret) { return -ENOENT; NULSTR_FOREACH(path, image_search_path[class]) { + _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; struct stat st; + int flags; - d = opendir(path); - if (!d) { - if (errno == ENOENT) - continue; + r = chase_symlinks_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d); + if (r == -ENOENT) + continue; + if (r < 0) + return r; - return -errno; - } - - /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people to - * symlink block devices into the search path */ - if (fstatat(dirfd(d), name, &st, 0) < 0) { + /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people + * to symlink block devices into the search path. (For now, we disable that when operating + * relative to some root directory.) */ + flags = root ? AT_SYMLINK_NOFOLLOW : 0; + if (fstatat(dirfd(d), name, &st, flags) < 0) { _cleanup_free_ char *raw = NULL; if (errno != ENOENT) @@ -444,8 +463,7 @@ int image_find(ImageClass class, const char *name, Image **ret) { if (!raw) return -ENOMEM; - if (fstatat(dirfd(d), raw, &st, 0) < 0) { - + if (fstatat(dirfd(d), raw, &st, flags) < 0) { if (errno == ENOENT) continue; @@ -455,13 +473,13 @@ int image_find(ImageClass class, const char *name, Image **ret) { if (!S_ISREG(st.st_mode)) continue; - r = image_make(name, dirfd(d), path, raw, &st, ret); + r = image_make(name, dirfd(d), resolved, raw, &st, ret); } else { if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)) continue; - r = image_make(name, dirfd(d), path, name, &st, ret); + r = image_make(name, dirfd(d), resolved, name, &st, ret); } if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) continue; @@ -475,7 +493,7 @@ int image_find(ImageClass class, const char *name, Image **ret) { } if (class == IMAGE_MACHINE && streq(name, ".host")) { - r = image_make(".host", AT_FDCWD, NULL, "/", NULL, ret); + r = image_make(".host", AT_FDCWD, NULL, empty_to_root(root), NULL, ret); if (r < 0) return r; @@ -500,14 +518,18 @@ int image_from_path(const char *path, Image **ret) { return image_make(NULL, AT_FDCWD, NULL, path, NULL, ret); } -int image_find_harder(ImageClass class, const char *name_or_path, Image **ret) { +int image_find_harder(ImageClass class, const char *name_or_path, const char *root, Image **ret) { if (image_name_is_valid(name_or_path)) - return image_find(class, name_or_path, ret); + return image_find(class, name_or_path, root, ret); return image_from_path(name_or_path, ret); } -int image_discover(ImageClass class, Hashmap *h) { +int image_discover( + ImageClass class, + const char *root, + Hashmap *h) { + const char *path; int r; @@ -516,29 +538,30 @@ int image_discover(ImageClass class, Hashmap *h) { assert(h); NULSTR_FOREACH(path, image_search_path[class]) { + _cleanup_free_ char *resolved = NULL; _cleanup_closedir_ DIR *d = NULL; struct dirent *de; - d = opendir(path); - if (!d) { - if (errno == ENOENT) - continue; - - return -errno; - } + r = chase_symlinks_and_opendir(path, root, CHASE_PREFIX_ROOT, &resolved, &d); + if (r == -ENOENT) + continue; + if (r < 0) + return r; FOREACH_DIRENT_ALL(de, d, return -errno) { _cleanup_(image_unrefp) Image *image = NULL; _cleanup_free_ char *truncated = NULL; const char *pretty; struct stat st; + int flags; if (dot_or_dot_dot(de->d_name)) continue; - /* As mentioned above, we follow symlinks on this fstatat(), because we want to permit people - * to symlink block devices into the search path */ - if (fstatat(dirfd(d), de->d_name, &st, 0) < 0) { + /* As mentioned above, we follow symlinks on this fstatat(), because we want to + * permit people to symlink block devices into the search path. */ + flags = root ? AT_SYMLINK_NOFOLLOW : 0; + if (fstatat(dirfd(d), de->d_name, &st, flags) < 0) { if (errno == ENOENT) continue; @@ -568,7 +591,7 @@ int image_discover(ImageClass class, Hashmap *h) { if (hashmap_contains(h, pretty)) continue; - r = image_make(pretty, dirfd(d), path, de->d_name, &st, &image); + r = image_make(pretty, dirfd(d), resolved, de->d_name, &st, &image); if (IN_SET(r, -ENOENT, -EMEDIUMTYPE)) continue; if (r < 0) @@ -587,7 +610,7 @@ int image_discover(ImageClass class, Hashmap *h) { if (class == IMAGE_MACHINE && !hashmap_contains(h, ".host")) { _cleanup_(image_unrefp) Image *image = NULL; - r = image_make(".host", AT_FDCWD, NULL, "/", NULL, &image); + r = image_make(".host", AT_FDCWD, NULL, empty_to_root("/"), NULL, &image); if (r < 0) return r; @@ -730,7 +753,7 @@ int image_rename(Image *i, const char *new_name) { if (r < 0) return r; - r = image_find(IMAGE_MACHINE, new_name, NULL); + r = image_find(IMAGE_MACHINE, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -843,7 +866,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) { if (r < 0) return r; - r = image_find(IMAGE_MACHINE, new_name, NULL); + r = image_find(IMAGE_MACHINE, new_name, NULL, NULL); if (r >= 0) return -EEXIST; if (r != -ENOENT) @@ -1042,7 +1065,6 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino); else return -ENOTTY; - if (r < 0) return -ENOMEM; } @@ -1107,7 +1129,7 @@ int image_read_metadata(Image *i) { case IMAGE_SUBVOLUME: case IMAGE_DIRECTORY: { - _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL; + _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **extension_release = NULL; sd_id128_t machine_id = SD_ID128_NULL; _cleanup_free_ char *hostname = NULL; _cleanup_free_ char *path = NULL; @@ -1154,10 +1176,15 @@ int image_read_metadata(Image *i) { if (r < 0) log_debug_errno(r, "Failed to read os-release in image, ignoring: %m"); + r = load_extension_release_pairs(i->path, i->name, &extension_release); + if (r < 0) + log_debug_errno(r, "Failed to read extension-release in image, ignoring: %m"); + free_and_replace(i->hostname, hostname); i->machine_id = machine_id; strv_free_and_replace(i->machine_info, machine_info); strv_free_and_replace(i->os_release, os_release); + strv_free_and_replace(i->extension_release, extension_release); break; } @@ -1183,6 +1210,7 @@ int image_read_metadata(Image *i) { i->machine_id = m->machine_id; strv_free_and_replace(i->machine_info, m->machine_info); strv_free_and_replace(i->os_release, m->os_release); + strv_free_and_replace(i->extension_release, m->extension_release); break; } @@ -1197,11 +1225,16 @@ int image_read_metadata(Image *i) { } int image_name_lock(const char *name, int operation, LockFile *ret) { + const char *p; + assert(name); assert(ret); /* Locks an image name, regardless of the precise path used. */ + if (streq(name, ".host")) + return -EBUSY; + if (!image_name_is_valid(name)) return -EINVAL; @@ -1210,41 +1243,33 @@ int image_name_lock(const char *name, int operation, LockFile *ret) { return 0; } - if (streq(name, ".host")) - return -EBUSY; - - const char *p = strjoina("/run/systemd/nspawn/locks/name-", name); (void) mkdir_p("/run/systemd/nspawn/locks", 0700); + + p = strjoina("/run/systemd/nspawn/locks/name-", name); return make_lock_file(p, operation, ret); } -bool image_name_is_valid(const char *s) { - if (!filename_is_valid(s)) - return false; +bool image_in_search_path( + ImageClass class, + const char *root, + const char *image) { - if (string_has_cc(s, NULL)) - return false; - - if (!utf8_is_valid(s)) - return false; - - /* Temporary files for atomically creating new files */ - if (startswith(s, ".#")) - return false; - - return true; -} - -bool image_in_search_path(ImageClass class, const char *image) { const char *path; assert(image); NULSTR_FOREACH(path, image_search_path[class]) { - const char *p; + const char *p, *q; size_t k; - p = path_startswith(image, path); + if (!empty_or_root(root)) { + q = path_startswith(path, root); + if (!q) + continue; + } else + q = path; + + p = path_startswith(q, path); if (!p) continue; diff --git a/src/shared/machine-image.h b/src/shared/discover-image.h similarity index 83% rename from src/shared/machine-image.h rename to src/shared/discover-image.h index 95a8f5cfb..3726e98d3 100644 --- a/src/shared/machine-image.h +++ b/src/shared/discover-image.h @@ -16,8 +16,9 @@ typedef enum ImageClass { IMAGE_MACHINE, IMAGE_PORTABLE, + IMAGE_EXTENSION, _IMAGE_CLASS_MAX, - _IMAGE_CLASS_INVALID = -1 + _IMAGE_CLASS_INVALID = -EINVAL, } ImageClass; typedef enum ImageType { @@ -26,7 +27,7 @@ typedef enum ImageType { IMAGE_RAW, IMAGE_BLOCK, _IMAGE_TYPE_MAX, - _IMAGE_TYPE_INVALID = -1 + _IMAGE_TYPE_INVALID = -EINVAL, } ImageType; typedef struct Image { @@ -49,6 +50,7 @@ typedef struct Image { sd_id128_t machine_id; char **machine_info; char **os_release; + char **extension_release; bool metadata_valid:1; bool discoverable:1; /* true if we know for sure that image_find() would find the image given just the short name */ @@ -61,10 +63,10 @@ Image *image_ref(Image *i); DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref); -int image_find(ImageClass class, const char *name, Image **ret); +int image_find(ImageClass class, const char *root, const char *name, Image **ret); int image_from_path(const char *path, Image **ret); -int image_find_harder(ImageClass class, const char *name_or_path, Image **ret); -int image_discover(ImageClass class, Hashmap *map); +int image_find_harder(ImageClass class, const char *root, const char *name_or_path, Image **ret); +int image_discover(ImageClass class, const char *root, Hashmap *map); int image_remove(Image *i); int image_rename(Image *i, const char *new_name); @@ -74,8 +76,6 @@ int image_read_only(Image *i, bool b); const char* image_type_to_string(ImageType t) _const_; ImageType image_type_from_string(const char *s) _pure_; -bool image_name_is_valid(const char *s) _pure_; - int image_path_lock(const char *path, int operation, LockFile *global, LockFile *local); int image_name_lock(const char *name, int operation, LockFile *ret); @@ -83,7 +83,7 @@ int image_set_limit(Image *i, uint64_t referenced_max); int image_read_metadata(Image *i); -bool image_in_search_path(ImageClass class, const char *image); +bool image_in_search_path(ImageClass class, const char *root, const char *image); static inline bool IMAGE_IS_HIDDEN(const struct Image *i) { assert(i); diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index d1f299ae9..cca92e7fb 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -23,17 +23,20 @@ #include "def.h" #include "device-nodes.h" #include "device-util.h" +#include "discover-image.h" #include "dissect-image.h" #include "dm-util.h" #include "env-file.h" +#include "extension-release.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" #include "fsck-util.h" #include "gpt.h" #include "hexdecoct.h" -#include "hostname-util.h" +#include "hostname-setup.h" #include "id128-util.h" +#include "import-util.h" #include "mkdir.h" #include "mount-util.h" #include "mountpoint-util.h" @@ -148,7 +151,8 @@ static int device_is_partition(sd_device *d, blkid_partition pp) { return false; r = sd_device_get_sysattr_value(d, "partition", &v); - if (r == -ENOENT) /* Not a partition device */ + if (r == -ENOENT || /* Not a partition device */ + ERRNO_IS_PRIVILEGE(r)) /* Not ready to access? */ return false; if (r < 0) return r; @@ -245,7 +249,7 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, assert(w); - if (device_for_action(device, DEVICE_ACTION_REMOVE)) + if (device_for_action(device, SD_DEVICE_REMOVE)) return 0; r = sd_device_get_parent(device, &pp); @@ -472,7 +476,7 @@ int dissect_image( _cleanup_(blkid_free_probep) blkid_probe b = NULL; _cleanup_free_ char *generic_node = NULL; sd_id128_t generic_uuid = SD_ID128_NULL; - const char *pttype = NULL; + const char *pttype = NULL, *sysname = NULL; blkid_partlist pl; int r, generic_nr, n_partitions; struct stat st; @@ -529,7 +533,7 @@ int dissect_image( if (!S_ISBLK(st.st_mode)) return -ENOTBLK; - r = sd_device_new_from_devnum(&d, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(&d, &st); if (r < 0) return r; @@ -579,6 +583,34 @@ int dissect_image( if (!m) return -ENOMEM; + r = sd_device_get_sysname(d, &sysname); + if (r < 0) + return log_debug_errno(r, "Failed to get device sysname: %m"); + if (startswith(sysname, "loop")) { + _cleanup_free_ char *name_stripped = NULL; + const char *full_path; + + r = sd_device_get_sysattr_value(d, "loop/backing_file", &full_path); + if (r < 0) + log_debug_errno(r, "Failed to lookup image name via loop device backing file sysattr, ignoring: %m"); + else { + r = raw_strip_suffixes(basename(full_path), &name_stripped); + if (r < 0) + return r; + } + + free_and_replace(m->image_name, name_stripped); + } else { + r = free_and_strdup(&m->image_name, sysname); + if (r < 0) + return r; + } + + if (!image_name_is_valid(m->image_name)) { + log_debug("Image name %s is not valid, ignoring", strempty(m->image_name)); + m->image_name = mfree(m->image_name); + } + if ((!(flags & DISSECT_IMAGE_GPT_ONLY) && (flags & DISSECT_IMAGE_REQUIRE_ROOT)) || (flags & DISSECT_IMAGE_NO_PARTITION_TABLE)) { @@ -1197,9 +1229,11 @@ DissectedImage* dissected_image_unref(DissectedImage *m) { free(m->partitions[i].mount_options); } + free(m->image_name); free(m->hostname); strv_free(m->machine_info); strv_free(m->os_release); + strv_free(m->extension_release); return mfree(m); } @@ -1253,6 +1287,7 @@ static int run_fsck(const char *node, const char *fstype) { if (r == 0) { /* Child */ execl("/sbin/fsck", "/sbin/fsck", "-aT", node, NULL); + log_open(); log_debug_errno(errno, "Failed to execl() fsck: %m"); _exit(FSCK_OPERATIONAL_ERROR); } @@ -1310,20 +1345,28 @@ static int mount_partition( } if (directory) { - if (!FLAGS_SET(flags, DISSECT_IMAGE_READ_ONLY)) { - /* Automatically create missing mount points, if necessary. */ - r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755); - if (r < 0) - return r; - } + /* Automatically create missing mount points inside the image, if necessary. */ + r = mkdir_p_root(where, directory, uid_shift, (gid_t) uid_shift, 0755); + if (r < 0 && r != -EROFS) + return r; r = chase_symlinks(directory, where, CHASE_PREFIX_ROOT, &chased, NULL); if (r < 0) return r; p = chased; - } else + } else { + /* Create top-level mount if missing – but only if this is asked for. This won't modify the + * image (as the branch above does) but the host hierarchy, and the created directory might + * survive our mount in the host hierarchy hence. */ + if (FLAGS_SET(flags, DISSECT_IMAGE_MKDIR)) { + r = mkdir_p(where, 0755); + if (r < 0) + return r; + } + p = where; + } /* If requested, turn on discard support. */ if (fstype_can_discard(fstype) && @@ -1340,20 +1383,14 @@ static int mount_partition( if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0) return -ENOMEM; - if (!strextend_with_separator(&options, ",", uid_option, NULL)) + if (!strextend_with_separator(&options, ",", uid_option)) return -ENOMEM; } if (!isempty(m->mount_options)) - if (!strextend_with_separator(&options, ",", m->mount_options, NULL)) + if (!strextend_with_separator(&options, ",", m->mount_options)) return -ENOMEM; - if (FLAGS_SET(flags, DISSECT_IMAGE_MKDIR)) { - r = mkdir_p(p, 0755); - if (r < 0) - return r; - } - r = mount_nofollow_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options); if (r < 0) return r; @@ -1370,7 +1407,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, /* Returns: * * -ENXIO → No root partition found - * -EMEDIUMTYPE → DISSECT_IMAGE_VALIDATE_OS set but no os-release file found + * -EMEDIUMTYPE → DISSECT_IMAGE_VALIDATE_OS set but no os-release/extension-release file found * -EUNATCH → Encrypted partition found for which no dm-crypt was set up yet * -EUCLEAN → fsck for file system failed * -EBUSY → File system already mounted/used elsewhere (kernel) @@ -1386,10 +1423,6 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, return r; } - /* Mask DISSECT_IMAGE_MKDIR for all subdirs: the idea is that only the top-level mount point is - * created if needed, but the image itself not modified. */ - flags &= ~DISSECT_IMAGE_MKDIR; - if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) { /* For us mounting root always means mounting /usr as well */ r = mount_partition(m->partitions + PARTITION_USR, where, "/usr", uid_shift, flags); @@ -1400,8 +1433,13 @@ int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, r = path_is_os_tree(where); if (r < 0) return r; - if (r == 0) - return -EMEDIUMTYPE; + if (r == 0) { + r = path_is_extension_tree(where, m->image_name); + if (r < 0) + return r; + if (r == 0) + return -EMEDIUMTYPE; + } } } @@ -1481,7 +1519,7 @@ int dissected_image_mount_and_warn(DissectedImage *m, const char *where, uid_t u if (r == -ENXIO) return log_error_errno(r, "Not root file system found in image."); if (r == -EMEDIUMTYPE) - return log_error_errno(r, "No suitable os-release file in image found."); + return log_error_errno(r, "No suitable os-release/extension-release file in image found."); if (r == -EUNATCH) return log_error_errno(r, "Encrypted file system discovered, but decryption not requested."); if (r == -EUCLEAN) @@ -1512,13 +1550,12 @@ struct DecryptedImage { DecryptedImage* decrypted_image_unref(DecryptedImage* d) { #if HAVE_LIBCRYPTSETUP - size_t i; int r; if (!d) return NULL; - for (i = 0; i < d->n_decrypted; i++) { + for (size_t i = 0; i < d->n_decrypted; i++) { DecryptedPartition *p = d->decrypted + i; if (p->device && p->name && !p->relinquished) { @@ -1532,6 +1569,7 @@ DecryptedImage* decrypted_image_unref(DecryptedImage* d) { free(p->name); } + free(d->decrypted); free(d); #endif return NULL; @@ -1672,7 +1710,7 @@ static int verity_can_reuse( #if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY /* Ensure that, if signatures are supported, we only reuse the device if the previous mount used the * same settings, so that a previous unsigned mount will not be reused if the user asks to use - * signing for the new one, and viceversa. */ + * signing for the new one, and vice versa. */ if (!!verity->root_hash_sig != !!(crypt_params.flags & CRYPT_VERITY_ROOT_HASH_SIGNATURE)) return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Error opening verity device, it already exists but signature settings are not the same."); #endif @@ -1681,12 +1719,12 @@ static int verity_can_reuse( return 0; } -static inline void dm_deferred_remove_clean(char *name) { +static inline char* dm_deferred_remove_clean(char *name) { if (!name) - return; + return NULL; (void) sym_crypt_deactivate_by_name(NULL, name, CRYPT_DEACTIVATE_DEFERRED); - free(name); + return mfree(name); } DEFINE_TRIVIAL_CLEANUP_FUNC(char *, dm_deferred_remove_clean); @@ -1964,19 +2002,15 @@ int dissected_image_decrypt_interactively( } int decrypted_image_relinquish(DecryptedImage *d) { - -#if HAVE_LIBCRYPTSETUP - size_t i; - int r; -#endif - assert(d); - /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a boolean so - * that we don't clean it up ourselves either anymore */ + /* Turns on automatic removal after the last use ended for all DM devices of this image, and sets a + * boolean so that we don't clean it up ourselves either anymore */ #if HAVE_LIBCRYPTSETUP - for (i = 0; i < d->n_decrypted; i++) { + int r; + + for (size_t i = 0; i < d->n_decrypted; i++) { DecryptedPartition *p = d->decrypted + i; if (p->relinquished) @@ -2125,7 +2159,7 @@ int verity_settings_load( if ((root_hash || verity->root_hash) && !verity->root_hash_sig) { if (root_hash_sig_path) { - r = read_full_file_full(AT_FDCWD, root_hash_sig_path, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size); + r = read_full_file(root_hash_sig_path, (char**) &root_hash_sig, &root_hash_sig_size); if (r < 0 && r != -ENOENT) return r; @@ -2141,7 +2175,7 @@ int verity_settings_load( if (!p) return -ENOMEM; - r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size); + r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size); if (r < 0 && r != -ENOENT) return r; if (r >= 0) @@ -2155,7 +2189,7 @@ int verity_settings_load( if (!p) return -ENOMEM; - r = read_full_file_full(AT_FDCWD, p, 0, NULL, (char**) &root_hash_sig, &root_hash_sig_size); + r = read_full_file(p, (char**) &root_hash_sig, &root_hash_sig_size); if (r < 0 && r != -ENOENT) return r; if (r >= 0) @@ -2207,24 +2241,26 @@ int dissected_image_acquire_metadata(DissectedImage *m) { META_MACHINE_ID, META_MACHINE_INFO, META_OS_RELEASE, + META_EXTENSION_RELEASE, _META_MAX, }; - static const char *const paths[_META_MAX] = { - [META_HOSTNAME] = "/etc/hostname\0", - [META_MACHINE_ID] = "/etc/machine-id\0", - [META_MACHINE_INFO] = "/etc/machine-info\0", - [META_OS_RELEASE] = "/etc/os-release\0" - "/usr/lib/os-release\0", + static const char *paths[_META_MAX] = { + [META_HOSTNAME] = "/etc/hostname\0", + [META_MACHINE_ID] = "/etc/machine-id\0", + [META_MACHINE_INFO] = "/etc/machine-info\0", + [META_OS_RELEASE] = "/etc/os-release\0" + "/usr/lib/os-release\0", + [META_EXTENSION_RELEASE] = NULL, }; - _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL; + _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL, **extension_release = NULL; _cleanup_close_pair_ int error_pipe[2] = { -1, -1 }; _cleanup_(rmdir_and_freep) char *t = NULL; _cleanup_(sigkill_waitp) pid_t child = 0; sd_id128_t machine_id = SD_ID128_NULL; _cleanup_free_ char *hostname = NULL; - unsigned n_meta_initialized = 0, k; + unsigned n_meta_initialized = 0; int fds[2 * _META_MAX], r, v; ssize_t n; @@ -2232,11 +2268,28 @@ int dissected_image_acquire_metadata(DissectedImage *m) { assert(m); - for (; n_meta_initialized < _META_MAX; n_meta_initialized ++) + /* As per the os-release spec, if the image is an extension it will have a file + * named after the image name in extension-release.d/ */ + if (m->image_name) { + char *ext; + + ext = strjoina("/usr/lib/extension-release.d/extension-release.", m->image_name, "0"); + ext[strlen(ext) - 1] = '\0'; /* Extra \0 for NULSTR_FOREACH using placeholder from above */ + paths[META_EXTENSION_RELEASE] = ext; + } else + log_debug("No image name available, will skip extension-release metadata"); + + for (; n_meta_initialized < _META_MAX; n_meta_initialized ++) { + if (!paths[n_meta_initialized]) { + fds[2*n_meta_initialized] = fds[2*n_meta_initialized+1] = -1; + continue; + } + if (pipe2(fds + 2*n_meta_initialized, O_CLOEXEC) < 0) { r = -errno; goto finish; } + } r = mkdtemp_malloc("/tmp/dissect-XXXXXX", &t); if (r < 0) @@ -2262,10 +2315,13 @@ int dissected_image_acquire_metadata(DissectedImage *m) { _exit(EXIT_FAILURE); } - for (k = 0; k < _META_MAX; k++) { + for (unsigned k = 0; k < _META_MAX; k++) { _cleanup_close_ int fd = -ENOENT; const char *p; + if (!paths[k]) + continue; + fds[2*k] = safe_close(fds[2*k]); NULSTR_FOREACH(p, paths[k]) { @@ -2279,7 +2335,7 @@ int dissected_image_acquire_metadata(DissectedImage *m) { continue; } - r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0); + r = copy_bytes(fd, fds[2*k+1], UINT64_MAX, 0); if (r < 0) { (void) write(error_pipe[1], &r, sizeof(r)); _exit(EXIT_FAILURE); @@ -2293,9 +2349,12 @@ int dissected_image_acquire_metadata(DissectedImage *m) { error_pipe[1] = safe_close(error_pipe[1]); - for (k = 0; k < _META_MAX; k++) { + for (unsigned k = 0; k < _META_MAX; k++) { _cleanup_fclose_ FILE *f = NULL; + if (!paths[k]) + continue; + fds[2*k+1] = safe_close(fds[2*k+1]); f = take_fdopen(&fds[2*k], "r"); @@ -2346,6 +2405,13 @@ int dissected_image_acquire_metadata(DissectedImage *m) { log_debug_errno(r, "Failed to read OS release file: %m"); break; + + case META_EXTENSION_RELEASE: + r = load_env_file_pairs(f, "extension-release", &extension_release); + if (r < 0) + log_debug_errno(r, "Failed to read extension release file: %m"); + + break; } } @@ -2369,9 +2435,10 @@ int dissected_image_acquire_metadata(DissectedImage *m) { m->machine_id = machine_id; strv_free_and_replace(m->machine_info, machine_info); strv_free_and_replace(m->os_release, os_release); + strv_free_and_replace(m->extension_release, extension_release); finish: - for (k = 0; k < n_meta_initialized; k++) + for (unsigned k = 0; k < n_meta_initialized; k++) safe_close_pair(fds + 2*k); return r; @@ -2554,4 +2621,108 @@ static const char *const partition_designator_table[] = { [PARTITION_VAR] = "var", }; +int verity_dissect_and_mount( + const char *src, + const char *dest, + const MountOptions *options, + const char *required_host_os_release_id, + const char *required_host_os_release_version_id, + const char *required_host_os_release_sysext_level) { + + _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_(verity_settings_done) VeritySettings verity = VERITY_SETTINGS_DEFAULT; + DissectImageFlags dissect_image_flags; + int r; + + assert(src); + assert(dest); + + r = verity_settings_load(&verity, src, NULL, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to load root hash: %m"); + + dissect_image_flags = verity.data_path ? DISSECT_IMAGE_NO_PARTITION_TABLE : 0; + + r = loop_device_make_by_path( + src, + -1, + verity.data_path ? 0 : LO_FLAGS_PARTSCAN, + &loop_device); + if (r < 0) + return log_debug_errno(r, "Failed to create loop device for image: %m"); + + r = dissect_image( + loop_device->fd, + &verity, + options, + dissect_image_flags, + &dissected_image); + /* No partition table? Might be a single-filesystem image, try again */ + if (!verity.data_path && r == -ENOPKG) + r = dissect_image( + loop_device->fd, + &verity, + options, + dissect_image_flags|DISSECT_IMAGE_NO_PARTITION_TABLE, + &dissected_image); + if (r < 0) + return log_debug_errno(r, "Failed to dissect image: %m"); + + r = dissected_image_decrypt( + dissected_image, + NULL, + &verity, + dissect_image_flags, + &decrypted_image); + if (r < 0) + return log_debug_errno(r, "Failed to decrypt dissected image: %m"); + + r = mkdir_p_label(dest, 0755); + if (r < 0) + return log_debug_errno(r, "Failed to create destination directory %s: %m", dest); + r = umount_recursive(dest, 0); + if (r < 0) + return log_debug_errno(r, "Failed to umount under destination directory %s: %m", dest); + + r = dissected_image_mount(dissected_image, dest, UID_INVALID, dissect_image_flags); + if (r < 0) + return log_debug_errno(r, "Failed to mount image: %m"); + + /* If we got os-release values from the caller, then we need to match them with the image's + * extension-release.d/ content. Return -EINVAL if there's any mismatch. + * First, check the distro ID. If that matches, then check the new SYSEXT_LEVEL value if + * available, or else fallback to VERSION_ID. */ + if (required_host_os_release_id && + (required_host_os_release_version_id || required_host_os_release_sysext_level)) { + _cleanup_strv_free_ char **extension_release = NULL; + + r = load_extension_release_pairs(dest, dissected_image->image_name, &extension_release); + if (r < 0) + return log_debug_errno(r, "Failed to parse image %s extension-release metadata: %m", dissected_image->image_name); + + r = extension_release_validate( + dissected_image->image_name, + required_host_os_release_id, + required_host_os_release_version_id, + required_host_os_release_sysext_level, + extension_release); + if (r == 0) + return log_debug_errno(SYNTHETIC_ERRNO(ESTALE), "Image %s extension-release metadata does not match the root's", dissected_image->image_name); + if (r < 0) + return log_debug_errno(r, "Failed to compare image %s extension-release metadata with the root's os-release: %m", dissected_image->image_name); + } + + if (decrypted_image) { + r = decrypted_image_relinquish(decrypted_image); + if (r < 0) + return log_debug_errno(r, "Failed to relinquish decrypted image: %m"); + } + + loop_device_relinquish(loop_device); + + return 0; +} + DEFINE_STRING_TABLE_LOOKUP(partition_designator, PartitionDesignator); diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 3b30e08f9..ddadda1c0 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -45,7 +45,7 @@ typedef enum PartitionDesignator { PARTITION_TMP, PARTITION_VAR, _PARTITION_DESIGNATOR_MAX, - _PARTITION_DESIGNATOR_INVALID = -1 + _PARTITION_DESIGNATOR_INVALID = -EINVAL, } PartitionDesignator; static inline PartitionDesignator PARTITION_VERITY_OF(PartitionDesignator p) { @@ -86,7 +86,7 @@ typedef enum DissectImageFlags { DISSECT_IMAGE_FSCK = 1 << 11, /* File system check the partition before mounting (no effect when combined with DISSECT_IMAGE_READ_ONLY) */ DISSECT_IMAGE_NO_PARTITION_TABLE = 1 << 12, /* Only recognize single file system images */ DISSECT_IMAGE_VERITY_SHARE = 1 << 13, /* When activating a verity device, reuse existing one if already open */ - DISSECT_IMAGE_MKDIR = 1 << 14, /* Make directory to mount right before mounting, if missing */ + DISSECT_IMAGE_MKDIR = 1 << 14, /* Make top-level directory to mount right before mounting, if missing */ } DissectImageFlags; struct DissectedImage { @@ -97,10 +97,12 @@ struct DissectedImage { DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX]; + char *image_name; char *hostname; sd_id128_t machine_id; char **machine_info; char **os_release; + char **extension_release; }; struct MountOptions { @@ -161,3 +163,5 @@ bool dissected_image_can_do_verity(const DissectedImage *image, PartitionDesigna bool dissected_image_has_verity(const DissectedImage *image, PartitionDesignator d); int mount_image_privately_interactively(const char *path, DissectImageFlags flags, char **ret_directory, LoopDevice **ret_loop_device, DecryptedImage **ret_decrypted_image); + +int verity_dissect_and_mount(const char *src, const char *dest, const MountOptions *options, const char *required_host_os_release_id, const char *required_host_os_release_version_id, const char *required_host_os_release_sysext_level); diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index ec42b29d0..e43aa1288 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -743,12 +743,12 @@ int dns_name_reverse(int family, const union in_addr_union *a, char **ret) { return 0; } -int dns_name_address(const char *p, int *family, union in_addr_union *address) { +int dns_name_address(const char *p, int *ret_family, union in_addr_union *ret_address) { int r; assert(p); - assert(family); - assert(address); + assert(ret_family); + assert(ret_address); r = dns_name_endswith(p, "in-addr.arpa"); if (r < 0) @@ -777,11 +777,11 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) { if (r <= 0) return r; - *family = AF_INET; - address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | - ((uint32_t) a[2] << 16) | - ((uint32_t) a[1] << 8) | - (uint32_t) a[0]); + *ret_family = AF_INET; + ret_address->in.s_addr = htobe32(((uint32_t) a[3] << 24) | + ((uint32_t) a[2] << 16) | + ((uint32_t) a[1] << 8) | + (uint32_t) a[0]); return 1; } @@ -822,11 +822,14 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) { if (r <= 0) return r; - *family = AF_INET6; - address->in6 = a; + *ret_family = AF_INET6; + ret_address->in6 = a; return 1; } + *ret_family = AF_UNSPEC; + *ret_address = IN_ADDR_NULL; + return 0; } @@ -1308,18 +1311,19 @@ int dns_name_apply_idna(const char *name, char **ret) { if (r != IDN2_OK) { log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s", t, r, sym_idn2_strerror(r)); + *ret = NULL; return 0; } if (!streq_ptr(name, s)) { log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", name, t, s); + *ret = NULL; return 0; } } *ret = TAKE_PTR(t); - return 1; /* *ret has been written */ } @@ -1329,6 +1333,7 @@ int dns_name_apply_idna(const char *name, char **ret) { return 0; if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL)) return -ENOSPC; + return -EINVAL; #elif HAVE_LIBIDN _cleanup_free_ char *buf = NULL; diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 77f596294..c25fcaacc 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -6,24 +6,10 @@ #include #include +#include "dns-def.h" #include "hashmap.h" #include "in-addr-util.h" -/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */ -#define DNS_LABEL_MAX 63 - -/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */ -#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) - -/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ -#define DNS_HOSTNAME_MAX 253 - -/* Maximum length of a full hostname, on the wire, including the final NUL byte */ -#define DNS_WIRE_FORMAT_HOSTNAME_MAX 255 - -/* Maximum number of labels per valid hostname */ -#define DNS_N_LABELS_MAX 127 - typedef enum DNSLabelFlags { DNS_LABEL_LDH = 1 << 0, /* Follow the "LDH" rule — only letters, digits, and internal hyphens. */ DNS_LABEL_NO_ESCAPES = 1 << 1, /* Do not treat backslashes specially */ diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index 20f70da31..ee32b0b09 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -783,13 +783,34 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat return 0; } +bool efi_has_tpm2(void) { + static int cache = -1; + + /* Returns whether the system has a TPM2 chip which is known to the EFI firmware. */ + + if (cache < 0) { + + /* First, check if we are on an EFI boot at all. */ + if (!is_efi_boot()) + cache = false; + else { + /* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see: + * https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf + * This table exists whenever the firmware is hooked up to TPM2. */ + cache = access("/sys/firmware/acpi/tables/TPM2", F_OK) >= 0; + if (!cache && errno != ENOENT) + log_debug_errno(errno, "Unable to test whether /sys/firmware/acpi/tables/TPM2 exists, assuming it doesn't: %m"); + } + } + + return cache; +} + #endif bool efi_loader_entry_name_valid(const char *s) { - if (isempty(s)) - return false; - if (strlen(s) > FILENAME_MAX) /* Make sure entry names fit in filenames */ + if (!filename_is_valid(s)) /* Make sure entry names fit in filenames */ return false; return in_charset(s, ALPHANUMERICAL "+-_."); diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h index 34476f4ce..bc5769bb6 100644 --- a/src/shared/efi-loader.h +++ b/src/shared/efi-loader.h @@ -1,10 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -#include "efivars.h" - #include +#include "efi-loader-features.h" +#include "efivars.h" + #if ENABLE_EFI int efi_reboot_to_firmware_supported(void); @@ -28,6 +29,8 @@ int efi_loader_get_features(uint64_t *ret); int efi_loader_get_config_timeout_one_shot(usec_t *ret); int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat); +bool efi_has_tpm2(void); + #else static inline int efi_reboot_to_firmware_supported(void) { @@ -90,6 +93,10 @@ static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct st return -EOPNOTSUPP; } +static inline bool efi_has_tpm2(void) { + return false; +} + #endif bool efi_loader_entry_name_valid(const char *s); diff --git a/src/shared/ethtool-util.c b/src/shared/ethtool-util.c index e6fab262f..654d36a83 100644 --- a/src/shared/ethtool-util.c +++ b/src/shared/ethtool-util.c @@ -150,6 +150,8 @@ static const char* const ethtool_link_mode_bit_table[] = { [ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT] = "400000baselr4-er4-fr4-full", [ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT] = "400000basedr4-full", [ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT] = "400000basecr4-full", + [ETHTOOL_LINK_MODE_100baseFX_Half_BIT] = "100basefx-half", + [ETHTOOL_LINK_MODE_100baseFX_Full_BIT] = "100basefx-full", }; /* Make sure the array is large enough to fit all bits */ assert_cc((ELEMENTSOF(ethtool_link_mode_bit_table)-1) / 32 < N_ADVERTISE); @@ -1090,7 +1092,7 @@ int config_parse_advertise(const char *unit, /* We reuse the kernel provided enum which does not contain negative value. So, the cast * below is mandatory. Otherwise, the check below always passes and access an invalid address. */ if ((int) mode < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, + log_syntax(unit, LOG_WARNING, filename, line, mode, "Failed to parse advertise mode, ignoring: %s", w); continue; } diff --git a/src/shared/ethtool-util.h b/src/shared/ethtool-util.h index f94b3e15b..11e290668 100644 --- a/src/shared/ethtool-util.h +++ b/src/shared/ethtool-util.h @@ -15,7 +15,7 @@ typedef enum Duplex { DUP_HALF = DUPLEX_HALF, DUP_FULL = DUPLEX_FULL, _DUP_MAX, - _DUP_INVALID = -1 + _DUP_INVALID = -EINVAL, } Duplex; typedef enum WakeOnLan { @@ -28,7 +28,7 @@ typedef enum WakeOnLan { WOL_MAGICSECURE, WOL_OFF, _WOL_MAX, - _WOL_INVALID = -1 + _WOL_INVALID = -EINVAL, } WakeOnLan; typedef enum NetDevFeature { @@ -40,7 +40,7 @@ typedef enum NetDevFeature { NET_DEV_FEAT_TSO, NET_DEV_FEAT_TSO6, _NET_DEV_FEAT_MAX, - _NET_DEV_FEAT_INVALID = -1 + _NET_DEV_FEAT_INVALID = -EINVAL, } NetDevFeature; typedef enum NetDevPort { @@ -53,7 +53,7 @@ typedef enum NetDevPort { NET_DEV_PORT_NONE = PORT_NONE, NET_DEV_PORT_OTHER = PORT_OTHER, _NET_DEV_PORT_MAX, - _NET_DEV_PORT_INVALID = -1 + _NET_DEV_PORT_INVALID = -EINVAL, } NetDevPort; #define ETHTOOL_LINK_MODE_MASK_MAX_KERNEL_NU32 (SCHAR_MAX) diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 61ee3b18d..031ca4cb4 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -11,11 +11,13 @@ #include "conf-files.h" #include "env-file.h" #include "env-util.h" +#include "errno-util.h" #include "exec-util.h" #include "fd-util.h" #include "fileio.h" #include "hashmap.h" #include "macro.h" +#include "missing_syscall.h" #include "process-util.h" #include "rlimit-util.h" #include "serialize.h" @@ -32,8 +34,7 @@ /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); -static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) { - +static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid, bool set_systemd_exec_pid) { pid_t _pid; int r; @@ -56,6 +57,12 @@ static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) { (void) rlimit_nofile_safe(); + if (set_systemd_exec_pid) { + r = setenv_systemd_exec_pid(false); + if (r < 0) + log_warning_errno(r, "Failed to set $SYSTEMD_EXEC_PID, ignoring: %m"); + } + if (!argv) { _argv[0] = (char*) path; _argv[1] = NULL; @@ -131,7 +138,7 @@ static int do_execute( return log_error_errno(fd, "Failed to open serialization file: %m"); } - r = do_spawn(t, argv, fd, &pid); + r = do_spawn(t, argv, fd, &pid, FLAGS_SET(flags, EXEC_DIR_SET_SYSTEMD_EXEC_PID)); if (r <= 0) continue; @@ -271,18 +278,12 @@ static int gather_environment_generate(int fd, void *arg) { return r; STRV_FOREACH_PAIR(x, y, new) { - char *p; - if (!env_name_is_valid(*x)) { log_warning("Invalid variable assignment \"%s=...\", ignoring.", *x); continue; } - p = strjoin(*x, "=", *y); - if (!p) - return -ENOMEM; - - r = strv_env_replace(env, p); + r = strv_env_assign(env, *x, *y); if (r < 0) return r; @@ -290,7 +291,7 @@ static int gather_environment_generate(int fd, void *arg) { return -errno; } - return r; + return 0; } static int gather_environment_collect(int fd, void *arg) { @@ -374,10 +375,9 @@ int exec_command_flags_from_strv(char **ex_opts, ExecCommandFlags *flags) { STRV_FOREACH(opt, ex_opts) { ex_flag = exec_command_flags_from_string(*opt); - if (ex_flag >= 0) - ret_flags |= ex_flag; - else - return -EINVAL; + if (ex_flag < 0) + return ex_flag; + ret_flags |= ex_flag; } *flags = ret_flags; @@ -393,6 +393,9 @@ int exec_command_flags_to_strv(ExecCommandFlags flags, char ***ex_opts) { assert(ex_opts); + if (flags < 0) + return flags; + for (i = 0; it != 0; it &= ~(1 << i), i++) { if (FLAGS_SET(flags, (1 << i))) { str = exec_command_flags_to_string(1 << i); @@ -444,3 +447,26 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) { else return 1 << idx; } + +int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) { +#if ENABLE_FEXECVE + execveat(executable_fd, "", argv, envp, AT_EMPTY_PATH); + + if (IN_SET(errno, ENOSYS, ENOENT) || ERRNO_IS_PRIVILEGE(errno)) + /* Old kernel or a script or an overzealous seccomp filter? Let's fall back to execve(). + * + * fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a + * script interpreter with a first line that begins with the characters #!) and the + * close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This + * error occurs because, by the time the script interpreter is executed, fd has already been + * closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd + * if it refers to a script." + * + * Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at + * least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks + * scripts which make use of $0. Thus, let's fall back to execve() in this case. + */ +#endif + execve(executable, argv, envp); + return -errno; +} diff --git a/src/shared/exec-util.h b/src/shared/exec-util.h index a69d57c7a..9ce5324de 100644 --- a/src/shared/exec-util.h +++ b/src/shared/exec-util.h @@ -15,9 +15,10 @@ enum { }; typedef enum { - EXEC_DIR_NONE = 0, /* No execdir flags */ - EXEC_DIR_PARALLEL = 1 << 0, /* Execute scripts in parallel, if possible */ - EXEC_DIR_IGNORE_ERRORS = 1 << 1, /* Ignore non-zero exit status of scripts */ + EXEC_DIR_NONE = 0, /* No execdir flags */ + EXEC_DIR_PARALLEL = 1 << 0, /* Execute scripts in parallel, if possible */ + EXEC_DIR_IGNORE_ERRORS = 1 << 1, /* Ignore non-zero exit status of scripts */ + EXEC_DIR_SET_SYSTEMD_EXEC_PID = 1 << 2, /* Set $SYSTEMD_EXEC_PID environment variable */ } ExecDirFlags; typedef enum ExecCommandFlags { @@ -26,7 +27,7 @@ typedef enum ExecCommandFlags { EXEC_COMMAND_NO_SETUID = 1 << 2, EXEC_COMMAND_AMBIENT_MAGIC = 1 << 3, EXEC_COMMAND_NO_ENV_EXPAND = 1 << 4, - _EXEC_COMMAND_FLAGS_INVALID = -1, + _EXEC_COMMAND_FLAGS_INVALID = -EINVAL, } ExecCommandFlags; int execute_directories( @@ -45,3 +46,5 @@ extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX]; const char* exec_command_flags_to_string(ExecCommandFlags i); ExecCommandFlags exec_command_flags_from_string(const char *s); + +int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]); diff --git a/src/shared/exit-status.c b/src/shared/exit-status.c index b71dd7afd..db978fb89 100644 --- a/src/shared/exit-status.c +++ b/src/shared/exit-status.c @@ -18,8 +18,8 @@ const ExitStatusMapping exit_status_mappings[256] = { * 8…63 │ (Currently unmapped) * 64…78 │ BSD defined exit codes * 79…199 │ (Currently unmapped) - * 200…242 │ systemd's private error codes (might be extended to 254 in future development) - * 243…254 │ (Currently unmapped, but see above) + * 200…243 │ systemd's private error codes (might be extended to 254 in future development) + * 244…254 │ (Currently unmapped, but see above) * * 255 │ EXIT_EXCEPTION (We use this to propagate exit-by-signal events. It's frequently used by others apps (like bash) * │ to indicate exit reason that cannot really be expressed in a single exit status value — such as a propagated diff --git a/src/shared/extension-release.c b/src/shared/extension-release.c new file mode 100644 index 000000000..29cbecbf5 --- /dev/null +++ b/src/shared/extension-release.c @@ -0,0 +1,96 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "env-util.h" +#include "extension-release.h" +#include "log.h" +#include "os-util.h" +#include "strv.h" + +int extension_release_validate( + const char *name, + const char *host_os_release_id, + const char *host_os_release_version_id, + const char *host_os_release_sysext_level, + char **extension_release) { + + const char *extension_release_id = NULL, *extension_release_sysext_level = NULL; + + assert(name); + assert(!isempty(host_os_release_id)); + + /* Now that we can look into the extension image, let's see if the OS version is compatible */ + if (strv_isempty(extension_release)) { + log_debug("Extension '%s' carries no extension-release data, ignoring extension.", name); + return 0; + } + + extension_release_id = strv_env_pairs_get(extension_release, "ID"); + if (isempty(extension_release_id)) { + log_debug("Extension '%s' does not contain ID in extension-release but requested to match '%s'", + name, strna(host_os_release_id)); + return 0; + } + + if (!streq_ptr(host_os_release_id, extension_release_id)) { + log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.", + name, strna(extension_release_id), strna(host_os_release_id)); + return 0; + } + + /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */ + if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) { + log_debug("No version info on the host (rolling release?), but ID in %s matched.", name); + return 1; + } + + /* If the extension has a sysext API level declared, then it must match the host API + * level. Otherwise, compare OS version as a whole */ + extension_release_sysext_level = strv_env_pairs_get(extension_release, "SYSEXT_LEVEL"); + if (!isempty(host_os_release_sysext_level) && !isempty(extension_release_sysext_level)) { + if (!streq_ptr(host_os_release_sysext_level, extension_release_sysext_level)) { + log_debug("Extension '%s' is for sysext API level '%s', but running on sysext API level '%s'", + name, strna(extension_release_sysext_level), strna(host_os_release_sysext_level)); + return 0; + } + } else if (!isempty(host_os_release_version_id)) { + const char *extension_release_version_id; + + extension_release_version_id = strv_env_pairs_get(extension_release, "VERSION_ID"); + if (isempty(extension_release_version_id)) { + log_debug("Extension '%s' does not contain VERSION_ID in extension-release but requested to match '%s'", + name, strna(host_os_release_version_id)); + return 0; + } + + if (!streq_ptr(host_os_release_version_id, extension_release_version_id)) { + log_debug("Extension '%s' is for OS '%s', but deployed on top of '%s'.", + name, strna(extension_release_version_id), strna(host_os_release_version_id)); + return 0; + } + } else if (isempty(host_os_release_version_id) && isempty(host_os_release_sysext_level)) { + /* Rolling releases do not typically set VERSION_ID (eg: ArchLinux) */ + log_debug("No version info on the host (rolling release?), but ID in %s matched.", name); + return 1; + } + + log_debug("Version info of extension '%s' matches host.", name); + return 1; +} + +int parse_env_extension_hierarchies(char ***ret_hierarchies) { + _cleanup_free_ char **l = NULL; + int r; + + r = getenv_path_list("SYSTEMD_SYSEXT_HIERARCHIES", &l); + if (r == -ENXIO) { + /* Default when unset */ + l = strv_new("/usr", "/opt"); + if (!l) + return -ENOMEM; + } else if (r < 0) + return r; + + *ret_hierarchies = TAKE_PTR(l); + return 0; +} diff --git a/src/shared/extension-release.h b/src/shared/extension-release.h new file mode 100644 index 000000000..d026a9b22 --- /dev/null +++ b/src/shared/extension-release.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +/* Given an image name (for logging purposes), a set of os-release values from the host and a key-value pair + * vector of extension-release variables, check that the distro and (system extension level or distro + * version) match and return 1, and 0 otherwise. */ +int extension_release_validate( + const char *name, + const char *host_os_release_id, + const char *host_os_release_version_id, + const char *host_os_release_sysext_level, + char **extension_release); + +/* Parse SYSTEMD_SYSEXT_HIERARCHIES and if not set, return "/usr /opt" */ +int parse_env_extension_hierarchies(char ***ret_hierarchies); diff --git a/src/shared/firewall-util-iptables.c b/src/shared/firewall-util-iptables.c new file mode 100644 index 000000000..982c61d8f --- /dev/null +++ b/src/shared/firewall-util-iptables.c @@ -0,0 +1,350 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* Temporary work-around for broken glibc vs. linux kernel header definitions + * This is already fixed upstream, remove this when distributions have updated. + */ +#define _NET_IF_H 1 + +#include +#include +#include +#include +#include +#include +#ifndef IFNAMSIZ +#define IFNAMSIZ 16 +#endif +#include +#include +#include +#include +#include + +#include "alloc-util.h" +#include "firewall-util.h" +#include "firewall-util-private.h" +#include "in-addr-util.h" +#include "macro.h" +#include "socket-util.h" + +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct xtc_handle*, iptc_free, NULL); + +static int entry_fill_basics( + struct ipt_entry *entry, + int protocol, + const char *in_interface, + const union in_addr_union *source, + unsigned source_prefixlen, + const char *out_interface, + const union in_addr_union *destination, + unsigned destination_prefixlen) { + + assert(entry); + + if (out_interface && !ifname_valid(out_interface)) + return -EINVAL; + if (in_interface && !ifname_valid(in_interface)) + return -EINVAL; + + entry->ip.proto = protocol; + + if (in_interface) { + size_t l; + + l = strlen(in_interface); + assert(l < sizeof entry->ip.iniface); + assert(l < sizeof entry->ip.iniface_mask); + + strcpy(entry->ip.iniface, in_interface); + memset(entry->ip.iniface_mask, 0xFF, l + 1); + } + if (source) { + entry->ip.src = source->in; + in4_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen); + } + + if (out_interface) { + size_t l = strlen(out_interface); + assert(l < sizeof entry->ip.outiface); + assert(l < sizeof entry->ip.outiface_mask); + + strcpy(entry->ip.outiface, out_interface); + memset(entry->ip.outiface_mask, 0xFF, l + 1); + } + if (destination) { + entry->ip.dst = destination->in; + in4_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen); + } + + return 0; +} + +int fw_iptables_add_masquerade( + bool add, + int af, + const union in_addr_union *source, + unsigned source_prefixlen) { + + static const xt_chainlabel chain = "POSTROUTING"; + _cleanup_(iptc_freep) struct xtc_handle *h = NULL; + struct ipt_entry *entry, *mask; + struct ipt_entry_target *t; + size_t sz; + struct nf_nat_ipv4_multi_range_compat *mr; + int r, protocol = 0; + const char *out_interface = NULL; + const union in_addr_union *destination = NULL; + unsigned destination_prefixlen = 0; + + if (af != AF_INET) + return -EOPNOTSUPP; + + if (!source || source_prefixlen == 0) + return -EINVAL; + + h = iptc_init("nat"); + if (!h) + return -errno; + + sz = XT_ALIGN(sizeof(struct ipt_entry)) + + XT_ALIGN(sizeof(struct ipt_entry_target)) + + XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); + + /* Put together the entry we want to add or remove */ + entry = alloca0(sz); + entry->next_offset = sz; + entry->target_offset = XT_ALIGN(sizeof(struct ipt_entry)); + r = entry_fill_basics(entry, protocol, NULL, source, source_prefixlen, out_interface, destination, destination_prefixlen); + if (r < 0) + return r; + + /* Fill in target part */ + t = ipt_get_target(entry); + t->u.target_size = + XT_ALIGN(sizeof(struct ipt_entry_target)) + + XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); + strncpy(t->u.user.name, "MASQUERADE", sizeof(t->u.user.name)); + mr = (struct nf_nat_ipv4_multi_range_compat*) t->data; + mr->rangesize = 1; + + /* Create a search mask entry */ + mask = alloca(sz); + memset(mask, 0xFF, sz); + + if (add) { + if (iptc_check_entry(chain, entry, (unsigned char*) mask, h)) + return 0; + if (errno != ENOENT) /* if other error than not existing yet, fail */ + return -errno; + + if (!iptc_insert_entry(chain, entry, 0, h)) + return -errno; + } else { + if (!iptc_delete_entry(chain, entry, (unsigned char*) mask, h)) { + if (errno == ENOENT) /* if it's already gone, all is good! */ + return 0; + + return -errno; + } + } + + if (!iptc_commit(h)) + return -errno; + + return 0; +} + +int fw_iptables_add_local_dnat( + bool add, + int af, + int protocol, + uint16_t local_port, + const union in_addr_union *remote, + uint16_t remote_port, + const union in_addr_union *previous_remote) { + + static const xt_chainlabel chain_pre = "PREROUTING", chain_output = "OUTPUT"; + _cleanup_(iptc_freep) struct xtc_handle *h = NULL; + struct ipt_entry *entry, *mask; + struct ipt_entry_target *t; + struct ipt_entry_match *m; + struct xt_addrtype_info_v1 *at; + struct nf_nat_ipv4_multi_range_compat *mr; + size_t sz, msz; + int r; + const char *in_interface = NULL; + const union in_addr_union *source = NULL; + unsigned source_prefixlen = 0; + const union in_addr_union *destination = NULL; + unsigned destination_prefixlen = 0; + + assert(add || !previous_remote); + + if (af != AF_INET) + return -EOPNOTSUPP; + + if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP)) + return -EOPNOTSUPP; + + if (local_port <= 0) + return -EINVAL; + + if (remote_port <= 0) + return -EINVAL; + + h = iptc_init("nat"); + if (!h) + return -errno; + + sz = XT_ALIGN(sizeof(struct ipt_entry)) + + XT_ALIGN(sizeof(struct ipt_entry_match)) + + XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) + + XT_ALIGN(sizeof(struct ipt_entry_target)) + + XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); + + if (protocol == IPPROTO_TCP) + msz = XT_ALIGN(sizeof(struct ipt_entry_match)) + + XT_ALIGN(sizeof(struct xt_tcp)); + else + msz = XT_ALIGN(sizeof(struct ipt_entry_match)) + + XT_ALIGN(sizeof(struct xt_udp)); + + sz += msz; + + /* Fill in basic part */ + entry = alloca0(sz); + entry->next_offset = sz; + entry->target_offset = + XT_ALIGN(sizeof(struct ipt_entry)) + + XT_ALIGN(sizeof(struct ipt_entry_match)) + + XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) + + msz; + r = entry_fill_basics(entry, protocol, in_interface, source, source_prefixlen, NULL, destination, destination_prefixlen); + if (r < 0) + return r; + + /* Fill in first match */ + m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry))); + m->u.match_size = msz; + if (protocol == IPPROTO_TCP) { + struct xt_tcp *tcp; + + strncpy(m->u.user.name, "tcp", sizeof(m->u.user.name)); + tcp = (struct xt_tcp*) m->data; + tcp->dpts[0] = tcp->dpts[1] = local_port; + tcp->spts[0] = 0; + tcp->spts[1] = 0xFFFF; + + } else { + struct xt_udp *udp; + + strncpy(m->u.user.name, "udp", sizeof(m->u.user.name)); + udp = (struct xt_udp*) m->data; + udp->dpts[0] = udp->dpts[1] = local_port; + udp->spts[0] = 0; + udp->spts[1] = 0xFFFF; + } + + /* Fill in second match */ + m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz); + m->u.match_size = + XT_ALIGN(sizeof(struct ipt_entry_match)) + + XT_ALIGN(sizeof(struct xt_addrtype_info_v1)); + strncpy(m->u.user.name, "addrtype", sizeof(m->u.user.name)); + m->u.user.revision = 1; + at = (struct xt_addrtype_info_v1*) m->data; + at->dest = XT_ADDRTYPE_LOCAL; + + /* Fill in target part */ + t = ipt_get_target(entry); + t->u.target_size = + XT_ALIGN(sizeof(struct ipt_entry_target)) + + XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); + strncpy(t->u.user.name, "DNAT", sizeof(t->u.user.name)); + mr = (struct nf_nat_ipv4_multi_range_compat*) t->data; + mr->rangesize = 1; + mr->range[0].flags = NF_NAT_RANGE_PROTO_SPECIFIED|NF_NAT_RANGE_MAP_IPS; + mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr; + if (protocol == IPPROTO_TCP) + mr->range[0].min.tcp.port = mr->range[0].max.tcp.port = htobe16(remote_port); + else + mr->range[0].min.udp.port = mr->range[0].max.udp.port = htobe16(remote_port); + + mask = alloca0(sz); + memset(mask, 0xFF, sz); + + if (add) { + /* Add the PREROUTING rule, if it is missing so far */ + if (!iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) { + if (errno != ENOENT) + return -EINVAL; + + if (!iptc_insert_entry(chain_pre, entry, 0, h)) + return -errno; + } + + /* If a previous remote is set, remove its entry */ + if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) { + mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr; + + if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) { + if (errno != ENOENT) + return -errno; + } + + mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr; + } + + /* Add the OUTPUT rule, if it is missing so far */ + if (!in_interface) { + + /* Don't apply onto loopback addresses */ + if (!destination) { + entry->ip.dst.s_addr = htobe32(0x7F000000); + entry->ip.dmsk.s_addr = htobe32(0xFF000000); + entry->ip.invflags = IPT_INV_DSTIP; + } + + if (!iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) { + if (errno != ENOENT) + return -errno; + + if (!iptc_insert_entry(chain_output, entry, 0, h)) + return -errno; + } + + /* If a previous remote is set, remove its entry */ + if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) { + mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr; + + if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) { + if (errno != ENOENT) + return -errno; + } + } + } + } else { + if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) { + if (errno != ENOENT) + return -errno; + } + + if (!in_interface) { + if (!destination) { + entry->ip.dst.s_addr = htobe32(0x7F000000); + entry->ip.dmsk.s_addr = htobe32(0xFF000000); + entry->ip.invflags = IPT_INV_DSTIP; + } + + if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) { + if (errno != ENOENT) + return -errno; + } + } + } + + if (!iptc_commit(h)) + return -errno; + + return 0; +} diff --git a/src/shared/firewall-util-nft.c b/src/shared/firewall-util-nft.c new file mode 100644 index 000000000..ecabc5fc4 --- /dev/null +++ b/src/shared/firewall-util-nft.c @@ -0,0 +1,1070 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sd-netlink.h" + +#include "alloc-util.h" +#include "firewall-util.h" +#include "firewall-util-private.h" +#include "in-addr-util.h" +#include "macro.h" +#include "socket-util.h" +#include "time-util.h" + +#define NFT_SYSTEMD_DNAT_MAP_NAME "map_port_ipport" +#define NFT_SYSTEMD_TABLE_NAME "io.systemd.nat" +#define NFT_SYSTEMD_MASQ_SET_NAME "masq_saddr" + +#define NFNL_DEFAULT_TIMEOUT_USECS (1ULL * USEC_PER_SEC) + +#define UDP_DPORT_OFFSET 2 + +static int nfnl_netlink_sendv(sd_netlink *nfnl, + sd_netlink_message *messages[], + size_t msgcount) { + _cleanup_free_ uint32_t *serial = NULL; + size_t i; + int r; + + assert(msgcount > 0); + + r = sd_netlink_sendv(nfnl, messages, msgcount, &serial); + if (r < 0) + return r; + + r = 0; + for (i = 1; i < msgcount - 1; i++) { + int tmp; + + /* If message is an error, this returns embedded errno */ + tmp = sd_netlink_read(nfnl, serial[i], NFNL_DEFAULT_TIMEOUT_USECS, NULL); + if (tmp < 0 && r == 0) + r = tmp; + } + + return r; +} + +static int nfnl_add_open_expr_container(sd_netlink_message *m, const char *name) { + int r; + + r = sd_netlink_message_open_array(m, NFTA_LIST_ELEM); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_EXPR_NAME, name); + if (r < 0) + return r; + + return sd_netlink_message_open_container_union(m, NFTA_EXPR_DATA, name); +} + +static int nfnl_add_expr_fib(sd_netlink_message *m, uint32_t nft_fib_flags, + enum nft_fib_result result, + enum nft_registers dreg) { + int r; + + r = nfnl_add_open_expr_container(m, "fib"); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_FIB_FLAGS, htobe32(nft_fib_flags)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_FIB_RESULT, htobe32(result)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_FIB_DREG, htobe32(dreg)); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_meta(sd_netlink_message *m, enum nft_meta_keys key, + enum nft_registers dreg) { + int r; + + r = nfnl_add_open_expr_container(m, "meta"); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_META_KEY, htobe32(key)); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_META_DREG, htobe32(dreg)); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_payload(sd_netlink_message *m, enum nft_payload_bases pb, + uint32_t offset, uint32_t len, enum nft_registers dreg) { + int r; + + r = nfnl_add_open_expr_container(m, "payload"); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_DREG, htobe32(dreg)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_BASE, htobe32(pb)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_OFFSET, htobe32(offset)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_PAYLOAD_LEN, htobe32(len)); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_lookup_set_data(sd_netlink_message *m, const char *set_name, + enum nft_registers sreg) { + int r; + + r = nfnl_add_open_expr_container(m, "lookup"); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_LOOKUP_SET, set_name); + if (r < 0) + return r; + + return sd_netlink_message_append_u32(m, NFTA_LOOKUP_SREG, htobe32(sreg)); +} + +static int nfnl_add_expr_lookup_set(sd_netlink_message *m, const char *set_name, + enum nft_registers sreg) { + int r; + + r = nfnl_add_expr_lookup_set_data(m, set_name, sreg); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_lookup_map(sd_netlink_message *m, const char *set_name, + enum nft_registers sreg, enum nft_registers dreg) { + int r; + + r = nfnl_add_expr_lookup_set_data(m, set_name, sreg); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_LOOKUP_DREG, htobe32(dreg)); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_data(sd_netlink_message *m, int attr, const void *data, uint32_t dlen) { + int r; + + r = sd_netlink_message_open_container(m, attr); + if (r < 0) + return r; + r = sd_netlink_message_append_data(m, NFTA_DATA_VALUE, data, dlen); + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); /* attr */ +} + +static int nfnl_add_expr_cmp_data(sd_netlink_message *m, const void *data, uint32_t dlen) { + return nfnl_add_expr_data(m, NFTA_CMP_DATA, data, dlen); +} + +static int nfnl_add_expr_cmp(sd_netlink_message *m, enum nft_cmp_ops cmp_op, + enum nft_registers sreg, const void *data, uint32_t dlen) { + int r; + + r = nfnl_add_open_expr_container(m, "cmp"); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_CMP_OP, htobe32(cmp_op)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_CMP_SREG, htobe32(sreg)); + if (r < 0) + return r; + + r = nfnl_add_expr_cmp_data(m, data, dlen); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_bitwise(sd_netlink_message *m, + enum nft_registers sreg, + enum nft_registers dreg, + const void *and, + const void *xor, uint32_t len) { + int r; + + r = nfnl_add_open_expr_container(m, "bitwise"); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_BITWISE_SREG, htobe32(sreg)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_BITWISE_DREG, htobe32(dreg)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_BITWISE_LEN, htobe32(len)); + if (r < 0) + return r; + + r = nfnl_add_expr_data(m, NFTA_BITWISE_MASK, and, len); + if (r < 0) + return r; + + r = nfnl_add_expr_data(m, NFTA_BITWISE_XOR, xor, len); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_EXPR_DATA */ + if (r < 0) + return r; + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int nfnl_add_expr_dnat(sd_netlink_message *m, + int family, + enum nft_registers areg, + enum nft_registers preg) { + int r; + + r = nfnl_add_open_expr_container(m, "nat"); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_NAT_TYPE, htobe32(NFT_NAT_DNAT)); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_NAT_FAMILY, htobe32(family)); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_NAT_REG_ADDR_MIN, htobe32(areg)); + if (r < 0) + return r; + r = sd_netlink_message_append_u32(m, NFTA_NAT_REG_PROTO_MIN, htobe32(preg)); + if (r < 0) + return r; + r = sd_netlink_message_close_container(m); + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); +} + +static int nfnl_add_expr_masq(sd_netlink_message *m) { + int r; + + r = sd_netlink_message_open_array(m, NFTA_LIST_ELEM); + if (r < 0) + return r; + + r = sd_netlink_message_append_string(m, NFTA_EXPR_NAME, "masq"); + if (r < 0) + return r; + + return sd_netlink_message_close_container(m); /* NFTA_LIST_ELEM */ +} + +static int sd_nfnl_message_new_masq_rule(sd_netlink *nfnl, sd_netlink_message **ret, int family, + const char *chain) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + /* -t nat -A POSTROUTING -p protocol -s source/pflen -o out_interface -d destination/pflen -j MASQUERADE */ + + r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, NFTA_RULE_EXPRESSIONS); + if (r < 0) + return r; + + /* 1st statement: ip saddr @masq_saddr. Place iph->saddr in reg1, resp. ipv6 in reg1..reg4. */ + if (family == AF_INET) + r = nfnl_add_expr_payload(m, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct iphdr, saddr), + sizeof(uint32_t), NFT_REG32_01); + else + r = nfnl_add_expr_payload(m, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct ip6_hdr, ip6_src.s6_addr), + sizeof(struct in6_addr), NFT_REG32_01); + if (r < 0) + return r; + + /* 1st statement: use reg1 content to make lookup in @masq_saddr set. */ + r = nfnl_add_expr_lookup_set(m, NFT_SYSTEMD_MASQ_SET_NAME, NFT_REG32_01); + if (r < 0) + return r; + + /* 2nd statement: masq. Only executed by kernel if the previous lookup was successful. */ + r = nfnl_add_expr_masq(m); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */ + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return 0; +} + +static int sd_nfnl_message_new_dnat_rule_pre(sd_netlink *nfnl, sd_netlink_message **ret, int family, + const char *chain) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + enum nft_registers proto_reg; + uint32_t local = RTN_LOCAL; + int r; + + /* -t nat -A PREROUTING -p protocol --dport local_port -i in_interface -s source/pflen + * -d destination/pflen -j DNAT --to-destination remote_addr:remote_port */ + + r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, NFTA_RULE_EXPRESSIONS); + if (r < 0) + return r; + + /* 1st statement: fib daddr type local */ + r = nfnl_add_expr_fib(m, NFTA_FIB_F_DADDR, NFT_FIB_RESULT_ADDRTYPE, NFT_REG32_01); + if (r < 0) + return r; + + /* 1st statement (cont.): compare RTN_LOCAL */ + r = nfnl_add_expr_cmp(m, NFT_CMP_EQ, NFT_REG32_01, &local, sizeof(local)); + if (r < 0) + return r; + + /* 2nd statement: lookup local port in map, fetch address:dport to map to */ + r = nfnl_add_expr_meta(m, NFT_META_L4PROTO, NFT_REG32_01); + if (r < 0) + return r; + + r = nfnl_add_expr_payload(m, NFT_PAYLOAD_TRANSPORT_HEADER, UDP_DPORT_OFFSET, + sizeof(uint16_t), NFT_REG32_02); + if (r < 0) + return r; + + /* 3rd statement: lookup 'l4proto . dport', e.g. 'tcp . 22' as key and + * store address and port for the dnat mapping in REG1/REG2. + */ + r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); + if (r < 0) + return r; + + proto_reg = family == AF_INET ? NFT_REG32_02 : NFT_REG32_05; + r = nfnl_add_expr_dnat(m, family, NFT_REG32_01, proto_reg); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */ + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return 0; +} + +static int sd_nfnl_message_new_dnat_rule_out(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *chain) { + static const uint32_t zero = 0, one = 1; + + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + enum nft_registers proto_reg; + int r; + + r = sd_nfnl_nft_message_new_rule(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, chain); + if (r < 0) + return r; + + r = sd_netlink_message_open_container(m, NFTA_RULE_EXPRESSIONS); + if (r < 0) + return r; + + /* 1st statement: exclude 127.0.0.1/8: ip daddr != 127.0.0.1/8, resp. avoid ::1 */ + if (family == AF_INET) { + uint32_t lonet = htobe32(UINT32_C(0x7F000000)), lomask = htobe32(UINT32_C(0xff000000)); + + r = nfnl_add_expr_payload(m, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct iphdr, daddr), + sizeof(lonet), NFT_REG32_01); + if (r < 0) + return r; + /* 1st statement (cont.): bitops/prefix */ + r = nfnl_add_expr_bitwise(m, NFT_REG32_01, NFT_REG32_01, &lomask, &zero, sizeof(lomask)); + if (r < 0) + return r; + + /* 1st statement (cont.): compare reg1 with 127/8 */ + r = nfnl_add_expr_cmp(m, NFT_CMP_NEQ, NFT_REG32_01, &lonet, sizeof(lonet)); + } else { + struct in6_addr loaddr = IN6ADDR_LOOPBACK_INIT; + + r = nfnl_add_expr_payload(m, NFT_PAYLOAD_NETWORK_HEADER, offsetof(struct ip6_hdr, ip6_dst.s6_addr), + sizeof(loaddr), NFT_REG32_01); + if (r < 0) + return r; + + r = nfnl_add_expr_cmp(m, NFT_CMP_NEQ, NFT_REG32_01, &loaddr, sizeof(loaddr)); + } + if (r < 0) + return r; + + /* 2nd statement: meta oif lo */ + r = nfnl_add_expr_meta(m, NFT_META_OIF, NFT_REG32_01); + if (r < 0) + return r; + + /* 2nd statement (cont.): compare to lo ifindex (1) */ + r = nfnl_add_expr_cmp(m, NFT_CMP_EQ, NFT_REG32_01, &one, sizeof(one)); + if (r < 0) + return r; + + /* 3rd statement: meta l4proto . th dport dnat ip . port to map @map_port_ipport */ + r = nfnl_add_expr_meta(m, NFT_META_L4PROTO, NFT_REG32_01); + if (r < 0) + return r; + + /* 3rd statement (cont): store the port number in reg2 */ + r = nfnl_add_expr_payload(m, NFT_PAYLOAD_TRANSPORT_HEADER, UDP_DPORT_OFFSET, + sizeof(uint16_t), NFT_REG32_02); + if (r < 0) + return r; + + /* 3rd statement (cont): use reg1 and reg2 and retrieve + * the new destination ip and port number. + * + * reg1 and reg2 are clobbered and will then contain the new + * address/port number. + */ + r = nfnl_add_expr_lookup_map(m, NFT_SYSTEMD_DNAT_MAP_NAME, NFT_REG32_01, NFT_REG32_01); + if (r < 0) + return r; + + /* 4th statement: dnat connection to address/port retrieved by the + * preceding expression. */ + proto_reg = family == AF_INET ? NFT_REG32_02 : NFT_REG32_05; + r = nfnl_add_expr_dnat(m, family, NFT_REG32_01, proto_reg); + if (r < 0) + return r; + + r = sd_netlink_message_close_container(m); /* NFTA_RULE_EXPRESSIONS */ + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return 0; +} + +static int nft_new_set(struct sd_netlink *nfnl, + sd_netlink_message **ret, + int family, const char *set_name, + uint32_t set_id, + uint32_t flags, uint32_t type, uint32_t klen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = sd_nfnl_nft_message_new_set(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name, set_id, klen); + if (r < 0) + return r; + + if (flags != 0) { + r = sd_netlink_message_append_u32(m, NFTA_SET_FLAGS, htobe32(flags)); + if (r < 0) + return r; + } + + r = sd_netlink_message_append_u32(m, NFTA_SET_KEY_TYPE, htobe32(type)); + if (r < 0) + return r; + + *ret = TAKE_PTR(m); + return r; +} + +static int nft_new_map(struct sd_netlink *nfnl, + sd_netlink_message **ret, + int family, const char *set_name, uint32_t set_id, + uint32_t flags, uint32_t type, uint32_t klen, uint32_t dtype, uint32_t dlen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = nft_new_set(nfnl, &m, family, set_name, set_id, flags | NFT_SET_MAP, type, klen); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_SET_DATA_TYPE, htobe32(dtype)); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_SET_DATA_LEN, htobe32(dlen)); + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return 0; +} + +static int nft_add_element(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *set_name, + const void *key, uint32_t klen, + const void *data, uint32_t dlen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + /* + * Ideally there would be an API that provides: + * + * 1) a init function to add the main ruleset skeleton + * 2) a function that populates the sets with all known address/port pairs to s/dnat for + * 3) a function that can remove address/port pairs again. + * + * At this time, the existing API is used which is built on a + * 'add/delete a rule' paradigm. + * + * This replicated here and each element gets added to the set + * one-by-one. + */ + r = sd_nfnl_nft_message_new_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem(m, 0, key, klen, data, dlen); + if (r < 0) + return r; + + /* could theoretically append more set elements to add here */ + r = sd_nfnl_nft_message_add_setelem_end(m); + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return 0; +} + +static int nft_del_element(sd_netlink *nfnl, + sd_netlink_message **ret, int family, const char *set_name, + const void *key, uint32_t klen, + const void *data, uint32_t dlen) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + r = sd_nfnl_nft_message_del_setelems_begin(nfnl, &m, family, NFT_SYSTEMD_TABLE_NAME, set_name); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem(m, 0, key, klen, data, dlen); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem_end(m); + if (r < 0) + return r; + *ret = TAKE_PTR(m); + return 0; +} + +/* This is needed so 'nft' userspace tool can properly format the contents + * of the set/map when someone uses 'nft' to inspect their content. + * + * The values cannot be changed, they are part of the nft tool type identifier ABI. + */ +#define TYPE_BITS 6 + +enum nft_key_types { + TYPE_IPADDR = 7, + TYPE_IP6ADDR = 8, + TYPE_INET_PROTOCOL = 12, + TYPE_INET_SERVICE = 13, +}; + +static uint32_t concat_types2(enum nft_key_types a, enum nft_key_types b) { + uint32_t type = (uint32_t)a; + + type <<= TYPE_BITS; + type |= (uint32_t)b; + + return type; +} + +/* enough space to hold netlink messages for table skeleton */ +#define NFT_INIT_MSGS 16 +static int fw_nftables_init_family(sd_netlink *nfnl, int family) { + sd_netlink_message *batch[NFT_INIT_MSGS] = {}; + size_t msgcnt = 0, i, ip_type_size; + uint32_t set_id = 0; + int ip_type, r; + + assert(IN_SET(family, AF_INET, AF_INET6)); + + r = sd_nfnl_message_batch_begin(nfnl, &batch[msgcnt]); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + /* Set F_EXCL so table add fails if the table already exists. */ + r = sd_nfnl_nft_message_new_table(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, NLM_F_EXCL | NLM_F_ACK); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + + r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, + "prerouting", "nat", + NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST + 1); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, + "output", "nat", + NF_INET_LOCAL_OUT, NF_IP_PRI_NAT_DST + 1); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + r = sd_nfnl_nft_message_new_basechain(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_TABLE_NAME, + "postrouting", "nat", + NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC + 1); + if (r < 0) + goto out_unref; + + if (family == AF_INET) { + ip_type_size = sizeof(uint32_t); + ip_type = TYPE_IPADDR; + } else { + assert(family == AF_INET6); + ip_type_size = sizeof(struct in6_addr); + ip_type = TYPE_IP6ADDR; + } + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + /* set to store ip address ranges we should masquerade for */ + r = nft_new_set(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_MASQ_SET_NAME, ++set_id, NFT_SET_INTERVAL, ip_type, ip_type_size); + if (r < 0) + goto out_unref; + + /* + * map to store ip address:port pair to dnat to. elements in concatenation + * are rounded up to 4 bytes. + * + * Example: ip protocol . tcp daddr is sizeof(uint32_t) + sizeof(uint32_t), not + * sizeof(uint8_t) + sizeof(uint16_t). + */ + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + r = nft_new_map(nfnl, &batch[msgcnt], family, NFT_SYSTEMD_DNAT_MAP_NAME, ++set_id, 0, + concat_types2(TYPE_INET_PROTOCOL, TYPE_INET_SERVICE), sizeof(uint32_t) * 2, + concat_types2(ip_type, TYPE_INET_SERVICE), ip_type_size + sizeof(uint32_t)); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + r = sd_nfnl_message_new_dnat_rule_pre(nfnl, &batch[msgcnt], family, "prerouting"); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + r = sd_nfnl_message_new_dnat_rule_out(nfnl, &batch[msgcnt], family, "output"); + if (r < 0) + goto out_unref; + + msgcnt++; + r = sd_nfnl_message_new_masq_rule(nfnl, &batch[msgcnt], family, "postrouting"); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt < NFT_INIT_MSGS); + r = sd_nfnl_message_batch_end(nfnl, &batch[msgcnt]); + if (r < 0) + goto out_unref; + + msgcnt++; + assert(msgcnt <= NFT_INIT_MSGS); + r = nfnl_netlink_sendv(nfnl, batch, msgcnt); + if (r == -EEXIST) + r = 0; + +out_unref: + for (i = 0; i < msgcnt; i++) + sd_netlink_message_unref(batch[i]); + + return r; +} + +int fw_nftables_init(FirewallContext *ctx) { + _cleanup_(sd_netlink_unrefp) sd_netlink *nfnl = NULL; + int r; + + r = sd_nfnl_socket_open(&nfnl); + if (r < 0) + return r; + + r = fw_nftables_init_family(nfnl, AF_INET); + if (r < 0) + return r; + + if (socket_ipv6_is_supported()) { + r = fw_nftables_init_family(nfnl, AF_INET6); + if (r < 0) + log_debug_errno(r, "Failed to init ipv6 NAT: %m"); + } + + ctx->nfnl = TAKE_PTR(nfnl); + return 0; +} + +void fw_nftables_exit(FirewallContext *ctx) { + ctx->nfnl = sd_netlink_unref(ctx->nfnl); +} + +static int nft_message_add_setelem_iprange(sd_netlink_message *m, + const union in_addr_union *source, + unsigned int prefixlen) { + uint32_t mask, start, end; + unsigned int nplen; + int r; + + assert(prefixlen <= 32); + nplen = 32 - prefixlen; + + mask = (1U << nplen) - 1U; + mask = htobe32(~mask); + start = source->in.s_addr & mask; + + r = sd_nfnl_nft_message_add_setelem(m, 0, &start, sizeof(start), NULL, 0); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem_end(m); + if (r < 0) + return r; + + end = be32toh(start) + (1U << nplen); + if (end < be32toh(start)) + end = 0U; + end = htobe32(end); + + r = sd_nfnl_nft_message_add_setelem(m, 1, &end, sizeof(end), NULL, 0); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_SET_ELEM_FLAGS, htobe32(NFT_SET_ELEM_INTERVAL_END)); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem_end(m); + if (r < 0) + return r; + + return 0; +} + +static int nft_message_add_setelem_ip6range( + sd_netlink_message *m, + const union in_addr_union *source, + unsigned int prefixlen) { + + union in_addr_union start, end; + int r; + + r = in_addr_prefix_range(AF_INET6, source, prefixlen, &start, &end); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem(m, 0, &start.in6, sizeof(start.in6), NULL, 0); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem_end(m); + if (r < 0) + return r; + + r = sd_nfnl_nft_message_add_setelem(m, 1, &end.in6, sizeof(end.in6), NULL, 0); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, NFTA_SET_ELEM_FLAGS, htobe32(NFT_SET_ELEM_INTERVAL_END)); + if (r < 0) + return r; + + return sd_nfnl_nft_message_add_setelem_end(m); +} + +#define NFT_MASQ_MSGS 3 + +static int fw_nftables_add_masquerade_internal( + FirewallContext *ctx, + bool add, + int af, + const union in_addr_union *source, + unsigned int source_prefixlen) { + + sd_netlink_message *transaction[NFT_MASQ_MSGS] = {}; + size_t tsize; + int r; + + if (!source || source_prefixlen == 0) + return -EINVAL; + + if (af == AF_INET6 && source_prefixlen < 8) + return -EINVAL; + + r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]); + if (r < 0) + return r; + tsize = 1; + if (add) + r = sd_nfnl_nft_message_new_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); + else + r = sd_nfnl_nft_message_del_setelems_begin(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_TABLE_NAME, NFT_SYSTEMD_MASQ_SET_NAME); + if (r < 0) + goto out_unref; + + if (af == AF_INET) + r = nft_message_add_setelem_iprange(transaction[tsize], source, source_prefixlen); + else + r = nft_message_add_setelem_ip6range(transaction[tsize], source, source_prefixlen); + if (r < 0) + goto out_unref; + + ++tsize; + assert(tsize < NFT_MASQ_MSGS); + r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]); + if (r < 0) + return r; + + ++tsize; + r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize); + +out_unref: + while (tsize > 0) + sd_netlink_message_unref(transaction[--tsize]); + return r < 0 ? r : 0; +} + +int fw_nftables_add_masquerade( + FirewallContext *ctx, + bool add, + int af, + const union in_addr_union *source, + unsigned int source_prefixlen) { + + int r; + + if (!socket_ipv6_is_supported() && af == AF_INET6) + return -EOPNOTSUPP; + + r = fw_nftables_add_masquerade_internal(ctx, add, af, source, source_prefixlen); + if (r != -ENOENT) + return r; + + /* When someone runs 'nft flush ruleset' in the same net namespace this will also tear down the + * systemd nat table. + * + * Unlike iptables -t nat -F (which will remove all rules added by the systemd iptables + * backend, iptables has builtin chains that cannot be deleted -- the next add operation will + * 'just work'. + * + * In the nftables case, everything gets removed. The next add operation will yield -ENOENT. + * + * If we see -ENOENT on add, replay the initial table setup. If that works, re-do the add + * operation. + * + * Note that this doesn't protect against external sabotage such as a + * 'while true; nft flush ruleset; done'. There is nothing that could be done about that short + * of extending the kernel to allow tables to be owned by stystemd-networkd and making them + * non-deleteable except by the 'owning process'. */ + + r = fw_nftables_init_family(ctx->nfnl, af); + if (r < 0) + return r; + + return fw_nftables_add_masquerade_internal(ctx, add, af, source, source_prefixlen); +} + +#define NFT_DNAT_MSGS 4 + +static int fw_nftables_add_local_dnat_internal( + FirewallContext *ctx, + bool add, + int af, + int protocol, + uint16_t local_port, + const union in_addr_union *remote, + uint16_t remote_port, + const union in_addr_union *previous_remote) { + + sd_netlink_message *transaction[NFT_DNAT_MSGS] = {}; + static bool ipv6_supported = true; + uint32_t data[5], key[2], dlen; + size_t tsize; + int r; + + assert(add || !previous_remote); + + if (!ipv6_supported && af == AF_INET6) + return -EOPNOTSUPP; + + if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP)) + return -EPROTONOSUPPORT; + + if (local_port <= 0) + return -EINVAL; + + key[0] = protocol; + key[1] = htobe16(local_port); + + if (!remote) + return -EOPNOTSUPP; + + if (remote_port <= 0) + return -EINVAL; + + if (af == AF_INET) { + dlen = 8; + data[1] = htobe16(remote_port); + } else { + assert(af == AF_INET6); + dlen = sizeof(data); + data[4] = htobe16(remote_port); + } + + r = sd_nfnl_message_batch_begin(ctx->nfnl, &transaction[0]); + if (r < 0) + return r; + + tsize = 1; + /* If a previous remote is set, remove its entry */ + if (add && previous_remote && !in_addr_equal(af, previous_remote, remote)) { + if (af == AF_INET) + data[0] = previous_remote->in.s_addr; + else + memcpy(data, &previous_remote->in6, sizeof(previous_remote->in6)); + + r = nft_del_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); + if (r < 0) + goto out_unref; + + tsize++; + } + + if (af == AF_INET) + data[0] = remote->in.s_addr; + else + memcpy(data, &remote->in6, sizeof(remote->in6)); + + assert(tsize < NFT_DNAT_MSGS); + if (add) + r = nft_add_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); + else + r = nft_del_element(ctx->nfnl, &transaction[tsize], af, NFT_SYSTEMD_DNAT_MAP_NAME, key, sizeof(key), data, dlen); + if (r < 0) + goto out_unref; + + tsize++; + assert(tsize < NFT_DNAT_MSGS); + + r = sd_nfnl_message_batch_end(ctx->nfnl, &transaction[tsize]); + if (r < 0) + goto out_unref; + + tsize++; + assert(tsize <= NFT_DNAT_MSGS); + + r = nfnl_netlink_sendv(ctx->nfnl, transaction, tsize); + if (r == -EOVERFLOW && af == AF_INET6) { + /* The current implementation of DNAT in systemd requires kernel's + * fdb9c405e35bdc6e305b9b4e20ebc141ed14fc81 (v5.8), and the older kernel returns + * -EOVERFLOW. Let's treat the error as -EOPNOTSUPP. */ + log_debug_errno(r, "The current implementation of IPv6 DNAT in systemd requires kernel 5.8 or newer, ignoring: %m"); + ipv6_supported = false; + r = -EOPNOTSUPP; + } + +out_unref: + while (tsize > 0) + sd_netlink_message_unref(transaction[--tsize]); + + return r < 0 ? r : 0; +} + +int fw_nftables_add_local_dnat( + FirewallContext *ctx, + bool add, + int af, + int protocol, + uint16_t local_port, + const union in_addr_union *remote, + uint16_t remote_port, + const union in_addr_union *previous_remote) { + + int r; + + if (!socket_ipv6_is_supported() && af == AF_INET6) + return -EOPNOTSUPP; + + r = fw_nftables_add_local_dnat_internal(ctx, add, af, protocol, local_port, remote, remote_port, previous_remote); + if (r != -ENOENT) + return r; + + /* See comment in fw_nftables_add_masquerade(). */ + r = fw_nftables_init_family(ctx->nfnl, af); + if (r < 0) + return r; + + /* table created anew; previous address already gone */ + return fw_nftables_add_local_dnat_internal(ctx, add, af, protocol, local_port, remote, remote_port, NULL); +} diff --git a/src/shared/firewall-util-private.h b/src/shared/firewall-util-private.h new file mode 100644 index 000000000..07e2d0bbd --- /dev/null +++ b/src/shared/firewall-util-private.h @@ -0,0 +1,64 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +#include "sd-netlink.h" + +#include "in-addr-util.h" + +typedef enum FirewallBackend { + FW_BACKEND_NONE, +#if HAVE_LIBIPTC + FW_BACKEND_IPTABLES, +#endif + FW_BACKEND_NFTABLES, + _FW_BACKEND_MAX, + _FW_BACKEND_INVALID = -EINVAL, +} FirewallBackend; + +struct FirewallContext { + FirewallBackend backend; + sd_netlink *nfnl; +}; + +const char *firewall_backend_to_string(FirewallBackend b) _const_; + +int fw_nftables_init(FirewallContext *ctx); +void fw_nftables_exit(FirewallContext *ctx); + +int fw_nftables_add_masquerade( + FirewallContext *ctx, + bool add, + int af, + const union in_addr_union *source, + unsigned source_prefixlen); + +int fw_nftables_add_local_dnat( + FirewallContext *ctx, + bool add, + int af, + int protocol, + uint16_t local_port, + const union in_addr_union *remote, + uint16_t remote_port, + const union in_addr_union *previous_remote); + +#if HAVE_LIBIPTC + +int fw_iptables_add_masquerade( + bool add, + int af, + const union in_addr_union *source, + unsigned source_prefixlen); + +int fw_iptables_add_local_dnat( + bool add, + int af, + int protocol, + uint16_t local_port, + const union in_addr_union *remote, + uint16_t remote_port, + const union in_addr_union *previous_remote); +#endif diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index 007d2cb39..afa3e02b4 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -1,350 +1,129 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* Temporary work-around for broken glibc vs. linux kernel header definitions - * This is already fixed upstream, remove this when distributions have updated. - */ -#define _NET_IF_H 1 - -#include -#include #include #include #include -#include -#ifndef IFNAMSIZ -#define IFNAMSIZ 16 -#endif -#include -#include -#include -#include -#include #include "alloc-util.h" #include "firewall-util.h" -#include "in-addr-util.h" -#include "macro.h" -#include "socket-util.h" +#include "firewall-util-private.h" +#include "log.h" +#include "string-table.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free); +static const char * const firewall_backend_table[_FW_BACKEND_MAX] = { + [FW_BACKEND_NONE] = "none", +#if HAVE_LIBIPTC + [FW_BACKEND_IPTABLES] = "iptables", +#endif + [FW_BACKEND_NFTABLES] = "nftables", +}; -static int entry_fill_basics( - struct ipt_entry *entry, - int protocol, - const char *in_interface, - const union in_addr_union *source, - unsigned source_prefixlen, - const char *out_interface, - const union in_addr_union *destination, - unsigned destination_prefixlen) { +DEFINE_STRING_TABLE_LOOKUP_TO_STRING(firewall_backend, FirewallBackend); - assert(entry); +static void firewall_backend_probe(FirewallContext *ctx) { + assert(ctx); - if (out_interface && !ifname_valid(out_interface)) - return -EINVAL; - if (in_interface && !ifname_valid(in_interface)) - return -EINVAL; + if (ctx->backend != _FW_BACKEND_INVALID) + return; - entry->ip.proto = protocol; + if (fw_nftables_init(ctx) >= 0) + ctx->backend = FW_BACKEND_NFTABLES; + else +#if HAVE_LIBIPTC + ctx->backend = FW_BACKEND_IPTABLES; +#else + ctx->backend = FW_BACKEND_NONE; +#endif - if (in_interface) { - size_t l; + if (ctx->backend != FW_BACKEND_NONE) + log_debug("Using %s as firewall backend.", firewall_backend_to_string(ctx->backend)); + else + log_debug("No firewall backend found."); +} - l = strlen(in_interface); - assert(l < sizeof entry->ip.iniface); - assert(l < sizeof entry->ip.iniface_mask); +int fw_ctx_new(FirewallContext **ret) { + _cleanup_free_ FirewallContext *ctx = NULL; - strcpy(entry->ip.iniface, in_interface); - memset(entry->ip.iniface_mask, 0xFF, l + 1); - } - if (source) { - entry->ip.src = source->in; - in4_addr_prefixlen_to_netmask(&entry->ip.smsk, source_prefixlen); - } + ctx = new(FirewallContext, 1); + if (!ctx) + return -ENOMEM; - if (out_interface) { - size_t l = strlen(out_interface); - assert(l < sizeof entry->ip.outiface); - assert(l < sizeof entry->ip.outiface_mask); + *ctx = (FirewallContext) { + .backend = _FW_BACKEND_INVALID, + }; - strcpy(entry->ip.outiface, out_interface); - memset(entry->ip.outiface_mask, 0xFF, l + 1); - } - if (destination) { - entry->ip.dst = destination->in; - in4_addr_prefixlen_to_netmask(&entry->ip.dmsk, destination_prefixlen); - } + firewall_backend_probe(ctx); + *ret = TAKE_PTR(ctx); return 0; } +FirewallContext *fw_ctx_free(FirewallContext *ctx) { + if (!ctx) + return NULL; + + fw_nftables_exit(ctx); + + return mfree(ctx); +} + int fw_add_masquerade( + FirewallContext **ctx, bool add, int af, - int protocol, const union in_addr_union *source, - unsigned source_prefixlen, - const char *out_interface, - const union in_addr_union *destination, - unsigned destination_prefixlen) { + unsigned source_prefixlen) { - static const xt_chainlabel chain = "POSTROUTING"; - _cleanup_(iptc_freep) struct xtc_handle *h = NULL; - struct ipt_entry *entry, *mask; - struct ipt_entry_target *t; - size_t sz; - struct nf_nat_ipv4_multi_range_compat *mr; int r; - if (af != AF_INET) - return -EOPNOTSUPP; + assert(ctx); - if (!IN_SET(protocol, 0, IPPROTO_TCP, IPPROTO_UDP)) - return -EOPNOTSUPP; - - h = iptc_init("nat"); - if (!h) - return -errno; - - sz = XT_ALIGN(sizeof(struct ipt_entry)) + - XT_ALIGN(sizeof(struct ipt_entry_target)) + - XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); - - /* Put together the entry we want to add or remove */ - entry = alloca0(sz); - entry->next_offset = sz; - entry->target_offset = XT_ALIGN(sizeof(struct ipt_entry)); - r = entry_fill_basics(entry, protocol, NULL, source, source_prefixlen, out_interface, destination, destination_prefixlen); - if (r < 0) - return r; - - /* Fill in target part */ - t = ipt_get_target(entry); - t->u.target_size = - XT_ALIGN(sizeof(struct ipt_entry_target)) + - XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); - strncpy(t->u.user.name, "MASQUERADE", sizeof(t->u.user.name)); - mr = (struct nf_nat_ipv4_multi_range_compat*) t->data; - mr->rangesize = 1; - - /* Create a search mask entry */ - mask = alloca(sz); - memset(mask, 0xFF, sz); - - if (add) { - if (iptc_check_entry(chain, entry, (unsigned char*) mask, h)) - return 0; - if (errno != ENOENT) /* if other error than not existing yet, fail */ - return -errno; - - if (!iptc_insert_entry(chain, entry, 0, h)) - return -errno; - } else { - if (!iptc_delete_entry(chain, entry, (unsigned char*) mask, h)) { - if (errno == ENOENT) /* if it's already gone, all is good! */ - return 0; - - return -errno; - } + if (!*ctx) { + r = fw_ctx_new(ctx); + if (r < 0) + return r; } - if (!iptc_commit(h)) - return -errno; - - return 0; + switch ((*ctx)->backend) { +#if HAVE_LIBIPTC + case FW_BACKEND_IPTABLES: + return fw_iptables_add_masquerade(add, af, source, source_prefixlen); +#endif + case FW_BACKEND_NFTABLES: + return fw_nftables_add_masquerade(*ctx, add, af, source, source_prefixlen); + default: + return -EOPNOTSUPP; + } } int fw_add_local_dnat( + FirewallContext **ctx, bool add, int af, int protocol, - const char *in_interface, - const union in_addr_union *source, - unsigned source_prefixlen, - const union in_addr_union *destination, - unsigned destination_prefixlen, uint16_t local_port, const union in_addr_union *remote, uint16_t remote_port, const union in_addr_union *previous_remote) { - static const xt_chainlabel chain_pre = "PREROUTING", chain_output = "OUTPUT"; - _cleanup_(iptc_freep) struct xtc_handle *h = NULL; - struct ipt_entry *entry, *mask; - struct ipt_entry_target *t; - struct ipt_entry_match *m; - struct xt_addrtype_info_v1 *at; - struct nf_nat_ipv4_multi_range_compat *mr; - size_t sz, msz; int r; - assert(add || !previous_remote); + assert(ctx); - if (af != AF_INET) - return -EOPNOTSUPP; - - if (!IN_SET(protocol, IPPROTO_TCP, IPPROTO_UDP)) - return -EOPNOTSUPP; - - if (local_port <= 0) - return -EINVAL; - - if (remote_port <= 0) - return -EINVAL; - - h = iptc_init("nat"); - if (!h) - return -errno; - - sz = XT_ALIGN(sizeof(struct ipt_entry)) + - XT_ALIGN(sizeof(struct ipt_entry_match)) + - XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) + - XT_ALIGN(sizeof(struct ipt_entry_target)) + - XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); - - if (protocol == IPPROTO_TCP) - msz = XT_ALIGN(sizeof(struct ipt_entry_match)) + - XT_ALIGN(sizeof(struct xt_tcp)); - else - msz = XT_ALIGN(sizeof(struct ipt_entry_match)) + - XT_ALIGN(sizeof(struct xt_udp)); - - sz += msz; - - /* Fill in basic part */ - entry = alloca0(sz); - entry->next_offset = sz; - entry->target_offset = - XT_ALIGN(sizeof(struct ipt_entry)) + - XT_ALIGN(sizeof(struct ipt_entry_match)) + - XT_ALIGN(sizeof(struct xt_addrtype_info_v1)) + - msz; - r = entry_fill_basics(entry, protocol, in_interface, source, source_prefixlen, NULL, destination, destination_prefixlen); - if (r < 0) - return r; - - /* Fill in first match */ - m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry))); - m->u.match_size = msz; - if (protocol == IPPROTO_TCP) { - struct xt_tcp *tcp; - - strncpy(m->u.user.name, "tcp", sizeof(m->u.user.name)); - tcp = (struct xt_tcp*) m->data; - tcp->dpts[0] = tcp->dpts[1] = local_port; - tcp->spts[0] = 0; - tcp->spts[1] = 0xFFFF; - - } else { - struct xt_udp *udp; - - strncpy(m->u.user.name, "udp", sizeof(m->u.user.name)); - udp = (struct xt_udp*) m->data; - udp->dpts[0] = udp->dpts[1] = local_port; - udp->spts[0] = 0; - udp->spts[1] = 0xFFFF; + if (!*ctx) { + r = fw_ctx_new(ctx); + if (r < 0) + return r; } - /* Fill in second match */ - m = (struct ipt_entry_match*) ((uint8_t*) entry + XT_ALIGN(sizeof(struct ipt_entry)) + msz); - m->u.match_size = - XT_ALIGN(sizeof(struct ipt_entry_match)) + - XT_ALIGN(sizeof(struct xt_addrtype_info_v1)); - strncpy(m->u.user.name, "addrtype", sizeof(m->u.user.name)); - m->u.user.revision = 1; - at = (struct xt_addrtype_info_v1*) m->data; - at->dest = XT_ADDRTYPE_LOCAL; - - /* Fill in target part */ - t = ipt_get_target(entry); - t->u.target_size = - XT_ALIGN(sizeof(struct ipt_entry_target)) + - XT_ALIGN(sizeof(struct nf_nat_ipv4_multi_range_compat)); - strncpy(t->u.user.name, "DNAT", sizeof(t->u.user.name)); - mr = (struct nf_nat_ipv4_multi_range_compat*) t->data; - mr->rangesize = 1; - mr->range[0].flags = NF_NAT_RANGE_PROTO_SPECIFIED|NF_NAT_RANGE_MAP_IPS; - mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr; - if (protocol == IPPROTO_TCP) - mr->range[0].min.tcp.port = mr->range[0].max.tcp.port = htobe16(remote_port); - else - mr->range[0].min.udp.port = mr->range[0].max.udp.port = htobe16(remote_port); - - mask = alloca0(sz); - memset(mask, 0xFF, sz); - - if (add) { - /* Add the PREROUTING rule, if it is missing so far */ - if (!iptc_check_entry(chain_pre, entry, (unsigned char*) mask, h)) { - if (errno != ENOENT) - return -EINVAL; - - if (!iptc_insert_entry(chain_pre, entry, 0, h)) - return -errno; - } - - /* If a previous remote is set, remove its entry */ - if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) { - mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr; - - if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) { - if (errno != ENOENT) - return -errno; - } - - mr->range[0].min_ip = mr->range[0].max_ip = remote->in.s_addr; - } - - /* Add the OUTPUT rule, if it is missing so far */ - if (!in_interface) { - - /* Don't apply onto loopback addresses */ - if (!destination) { - entry->ip.dst.s_addr = htobe32(0x7F000000); - entry->ip.dmsk.s_addr = htobe32(0xFF000000); - entry->ip.invflags = IPT_INV_DSTIP; - } - - if (!iptc_check_entry(chain_output, entry, (unsigned char*) mask, h)) { - if (errno != ENOENT) - return -errno; - - if (!iptc_insert_entry(chain_output, entry, 0, h)) - return -errno; - } - - /* If a previous remote is set, remove its entry */ - if (previous_remote && previous_remote->in.s_addr != remote->in.s_addr) { - mr->range[0].min_ip = mr->range[0].max_ip = previous_remote->in.s_addr; - - if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) { - if (errno != ENOENT) - return -errno; - } - } - } - } else { - if (!iptc_delete_entry(chain_pre, entry, (unsigned char*) mask, h)) { - if (errno != ENOENT) - return -errno; - } - - if (!in_interface) { - if (!destination) { - entry->ip.dst.s_addr = htobe32(0x7F000000); - entry->ip.dmsk.s_addr = htobe32(0xFF000000); - entry->ip.invflags = IPT_INV_DSTIP; - } - - if (!iptc_delete_entry(chain_output, entry, (unsigned char*) mask, h)) { - if (errno != ENOENT) - return -errno; - } - } + switch ((*ctx)->backend) { +#if HAVE_LIBIPTC + case FW_BACKEND_IPTABLES: + return fw_iptables_add_local_dnat(add, af, protocol, local_port, remote, remote_port, previous_remote); +#endif + case FW_BACKEND_NFTABLES: + return fw_nftables_add_local_dnat(*ctx, add, af, protocol, local_port, remote, remote_port, previous_remote); + default: + return -EOPNOTSUPP; } - - if (!iptc_commit(h)) - return -errno; - - return 0; } diff --git a/src/shared/firewall-util.h b/src/shared/firewall-util.h index 0a51a3c69..7725a5e58 100644 --- a/src/shared/firewall-util.h +++ b/src/shared/firewall-util.h @@ -6,60 +6,26 @@ #include "in-addr-util.h" -#if HAVE_LIBIPTC +typedef struct FirewallContext FirewallContext; + +int fw_ctx_new(FirewallContext **ret); +FirewallContext *fw_ctx_free(FirewallContext *ctx); + +DEFINE_TRIVIAL_CLEANUP_FUNC(FirewallContext *, fw_ctx_free); int fw_add_masquerade( + FirewallContext **ctx, bool add, int af, - int protocol, const union in_addr_union *source, - unsigned source_prefixlen, - const char *out_interface, - const union in_addr_union *destination, - unsigned destination_prefixlen); + unsigned source_prefixlen); int fw_add_local_dnat( + FirewallContext **ctx, bool add, int af, int protocol, - const char *in_interface, - const union in_addr_union *source, - unsigned source_prefixlen, - const union in_addr_union *destination, - unsigned destination_prefixlen, uint16_t local_port, const union in_addr_union *remote, uint16_t remote_port, const union in_addr_union *previous_remote); - -#else - -static inline int fw_add_masquerade( - bool add, - int af, - int protocol, - const union in_addr_union *source, - unsigned source_prefixlen, - const char *out_interface, - const union in_addr_union *destination, - unsigned destination_prefixlen) { - return -EOPNOTSUPP; -} - -static inline int fw_add_local_dnat( - bool add, - int af, - int protocol, - const char *in_interface, - const union in_addr_union *source, - unsigned source_prefixlen, - const union in_addr_union *destination, - unsigned destination_prefixlen, - uint16_t local_port, - const union in_addr_union *remote, - uint16_t remote_port, - const union in_addr_union *previous_remote) { - return -EOPNOTSUPP; -} - -#endif diff --git a/src/shared/format-table.c b/src/shared/format-table.c index a13a198b7..6bbc8bd50 100644 --- a/src/shared/format-table.c +++ b/src/shared/format-table.c @@ -20,11 +20,14 @@ #include "parse-util.h" #include "path-util.h" #include "pretty-print.h" +#include "process-util.h" +#include "signal-util.h" #include "sort-util.h" #include "string-util.h" #include "strxcpyx.h" #include "terminal-util.h" #include "time-util.h" +#include "user-util.h" #include "utf8.h" #include "util.h" @@ -100,6 +103,9 @@ typedef struct TableData { int ifindex; union in_addr_union address; sd_id128_t id128; + uid_t uid; + gid_t gid; + pid_t pid; /* … add more here as we start supporting more cell data types … */ }; } TableData; @@ -116,7 +122,7 @@ static size_t TABLE_CELL_TO_INDEX(TableCell *cell) { } static TableCell* TABLE_INDEX_TO_CELL(size_t index) { - assert(index != (size_t) -1); + assert(index != SIZE_MAX); return SIZE_TO_PTR(index + 1); } @@ -125,9 +131,9 @@ struct Table { size_t n_cells; bool header; /* Whether to show the header row? */ - size_t width; /* If == 0 format this as wide as necessary. If (size_t) -1 format this to console + size_t width; /* If == 0 format this as wide as necessary. If SIZE_MAX format this to console * width or less wide, but not wider. Otherwise the width to format this table in. */ - size_t cell_height_max; /* Maximum number of lines per cell. (If there are more, ellipsis is shown. If (size_t) -1 then no limit is set, the default. == 0 is not allowed.) */ + size_t cell_height_max; /* Maximum number of lines per cell. (If there are more, ellipsis is shown. If SIZE_MAX then no limit is set, the default. == 0 is not allowed.) */ TableData **data; size_t n_allocated; @@ -155,8 +161,8 @@ Table *table_new_raw(size_t n_columns) { *t = (struct Table) { .n_columns = n_columns, .header = true, - .width = (size_t) -1, - .cell_height_max = (size_t) -1, + .width = SIZE_MAX, + .cell_height_max = SIZE_MAX, }; return TAKE_PTR(t); @@ -284,6 +290,7 @@ static size_t table_data_size(TableDataType type, const void *data) { case TABLE_UINT: case TABLE_PERCENT: case TABLE_IFINDEX: + case TABLE_SIGNAL: return sizeof(int); case TABLE_IN_ADDR: @@ -296,6 +303,13 @@ static size_t table_data_size(TableDataType type, const void *data) { case TABLE_ID128: return sizeof(sd_id128_t); + case TABLE_UID: + return sizeof(uid_t); + case TABLE_GID: + return sizeof(gid_t); + case TABLE_PID: + return sizeof(pid_t); + default: assert_not_reached("Uh? Unexpected cell type"); } @@ -413,16 +427,16 @@ int table_add_cell_full( p = NULL; /* If formatting parameters are left unspecified, copy from the previous row */ - if (minimum_width == (size_t) -1) + if (minimum_width == SIZE_MAX) minimum_width = p ? p->minimum_width : 1; - if (weight == (unsigned) -1) + if (weight == UINT_MAX) weight = p ? p->weight : DEFAULT_WEIGHT; - if (align_percent == (unsigned) -1) + if (align_percent == UINT_MAX) align_percent = p ? p->align_percent : 0; - if (ellipsize_percent == (unsigned) -1) + if (ellipsize_percent == UINT_MAX) ellipsize_percent = p ? p->ellipsize_percent : 100; assert(align_percent <= 100); @@ -577,7 +591,7 @@ int table_set_minimum_width(Table *t, TableCell *cell, size_t minimum_width) { assert(t); assert(cell); - if (minimum_width == (size_t) -1) + if (minimum_width == SIZE_MAX) minimum_width = 1; r = table_dedup_cell(t, cell); @@ -608,7 +622,7 @@ int table_set_weight(Table *t, TableCell *cell, unsigned weight) { assert(t); assert(cell); - if (weight == (unsigned) -1) + if (weight == UINT_MAX) weight = DEFAULT_WEIGHT; r = table_dedup_cell(t, cell); @@ -625,7 +639,7 @@ int table_set_align_percent(Table *t, TableCell *cell, unsigned percent) { assert(t); assert(cell); - if (percent == (unsigned) -1) + if (percent == UINT_MAX) percent = 0; assert(percent <= 100); @@ -644,7 +658,7 @@ int table_set_ellipsize_percent(Table *t, TableCell *cell, unsigned percent) { assert(t); assert(cell); - if (percent == (unsigned) -1) + if (percent == UINT_MAX) percent = 100; assert(percent <= 100); @@ -801,6 +815,9 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) { bool b; union in_addr_union address; sd_id128_t id128; + uid_t uid; + gid_t gid; + pid_t pid; } buffer; switch (type) { @@ -840,6 +857,7 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) { break; case TABLE_INT: + case TABLE_SIGNAL: buffer.int_val = va_arg(ap, int); data = &buffer.int_val; break; @@ -931,6 +949,21 @@ int table_add_many_internal(Table *t, TableDataType first_type, ...) { data = &buffer.id128; break; + case TABLE_UID: + buffer.uid = va_arg(ap, uid_t); + data = &buffer.uid; + break; + + case TABLE_GID: + buffer.gid = va_arg(ap, gid_t); + data = &buffer.gid; + break; + + case TABLE_PID: + buffer.pid = va_arg(ap, pid_t); + data = &buffer.pid; + break; + case TABLE_SET_MINIMUM_WIDTH: { size_t w = va_arg(ap, size_t); @@ -1034,7 +1067,7 @@ void table_set_width(Table *t, size_t width) { void table_set_cell_height_max(Table *t, size_t height) { assert(t); - assert(height >= 1 || height == (size_t) -1); + assert(height >= 1 || height == SIZE_MAX); t->cell_height_max = height; } @@ -1045,23 +1078,27 @@ int table_set_empty_string(Table *t, const char *empty) { return free_and_strdup(&t->empty_string, empty); } -int table_set_display_all(Table *t) { +static int table_set_display_all(Table *t) { + size_t *d; + assert(t); - size_t allocated = t->n_display_map; + /* Initialize the display map to the identity */ - if (!GREEDY_REALLOC(t->display_map, allocated, MAX(t->n_columns, allocated))) + d = reallocarray(t->display_map, t->n_columns, sizeof(size_t)); + if (!d) return -ENOMEM; for (size_t i = 0; i < t->n_columns; i++) - t->display_map[i] = i; + d[i] = i; + t->display_map = d; t->n_display_map = t->n_columns; return 0; } -int table_set_display(Table *t, size_t first_column, ...) { +int table_set_display_internal(Table *t, size_t first_column, ...) { size_t allocated, column; va_list ap; @@ -1082,7 +1119,7 @@ int table_set_display(Table *t, size_t first_column, ...) { t->display_map[t->n_display_map++] = column; column = va_arg(ap, size_t); - if (column == (size_t) -1) + if (column == SIZE_MAX) break; } @@ -1091,7 +1128,7 @@ int table_set_display(Table *t, size_t first_column, ...) { return 0; } -int table_set_sort(Table *t, size_t first_column, ...) { +int table_set_sort_internal(Table *t, size_t first_column, ...) { size_t allocated, column; va_list ap; @@ -1112,7 +1149,7 @@ int table_set_sort(Table *t, size_t first_column, ...) { t->sort_map[t->n_sort_map++] = column; column = va_arg(ap, size_t); - if (column == (size_t) -1) + if (column == SIZE_MAX) break; } va_end(ap); @@ -1189,6 +1226,7 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t return CMP(a->size, b->size); case TABLE_INT: + case TABLE_SIGNAL: return CMP(a->int_val, b->int_val); case TABLE_INT8: @@ -1234,6 +1272,15 @@ static int cell_data_compare(TableData *a, size_t index_a, TableData *b, size_t case TABLE_ID128: return memcmp(&a->id128, &b->id128, sizeof(sd_id128_t)); + case TABLE_UID: + return CMP(a->uid, b->uid); + + case TABLE_GID: + return CMP(a->gid, b->gid); + + case TABLE_PID: + return CMP(a->pid, b->pid); + default: ; } @@ -1274,9 +1321,9 @@ static int table_data_compare(const size_t *a, const size_t *b, Table *t) { } static char* format_strv_width(char **strv, size_t column_width) { + _cleanup_free_ char *buf = NULL; /* buf must be freed after f */ _cleanup_fclose_ FILE *f = NULL; size_t sz = 0; - _cleanup_free_ char *buf = NULL; f = open_memstream_unlocked(&buf, &sz); if (!f) @@ -1618,6 +1665,67 @@ static const char *table_data_format(Table *t, TableData *d, bool avoid_uppercas break; } + case TABLE_UID: { + _cleanup_free_ char *p = NULL; + + if (!uid_is_valid(d->uid)) + return "n/a"; + + p = new(char, DECIMAL_STR_WIDTH(d->uid) + 1); + if (!p) + return NULL; + + sprintf(p, UID_FMT, d->uid); + d->formatted = TAKE_PTR(p); + break; + } + + case TABLE_GID: { + _cleanup_free_ char *p = NULL; + + if (!gid_is_valid(d->gid)) + return "n/a"; + + p = new(char, DECIMAL_STR_WIDTH(d->gid) + 1); + if (!p) + return NULL; + + sprintf(p, GID_FMT, d->gid); + d->formatted = TAKE_PTR(p); + break; + } + + case TABLE_PID: { + _cleanup_free_ char *p = NULL; + + if (!pid_is_valid(d->pid)) + return "n/a"; + + p = new(char, DECIMAL_STR_WIDTH(d->pid) + 1); + if (!p) + return NULL; + + sprintf(p, PID_FMT, d->pid); + d->formatted = TAKE_PTR(p); + break; + } + + case TABLE_SIGNAL: { + _cleanup_free_ char *p = NULL; + const char *suffix; + + suffix = signal_to_string(d->int_val); + if (!suffix) + return "n/a"; + + p = strjoin("SIG", suffix); + if (!p) + return NULL; + + d->formatted = TAKE_PTR(p); + break; + } + default: assert_not_reached("Unexpected type?"); } @@ -1654,7 +1762,7 @@ static int console_width_height( k = utf8_console_width(s); s = NULL; } - if (k == (size_t) -1) + if (k == SIZE_MAX) return -EINVAL; if (k > max_width) max_width = k; @@ -1690,7 +1798,7 @@ static int table_data_requested_width_height( if (!t) return -ENOMEM; - if (table->cell_height_max != (size_t) -1) { + if (table->cell_height_max != SIZE_MAX) { r = string_truncate_lines(t, table->cell_height_max, &truncated); if (r < 0) return r; @@ -1704,7 +1812,7 @@ static int table_data_requested_width_height( if (r < 0) return r; - if (d->maximum_width != (size_t) -1 && width > d->maximum_width) + if (d->maximum_width != SIZE_MAX && width > d->maximum_width) width = d->maximum_width; if (width < d->minimum_width) @@ -1861,14 +1969,14 @@ int table_print(Table *t, FILE *f) { for (size_t j = 0; j < display_columns; j++) { minimum_width[j] = 1; - maximum_width[j] = (size_t) -1; + maximum_width[j] = SIZE_MAX; } for (unsigned pass = 0; pass < 2; pass++) { /* First pass: determine column sizes */ for (size_t j = 0; j < display_columns; j++) - requested_width[j] = (size_t) -1; + requested_width[j] = SIZE_MAX; bool any_soft = false; @@ -1916,7 +2024,7 @@ int table_print(Table *t, FILE *f) { } /* Determine the biggest width that any cell in this column would like to have */ - if (requested_width[j] == (size_t) -1 || + if (requested_width[j] == SIZE_MAX || requested_width[j] < req_width) requested_width[j] = req_width; @@ -1925,8 +2033,8 @@ int table_print(Table *t, FILE *f) { minimum_width[j] = d->minimum_width; /* Determine the maximum width any cell in this column needs */ - if (d->maximum_width != (size_t) -1 && - (maximum_width[j] == (size_t) -1 || + if (d->maximum_width != SIZE_MAX && + (maximum_width[j] == SIZE_MAX || maximum_width[j] > d->maximum_width)) maximum_width[j] = d->maximum_width; @@ -1945,8 +2053,8 @@ int table_print(Table *t, FILE *f) { table_minimum_width += minimum_width[j]; - if (maximum_width[j] == (size_t) -1) - table_maximum_width = (size_t) -1; + if (maximum_width[j] == SIZE_MAX) + table_maximum_width = SIZE_MAX; else table_maximum_width += maximum_width[j]; @@ -1954,7 +2062,7 @@ int table_print(Table *t, FILE *f) { } /* Calculate effective table width */ - if (t->width != 0 && t->width != (size_t) -1) + if (t->width != 0 && t->width != SIZE_MAX) table_effective_width = t->width; else if (t->width == 0 || ((pass > 0 || !any_soft) && (pager_have() || !isatty(STDOUT_FILENO)))) @@ -1962,7 +2070,7 @@ int table_print(Table *t, FILE *f) { else table_effective_width = MIN(table_requested_width, columns()); - if (table_maximum_width != (size_t) -1 && table_effective_width > table_maximum_width) + if (table_maximum_width != SIZE_MAX && table_effective_width > table_maximum_width) table_effective_width = table_maximum_width; if (table_effective_width < table_minimum_width) @@ -1987,14 +2095,13 @@ int table_print(Table *t, FILE *f) { else width[j] = requested_width[j] + (extra * column_weight[j]) / weight_sum; - if (maximum_width[j] != (size_t) -1 && width[j] > maximum_width[j]) + if (maximum_width[j] != SIZE_MAX && width[j] > maximum_width[j]) width[j] = maximum_width[j]; if (width[j] < minimum_width[j]) width[j] = minimum_width[j]; - assert(width[j] >= requested_width[j]); - delta = width[j] - requested_width[j]; + delta = LESS_BY(width[j], requested_width[j]); /* Subtract what we just added from the rest */ if (extra > delta) @@ -2016,7 +2123,7 @@ int table_print(Table *t, FILE *f) { extra = table_effective_width - table_minimum_width; for (size_t j = 0; j < display_columns; j++) - width[j] = (size_t) -1; + width[j] = SIZE_MAX; for (;;) { bool restart = false; @@ -2025,7 +2132,7 @@ int table_print(Table *t, FILE *f) { size_t delta, w; /* Did this column already get something assigned? If so, let's skip to the next */ - if (width[j] != (size_t) -1) + if (width[j] != SIZE_MAX) continue; if (weight_sum == 0) @@ -2107,7 +2214,7 @@ int table_print(Table *t, FILE *f) { return r; if (r > 0) { /* There are more lines to come */ - if ((t->cell_height_max == (size_t) -1 || n_subline + 1 < t->cell_height_max)) + if ((t->cell_height_max == SIZE_MAX || n_subline + 1 < t->cell_height_max)) more_sublines = true; /* There are more lines to come */ else lines_truncated = true; @@ -2155,6 +2262,12 @@ int table_print(Table *t, FILE *f) { if (!aligned) return -ENOMEM; + /* Drop trailing white spaces of last column when no cosmetics is set. */ + if (j == display_columns - 1 && + (!colors_enabled() || (!table_data_color(d) && row != t->data)) && + (!urlify_enabled() || !d->url)) + delete_trailing_chars(aligned, NULL); + free_and_replace(buffer, aligned); field = buffer; } @@ -2211,8 +2324,8 @@ int table_print(Table *t, FILE *f) { } int table_format(Table *t, char **ret) { + _cleanup_free_ char *buf = NULL; _cleanup_fclose_ FILE *f = NULL; - char *buf = NULL; size_t sz = 0; int r; @@ -2226,7 +2339,7 @@ int table_format(Table *t, char **ret) { f = safe_fclose(f); - *ret = buf; + *ret = TAKE_PTR(buf); return 0; } @@ -2336,7 +2449,7 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) { case TABLE_SIZE: case TABLE_BPS: - if (d->size == (uint64_t) -1) + if (d->size == UINT64_MAX) return json_variant_new_null(ret); return json_variant_new_unsigned(ret, d->size); @@ -2375,6 +2488,9 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) { return json_variant_new_integer(ret, d->percent); case TABLE_IFINDEX: + if (d->ifindex <= 0) + return json_variant_new_null(ret); + return json_variant_new_integer(ret, d->ifindex); case TABLE_IN_ADDR: @@ -2393,6 +2509,30 @@ static int table_data_to_json(TableData *d, JsonVariant **ret) { return json_variant_new_string(ret, id128_to_uuid_string(d->id128, buf)); } + case TABLE_UID: + if (!uid_is_valid(d->uid)) + return json_variant_new_null(ret); + + return json_variant_new_integer(ret, d->uid); + + case TABLE_GID: + if (!gid_is_valid(d->gid)) + return json_variant_new_null(ret); + + return json_variant_new_integer(ret, d->gid); + + case TABLE_PID: + if (!pid_is_valid(d->pid)) + return json_variant_new_null(ret); + + return json_variant_new_integer(ret, d->pid); + + case TABLE_SIGNAL: + if (!SIGNAL_VALID(d->int_val)) + return json_variant_new_null(ret); + + return json_variant_new_integer(ret, d->int_val); + default: return -EINVAL; } @@ -2536,6 +2676,9 @@ int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) { assert(t); + if (flags & JSON_FORMAT_OFF) /* If JSON output is turned off, use regular output */ + return table_print(t, f); + if (!f) f = stdout; @@ -2547,3 +2690,30 @@ int table_print_json(Table *t, FILE *f, JsonFormatFlags flags) { return fflush_and_check(f); } + +int table_print_with_pager( + Table *t, + JsonFormatFlags json_format_flags, + PagerFlags pager_flags, + bool show_header) { + + bool saved_header; + int r; + + assert(t); + + /* A all-in-one solution for showing tables, and turning on a pager first. Also optionally suppresses + * the table header and logs about any error. */ + + if (json_format_flags & (JSON_FORMAT_OFF|JSON_FORMAT_PRETTY|JSON_FORMAT_PRETTY_AUTO)) + (void) pager_open(pager_flags); + + saved_header = t->header; + t->header = show_header; + r = table_print_json(t, stdout, json_format_flags); + t->header = saved_header; + if (r < 0) + return table_log_print_error(r); + + return 0; +} diff --git a/src/shared/format-table.h b/src/shared/format-table.h index 965549b60..57f167f7f 100644 --- a/src/shared/format-table.h +++ b/src/shared/format-table.h @@ -7,6 +7,7 @@ #include "json.h" #include "macro.h" +#include "pager.h" typedef enum TableDataType { TABLE_EMPTY, @@ -38,6 +39,10 @@ typedef enum TableDataType { TABLE_IN6_ADDR, /* Takes a union in_addr_union (or a struct in6_addr) */ TABLE_ID128, TABLE_UUID, + TABLE_UID, + TABLE_GID, + TABLE_PID, + TABLE_SIGNAL, _TABLE_DATA_TYPE_MAX, /* The following are not really data types, but commands for table_add_cell_many() to make changes to @@ -53,19 +58,9 @@ typedef enum TableDataType { TABLE_SET_URL, TABLE_SET_UPPERCASE, - _TABLE_DATA_TYPE_INVALID = -1, + _TABLE_DATA_TYPE_INVALID = -EINVAL, } TableDataType; -/* PIDs are just 32bit signed integers on Linux */ -#define TABLE_PID TABLE_INT32 -assert_cc(sizeof(pid_t) == sizeof(int32_t)); - -/* UIDs/GIDs are just 32bit unsigned integers on Linux */ -#define TABLE_UID TABLE_UINT32 -#define TABLE_GID TABLE_UINT32 -assert_cc(sizeof(uid_t) == sizeof(uint32_t)); -assert_cc(sizeof(gid_t) == sizeof(uint32_t)); - typedef struct Table Table; typedef struct TableCell TableCell; @@ -78,7 +73,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Table*, table_unref); int table_add_cell_full(Table *t, TableCell **ret_cell, TableDataType type, const void *data, size_t minimum_width, size_t maximum_width, unsigned weight, unsigned align_percent, unsigned ellipsize_percent); static inline int table_add_cell(Table *t, TableCell **ret_cell, TableDataType type, const void *data) { - return table_add_cell_full(t, ret_cell, type, data, (size_t) -1, (size_t) -1, (unsigned) -1, (unsigned) -1, (unsigned) -1); + return table_add_cell_full(t, ret_cell, type, data, SIZE_MAX, SIZE_MAX, UINT_MAX, UINT_MAX, UINT_MAX); } int table_add_cell_stringf(Table *t, TableCell **ret_cell, const char *format, ...) _printf_(3, 4); @@ -105,9 +100,10 @@ void table_set_header(Table *table, bool b); void table_set_width(Table *t, size_t width); void table_set_cell_height_max(Table *t, size_t height); int table_set_empty_string(Table *t, const char *empty); -int table_set_display_all(Table *t); -int table_set_display(Table *t, size_t first_column, ...); -int table_set_sort(Table *t, size_t first_column, ...); +int table_set_display_internal(Table *t, size_t first_column, ...); +#define table_set_display(...) table_set_display_internal(__VA_ARGS__, SIZE_MAX) +int table_set_sort_internal(Table *t, size_t first_column, ...); +#define table_set_sort(...) table_set_sort_internal(__VA_ARGS__, SIZE_MAX) int table_set_reverse(Table *t, size_t column, bool b); int table_hide_column_from_display(Table *t, size_t column); @@ -129,6 +125,8 @@ const void *table_get_at(Table *t, size_t row, size_t column); int table_to_json(Table *t, JsonVariant **ret); int table_print_json(Table *t, FILE *f, JsonFormatFlags json_flags); +int table_print_with_pager(Table *t, JsonFormatFlags json_format_flags, PagerFlags pager_flags, bool show_header); + #define table_log_add_error(r) \ log_error_errno(r, "Failed to add cell(s) to table: %m") diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index 292b97cd6..f683f0598 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -79,34 +79,95 @@ int fstab_is_mount_point(const char *mount) { return false; } -int fstab_filter_options(const char *opts, const char *names, - const char **ret_namefound, char **ret_value, char **ret_filtered) { +int fstab_filter_options( + const char *opts, + const char *names, + const char **ret_namefound, + char **ret_value, + char ***ret_values, + char **ret_filtered) { + const char *name, *namefound = NULL, *x; - _cleanup_strv_free_ char **stor = NULL; - _cleanup_free_ char *v = NULL, **strv = NULL; + _cleanup_strv_free_ char **stor = NULL, **values = NULL; + _cleanup_free_ char *value = NULL, **filtered = NULL; int r; assert(names && *names); + assert(!(ret_value && ret_values)); if (!opts) goto answer; - /* If !ret_value and !ret_filtered, this function is not allowed to fail. */ + /* Finds any options matching 'names', and returns: + * - the last matching option name in ret_namefound, + * - the last matching value in ret_value, + * - any matching values in ret_values, + * - the rest of the option string in ret_filtered. + * + * If !ret_value and !ret_values and !ret_filtered, this function is not allowed to fail. + * + * Returns negative on error, true if any matching options were found, false otherwise. */ - if (!ret_filtered) { + if (ret_filtered || ret_value || ret_values) { + /* For backwards compatibility, we need to pass-through escape characters. + * The only ones we "consume" are the ones used as "\," or "\\". */ + r = strv_split_full(&stor, opts, ",", EXTRACT_UNESCAPE_SEPARATORS | EXTRACT_UNESCAPE_RELAX); + if (r < 0) + return r; + + filtered = memdup(stor, sizeof(char*) * (strv_length(stor) + 1)); + if (!filtered) + return -ENOMEM; + + char **t = filtered; + for (char **s = t; *s; s++) { + NULSTR_FOREACH(name, names) { + x = startswith(*s, name); + if (!x) + continue; + /* Match name, but when ret_values, only when followed by assignment. */ + if (*x == '=' || (!ret_values && *x == '\0')) + goto found; + } + + *t = *s; + t++; + continue; + found: + /* Keep the last occurrence found */ + namefound = name; + + if (ret_value || ret_values) { + assert(IN_SET(*x, '=', '\0')); + + if (ret_value) { + r = free_and_strdup(&value, *x == '=' ? x + 1 : NULL); + if (r < 0) + return r; + } else if (*x) { + r = strv_extend(&values, x + 1); + if (r < 0) + return r; + } + } + } + *t = NULL; + } else for (const char *word = opts;;) { const char *end = word; - /* Look for an *non-escaped* comma separator. Only commas can be escaped, so "\," is - * the only valid escape sequence, so we can do a very simple test here. */ + /* Look for a *non-escaped* comma separator. Only commas and backslashes can be + * escaped, so "\," and "\\" are the only valid escape sequences, and we can do a + * very simple test here. */ for (;;) { - size_t n = strcspn(end, ","); + end += strcspn(end, ",\\"); - end += n; - if (n > 0 && end[-1] == '\\') - end++; - else + if (IN_SET(*end, ',', '\0')) break; + assert(*end == '\\'); + end ++; /* Skip the backslash */ + if (*end != '\0') + end ++; /* Skip the escaped char, but watch out for a trailing comma */ } NULSTR_FOREACH(name, names) { @@ -119,17 +180,6 @@ int fstab_filter_options(const char *opts, const char *names, x = word + strlen(name); if (IN_SET(*x, '\0', '=', ',')) { namefound = name; - if (ret_value) { - bool eq = *x == '='; - assert(eq || IN_SET(*x, ',', '\0')); - - r = free_and_strndup(&v, - eq ? x + 1 : NULL, - eq ? end - x - 1 : 0); - if (r < 0) - return r; - } - break; } } @@ -139,38 +189,6 @@ int fstab_filter_options(const char *opts, const char *names, else break; } - } else { - r = strv_split_full(&stor, opts, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS); - if (r < 0) - return r; - - strv = memdup(stor, sizeof(char*) * (strv_length(stor) + 1)); - if (!strv) - return -ENOMEM; - - char **t = strv; - for (char **s = strv; *s; s++) { - NULSTR_FOREACH(name, names) { - x = startswith(*s, name); - if (x && IN_SET(*x, '\0', '=')) - goto found; - } - - *t = *s; - t++; - continue; - found: - /* Keep the last occurrence found */ - namefound = name; - if (ret_value) { - assert(IN_SET(*x, '=', '\0')); - r = free_and_strdup(&v, *x == '=' ? x + 1 : NULL); - if (r < 0) - return r; - } - } - *t = NULL; - } answer: if (ret_namefound) @@ -178,54 +196,27 @@ answer: if (ret_filtered) { char *f; - f = strv_join_full(strv, ",", NULL, true); + f = strv_join_full(filtered, ",", NULL, true); if (!f) return -ENOMEM; *ret_filtered = f; } if (ret_value) - *ret_value = TAKE_PTR(v); + *ret_value = TAKE_PTR(value); + if (ret_values) + *ret_values = TAKE_PTR(values); return !!namefound; } -int fstab_extract_values(const char *opts, const char *name, char ***values) { - _cleanup_strv_free_ char **optsv = NULL, **res = NULL; - char **s; - - assert(opts); - assert(name); - assert(values); - - optsv = strv_split(opts, ","); - if (!optsv) - return -ENOMEM; - - STRV_FOREACH(s, optsv) { - char *arg; - int r; - - arg = startswith(*s, name); - if (!arg || *arg != '=') - continue; - r = strv_extend(&res, arg + 1); - if (r < 0) - return r; - } - - *values = TAKE_PTR(res); - - return !!*values; -} - int fstab_find_pri(const char *options, int *ret) { _cleanup_free_ char *opt = NULL; int r, pri; assert(ret); - r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL); + r = fstab_filter_options(options, "pri\0", NULL, &opt, NULL, NULL); if (r < 0) return r; if (r == 0 || !opt) diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h index 1a602cb56..6b596baaf 100644 --- a/src/shared/fstab-util.h +++ b/src/shared/fstab-util.h @@ -10,12 +10,16 @@ bool fstab_is_extrinsic(const char *mount, const char *opts); int fstab_is_mount_point(const char *mount); int fstab_has_fstype(const char *fstype); -int fstab_filter_options(const char *opts, const char *names, const char **namefound, char **value, char **filtered); - -int fstab_extract_values(const char *opts, const char *name, char ***values); +int fstab_filter_options( + const char *opts, + const char *names, + const char **ret_namefound, + char **ret_value, + char ***ret_values, + char **ret_filtered); static inline bool fstab_test_option(const char *opts, const char *names) { - return !!fstab_filter_options(opts, names, NULL, NULL, NULL); + return !!fstab_filter_options(opts, names, NULL, NULL, NULL, NULL); } int fstab_find_pri(const char *options, int *ret); @@ -26,7 +30,7 @@ static inline bool fstab_test_yes_no_option(const char *opts, const char *yes_no /* If first name given is last, return 1. * If second name given is last or neither is found, return 0. */ - assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL) >= 0); + assert_se(fstab_filter_options(opts, yes_no, &opt, NULL, NULL, NULL) >= 0); return opt == yes_no; } diff --git a/src/shared/generate-ip-protocol-list.sh b/src/shared/generate-ip-protocol-list.sh index 3f9197949..749a1305c 100755 --- a/src/shared/generate-ip-protocol-list.sh +++ b/src/shared/generate-ip-protocol-list.sh @@ -1,4 +1,6 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later + set -eu $1 -dM -include netinet/in.h - +#include +#include +#include +#include + +#include "alloc-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "fs-util.h" +#include "hostname-setup.h" +#include "hostname-util.h" +#include "log.h" +#include "macro.h" +#include "proc-cmdline.h" +#include "string-table.h" +#include "string-util.h" +#include "util.h" + +static int sethostname_idempotent_full(const char *s, bool really) { + char buf[HOST_NAME_MAX + 1] = {}; + + assert(s); + + if (gethostname(buf, sizeof(buf) - 1) < 0) + return -errno; + + if (streq(buf, s)) + return 0; + + if (really && + sethostname(s, strlen(s)) < 0) + return -errno; + + return 1; +} + +int sethostname_idempotent(const char *s) { + return sethostname_idempotent_full(s, true); +} + +bool get_hostname_filtered(char ret[static HOST_NAME_MAX + 1]) { + char buf[HOST_NAME_MAX + 1] = {}; + + /* Returns true if we got a good hostname, false otherwise. */ + + if (gethostname(buf, sizeof(buf) - 1) < 0) + return false; /* This can realistically only fail with ENAMETOOLONG. + * Let's treat that case the same as an invalid hostname. */ + + if (isempty(buf)) + return false; + + /* This is the built-in kernel default hostname */ + if (streq(buf, "(none)")) + return false; + + memcpy(ret, buf, sizeof buf); + return true; +} + +int shorten_overlong(const char *s, char **ret) { + char *h, *p; + + /* Shorten an overlong name to HOST_NAME_MAX or to the first dot, + * whatever comes earlier. */ + + assert(s); + + h = strdup(s); + if (!h) + return -ENOMEM; + + if (hostname_is_valid(h, 0)) { + *ret = h; + return 0; + } + + p = strchr(h, '.'); + if (p) + *p = 0; + + strshorten(h, HOST_NAME_MAX); + + if (!hostname_is_valid(h, 0)) { + free(h); + return -EDOM; + } + + *ret = h; + return 1; +} + +int read_etc_hostname_stream(FILE *f, char **ret) { + int r; + + assert(f); + assert(ret); + + for (;;) { + _cleanup_free_ char *line = NULL; + char *p; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return r; + if (r == 0) /* EOF without any hostname? the file is empty, let's treat that exactly like no file at all: ENOENT */ + return -ENOENT; + + p = strstrip(line); + + /* File may have empty lines or comments, ignore them */ + if (!IN_SET(*p, '\0', '#')) { + char *copy; + + hostname_cleanup(p); /* normalize the hostname */ + + if (!hostname_is_valid(p, VALID_HOSTNAME_TRAILING_DOT)) /* check that the hostname we return is valid */ + return -EBADMSG; + + copy = strdup(p); + if (!copy) + return -ENOMEM; + + *ret = copy; + return 0; + } + } +} + +int read_etc_hostname(const char *path, char **ret) { + _cleanup_fclose_ FILE *f = NULL; + + assert(ret); + + if (!path) + path = "/etc/hostname"; + + f = fopen(path, "re"); + if (!f) + return -errno; + + return read_etc_hostname_stream(f, ret); +} + +void hostname_update_source_hint(const char *hostname, HostnameSource source) { + int r; + + /* Why save the value and not just create a flag file? This way we will + * notice if somebody sets the hostname directly (not going through hostnamed). + */ + + if (source == HOSTNAME_DEFAULT) { + r = write_string_file("/run/systemd/default-hostname", hostname, + WRITE_STRING_FILE_CREATE | WRITE_STRING_FILE_ATOMIC); + if (r < 0) + log_warning_errno(r, "Failed to create \"/run/systemd/default-hostname\": %m"); + } else + unlink_or_warn("/run/systemd/default-hostname"); +} + +int hostname_setup(bool really) { + _cleanup_free_ char *b = NULL; + const char *hn = NULL; + HostnameSource source; + bool enoent = false; + int r; + + r = proc_cmdline_get_key("systemd.hostname", 0, &b); + if (r < 0) + log_warning_errno(r, "Failed to retrieve system hostname from kernel command line, ignoring: %m"); + else if (r > 0) { + if (hostname_is_valid(b, true)) { + hn = b; + source = HOSTNAME_TRANSIENT; + } else { + log_warning("Hostname specified on kernel command line is invalid, ignoring: %s", b); + b = mfree(b); + } + } + + if (!hn) { + r = read_etc_hostname(NULL, &b); + if (r < 0) { + if (r == -ENOENT) + enoent = true; + else + log_warning_errno(r, "Failed to read configured hostname: %m"); + } else { + hn = b; + source = HOSTNAME_STATIC; + } + } + + if (!hn) { + /* Don't override the hostname if it is already set and not explicitly configured */ + + char buf[HOST_NAME_MAX + 1] = {}; + if (get_hostname_filtered(buf)) { + log_debug("No hostname configured, leaving existing hostname <%s> in place.", buf); + return 0; + } + + if (enoent) + log_info("No hostname configured, using default hostname."); + + hn = b = get_default_hostname(); + if (!hn) + return log_oom(); + + source = HOSTNAME_DEFAULT; + + } + + r = sethostname_idempotent_full(hn, really); + if (r < 0) + return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn); + if (r == 0) + log_debug("Hostname was already set to <%s>.", hn); + else + log_info("Hostname %s to <%s>.", + really ? "set" : "would have been set", + hn); + + if (really) + hostname_update_source_hint(hn, source); + + return r; +} + +static const char* const hostname_source_table[] = { + [HOSTNAME_STATIC] = "static", + [HOSTNAME_TRANSIENT] = "transient", + [HOSTNAME_DEFAULT] = "default", +}; + +DEFINE_STRING_TABLE_LOOKUP(hostname_source, HostnameSource); diff --git a/src/shared/hostname-setup.h b/src/shared/hostname-setup.h new file mode 100644 index 000000000..5ac7241a5 --- /dev/null +++ b/src/shared/hostname-setup.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +typedef enum HostnameSource { + HOSTNAME_STATIC, /* from /etc/hostname */ + HOSTNAME_TRANSIENT, /* a transient hostname set through systemd, hostnamed, the container manager, or otherwise */ + HOSTNAME_DEFAULT, /* the os-release default or the compiled-in fallback were used */ + _HOSTNAME_INVALID = -EINVAL, +} HostnameSource; + +const char* hostname_source_to_string(HostnameSource source) _const_; +HostnameSource hostname_source_from_string(const char *str) _pure_; + +int sethostname_idempotent(const char *s); + +int shorten_overlong(const char *s, char **ret); + +int read_etc_hostname_stream(FILE *f, char **ret); +int read_etc_hostname(const char *path, char **ret); + +bool get_hostname_filtered(char ret[static HOST_NAME_MAX + 1]); +void hostname_update_source_hint(const char *hostname, HostnameSource source); +int hostname_setup(bool really); diff --git a/src/shared/id128-print.h b/src/shared/id128-print.h index d69cb9b55..7b2e593f1 100644 --- a/src/shared/id128-print.h +++ b/src/shared/id128-print.h @@ -11,7 +11,7 @@ typedef enum Id128PrettyPrintMode { ID128_PRINT_UUID, ID128_PRINT_PRETTY, _ID128_PRETTY_PRINT_MODE_MAX, - _ID128_PRETTY_PRINT_MODE_INVALID = -1 + _ID128_PRETTY_PRINT_MODE_INVALID = -EINVAL, } Id128PrettyPrintMode; int id128_pretty_print_sample(const char *name, sd_id128_t id); diff --git a/src/shared/idn-util.c b/src/shared/idn-util.c index 83c4b3c53..1c4472dc6 100644 --- a/src/shared/idn-util.c +++ b/src/shared/idn-util.c @@ -35,9 +35,9 @@ int dlopen_idn(void) { r = dlsym_many_and_warn( dl, LOG_DEBUG, - &sym_idn2_lookup_u8, "idn2_lookup_u8", - &sym_idn2_strerror, "idn2_strerror", - &sym_idn2_to_unicode_8z8z, "idn2_to_unicode_8z8z", + DLSYM_ARG(idn2_lookup_u8), + DLSYM_ARG(idn2_strerror), + DLSYM_ARG(idn2_to_unicode_8z8z), NULL); if (r < 0) return r; @@ -76,10 +76,10 @@ int dlopen_idn(void) { r = dlsym_many_and_warn( dl, LOG_DEBUG, - &sym_idna_to_ascii_4i, "idna_to_ascii_4i", - &sym_idna_to_unicode_44i, "idna_to_unicode_44i", - &sym_stringprep_ucs4_to_utf8, "stringprep_ucs4_to_utf8", - &sym_stringprep_utf8_to_ucs4, "stringprep_utf8_to_ucs4", + DLSYM_ARG(idna_to_ascii_4i), + DLSYM_ARG(idna_to_unicode_44i), + DLSYM_ARG(stringprep_ucs4_to_utf8), + DLSYM_ARG(stringprep_utf8_to_ucs4), NULL); if (r < 0) return r; diff --git a/src/shared/import-util.c b/src/shared/import-util.c index 298c066df..2a30e4068 100644 --- a/src/shared/import-util.c +++ b/src/shared/import-util.c @@ -143,15 +143,7 @@ int raw_strip_suffixes(const char *p, char **ret) { int import_assign_pool_quota_and_warn(const char *path) { int r; - r = btrfs_subvol_auto_qgroup("/var/lib/machines", 0, true); - if (r == -ENOTTY) { - log_debug_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines, as directory is not on btrfs or not a subvolume. Ignoring."); - return 0; - } - if (r < 0) - return log_error_errno(r, "Failed to set up default quota hierarchy for /var/lib/machines: %m"); - if (r > 0) - log_info("Set up default quota hierarchy for /var/lib/machines."); + assert(path); r = btrfs_subvol_auto_qgroup(path, 0, true); if (r == -ENOTTY) { diff --git a/src/shared/import-util.h b/src/shared/import-util.h index 8d017f61d..c7ec3b4ea 100644 --- a/src/shared/import-util.h +++ b/src/shared/import-util.h @@ -10,7 +10,7 @@ typedef enum ImportVerify { IMPORT_VERIFY_CHECKSUM, IMPORT_VERIFY_SIGNATURE, _IMPORT_VERIFY_MAX, - _IMPORT_VERIFY_INVALID = -1, + _IMPORT_VERIFY_INVALID = -EINVAL, } ImportVerify; int import_url_last_component(const char *url, char **ret); diff --git a/src/shared/initreq.h b/src/shared/initreq.h index 1bf5b8edd..da9783c09 100644 --- a/src/shared/initreq.h +++ b/src/shared/initreq.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2+ */ +/* SPDX-License-Identifier: LGPL-2.0-or-later */ /* * initreq.h Interface to talk to init through /dev/initctl. * diff --git a/src/shared/install.c b/src/shared/install.c index 302497a96..c6cea4312 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -14,6 +14,7 @@ #include "conf-parser.h" #include "def.h" #include "dirent-util.h" +#include "errno-list.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" @@ -261,7 +262,7 @@ static const char* config_path_from_flags(const LookupPaths *paths, UnitFileFlag int unit_file_changes_add( UnitFileChange **changes, size_t *n_changes, - int type, + int type_or_errno, /* UNIT_FILE_SYMLINK, _UNLINK, _IS_MASKED, _IS_DANGLING if positive or errno if negative */ const char *path, const char *source) { @@ -271,6 +272,11 @@ int unit_file_changes_add( assert(path); assert(!changes == !n_changes); + if (type_or_errno >= 0) + assert(type_or_errno < _UNIT_FILE_CHANGE_TYPE_MAX); + else + assert(type_or_errno >= -ERRNO_MAX); + if (!changes) return 0; @@ -280,19 +286,25 @@ int unit_file_changes_add( *changes = c; p = strdup(path); - if (source) - s = strdup(source); - - if (!p || (source && !s)) + if (!p) return -ENOMEM; path_simplify(p, false); - if (s) - path_simplify(s, false); - c[*n_changes] = (UnitFileChange) { type, p, s }; - p = s = NULL; - (*n_changes) ++; + if (source) { + s = strdup(source); + if (!s) + return -ENOMEM; + + path_simplify(s, false); + } + + c[(*n_changes)++] = (UnitFileChange) { + .type_or_errno = type_or_errno, + .path = TAKE_PTR(p), + .source = TAKE_PTR(s), + }; + return 0; } @@ -315,9 +327,9 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang assert(verb || r >= 0); for (size_t i = 0; i < n_changes; i++) { - assert(verb || changes[i].type >= 0); + assert(verb || changes[i].type_or_errno >= 0); - switch(changes[i].type) { + switch(changes[i].type_or_errno) { case UNIT_FILE_SYMLINK: if (!quiet) log_info("Created symlink %s %s %s.", @@ -340,45 +352,45 @@ void unit_file_dump_changes(int r, const char *verb, const UnitFileChange *chang break; case -EEXIST: if (changes[i].source) - log_error_errno(changes[i].type, + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file %s already exists and is a symlink to %s.", verb, changes[i].path, changes[i].source); else - log_error_errno(changes[i].type, + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file %s already exists.", verb, changes[i].path); logged = true; break; case -ERFKILL: - log_error_errno(changes[i].type, "Failed to %s unit, unit %s is masked.", + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is masked.", verb, changes[i].path); logged = true; break; case -EADDRNOTAVAIL: - log_error_errno(changes[i].type, "Failed to %s unit, unit %s is transient or generated.", + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s is transient or generated.", verb, changes[i].path); logged = true; break; case -EUCLEAN: - log_error_errno(changes[i].type, + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, \"%s\" is not a valid unit name.", verb, changes[i].path); logged = true; break; case -ELOOP: - log_error_errno(changes[i].type, "Failed to %s unit, refusing to operate on linked unit file %s", + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, refusing to operate on linked unit file %s", verb, changes[i].path); logged = true; break; case -ENOENT: - log_error_errno(changes[i].type, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, unit %s does not exist.", verb, changes[i].path); logged = true; break; default: - assert(changes[i].type < 0); - log_error_errno(changes[i].type, "Failed to %s unit, file %s: %m.", + assert(changes[i].type_or_errno < 0); + log_error_errno(changes[i].type_or_errno, "Failed to %s unit, file %s: %m.", verb, changes[i].path); logged = true; } @@ -693,132 +705,88 @@ static int is_symlink_with_known_name(const UnitFileInstallInfo *i, const char * return false; } -static int find_symlinks_fd( +static int find_symlinks_in_directory( + DIR *dir, + const char *dir_path, const char *root_dir, const UnitFileInstallInfo *i, bool match_aliases, bool ignore_same_name, - int fd, - const char *path, const char *config_path, bool *same_name_link) { - _cleanup_closedir_ DIR *d = NULL; struct dirent *de; int r = 0; - assert(i); - assert(fd >= 0); - assert(path); - assert(config_path); - assert(same_name_link); + FOREACH_DIRENT(de, dir, return -errno) { + _cleanup_free_ char *dest = NULL; + bool found_path = false, found_dest, b = false; + int q; - d = fdopendir(fd); - if (!d) { - safe_close(fd); - return -errno; - } + dirent_ensure_type(dir, de); - FOREACH_DIRENT(de, d, return -errno) { + if (de->d_type != DT_LNK) + continue; - dirent_ensure_type(d, de); - - if (de->d_type == DT_DIR) { - _cleanup_free_ char *p = NULL; - int nfd, q; - - nfd = openat(fd, de->d_name, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW); - if (nfd < 0) { - if (errno == ENOENT) - continue; - - if (r == 0) - r = -errno; - continue; - } - - p = path_make_absolute(de->d_name, path); - if (!p) { - safe_close(nfd); - return -ENOMEM; - } - - /* This will close nfd, regardless whether it succeeds or not */ - q = find_symlinks_fd(root_dir, i, match_aliases, ignore_same_name, nfd, - p, config_path, same_name_link); - if (q > 0) - return 1; + /* Acquire symlink destination */ + q = readlinkat_malloc(dirfd(dir), de->d_name, &dest); + if (q == -ENOENT) + continue; + if (q < 0) { if (r == 0) r = q; + continue; + } - } else if (de->d_type == DT_LNK) { - _cleanup_free_ char *p = NULL, *dest = NULL; - bool found_path = false, found_dest, b = false; - int q; + /* Make absolute */ + if (!path_is_absolute(dest)) { + char *x; - /* Acquire symlink name */ - p = path_make_absolute(de->d_name, path); - if (!p) + x = path_join(dir_path, dest); + if (!x) return -ENOMEM; - /* Acquire symlink destination */ - q = readlink_malloc(p, &dest); - if (q == -ENOENT) - continue; - if (q < 0) { - if (r == 0) - r = q; - continue; - } + free_and_replace(dest, x); + } - /* Make absolute */ - if (!path_is_absolute(dest)) { - char *x; + assert(unit_name_is_valid(i->name, UNIT_NAME_ANY)); + if (!ignore_same_name) + /* Check if the symlink itself matches what we are looking for. + * + * If ignore_same_name is specified, we are in one of the directories which + * have lower priority than the unit file, and even if a file or symlink with + * this name was found, we should ignore it. */ + found_path = streq(de->d_name, i->name); - x = path_join(root_dir, dest); - if (!x) - return -ENOMEM; + /* Check if what the symlink points to matches what we are looking for */ + found_dest = streq(basename(dest), i->name); - free_and_replace(dest, x); - } + if (found_path && found_dest) { + _cleanup_free_ char *p = NULL, *t = NULL; - assert(unit_name_is_valid(i->name, UNIT_NAME_ANY)); - if (!ignore_same_name) - /* Check if the symlink itself matches what we are looking for. - * - * If ignore_same_name is specified, we are in one of the directories which - * have lower priority than the unit file, and even if a file or symlink with - * this name was found, we should ignore it. */ - found_path = streq(de->d_name, i->name); + /* Filter out same name links in the main + * config path */ + p = path_make_absolute(de->d_name, dir_path); + t = path_make_absolute(i->name, config_path); - /* Check if what the symlink points to matches what we are looking for */ - found_dest = streq(basename(dest), i->name); + if (!p || !t) + return -ENOMEM; - if (found_path && found_dest) { - _cleanup_free_ char *t = NULL; + b = path_equal(p, t); + } - /* Filter out same name links in the main - * config path */ - t = path_make_absolute(i->name, config_path); - if (!t) - return -ENOMEM; + if (b) + *same_name_link = true; + else if (found_path || found_dest) { + if (!match_aliases) + return 1; - b = path_equal(t, p); - } - - if (b) - *same_name_link = true; - else if (found_path || found_dest) { - if (!match_aliases) - return 1; - - /* Check if symlink name is in the set of names used by [Install] */ - q = is_symlink_with_known_name(i, de->d_name); - if (q < 0) - return q; - if (q > 0) - return 1; - } + /* Check if symlink name is in the set of names used by [Install] */ + q = is_symlink_with_known_name(i, de->d_name); + if (q < 0) + return q; + if (q > 0) + return 1; } } @@ -833,22 +801,55 @@ static int find_symlinks( const char *config_path, bool *same_name_link) { - int fd; + _cleanup_closedir_ DIR *config_dir = NULL; + struct dirent *de; + int r = 0; assert(i); assert(config_path); assert(same_name_link); - fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC); - if (fd < 0) { + config_dir = opendir(config_path); + if (!config_dir) { if (IN_SET(errno, ENOENT, ENOTDIR, EACCES)) return 0; return -errno; } - /* This takes possession of fd and closes it */ - return find_symlinks_fd(root_dir, i, match_name, ignore_same_name, fd, - config_path, config_path, same_name_link); + FOREACH_DIRENT(de, config_dir, return -errno) { + const char *suffix; + _cleanup_free_ const char *path = NULL; + _cleanup_closedir_ DIR *d = NULL; + + dirent_ensure_type(config_dir, de); + + if (de->d_type != DT_DIR) + continue; + + suffix = strrchr(de->d_name, '.'); + if (!STRPTR_IN_SET(suffix, ".wants", ".requires")) + continue; + + path = path_join(config_path, de->d_name); + if (!path) + return -ENOMEM; + + d = opendir(path); + if (!d) { + log_error_errno(errno, "Failed to open directory '%s' while scanning for symlinks, ignoring: %m", path); + continue; + } + + r = find_symlinks_in_directory(d, path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link); + if (r > 0) + return 1; + else if (r < 0) + log_debug_errno(r, "Failed to lookup for symlinks in '%s': %m", path); + } + + /* We didn't find any suitable symlinks in .wants or .requires directories, let's look for linked unit files in this directory. */ + rewinddir(config_dir); + return find_symlinks_in_directory(config_dir, config_path, root_dir, i, match_name, ignore_same_name, config_path, same_name_link); } static int find_symlinks_in_scope( @@ -1041,10 +1042,6 @@ static int install_info_add( return 0; } - r = ordered_hashmap_ensure_allocated(&c->will_process, &string_hash_ops); - if (r < 0) - return r; - i = new(UnitFileInstallInfo, 1); if (!i) return -ENOMEM; @@ -1068,7 +1065,7 @@ static int install_info_add( } } - r = ordered_hashmap_put(c->will_process, i->name, i); + r = ordered_hashmap_ensure_put(&c->will_process, &string_hash_ops, i->name, i); if (r < 0) goto fail; @@ -1327,8 +1324,8 @@ static int unit_file_load_or_readlink( const char *path, const char *root_dir, SearchFlags flags) { + _cleanup_free_ char *resolved = NULL; - struct stat st; int r; r = unit_file_load(c, info, path, root_dir, flags); @@ -1343,9 +1340,7 @@ static int unit_file_load_or_readlink( * so let's see if the path is a (possibly dangling) symlink to /dev/null. */ info->type = UNIT_FILE_TYPE_MASKED; - else if (r > 0 && - stat(resolved, &st) >= 0 && - null_or_empty(&st)) + else if (r > 0 && null_or_empty_path(resolved) > 0) info->type = UNIT_FILE_TYPE_MASKED; @@ -3350,12 +3345,12 @@ int unit_file_preset_all( return execute_preset(scope, &plus, &minus, &paths, config_path, NULL, mode, !!(flags & UNIT_FILE_FORCE), changes, n_changes); } -static void unit_file_list_free_one(UnitFileList *f) { +static UnitFileList* unit_file_list_free_one(UnitFileList *f) { if (!f) - return; + return NULL; free(f->path); - free(f); + return mfree(f); } Hashmap* unit_file_list_free(Hashmap *h) { @@ -3468,7 +3463,7 @@ static const char* const unit_file_change_type_table[_UNIT_FILE_CHANGE_TYPE_MAX] [UNIT_FILE_IS_DANGLING] = "dangling", }; -DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, UnitFileChangeType); +DEFINE_STRING_TABLE_LOOKUP(unit_file_change_type, int); static const char* const unit_file_preset_mode_table[_UNIT_FILE_PRESET_MAX] = { [UNIT_FILE_PRESET_FULL] = "full", diff --git a/src/shared/install.h b/src/shared/install.h index 84bf1f59d..948faa0ca 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include + typedef enum UnitFilePresetMode UnitFilePresetMode; typedef enum UnitFileChangeType UnitFileChangeType; typedef enum UnitFileFlags UnitFileFlags; @@ -9,8 +11,6 @@ typedef struct UnitFileChange UnitFileChange; typedef struct UnitFileList UnitFileList; typedef struct UnitFileInstallInfo UnitFileInstallInfo; -#include - #include "hashmap.h" #include "macro.h" #include "path-lookup.h" @@ -22,16 +22,18 @@ enum UnitFilePresetMode { UNIT_FILE_PRESET_ENABLE_ONLY, UNIT_FILE_PRESET_DISABLE_ONLY, _UNIT_FILE_PRESET_MAX, - _UNIT_FILE_PRESET_INVALID = -1 + _UNIT_FILE_PRESET_INVALID = -EINVAL, }; -enum UnitFileChangeType { +/* This enum type is anonymous, since we usually store it in an 'int', as we overload it with negative errno + * values. */ +enum { UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK, UNIT_FILE_IS_MASKED, UNIT_FILE_IS_DANGLING, _UNIT_FILE_CHANGE_TYPE_MAX, - _UNIT_FILE_CHANGE_TYPE_INVALID = INT_MIN + _UNIT_FILE_CHANGE_TYPE_INVALID = -EINVAL, }; enum UnitFileFlags { @@ -42,20 +44,18 @@ enum UnitFileFlags { _UNIT_FILE_FLAGS_MASK_PUBLIC = UNIT_FILE_RUNTIME|UNIT_FILE_PORTABLE|UNIT_FILE_FORCE, }; -/* type can either one of the UnitFileChangeTypes listed above, or a negative error. - * If source is specified, it should be the contents of the path symlink. - * In case of an error, source should be the existing symlink contents or NULL - */ +/* type can either one of the UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK, … listed above, or a negative errno value. + * If source is specified, it should be the contents of the path symlink. In case of an error, source should + * be the existing symlink contents or NULL. */ struct UnitFileChange { - int type; /* UnitFileChangeType or bust */ + int type_or_errno; /* UNIT_FILE_SYMLINK, … if positive, errno if negative */ char *path; char *source; }; static inline bool unit_file_changes_have_modification(const UnitFileChange* changes, size_t n_changes) { - size_t i; - for (i = 0; i < n_changes; i++) - if (IN_SET(changes[i].type, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK)) + for (size_t i = 0; i < n_changes; i++) + if (IN_SET(changes[i].type_or_errno, UNIT_FILE_SYMLINK, UNIT_FILE_UNLINK)) return true; return false; } @@ -70,7 +70,7 @@ enum UnitFileType { UNIT_FILE_TYPE_SYMLINK, UNIT_FILE_TYPE_MASKED, _UNIT_FILE_TYPE_MAX, - _UNIT_FILE_TYPE_INVALID = -1, + _UNIT_FILE_TYPE_INVALID = -EINVAL, }; struct UnitFileInstallInfo { @@ -206,8 +206,8 @@ const char *unit_file_state_to_string(UnitFileState s) _const_; UnitFileState unit_file_state_from_string(const char *s) _pure_; /* from_string conversion is unreliable because of the overlap between -EPERM and -1 for error. */ -const char *unit_file_change_type_to_string(UnitFileChangeType s) _const_; -UnitFileChangeType unit_file_change_type_from_string(const char *s) _pure_; +const char *unit_file_change_type_to_string(int s) _const_; +int unit_file_change_type_from_string(const char *s) _pure_; const char *unit_file_preset_mode_to_string(UnitFilePresetMode m) _const_; UnitFilePresetMode unit_file_preset_mode_from_string(const char *s) _pure_; diff --git a/src/shared/ip-protocol-to-name.awk b/src/shared/ip-protocol-to-name.awk index 824f811f5..a0671e7ee 100644 --- a/src/shared/ip-protocol-to-name.awk +++ b/src/shared/ip-protocol-to-name.awk @@ -1,3 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + BEGIN{ print "static const char* const ip_protocol_names[] = { " } diff --git a/src/shared/ipvlan-util.h b/src/shared/ipvlan-util.h index 90f755b47..a475b3757 100644 --- a/src/shared/ipvlan-util.h +++ b/src/shared/ipvlan-util.h @@ -11,7 +11,7 @@ typedef enum IPVlanMode { NETDEV_IPVLAN_MODE_L3 = IPVLAN_MODE_L3, NETDEV_IPVLAN_MODE_L3S = IPVLAN_MODE_L3S, _NETDEV_IPVLAN_MODE_MAX, - _NETDEV_IPVLAN_MODE_INVALID = -1 + _NETDEV_IPVLAN_MODE_INVALID = -EINVAL, } IPVlanMode; typedef enum IPVlanFlags { @@ -19,7 +19,7 @@ typedef enum IPVlanFlags { NETDEV_IPVLAN_FLAGS_PRIVATE = IPVLAN_F_PRIVATE, NETDEV_IPVLAN_FLAGS_VEPA = IPVLAN_F_VEPA, _NETDEV_IPVLAN_FLAGS_MAX, - _NETDEV_IPVLAN_FLAGS_INVALID = -1 + _NETDEV_IPVLAN_FLAGS_INVALID = -EINVAL, } IPVlanFlags; const char *ipvlan_mode_to_string(IPVlanMode d) _const_; diff --git a/src/shared/json-internal.h b/src/shared/json-internal.h index 63afd2241..72a735171 100644 --- a/src/shared/json-internal.h +++ b/src/shared/json-internal.h @@ -70,7 +70,7 @@ enum { /* JSON tokens */ JSON_TOKEN_BOOLEAN, JSON_TOKEN_NULL, _JSON_TOKEN_MAX, - _JSON_TOKEN_INVALID = -1, + _JSON_TOKEN_INVALID = -EINVAL, }; int json_tokenize(const char **p, char **ret_string, JsonValue *ret_value, unsigned *ret_line, unsigned *ret_column, void **state, unsigned *line, unsigned *column); diff --git a/src/shared/json.c b/src/shared/json.c index ddf6dcb66..ef1e93764 100644 --- a/src/shared/json.c +++ b/src/shared/json.c @@ -64,7 +64,10 @@ struct JsonVariant { JsonSource *source; unsigned line, column; - JsonVariantType type:5; + /* The current 'depth' of the JsonVariant, i.e. how many levels of member variants this has */ + uint16_t depth; + + JsonVariantType type:8; /* A marker whether this variant is embedded into in array/object or not. If true, the 'parent' pointer above * is valid. If false, the 'n_ref' field above is valid instead. */ @@ -87,9 +90,6 @@ struct JsonVariant { /* If in addition to this object all objects referenced by it are also ordered strictly by name */ bool normalized:1; - /* The current 'depth' of the JsonVariant, i.e. how many levels of member variants this has */ - uint16_t depth; - union { /* For simple types we store the value in-line. */ JsonValue value; @@ -393,10 +393,10 @@ int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n) { assert_return(ret, -EINVAL); if (!s) { - assert_return(IN_SET(n, 0, (size_t) -1), -EINVAL); + assert_return(IN_SET(n, 0, SIZE_MAX), -EINVAL); return json_variant_new_null(ret); } - if (n == (size_t) -1) /* determine length automatically */ + if (n == SIZE_MAX) /* determine length automatically */ n = strlen(s); else if (memchr(s, 0, n)) /* don't allow embedded NUL, as we can't express that in JSON */ return -EINVAL; @@ -433,6 +433,19 @@ int json_variant_new_base64(JsonVariant **ret, const void *p, size_t n) { return json_variant_new_stringn(ret, s, k); } +int json_variant_new_hex(JsonVariant **ret, const void *p, size_t n) { + _cleanup_free_ char *s = NULL; + + assert_return(ret, -EINVAL); + assert_return(n == 0 || p, -EINVAL); + + s = hexmem(p, n); + if (!s) + return -ENOMEM; + + return json_variant_new_stringn(ret, s, n*2); +} + int json_variant_new_id128(JsonVariant **ret, sd_id128_t id) { char s[SD_ID128_STRING_MAX]; @@ -1495,7 +1508,7 @@ static void json_format_string(FILE *f, const char *q, JsonFormatFlags flags) { fputc('"', f); if (flags & JSON_FORMAT_COLOR) - fputs(ANSI_GREEN, f); + fputs(ansi_green(), f); for (; *q; q++) switch (*q) { @@ -1557,7 +1570,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha return -errno; if (flags & JSON_FORMAT_COLOR) - fputs(ANSI_HIGHLIGHT_BLUE, f); + fputs(ansi_highlight_blue(), f); fprintf(f, "%.*Le", DECIMAL_DIG, json_variant_real(v)); @@ -1570,7 +1583,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha case JSON_VARIANT_INTEGER: if (flags & JSON_FORMAT_COLOR) - fputs(ANSI_HIGHLIGHT_BLUE, f); + fputs(ansi_highlight_blue(), f); fprintf(f, "%" PRIdMAX, json_variant_integer(v)); @@ -1580,7 +1593,7 @@ static int json_format(FILE *f, JsonVariant *v, JsonFormatFlags flags, const cha case JSON_VARIANT_UNSIGNED: if (flags & JSON_FORMAT_COLOR) - fputs(ANSI_HIGHLIGHT_BLUE, f); + fputs(ansi_highlight_blue(), f); fprintf(f, "%" PRIuMAX, json_variant_unsigned(v)); @@ -1753,6 +1766,9 @@ int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret) { assert_return(v, -EINVAL); assert_return(ret, -EINVAL); + if (flags & JSON_FORMAT_OFF) + return -ENOEXEC; + { _cleanup_fclose_ FILE *f = NULL; @@ -2492,7 +2508,7 @@ static int json_parse_string(const char **p, char **ret) { continue; } - len = utf8_encoded_valid_unichar(c, (size_t) -1); + len = utf8_encoded_valid_unichar(c, SIZE_MAX); if (len < 0) return len; @@ -2812,7 +2828,7 @@ typedef struct JsonStack { size_t n_elements, n_elements_allocated; unsigned line_before; unsigned column_before; - size_t n_suppress; /* When building: if > 0, suppress this many subsequent elements. If == (size_t) -1, suppress all subsequent elements */ + size_t n_suppress; /* When building: if > 0, suppress this many subsequent elements. If == SIZE_MAX, suppress all subsequent elements */ } JsonStack; static void json_stack_release(JsonStack *s) { @@ -3195,7 +3211,7 @@ int json_parse_file_at(FILE *f, int dir_fd, const char *path, JsonParseFlags fla if (f) r = read_full_stream(f, &text, NULL); else if (path) - r = read_full_file_full(dir_fd, path, 0, NULL, &text, NULL); + r = read_full_file_full(dir_fd, path, UINT64_MAX, SIZE_MAX, 0, NULL, &text, NULL); else return -EINVAL; if (r < 0) @@ -3516,7 +3532,7 @@ int json_buildv(JsonVariant **ret, va_list ap) { stack[n_stack++] = (JsonStack) { .expect = EXPECT_ARRAY_ELEMENT, - .n_suppress = current->n_suppress != 0 ? (size_t) -1 : 0, /* if we shall suppress the + .n_suppress = current->n_suppress != 0 ? SIZE_MAX : 0, /* if we shall suppress the * new array, then we should * also suppress all array * members */ @@ -3603,6 +3619,36 @@ int json_buildv(JsonVariant **ret, va_list ap) { break; } + case _JSON_BUILD_HEX: { + const void *p; + size_t n; + + if (!IN_SET(current->expect, EXPECT_TOPLEVEL, EXPECT_OBJECT_VALUE, EXPECT_ARRAY_ELEMENT)) { + r = -EINVAL; + goto finish; + } + + p = va_arg(ap, const void *); + n = va_arg(ap, size_t); + + if (current->n_suppress == 0) { + r = json_variant_new_hex(&add, p, n); + if (r < 0) + goto finish; + } + + n_subtract = 1; + + if (current->expect == EXPECT_TOPLEVEL) + current->expect = EXPECT_END; + else if (current->expect == EXPECT_OBJECT_VALUE) + current->expect = EXPECT_OBJECT_KEY; + else + assert(current->expect == EXPECT_ARRAY_ELEMENT); + + break; + } + case _JSON_BUILD_ID128: { sd_id128_t id; @@ -3683,7 +3729,7 @@ int json_buildv(JsonVariant **ret, va_list ap) { stack[n_stack++] = (JsonStack) { .expect = EXPECT_OBJECT_KEY, - .n_suppress = current->n_suppress != 0 ? (size_t) -1 : 0, /* if we shall suppress the + .n_suppress = current->n_suppress != 0 ? SIZE_MAX : 0, /* if we shall suppress the * new object, then we should * also suppress all object * members */ @@ -3755,7 +3801,7 @@ int json_buildv(JsonVariant **ret, va_list ap) { n_subtract = 1; /* we generated one item */ - if (!b && current->n_suppress != (size_t) -1) + if (!b && current->n_suppress != SIZE_MAX) current->n_suppress += 2; /* Suppress this one and the next item */ current->expect = EXPECT_OBJECT_VALUE; @@ -3773,9 +3819,9 @@ int json_buildv(JsonVariant **ret, va_list ap) { } /* If we are supposed to suppress items, let's subtract how many items where generated from that - * counter. Except if the counter is (size_t) -1, i.e. we shall suppress an infinite number of elements + * counter. Except if the counter is SIZE_MAX, i.e. we shall suppress an infinite number of elements * on this stack level */ - if (current->n_suppress != (size_t) -1) { + if (current->n_suppress != SIZE_MAX) { if (current->n_suppress <= n_subtract) /* Saturated */ current->n_suppress = 0; else @@ -3845,7 +3891,7 @@ int json_log_internal( if (source && source_line > 0 && source_column > 0) return log_struct_internal( - LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level), + level, error, file, line, func, "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, @@ -3854,9 +3900,19 @@ int json_log_internal( "CONFIG_COLUMN=%u", source_column, LOG_MESSAGE("%s:%u:%u: %s", source, source_line, source_column, buffer), NULL); + else if (source_line > 0 && source_column > 0) + return log_struct_internal( + level, + error, + file, line, func, + "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, + "CONFIG_LINE=%u", source_line, + "CONFIG_COLUMN=%u", source_column, + LOG_MESSAGE("(string):%u:%u: %s", source_line, source_column, buffer), + NULL); else return log_struct_internal( - LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, level), + level, error, file, line, func, "MESSAGE_ID=" SD_MESSAGE_INVALID_CONFIGURATION_STR, @@ -4007,7 +4063,7 @@ int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchF return 0; } -int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { +int json_dispatch_intmax(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { intmax_t *i = userdata; assert(variant); @@ -4020,7 +4076,7 @@ int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFl return 0; } -int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { +int json_dispatch_uintmax(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { uintmax_t *u = userdata; assert(variant); @@ -4177,7 +4233,7 @@ int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFl assert_cc(sizeof(gid_t) == sizeof(uint32_t)); DISABLE_WARNING_TYPE_LIMITS; - assert_cc(((uid_t) -1 < (uid_t) 0) == ((gid_t) -1 < (gid_t) 0)); + assert_cc((UID_INVALID < (uid_t) 0) == (GID_INVALID < (gid_t) 0)); REENABLE_WARNING; if (json_variant_is_null(variant)) { @@ -4392,7 +4448,15 @@ int json_variant_unbase64(JsonVariant *v, void **ret, size_t *ret_size) { if (!json_variant_is_string(v)) return -EINVAL; - return unbase64mem(json_variant_string(v), (size_t) -1, ret, ret_size); + return unbase64mem(json_variant_string(v), SIZE_MAX, ret, ret_size); +} + +int json_variant_unhex(JsonVariant *v, void **ret, size_t *ret_size) { + + if (!json_variant_is_string(v)) + return -EINVAL; + + return unhexmem(json_variant_string(v), SIZE_MAX, ret, ret_size); } static const char* const json_variant_type_table[_JSON_VARIANT_TYPE_MAX] = { diff --git a/src/shared/json.h b/src/shared/json.h index 0809f3187..148701a54 100644 --- a/src/shared/json.h +++ b/src/shared/json.h @@ -53,11 +53,12 @@ typedef enum JsonVariantType { JSON_VARIANT_OBJECT, JSON_VARIANT_NULL, _JSON_VARIANT_TYPE_MAX, - _JSON_VARIANT_TYPE_INVALID = -1 + _JSON_VARIANT_TYPE_INVALID = -EINVAL, } JsonVariantType; int json_variant_new_stringn(JsonVariant **ret, const char *s, size_t n); int json_variant_new_base64(JsonVariant **ret, const void *p, size_t n); +int json_variant_new_hex(JsonVariant **ret, const void *p, size_t n); int json_variant_new_integer(JsonVariant **ret, intmax_t i); int json_variant_new_unsigned(JsonVariant **ret, uintmax_t u); int json_variant_new_real(JsonVariant **ret, long double d); @@ -70,7 +71,7 @@ int json_variant_new_null(JsonVariant **ret); int json_variant_new_id128(JsonVariant **ret, sd_id128_t id); static inline int json_variant_new_string(JsonVariant **ret, const char *s) { - return json_variant_new_stringn(ret, s, (size_t) -1); + return json_variant_new_stringn(ret, s, SIZE_MAX); } JsonVariant *json_variant_ref(JsonVariant *v); @@ -174,6 +175,7 @@ typedef enum JsonFormatFlags { JSON_FORMAT_SSE = 1 << 6, /* prefix/suffix with W3C server-sent events */ JSON_FORMAT_SEQ = 1 << 7, /* prefix/suffix with RFC 7464 application/json-seq */ JSON_FORMAT_FLUSH = 1 << 8, /* call fflush() after dumping JSON */ + JSON_FORMAT_OFF = 1 << 9, /* make json_variant_format() fail with -ENOEXEC */ } JsonFormatFlags; int json_variant_format(JsonVariant *v, JsonFormatFlags flags, char **ret); @@ -227,6 +229,7 @@ enum { _JSON_BUILD_LITERAL, _JSON_BUILD_STRV, _JSON_BUILD_BASE64, + _JSON_BUILD_HEX, _JSON_BUILD_ID128, _JSON_BUILD_BYTE_ARRAY, _JSON_BUILD_MAX, @@ -249,6 +252,7 @@ enum { #define JSON_BUILD_LITERAL(l) _JSON_BUILD_LITERAL, ({ const char *_x = l; _x; }) #define JSON_BUILD_STRV(l) _JSON_BUILD_STRV, ({ char **_x = l; _x; }) #define JSON_BUILD_BASE64(p, n) _JSON_BUILD_BASE64, ({ const void *_x = p; _x; }), ({ size_t _y = n; _y; }) +#define JSON_BUILD_HEX(p, n) _JSON_BUILD_HEX, ({ const void *_x = p; _x; }), ({ size_t _y = n; _y; }) #define JSON_BUILD_ID128(id) _JSON_BUILD_ID128, ({ sd_id128_t _x = id; _x; }) #define JSON_BUILD_BYTE_ARRAY(v, n) _JSON_BUILD_BYTE_ARRAY, ({ const void *_x = v; _x; }), ({ size_t _y = n; _y; }) @@ -289,8 +293,8 @@ int json_dispatch_strv(const char *name, JsonVariant *variant, JsonDispatchFlags int json_dispatch_boolean(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_tristate(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_variant(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); -int json_dispatch_integer(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); -int json_dispatch_unsigned(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); +int json_dispatch_intmax(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); +int json_dispatch_uintmax(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_uint32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_int32(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); int json_dispatch_uid_gid(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); @@ -299,10 +303,10 @@ int json_dispatch_id128(const char *name, JsonVariant *variant, JsonDispatchFlag int json_dispatch_unsupported(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata); assert_cc(sizeof(uintmax_t) == sizeof(uint64_t)); -#define json_dispatch_uint64 json_dispatch_unsigned +#define json_dispatch_uint64 json_dispatch_uintmax assert_cc(sizeof(intmax_t) == sizeof(int64_t)); -#define json_dispatch_int64 json_dispatch_integer +#define json_dispatch_int64 json_dispatch_intmax assert_cc(sizeof(uint32_t) == sizeof(unsigned)); #define json_dispatch_uint json_dispatch_uint32 @@ -351,6 +355,7 @@ int json_log_internal(JsonVariant *variant, int level, int error, const char *fi }) int json_variant_unbase64(JsonVariant *v, void **ret, size_t *ret_size); +int json_variant_unhex(JsonVariant *v, void **ret, size_t *ret_size); const char *json_variant_type_to_string(JsonVariantType t); JsonVariantType json_variant_type_from_string(const char *s); diff --git a/src/shared/kbd-util.c b/src/shared/kbd-util.c new file mode 100644 index 000000000..92abaea65 --- /dev/null +++ b/src/shared/kbd-util.c @@ -0,0 +1,134 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "errno-util.h" +#include "kbd-util.h" +#include "log.h" +#include "nulstr-util.h" +#include "path-util.h" +#include "set.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" + +static thread_local const char *keymap_name = NULL; +static thread_local Set *keymaps = NULL; + +static int nftw_cb( + const char *fpath, + const struct stat *sb, + int tflag, + struct FTW *ftwbuf) { + + _cleanup_free_ char *p = NULL; + int r; + + /* If keymap_name is non-null, return true if keymap keymap_name is found. + * Otherwise, add all keymaps to keymaps. */ + + if (tflag != FTW_F) + return 0; + + fpath = basename(fpath); + + const char *e = endswith(fpath, ".map") ?: endswith(fpath, ".map.gz"); + if (!e) + return 0; + + p = strndup(fpath, e - fpath); + if (!p) { + errno = ENOMEM; + return -1; + } + + if (keymap_name) + return streq(p, keymap_name); + + if (!keymap_is_valid(p)) + return 0; + + r = set_consume(keymaps, TAKE_PTR(p)); + if (r < 0 && r != -EEXIST) { + errno = -r; + return -1; + } + + return 0; +} + +int get_keymaps(char ***ret) { + keymaps = set_new(&string_hash_ops); + if (!keymaps) + return -ENOMEM; + + const char *dir; + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) + if (nftw(dir, nftw_cb, 20, FTW_PHYS) < 0) { + if (errno == ENOENT) + continue; + if (ERRNO_IS_RESOURCE(errno)) { + keymaps = set_free_free(keymaps); + return log_warning_errno(errno, "Failed to read keymap list from %s: %m", dir); + } + log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir); + } + + _cleanup_strv_free_ char **l = set_get_strv(keymaps); + if (!l) { + keymaps = set_free_free(keymaps); + return -ENOMEM; + } + + keymaps = set_free(keymaps); + + if (strv_isempty(l)) + return -ENOENT; + + strv_sort(l); + + *ret = TAKE_PTR(l); + + return 0; +} + +bool keymap_is_valid(const char *name) { + if (isempty(name)) + return false; + + if (strlen(name) >= 128) + return false; + + if (!utf8_is_valid(name)) + return false; + + if (!filename_is_valid(name)) + return false; + + if (!string_is_safe(name)) + return false; + + return true; +} + +int keymap_exists(const char *name) { + int r = 0; + + if (!keymap_is_valid(name)) + return -EINVAL; + + keymap_name = name; + + const char *dir; + NULSTR_FOREACH(dir, KBD_KEYMAP_DIRS) { + r = nftw(dir, nftw_cb, 20, FTW_PHYS); + if (r > 0) + break; + if (r < 0 && errno != ENOENT) + log_debug_errno(errno, "Failed to read keymap list from %s, ignoring: %m", dir); + } + + keymap_name = NULL; + + return r > 0; +} diff --git a/src/basic/kbd-util.h b/src/shared/kbd-util.h similarity index 94% rename from src/basic/kbd-util.h rename to src/shared/kbd-util.h index 6714aeb9e..a2fc2e6a3 100644 --- a/src/basic/kbd-util.h +++ b/src/shared/kbd-util.h @@ -18,3 +18,4 @@ int get_keymaps(char ***l); bool keymap_is_valid(const char *name); +int keymap_exists(const char *name); diff --git a/src/core/killall.c b/src/shared/killall.c similarity index 99% rename from src/core/killall.c rename to src/shared/killall.c index 6f60f09c4..d9fcfc21a 100644 --- a/src/core/killall.c +++ b/src/shared/killall.c @@ -87,7 +87,7 @@ static void log_children_no_yet_killed(Set *pids) { if (get_process_comm(PTR_TO_PID(p), &s) < 0) (void) asprintf(&s, PID_FMT, PTR_TO_PID(p)); - if (!strextend(&lst_child, ", ", s, NULL)) { + if (!strextend(&lst_child, ", ", s)) { log_oom(); return; } diff --git a/src/core/killall.h b/src/shared/killall.h similarity index 100% rename from src/core/killall.h rename to src/shared/killall.h diff --git a/src/shared/libfido2-util.c b/src/shared/libfido2-util.c new file mode 100644 index 000000000..22b8aba07 --- /dev/null +++ b/src/shared/libfido2-util.c @@ -0,0 +1,874 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "libfido2-util.h" + +#if HAVE_LIBFIDO2 +#include "alloc-util.h" +#include "ask-password-api.h" +#include "dlfcn-util.h" +#include "format-table.h" +#include "locale-util.h" +#include "log.h" +#include "memory-util.h" +#include "random-util.h" +#include "strv.h" + +static void *libfido2_dl = NULL; + +int (*sym_fido_assert_allow_cred)(fido_assert_t *, const unsigned char *, size_t) = NULL; +void (*sym_fido_assert_free)(fido_assert_t **) = NULL; +size_t (*sym_fido_assert_hmac_secret_len)(const fido_assert_t *, size_t) = NULL; +const unsigned char* (*sym_fido_assert_hmac_secret_ptr)(const fido_assert_t *, size_t) = NULL; +fido_assert_t* (*sym_fido_assert_new)(void) = NULL; +int (*sym_fido_assert_set_clientdata_hash)(fido_assert_t *, const unsigned char *, size_t) = NULL; +int (*sym_fido_assert_set_extensions)(fido_assert_t *, int) = NULL; +int (*sym_fido_assert_set_hmac_salt)(fido_assert_t *, const unsigned char *, size_t) = NULL; +int (*sym_fido_assert_set_rp)(fido_assert_t *, const char *) = NULL; +int (*sym_fido_assert_set_up)(fido_assert_t *, fido_opt_t) = NULL; +size_t (*sym_fido_cbor_info_extensions_len)(const fido_cbor_info_t *) = NULL; +char **(*sym_fido_cbor_info_extensions_ptr)(const fido_cbor_info_t *) = NULL; +void (*sym_fido_cbor_info_free)(fido_cbor_info_t **) = NULL; +fido_cbor_info_t* (*sym_fido_cbor_info_new)(void) = NULL; +size_t (*sym_fido_cbor_info_options_len)(const fido_cbor_info_t *) = NULL; +char** (*sym_fido_cbor_info_options_name_ptr)(const fido_cbor_info_t *) = NULL; +const bool* (*sym_fido_cbor_info_options_value_ptr)(const fido_cbor_info_t *) = NULL; +void (*sym_fido_cred_free)(fido_cred_t **) = NULL; +size_t (*sym_fido_cred_id_len)(const fido_cred_t *) = NULL; +const unsigned char* (*sym_fido_cred_id_ptr)(const fido_cred_t *) = NULL; +fido_cred_t* (*sym_fido_cred_new)(void) = NULL; +int (*sym_fido_cred_set_clientdata_hash)(fido_cred_t *, const unsigned char *, size_t) = NULL; +int (*sym_fido_cred_set_extensions)(fido_cred_t *, int) = NULL; +int (*sym_fido_cred_set_rk)(fido_cred_t *, fido_opt_t) = NULL; +int (*sym_fido_cred_set_rp)(fido_cred_t *, const char *, const char *) = NULL; +int (*sym_fido_cred_set_type)(fido_cred_t *, int) = NULL; +int (*sym_fido_cred_set_user)(fido_cred_t *, const unsigned char *, size_t, const char *, const char *, const char *) = NULL; +int (*sym_fido_cred_set_uv)(fido_cred_t *, fido_opt_t) = NULL; +void (*sym_fido_dev_free)(fido_dev_t **) = NULL; +int (*sym_fido_dev_get_assert)(fido_dev_t *, fido_assert_t *, const char *) = NULL; +int (*sym_fido_dev_get_cbor_info)(fido_dev_t *, fido_cbor_info_t *) = NULL; +void (*sym_fido_dev_info_free)(fido_dev_info_t **, size_t) = NULL; +int (*sym_fido_dev_info_manifest)(fido_dev_info_t *, size_t, size_t *) = NULL; +const char* (*sym_fido_dev_info_manufacturer_string)(const fido_dev_info_t *) = NULL; +const char* (*sym_fido_dev_info_product_string)(const fido_dev_info_t *) = NULL; +fido_dev_info_t* (*sym_fido_dev_info_new)(size_t) = NULL; +const char* (*sym_fido_dev_info_path)(const fido_dev_info_t *) = NULL; +const fido_dev_info_t* (*sym_fido_dev_info_ptr)(const fido_dev_info_t *, size_t) = NULL; +bool (*sym_fido_dev_is_fido2)(const fido_dev_t *) = NULL; +int (*sym_fido_dev_make_cred)(fido_dev_t *, fido_cred_t *, const char *) = NULL; +fido_dev_t* (*sym_fido_dev_new)(void) = NULL; +int (*sym_fido_dev_open)(fido_dev_t *, const char *) = NULL; +const char* (*sym_fido_strerr)(int) = NULL; + +int dlopen_libfido2(void) { + _cleanup_(dlclosep) void *dl = NULL; + int r; + + if (libfido2_dl) + return 0; /* Already loaded */ + + dl = dlopen("libfido2.so.1", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "libfido2 support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + DLSYM_ARG(fido_assert_allow_cred), + DLSYM_ARG(fido_assert_free), + DLSYM_ARG(fido_assert_hmac_secret_len), + DLSYM_ARG(fido_assert_hmac_secret_ptr), + DLSYM_ARG(fido_assert_new), + DLSYM_ARG(fido_assert_set_clientdata_hash), + DLSYM_ARG(fido_assert_set_extensions), + DLSYM_ARG(fido_assert_set_hmac_salt), + DLSYM_ARG(fido_assert_set_rp), + DLSYM_ARG(fido_assert_set_up), + DLSYM_ARG(fido_cbor_info_extensions_len), + DLSYM_ARG(fido_cbor_info_extensions_ptr), + DLSYM_ARG(fido_cbor_info_free), + DLSYM_ARG(fido_cbor_info_new), + DLSYM_ARG(fido_cbor_info_options_len), + DLSYM_ARG(fido_cbor_info_options_name_ptr), + DLSYM_ARG(fido_cbor_info_options_value_ptr), + DLSYM_ARG(fido_cred_free), + DLSYM_ARG(fido_cred_id_len), + DLSYM_ARG(fido_cred_id_ptr), + DLSYM_ARG(fido_cred_new), + DLSYM_ARG(fido_cred_set_clientdata_hash), + DLSYM_ARG(fido_cred_set_extensions), + DLSYM_ARG(fido_cred_set_rk), + DLSYM_ARG(fido_cred_set_rp), + DLSYM_ARG(fido_cred_set_type), + DLSYM_ARG(fido_cred_set_user), + DLSYM_ARG(fido_cred_set_uv), + DLSYM_ARG(fido_dev_free), + DLSYM_ARG(fido_dev_get_assert), + DLSYM_ARG(fido_dev_get_cbor_info), + DLSYM_ARG(fido_dev_info_free), + DLSYM_ARG(fido_dev_info_manifest), + DLSYM_ARG(fido_dev_info_manufacturer_string), + DLSYM_ARG(fido_dev_info_new), + DLSYM_ARG(fido_dev_info_path), + DLSYM_ARG(fido_dev_info_product_string), + DLSYM_ARG(fido_dev_info_ptr), + DLSYM_ARG(fido_dev_is_fido2), + DLSYM_ARG(fido_dev_make_cred), + DLSYM_ARG(fido_dev_new), + DLSYM_ARG(fido_dev_open), + DLSYM_ARG(fido_strerr), + NULL); + if (r < 0) + return r; + + /* Note that we never release the reference here, because there's no real reason to, after all this + * was traditionally a regular shared library dependency which lives forever too. */ + libfido2_dl = TAKE_PTR(dl); + return 1; +} + +static int verify_features( + fido_dev_t *d, + const char *path, + int log_level, /* the log level to use when device is not FIDO2 with hmac-secret */ + bool *ret_has_rk, + bool *ret_has_client_pin, + bool *ret_has_up, + bool *ret_has_uv) { + + _cleanup_(fido_cbor_info_free_wrapper) fido_cbor_info_t *di = NULL; + bool found_extension = false; + char **e, **o; + const bool *b; + bool has_rk = false, has_client_pin = false, has_up = true, has_uv = false; /* Defaults are per table in 5.4 in FIDO2 spec */ + size_t n; + int r; + + assert(d); + assert(path); + + if (!sym_fido_dev_is_fido2(d)) + return log_full_errno(log_level, + SYNTHETIC_ERRNO(ENODEV), + "Specified device %s is not a FIDO2 device.", path); + + di = sym_fido_cbor_info_new(); + if (!di) + return log_oom(); + + r = sym_fido_dev_get_cbor_info(d, di); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to get CBOR device info for %s: %s", path, sym_fido_strerr(r)); + + e = sym_fido_cbor_info_extensions_ptr(di); + n = sym_fido_cbor_info_extensions_len(di); + for (size_t i = 0; i < n; i++) { + log_debug("FIDO2 device implements extension: %s", e[i]); + if (streq(e[i], "hmac-secret")) + found_extension = true; + } + + o = sym_fido_cbor_info_options_name_ptr(di); + b = sym_fido_cbor_info_options_value_ptr(di); + n = sym_fido_cbor_info_options_len(di); + for (size_t i = 0; i < n; i++) { + log_debug("FIDO2 device implements option %s: %s", o[i], yes_no(b[i])); + if (streq(o[i], "rk")) + has_rk = b[i]; + if (streq(o[i], "clientPin")) + has_client_pin = b[i]; + if (streq(o[i], "up")) + has_up = b[i]; + if (streq(o[i], "uv")) + has_uv = b[i]; + } + + if (!found_extension) + return log_full_errno(log_level, + SYNTHETIC_ERRNO(ENODEV), + "Specified device %s is a FIDO2 device, but does not support the required HMAC-SECRET extension.", path); + + log_debug("Has rk ('Resident Key') support: %s\n" + "Has clientPin support: %s\n" + "Has up ('User Presence') support: %s\n" + "Has uv ('User Verification') support: %s\n", + yes_no(has_rk), + yes_no(has_client_pin), + yes_no(has_up), + yes_no(has_uv)); + + if (ret_has_rk) + *ret_has_rk = has_rk; + if (ret_has_client_pin) + *ret_has_client_pin = has_client_pin; + if (ret_has_up) + *ret_has_up = has_up; + if (ret_has_uv) + *ret_has_uv = has_uv; + + return 0; +} + +static int fido2_use_hmac_hash_specific_token( + const char *path, + const char *rp_id, + const void *salt, + size_t salt_size, + const void *cid, + size_t cid_size, + char **pins, + bool up, /* user presence permitted */ + void **ret_hmac, + size_t *ret_hmac_size) { + + _cleanup_(fido_assert_free_wrapper) fido_assert_t *a = NULL; + _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL; + _cleanup_(erase_and_freep) void *hmac_copy = NULL; + bool has_up, has_client_pin; + size_t hmac_size; + const void *hmac; + int r; + + assert(path); + assert(rp_id); + assert(salt); + assert(cid); + assert(ret_hmac); + assert(ret_hmac_size); + + d = sym_fido_dev_new(); + if (!d) + return log_oom(); + + r = sym_fido_dev_open(d, path); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r)); + + r = verify_features(d, path, LOG_ERR, NULL, &has_client_pin, &has_up, NULL); + if (r < 0) + return r; + + a = sym_fido_assert_new(); + if (!a) + return log_oom(); + + r = sym_fido_assert_set_extensions(a, FIDO_EXT_HMAC_SECRET); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_set_hmac_salt(a, salt, salt_size); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set salt on FIDO2 assertion: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_set_rp(a, rp_id); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_allow_cred(a, cid, cid_size); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r)); + + if (has_up) { + r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 assertion user presence: %s", sym_fido_strerr(r)); + } + + log_info("Asking FIDO2 token for authentication."); + + r = sym_fido_dev_get_assert(d, a, NULL); /* try without pin and without up first */ + if (r == FIDO_ERR_UP_REQUIRED && up) { + + if (!has_up) + log_warning("Weird, device asked for User Presence check, but does not advertise it as feature. Ignoring."); + + r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 assertion user presence: %s", sym_fido_strerr(r)); + + log_info("Security token requires user presence."); + + r = sym_fido_dev_get_assert(d, a, NULL); /* try without pin but with up now */ + } + if (r == FIDO_ERR_PIN_REQUIRED) { + char **i; + + if (!has_client_pin) + log_warning("Weird, device asked for client PIN, but does not advertise it as feature. Ignoring."); + + /* OK, we needed a pin, try with all pins in turn */ + STRV_FOREACH(i, pins) { + r = sym_fido_dev_get_assert(d, a, *i); + if (r != FIDO_ERR_PIN_INVALID) + break; + } + } + + switch (r) { + case FIDO_OK: + break; + case FIDO_ERR_NO_CREDENTIALS: + return log_error_errno(SYNTHETIC_ERRNO(EBADSLT), + "Wrong security token; needed credentials not present on token."); + case FIDO_ERR_PIN_REQUIRED: + return log_error_errno(SYNTHETIC_ERRNO(ENOANO), + "Security token requires PIN."); + case FIDO_ERR_PIN_AUTH_BLOCKED: + return log_error_errno(SYNTHETIC_ERRNO(EOWNERDEAD), + "PIN of security token is blocked, please remove/reinsert token."); + case FIDO_ERR_PIN_INVALID: + return log_error_errno(SYNTHETIC_ERRNO(ENOLCK), + "PIN of security token incorrect."); + case FIDO_ERR_UP_REQUIRED: + return log_error_errno(SYNTHETIC_ERRNO(EMEDIUMTYPE), + "User presence required."); + case FIDO_ERR_ACTION_TIMEOUT: + return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), + "Token action timeout. (User didn't interact with token quickly enough.)"); + default: + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to ask token for assertion: %s", sym_fido_strerr(r)); + } + + hmac = sym_fido_assert_hmac_secret_ptr(a, 0); + if (!hmac) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve HMAC secret."); + + hmac_size = sym_fido_assert_hmac_secret_len(a, 0); + + hmac_copy = memdup(hmac, hmac_size); + if (!hmac_copy) + return log_oom(); + + *ret_hmac = TAKE_PTR(hmac_copy); + *ret_hmac_size = hmac_size; + return 0; +} + +int fido2_use_hmac_hash( + const char *device, + const char *rp_id, + const void *salt, + size_t salt_size, + const void *cid, + size_t cid_size, + char **pins, + bool up, /* user presence permitted */ + void **ret_hmac, + size_t *ret_hmac_size) { + + size_t allocated = 64, found = 0; + fido_dev_info_t *di = NULL; + int r; + + r = dlopen_libfido2(); + if (r < 0) + return log_error_errno(r, "FIDO2 support is not installed."); + + if (device) + return fido2_use_hmac_hash_specific_token(device, rp_id, salt, salt_size, cid, cid_size, pins, up, ret_hmac, ret_hmac_size); + + di = sym_fido_dev_info_new(allocated); + if (!di) + return log_oom(); + + r = sym_fido_dev_info_manifest(di, allocated, &found); + if (r == FIDO_ERR_INTERNAL) { + /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ + r = log_debug_errno(SYNTHETIC_ERRNO(EAGAIN), "Got FIDO_ERR_INTERNAL, assuming no devices."); + goto finish; + } + if (r != FIDO_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r)); + goto finish; + } + + for (size_t i = 0; i < found; i++) { + const fido_dev_info_t *entry; + const char *path; + + entry = sym_fido_dev_info_ptr(di, i); + if (!entry) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to get device information for FIDO device %zu.", i); + goto finish; + } + + path = sym_fido_dev_info_path(entry); + if (!path) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to query FIDO device path."); + goto finish; + } + + r = fido2_use_hmac_hash_specific_token(path, rp_id, salt, salt_size, cid, cid_size, pins, up, ret_hmac, ret_hmac_size); + if (!IN_SET(r, + -EBADSLT, /* device doesn't understand our credential hash */ + -ENODEV /* device is not a FIDO2 device with HMAC-SECRET */)) + goto finish; + } + + r = -EAGAIN; + +finish: + sym_fido_dev_info_free(&di, allocated); + return r; +} + +#define FIDO2_SALT_SIZE 32 + +int fido2_generate_hmac_hash( + const char *device, + const char *rp_id, + const char *rp_name, + const void *user_id, size_t user_id_len, + const char *user_name, + const char *user_display_name, + const char *user_icon, + const char *askpw_icon_name, + void **ret_cid, size_t *ret_cid_size, + void **ret_salt, size_t *ret_salt_size, + void **ret_secret, size_t *ret_secret_size, + char **ret_usedpin) { + + _cleanup_(erase_and_freep) void *salt = NULL, *secret_copy = NULL; + _cleanup_(fido_assert_free_wrapper) fido_assert_t *a = NULL; + _cleanup_(fido_cred_free_wrapper) fido_cred_t *c = NULL; + _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL; + _cleanup_(erase_and_freep) char *used_pin = NULL; + bool has_rk, has_client_pin, has_up, has_uv; + _cleanup_free_ char *cid_copy = NULL; + size_t cid_size, secret_size; + const void *cid, *secret; + int r; + + assert(device); + assert(ret_cid); + assert(ret_cid_size); + assert(ret_salt); + assert(ret_salt_size); + assert(ret_secret); + assert(ret_secret_size); + + /* Construction is like this: we generate a salt of 32 bytes. We then ask the FIDO2 device to + * HMAC-SHA256 it for us with its internal key. The result is the key used by LUKS and account + * authentication. LUKS and UNIX password auth all do their own salting before hashing, so that FIDO2 + * device never sees the volume key. + * + * S = HMAC-SHA256(I, D) + * + * with: S → LUKS/account authentication key (never stored) + * I → internal key on FIDO2 device (stored in the FIDO2 device) + * D → salt we generate here (stored in the privileged part of the JSON record) + * + */ + + assert(device); + + r = dlopen_libfido2(); + if (r < 0) + return log_error_errno(r, "FIDO2 token support is not installed."); + + salt = malloc(FIDO2_SALT_SIZE); + if (!salt) + return log_oom(); + + r = genuine_random_bytes(salt, FIDO2_SALT_SIZE, RANDOM_BLOCK); + if (r < 0) + return log_error_errno(r, "Failed to generate salt: %m"); + + d = sym_fido_dev_new(); + if (!d) + return log_oom(); + + r = sym_fido_dev_open(d, device); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to open FIDO2 device %s: %s", device, sym_fido_strerr(r)); + + r = verify_features(d, device, LOG_ERR, &has_rk, &has_client_pin, &has_up, &has_uv); + if (r < 0) + return r; + + c = sym_fido_cred_new(); + if (!c) + return log_oom(); + + r = sym_fido_cred_set_extensions(c, FIDO_EXT_HMAC_SECRET); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to enable HMAC-SECRET extension on FIDO2 credential: %s", sym_fido_strerr(r)); + + r = sym_fido_cred_set_rp(c, rp_id, rp_name); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 credential relying party ID/name: %s", sym_fido_strerr(r)); + + r = sym_fido_cred_set_type(c, COSE_ES256); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 credential type to ES256: %s", sym_fido_strerr(r)); + + r = sym_fido_cred_set_user( + c, + user_id, user_id_len, + user_name, + user_display_name, + user_icon); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 credential user data: %s", sym_fido_strerr(r)); + + r = sym_fido_cred_set_clientdata_hash(c, (const unsigned char[32]) {}, 32); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 client data hash: %s", sym_fido_strerr(r)); + + if (has_rk) { + r = sym_fido_cred_set_rk(c, FIDO_OPT_FALSE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to turn off FIDO2 resident key option of credential: %s", sym_fido_strerr(r)); + } + + if (has_uv) { + r = sym_fido_cred_set_uv(c, FIDO_OPT_FALSE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to turn off FIDO2 user verification option of credential: %s", sym_fido_strerr(r)); + } + + log_info("Initializing FIDO2 credential on security token."); + + log_notice("%s%s(Hint: This might require verification of user presence on security token.)", + emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", + emoji_enabled() ? " " : ""); + + r = sym_fido_dev_make_cred(d, c, NULL); + if (r == FIDO_ERR_PIN_REQUIRED) { + for (;;) { + _cleanup_(strv_free_erasep) char **pin = NULL; + char **i; + + if (!has_client_pin) + log_warning("Weird, device asked for client PIN, but does not advertise it as feature. Ignoring."); + + r = ask_password_auto("Please enter security token PIN:", askpw_icon_name, NULL, "fido2-pin", USEC_INFINITY, 0, &pin); + if (r < 0) + return log_error_errno(r, "Failed to acquire user PIN: %m"); + + r = FIDO_ERR_PIN_INVALID; + STRV_FOREACH(i, pin) { + if (isempty(*i)) { + log_info("PIN may not be empty."); + continue; + } + + r = sym_fido_dev_make_cred(d, c, *i); + if (r == FIDO_OK) { + used_pin = strdup(*i); + if (!used_pin) + return log_oom(); + break; + } + if (r != FIDO_ERR_PIN_INVALID) + break; + } + + if (r != FIDO_ERR_PIN_INVALID) + break; + + log_notice("PIN incorrect, please try again."); + } + } + if (r == FIDO_ERR_PIN_AUTH_BLOCKED) + return log_notice_errno(SYNTHETIC_ERRNO(EPERM), + "Token PIN is currently blocked, please remove and reinsert token."); + if (r == FIDO_ERR_ACTION_TIMEOUT) + return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), + "Token action timeout. (User didn't interact with token quickly enough.)"); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to generate FIDO2 credential: %s", sym_fido_strerr(r)); + + cid = sym_fido_cred_id_ptr(c); + if (!cid) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to get FIDO2 credential ID."); + + cid_size = sym_fido_cred_id_len(c); + + a = sym_fido_assert_new(); + if (!a) + return log_oom(); + + r = sym_fido_assert_set_extensions(a, FIDO_EXT_HMAC_SECRET); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to enable HMAC-SECRET extension on FIDO2 assertion: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_set_hmac_salt(a, salt, FIDO2_SALT_SIZE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set salt on FIDO2 assertion: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_set_rp(a, rp_id); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 assertion ID: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_set_clientdata_hash(a, (const unsigned char[32]) {}, 32); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to set FIDO2 assertion client data hash: %s", sym_fido_strerr(r)); + + r = sym_fido_assert_allow_cred(a, cid, cid_size); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to add FIDO2 assertion credential ID: %s", sym_fido_strerr(r)); + + if (has_up) { + r = sym_fido_assert_set_up(a, FIDO_OPT_FALSE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to turn off FIDO2 assertion user presence: %s", sym_fido_strerr(r)); + } + + log_info("Generating secret key on FIDO2 security token."); + + r = sym_fido_dev_get_assert(d, a, used_pin); + if (r == FIDO_ERR_UP_REQUIRED) { + + if (!has_up) + log_warning("Weird, device asked for User Presence check, but does not advertise it as feature. Ignoring."); + + r = sym_fido_assert_set_up(a, FIDO_OPT_TRUE); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to turn on FIDO2 assertion user presence: %s", sym_fido_strerr(r)); + + log_notice("%s%sIn order to allow secret key generation, please verify presence on security token.", + emoji_enabled() ? special_glyph(SPECIAL_GLYPH_TOUCH) : "", + emoji_enabled() ? " " : ""); + + r = sym_fido_dev_get_assert(d, a, used_pin); + } + if (r == FIDO_ERR_ACTION_TIMEOUT) + return log_error_errno(SYNTHETIC_ERRNO(ENOSTR), + "Token action timeout. (User didn't interact with token quickly enough.)"); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to ask token for assertion: %s", sym_fido_strerr(r)); + + secret = sym_fido_assert_hmac_secret_ptr(a, 0); + if (!secret) + return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to retrieve HMAC secret."); + + secret_size = sym_fido_assert_hmac_secret_len(a, 0); + + secret_copy = memdup(secret, secret_size); + if (!secret_copy) + return log_oom(); + + cid_copy = memdup(cid, cid_size); + if (!cid_copy) + return log_oom(); + + *ret_cid = TAKE_PTR(cid_copy); + *ret_cid_size = cid_size; + *ret_salt = TAKE_PTR(salt); + *ret_salt_size = FIDO2_SALT_SIZE; + *ret_secret = TAKE_PTR(secret_copy); + *ret_secret_size = secret_size; + + if (ret_usedpin) + *ret_usedpin = TAKE_PTR(used_pin); + + return 0; +} +#endif + +#if HAVE_LIBFIDO2 +static int check_device_is_fido2_with_hmac_secret(const char *path) { + _cleanup_(fido_dev_free_wrapper) fido_dev_t *d = NULL; + int r; + + d = sym_fido_dev_new(); + if (!d) + return log_oom(); + + r = sym_fido_dev_open(d, path); + if (r != FIDO_OK) + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to open FIDO2 device %s: %s", path, sym_fido_strerr(r)); + + r = verify_features(d, path, LOG_DEBUG, NULL, NULL, NULL, NULL); + if (r == -ENODEV) /* Not a FIDO2 device, or not implementing 'hmac-secret' */ + return false; + if (r < 0) + return r; + + return true; +} +#endif + +int fido2_list_devices(void) { +#if HAVE_LIBFIDO2 + _cleanup_(table_unrefp) Table *t = NULL; + size_t allocated = 64, found = 0; + fido_dev_info_t *di = NULL; + int r; + + r = dlopen_libfido2(); + if (r < 0) + return log_error_errno(r, "FIDO2 token support is not installed."); + + di = sym_fido_dev_info_new(allocated); + if (!di) + return log_oom(); + + r = sym_fido_dev_info_manifest(di, allocated, &found); + if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { + /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ + log_info("No FIDO2 devices found."); + r = 0; + goto finish; + } + if (r != FIDO_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO2 devices: %s", sym_fido_strerr(r)); + goto finish; + } + + t = table_new("path", "manufacturer", "product"); + if (!t) { + r = log_oom(); + goto finish; + } + + for (size_t i = 0; i < found; i++) { + const fido_dev_info_t *entry; + + entry = sym_fido_dev_info_ptr(di, i); + if (!entry) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to get device information for FIDO device %zu.", i); + goto finish; + } + + r = check_device_is_fido2_with_hmac_secret(sym_fido_dev_info_path(entry)); + if (r < 0) + goto finish; + if (!r) + continue; + + r = table_add_many( + t, + TABLE_PATH, sym_fido_dev_info_path(entry), + TABLE_STRING, sym_fido_dev_info_manufacturer_string(entry), + TABLE_STRING, sym_fido_dev_info_product_string(entry)); + if (r < 0) { + table_log_add_error(r); + goto finish; + } + } + + r = table_print(t, stdout); + if (r < 0) { + log_error_errno(r, "Failed to show device table: %m"); + goto finish; + } + + r = 0; + +finish: + sym_fido_dev_info_free(&di, allocated); + return r; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 tokens not supported on this build."); +#endif +} + +int fido2_find_device_auto(char **ret) { +#if HAVE_LIBFIDO2 + _cleanup_free_ char *copy = NULL; + size_t di_size = 64, found = 0; + const fido_dev_info_t *entry; + fido_dev_info_t *di = NULL; + const char *path; + int r; + + r = dlopen_libfido2(); + if (r < 0) + return log_error_errno(r, "FIDO2 token support is not installed."); + + di = sym_fido_dev_info_new(di_size); + if (!di) + return log_oom(); + + r = sym_fido_dev_info_manifest(di, di_size, &found); + if (r == FIDO_ERR_INTERNAL || (r == FIDO_OK && found == 0)) { + /* The library returns FIDO_ERR_INTERNAL when no devices are found. I wish it wouldn't. */ + r = log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No FIDO devices found."); + goto finish; + } + if (r != FIDO_OK) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to enumerate FIDO devices: %s", sym_fido_strerr(r)); + goto finish; + } + if (found > 1) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), "More than one FIDO device found."); + goto finish; + } + + entry = sym_fido_dev_info_ptr(di, 0); + if (!entry) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to get device information for FIDO device 0."); + goto finish; + } + + r = check_device_is_fido2_with_hmac_secret(sym_fido_dev_info_path(entry)); + if (r < 0) + goto finish; + if (!r) { + r = log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "FIDO device discovered does not implement FIDO2 with 'hmac-secret' extension."); + goto finish; + } + + path = sym_fido_dev_info_path(entry); + if (!path) { + r = log_error_errno(SYNTHETIC_ERRNO(EIO), + "Failed to query FIDO device path."); + goto finish; + } + + copy = strdup(path); + if (!copy) { + r = log_oom(); + goto finish; + } + + *ret = TAKE_PTR(copy); + r = 0; + +finish: + sym_fido_dev_info_free(&di, di_size); + return r; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "FIDO2 tokens not supported on this build."); +#endif +} diff --git a/src/shared/libfido2-util.h b/src/shared/libfido2-util.h new file mode 100644 index 000000000..3648ea44c --- /dev/null +++ b/src/shared/libfido2-util.h @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "macro.h" + +#if HAVE_LIBFIDO2 +#include + +extern int (*sym_fido_assert_allow_cred)(fido_assert_t *, const unsigned char *, size_t); +extern void (*sym_fido_assert_free)(fido_assert_t **); +extern size_t (*sym_fido_assert_hmac_secret_len)(const fido_assert_t *, size_t); +extern const unsigned char* (*sym_fido_assert_hmac_secret_ptr)(const fido_assert_t *, size_t); +extern fido_assert_t* (*sym_fido_assert_new)(void); +extern int (*sym_fido_assert_set_clientdata_hash)(fido_assert_t *, const unsigned char *, size_t); +extern int (*sym_fido_assert_set_extensions)(fido_assert_t *, int); +extern int (*sym_fido_assert_set_hmac_salt)(fido_assert_t *, const unsigned char *, size_t); +extern int (*sym_fido_assert_set_rp)(fido_assert_t *, const char *); +extern int (*sym_fido_assert_set_up)(fido_assert_t *, fido_opt_t); +extern size_t (*sym_fido_cbor_info_extensions_len)(const fido_cbor_info_t *); +extern char **(*sym_fido_cbor_info_extensions_ptr)(const fido_cbor_info_t *); +extern void (*sym_fido_cbor_info_free)(fido_cbor_info_t **); +extern fido_cbor_info_t* (*sym_fido_cbor_info_new)(void); +extern size_t (*sym_fido_cbor_info_options_len)(const fido_cbor_info_t *); +extern char** (*sym_fido_cbor_info_options_name_ptr)(const fido_cbor_info_t *); +extern const bool* (*sym_fido_cbor_info_options_value_ptr)(const fido_cbor_info_t *); +extern void (*sym_fido_cred_free)(fido_cred_t **); +extern size_t (*sym_fido_cred_id_len)(const fido_cred_t *); +extern const unsigned char* (*sym_fido_cred_id_ptr)(const fido_cred_t *); +extern fido_cred_t* (*sym_fido_cred_new)(void); +extern int (*sym_fido_cred_set_clientdata_hash)(fido_cred_t *, const unsigned char *, size_t); +extern int (*sym_fido_cred_set_extensions)(fido_cred_t *, int); +extern int (*sym_fido_cred_set_rk)(fido_cred_t *, fido_opt_t); +extern int (*sym_fido_cred_set_rp)(fido_cred_t *, const char *, const char *); +extern int (*sym_fido_cred_set_type)(fido_cred_t *, int); +extern int (*sym_fido_cred_set_user)(fido_cred_t *, const unsigned char *, size_t, const char *, const char *, const char *); +extern int (*sym_fido_cred_set_uv)(fido_cred_t *, fido_opt_t); +extern void (*sym_fido_dev_free)(fido_dev_t **); +extern int (*sym_fido_dev_get_assert)(fido_dev_t *, fido_assert_t *, const char *); +extern int (*sym_fido_dev_get_cbor_info)(fido_dev_t *, fido_cbor_info_t *); +extern void (*sym_fido_dev_info_free)(fido_dev_info_t **, size_t); +extern int (*sym_fido_dev_info_manifest)(fido_dev_info_t *, size_t, size_t *); +extern const char* (*sym_fido_dev_info_manufacturer_string)(const fido_dev_info_t *); +extern const char* (*sym_fido_dev_info_product_string)(const fido_dev_info_t *); +extern fido_dev_info_t* (*sym_fido_dev_info_new)(size_t); +extern const char* (*sym_fido_dev_info_path)(const fido_dev_info_t *); +extern const fido_dev_info_t* (*sym_fido_dev_info_ptr)(const fido_dev_info_t *, size_t); +extern bool (*sym_fido_dev_is_fido2)(const fido_dev_t *); +extern int (*sym_fido_dev_make_cred)(fido_dev_t *, fido_cred_t *, const char *); +extern fido_dev_t* (*sym_fido_dev_new)(void); +extern int (*sym_fido_dev_open)(fido_dev_t *, const char *); +extern const char* (*sym_fido_strerr)(int); + +int dlopen_libfido2(void); + +static inline void fido_cbor_info_free_wrapper(fido_cbor_info_t **p) { + if (*p) + sym_fido_cbor_info_free(p); +} + +static inline void fido_assert_free_wrapper(fido_assert_t **p) { + if (*p) + sym_fido_assert_free(p); +} + +static inline void fido_dev_free_wrapper(fido_dev_t **p) { + if (*p) + sym_fido_dev_free(p); +} + +static inline void fido_cred_free_wrapper(fido_cred_t **p) { + if (*p) + sym_fido_cred_free(p); +} + +int fido2_use_hmac_hash( + const char *device, + const char *rp_id, + const void *salt, + size_t salt_size, + const void *cid, + size_t cid_size, + char **pins, + bool up, /* user presence permitted */ + void **ret_hmac, + size_t *ret_hmac_size); + +int fido2_generate_hmac_hash( + const char *device, + const char *rp_id, + const char *rp_name, + const void *user_id, size_t user_id_len, + const char *user_name, + const char *user_display_name, + const char *user_icon, + const char *askpw_icon_name, + void **ret_cid, size_t *ret_cid_size, + void **ret_salt, size_t *ret_salt_size, + void **ret_secret, size_t *ret_secret_size, + char **ret_usedpin); + +#endif + +int fido2_list_devices(void); +int fido2_find_device_auto(char **ret); diff --git a/src/shared/libmount-util.h b/src/shared/libmount-util.h index db9728c33..cf19c56ed 100644 --- a/src/shared/libmount-util.h +++ b/src/shared/libmount-util.h @@ -8,8 +8,8 @@ #include "macro.h" -DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct libmnt_table*, mnt_free_table, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct libmnt_iter*, mnt_free_iter, NULL); static inline int libmount_parse( const char *path, diff --git a/src/shared/linux/auto_dev-ioctl.h b/src/shared/linux/auto_dev-ioctl.h index 261546c66..63f32e3b1 100644 --- a/src/shared/linux/auto_dev-ioctl.h +++ b/src/shared/linux/auto_dev-ioctl.h @@ -82,7 +82,7 @@ struct args_ismountpoint { /* * All the ioctls use this structure. * When sending a path size must account for the total length - * of the chunk of memory otherwise is is the size of the + * of the chunk of memory otherwise it is the size of the * structure. */ diff --git a/src/shared/linux/bpf.h b/src/shared/linux/bpf.h index 359fc3703..e6ceac3f7 100644 --- a/src/shared/linux/bpf.h +++ b/src/shared/linux/bpf.h @@ -14,6 +14,7 @@ /* Extended instruction set based on top of classic BPF */ /* instruction classes */ +#define BPF_JMP32 0x06 /* jmp mode in word width */ #define BPF_ALU64 0x07 /* alu mode in double word width */ /* ld/ldx fields */ @@ -80,6 +81,12 @@ struct bpf_cgroup_storage_key { __u32 attach_type; /* program attach type */ }; +union bpf_iter_link_info { + struct { + __u32 map_fd; + } map; +}; + /* BPF syscall commands, see bpf(2) man-page for details. */ enum bpf_cmd { BPF_MAP_CREATE, @@ -104,6 +111,20 @@ enum bpf_cmd { BPF_BTF_GET_FD_BY_ID, BPF_TASK_FD_QUERY, BPF_MAP_LOOKUP_AND_DELETE_ELEM, + BPF_MAP_FREEZE, + BPF_BTF_GET_NEXT_ID, + BPF_MAP_LOOKUP_BATCH, + BPF_MAP_LOOKUP_AND_DELETE_BATCH, + BPF_MAP_UPDATE_BATCH, + BPF_MAP_DELETE_BATCH, + BPF_LINK_CREATE, + BPF_LINK_UPDATE, + BPF_LINK_GET_FD_BY_ID, + BPF_LINK_GET_NEXT_ID, + BPF_ENABLE_STATS, + BPF_ITER_CREATE, + BPF_LINK_DETACH, + BPF_PROG_BIND_MAP, }; enum bpf_map_type { @@ -131,6 +152,11 @@ enum bpf_map_type { BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE, BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK, + BPF_MAP_TYPE_SK_STORAGE, + BPF_MAP_TYPE_DEVMAP_HASH, + BPF_MAP_TYPE_STRUCT_OPS, + BPF_MAP_TYPE_RINGBUF, + BPF_MAP_TYPE_INODE_STORAGE, }; /* Note that tracing related programs such as @@ -165,6 +191,14 @@ enum bpf_prog_type { BPF_PROG_TYPE_LIRC_MODE2, BPF_PROG_TYPE_SK_REUSEPORT, BPF_PROG_TYPE_FLOW_DISSECTOR, + BPF_PROG_TYPE_CGROUP_SYSCTL, + BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE, + BPF_PROG_TYPE_CGROUP_SOCKOPT, + BPF_PROG_TYPE_TRACING, + BPF_PROG_TYPE_STRUCT_OPS, + BPF_PROG_TYPE_EXT, + BPF_PROG_TYPE_LSM, + BPF_PROG_TYPE_SK_LOOKUP, }; enum bpf_attach_type { @@ -186,11 +220,43 @@ enum bpf_attach_type { BPF_CGROUP_UDP6_SENDMSG, BPF_LIRC_MODE2, BPF_FLOW_DISSECTOR, + BPF_CGROUP_SYSCTL, + BPF_CGROUP_UDP4_RECVMSG, + BPF_CGROUP_UDP6_RECVMSG, + BPF_CGROUP_GETSOCKOPT, + BPF_CGROUP_SETSOCKOPT, + BPF_TRACE_RAW_TP, + BPF_TRACE_FENTRY, + BPF_TRACE_FEXIT, + BPF_MODIFY_RETURN, + BPF_LSM_MAC, + BPF_TRACE_ITER, + BPF_CGROUP_INET4_GETPEERNAME, + BPF_CGROUP_INET6_GETPEERNAME, + BPF_CGROUP_INET4_GETSOCKNAME, + BPF_CGROUP_INET6_GETSOCKNAME, + BPF_XDP_DEVMAP, + BPF_CGROUP_INET_SOCK_RELEASE, + BPF_XDP_CPUMAP, + BPF_SK_LOOKUP, + BPF_XDP, __MAX_BPF_ATTACH_TYPE }; #define MAX_BPF_ATTACH_TYPE __MAX_BPF_ATTACH_TYPE +enum bpf_link_type { + BPF_LINK_TYPE_UNSPEC = 0, + BPF_LINK_TYPE_RAW_TRACEPOINT = 1, + BPF_LINK_TYPE_TRACING = 2, + BPF_LINK_TYPE_CGROUP = 3, + BPF_LINK_TYPE_ITER = 4, + BPF_LINK_TYPE_NETNS = 5, + BPF_LINK_TYPE_XDP = 6, + + MAX_BPF_LINK_TYPE, +}; + /* cgroup-bpf attach flags used in BPF_PROG_ATTACH command * * NONE(default): No further bpf programs allowed in the subtree. @@ -214,6 +280,11 @@ enum bpf_attach_type { * When children program makes decision (like picking TCP CA or sock bind) * parent program has a chance to override it. * + * With BPF_F_ALLOW_MULTI a new program is added to the end of the list of + * programs for a cgroup. Though it's possible to replace an old program at + * any position by also specifying BPF_F_REPLACE flag and position itself in + * replace_bpf_fd attribute. Old program at this position will be released. + * * A cgroup with MULTI or OVERRIDE flag allows any attach flags in sub-cgroups. * A cgroup with NONE doesn't allow any programs in sub-cgroups. * Ex1: @@ -232,6 +303,7 @@ enum bpf_attach_type { */ #define BPF_F_ALLOW_OVERRIDE (1U << 0) #define BPF_F_ALLOW_MULTI (1U << 1) +#define BPF_F_REPLACE (1U << 2) /* If BPF_F_STRICT_ALIGNMENT is used in BPF_PROG_LOAD command, the * verifier will perform strict alignment checking as if the kernel @@ -254,8 +326,66 @@ enum bpf_attach_type { */ #define BPF_F_ANY_ALIGNMENT (1U << 1) -/* when bpf_ldimm64->src_reg == BPF_PSEUDO_MAP_FD, bpf_ldimm64->imm == fd */ +/* BPF_F_TEST_RND_HI32 is used in BPF_PROG_LOAD command for testing purpose. + * Verifier does sub-register def/use analysis and identifies instructions whose + * def only matters for low 32-bit, high 32-bit is never referenced later + * through implicit zero extension. Therefore verifier notifies JIT back-ends + * that it is safe to ignore clearing high 32-bit for these instructions. This + * saves some back-ends a lot of code-gen. However such optimization is not + * necessary on some arches, for example x86_64, arm64 etc, whose JIT back-ends + * hence hasn't used verifier's analysis result. But, we really want to have a + * way to be able to verify the correctness of the described optimization on + * x86_64 on which testsuites are frequently exercised. + * + * So, this flag is introduced. Once it is set, verifier will randomize high + * 32-bit for those instructions who has been identified as safe to ignore them. + * Then, if verifier is not doing correct analysis, such randomization will + * regress tests to expose bugs. + */ +#define BPF_F_TEST_RND_HI32 (1U << 2) + +/* The verifier internal test flag. Behavior is undefined */ +#define BPF_F_TEST_STATE_FREQ (1U << 3) + +/* If BPF_F_SLEEPABLE is used in BPF_PROG_LOAD command, the verifier will + * restrict map and helper usage for such programs. Sleepable BPF programs can + * only be attached to hooks where kernel execution context allows sleeping. + * Such programs are allowed to use helpers that may sleep like + * bpf_copy_from_user(). + */ +#define BPF_F_SLEEPABLE (1U << 4) + +/* When BPF ldimm64's insn[0].src_reg != 0 then this can have + * the following extensions: + * + * insn[0].src_reg: BPF_PSEUDO_MAP_FD + * insn[0].imm: map fd + * insn[1].imm: 0 + * insn[0].off: 0 + * insn[1].off: 0 + * ldimm64 rewrite: address of map + * verifier type: CONST_PTR_TO_MAP + */ #define BPF_PSEUDO_MAP_FD 1 +/* insn[0].src_reg: BPF_PSEUDO_MAP_VALUE + * insn[0].imm: map fd + * insn[1].imm: offset into value + * insn[0].off: 0 + * insn[1].off: 0 + * ldimm64 rewrite: address of map[0]+offset + * verifier type: PTR_TO_MAP_VALUE + */ +#define BPF_PSEUDO_MAP_VALUE 2 +/* insn[0].src_reg: BPF_PSEUDO_BTF_ID + * insn[0].imm: kernel btd id of VAR + * insn[1].imm: 0 + * insn[0].off: 0 + * insn[1].off: 0 + * ldimm64 rewrite: address of the kernel variable + * verifier type: PTR_TO_BTF_ID or PTR_TO_MEM, depending on whether the var + * is struct/union. + */ +#define BPF_PSEUDO_BTF_ID 3 /* when bpf_call->src_reg == BPF_PSEUDO_CALL, bpf_call->imm == pc-relative * offset to another bpf function @@ -263,37 +393,72 @@ enum bpf_attach_type { #define BPF_PSEUDO_CALL 1 /* flags for BPF_MAP_UPDATE_ELEM command */ -#define BPF_ANY 0 /* create new element or update existing */ -#define BPF_NOEXIST 1 /* create new element if it didn't exist */ -#define BPF_EXIST 2 /* update existing element */ +enum { + BPF_ANY = 0, /* create new element or update existing */ + BPF_NOEXIST = 1, /* create new element if it didn't exist */ + BPF_EXIST = 2, /* update existing element */ + BPF_F_LOCK = 4, /* spin_lock-ed map_lookup/map_update */ +}; /* flags for BPF_MAP_CREATE command */ -#define BPF_F_NO_PREALLOC (1U << 0) +enum { + BPF_F_NO_PREALLOC = (1U << 0), /* Instead of having one common LRU list in the * BPF_MAP_TYPE_LRU_[PERCPU_]HASH map, use a percpu LRU list * which can scale and perform better. * Note, the LRU nodes (including free nodes) cannot be moved * across different LRU lists. */ -#define BPF_F_NO_COMMON_LRU (1U << 1) + BPF_F_NO_COMMON_LRU = (1U << 1), /* Specify numa node during map creation */ -#define BPF_F_NUMA_NODE (1U << 2) + BPF_F_NUMA_NODE = (1U << 2), -#define BPF_OBJ_NAME_LEN 16U - -/* Flags for accessing BPF object */ -#define BPF_F_RDONLY (1U << 3) -#define BPF_F_WRONLY (1U << 4) +/* Flags for accessing BPF object from syscall side. */ + BPF_F_RDONLY = (1U << 3), + BPF_F_WRONLY = (1U << 4), /* Flag for stack_map, store build_id+offset instead of pointer */ -#define BPF_F_STACK_BUILD_ID (1U << 5) + BPF_F_STACK_BUILD_ID = (1U << 5), /* Zero-initialize hash function seed. This should only be used for testing. */ -#define BPF_F_ZERO_SEED (1U << 6) + BPF_F_ZERO_SEED = (1U << 6), -/* flags for BPF_PROG_QUERY */ +/* Flags for accessing BPF object from program side. */ + BPF_F_RDONLY_PROG = (1U << 7), + BPF_F_WRONLY_PROG = (1U << 8), + +/* Clone map from listener for newly accepted socket */ + BPF_F_CLONE = (1U << 9), + +/* Enable memory-mapping BPF map */ + BPF_F_MMAPABLE = (1U << 10), + +/* Share perf_event among processes */ + BPF_F_PRESERVE_ELEMS = (1U << 11), + +/* Create a map that is suitable to be an inner map with dynamic max entries */ + BPF_F_INNER_MAP = (1U << 12), +}; + +/* Flags for BPF_PROG_QUERY. */ + +/* Query effective (directly attached + inherited from ancestor cgroups) + * programs that will be executed for events within a cgroup. + * attach_flags with this flag are returned only for directly attached programs. + */ #define BPF_F_QUERY_EFFECTIVE (1U << 0) +/* Flags for BPF_PROG_TEST_RUN */ + +/* If set, run the test on the cpu specified by bpf_attr.test.cpu */ +#define BPF_F_TEST_RUN_ON_CPU (1U << 0) + +/* type for BPF_ENABLE_STATS */ +enum bpf_stats_type { + /* enabled run_time_ns and run_cnt */ + BPF_STATS_RUN_TIME = 0, +}; + enum bpf_stack_build_id_status { /* user space need an empty entry to identify end of a trace */ BPF_STACK_BUILD_ID_EMPTY = 0, @@ -313,6 +478,8 @@ struct bpf_stack_build_id { }; }; +#define BPF_OBJ_NAME_LEN 16U + union bpf_attr { struct { /* anonymous struct used by BPF_MAP_CREATE command */ __u32 map_type; /* one of enum bpf_map_type */ @@ -331,6 +498,10 @@ union bpf_attr { __u32 btf_fd; /* fd pointing to a BTF type data */ __u32 btf_key_type_id; /* BTF type_id of the key */ __u32 btf_value_type_id; /* BTF type_id of the value */ + __u32 btf_vmlinux_value_type_id;/* BTF type_id of a kernel- + * struct stored as the + * map value + */ }; struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */ @@ -343,6 +514,23 @@ union bpf_attr { __u64 flags; }; + struct { /* struct used by BPF_MAP_*_BATCH commands */ + __aligned_u64 in_batch; /* start batch, + * NULL to start from beginning + */ + __aligned_u64 out_batch; /* output: next start batch */ + __aligned_u64 keys; + __aligned_u64 values; + __u32 count; /* input/output: + * input: # of key/value + * elements + * output: # of filled elements + */ + __u32 map_fd; + __u64 elem_flags; + __u64 flags; + } batch; + struct { /* anonymous struct used by BPF_PROG_LOAD command */ __u32 prog_type; /* one of enum bpf_prog_type */ __u32 insn_cnt; @@ -367,6 +555,8 @@ union bpf_attr { __u32 line_info_rec_size; /* userspace bpf_line_info size */ __aligned_u64 line_info; /* line info */ __u32 line_info_cnt; /* number of bpf_line_info records */ + __u32 attach_btf_id; /* in-kernel BTF type id to attach to */ + __u32 attach_prog_fd; /* 0 to attach to vmlinux */ }; struct { /* anonymous struct used by BPF_OBJ_* commands */ @@ -380,6 +570,10 @@ union bpf_attr { __u32 attach_bpf_fd; /* eBPF program to attach */ __u32 attach_type; __u32 attach_flags; + __u32 replace_bpf_fd; /* previously attached eBPF + * program to replace if + * BPF_F_REPLACE is used + */ }; struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */ @@ -394,6 +588,15 @@ union bpf_attr { __aligned_u64 data_out; __u32 repeat; __u32 duration; + __u32 ctx_size_in; /* input: len of ctx_in */ + __u32 ctx_size_out; /* input/output: len of ctx_out + * returns ENOSPC if ctx_out + * is too small. + */ + __aligned_u64 ctx_in; + __aligned_u64 ctx_out; + __u32 flags; + __u32 cpu; } test; struct { /* anonymous struct used by BPF_*_GET_*_ID */ @@ -402,6 +605,7 @@ union bpf_attr { __u32 prog_id; __u32 map_id; __u32 btf_id; + __u32 link_id; }; __u32 next_id; __u32 open_flags; @@ -422,7 +626,7 @@ union bpf_attr { __u32 prog_cnt; } query; - struct { + struct { /* anonymous struct used by BPF_RAW_TRACEPOINT_OPEN command */ __u64 name; __u32 prog_fd; } raw_tracepoint; @@ -450,6 +654,53 @@ union bpf_attr { __u64 probe_offset; /* output: probe_offset */ __u64 probe_addr; /* output: probe_addr */ } task_fd_query; + + struct { /* struct used by BPF_LINK_CREATE command */ + __u32 prog_fd; /* eBPF program to attach */ + union { + __u32 target_fd; /* object to attach to */ + __u32 target_ifindex; /* target ifindex */ + }; + __u32 attach_type; /* attach type */ + __u32 flags; /* extra flags */ + union { + __u32 target_btf_id; /* btf_id of target to attach to */ + struct { + __aligned_u64 iter_info; /* extra bpf_iter_link_info */ + __u32 iter_info_len; /* iter_info length */ + }; + }; + } link_create; + + struct { /* struct used by BPF_LINK_UPDATE command */ + __u32 link_fd; /* link fd */ + /* new program fd to update link with */ + __u32 new_prog_fd; + __u32 flags; /* extra flags */ + /* expected link's program fd; is specified only if + * BPF_F_REPLACE flag is set in flags */ + __u32 old_prog_fd; + } link_update; + + struct { + __u32 link_fd; + } link_detach; + + struct { /* struct used by BPF_ENABLE_STATS command */ + __u32 type; + } enable_stats; + + struct { /* struct used by BPF_ITER_CREATE command */ + __u32 link_fd; + __u32 flags; + } iter_create; + + struct { /* struct used by BPF_PROG_BIND_MAP command */ + __u32 prog_fd; + __u32 map_fd; + __u32 flags; /* extra flags */ + } prog_bind_map; + } __attribute__((aligned(8))); /* The description below is an attempt at providing documentation to eBPF @@ -476,7 +727,7 @@ union bpf_attr { * Map value associated to *key*, or **NULL** if no entry was * found. * - * int bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) + * long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags) * Description * Add or update the value of the entry associated to *key* in * *map* with *value*. *flags* is one of: @@ -494,36 +745,31 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_map_delete_elem(struct bpf_map *map, const void *key) + * long bpf_map_delete_elem(struct bpf_map *map, const void *key) * Description * Delete entry with *key* from *map*. * Return * 0 on success, or a negative error in case of failure. * - * int bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags) - * Description - * Push an element *value* in *map*. *flags* is one of: - * - * **BPF_EXIST** - * If the queue/stack is full, the oldest element is removed to - * make room for this. - * Return - * 0 on success, or a negative error in case of failure. - * - * int bpf_probe_read(void *dst, u32 size, const void *src) + * long bpf_probe_read(void *dst, u32 size, const void *unsafe_ptr) * Description * For tracing programs, safely attempt to read *size* bytes from - * address *src* and store the data in *dst*. + * kernel space address *unsafe_ptr* and store the data in *dst*. + * + * Generally, use **bpf_probe_read_user**\ () or + * **bpf_probe_read_kernel**\ () instead. * Return * 0 on success, or a negative error in case of failure. * * u64 bpf_ktime_get_ns(void) * Description * Return the time elapsed since system boot, in nanoseconds. + * Does not include time the system was suspended. + * See: **clock_gettime**\ (**CLOCK_MONOTONIC**) * Return * Current *ktime*. * - * int bpf_trace_printk(const char *fmt, u32 fmt_size, ...) + * long bpf_trace_printk(const char *fmt, u32 fmt_size, ...) * Description * This helper is a "printk()-like" facility for debugging. It * prints a message defined by format *fmt* (of size *fmt_size*) @@ -533,6 +779,8 @@ union bpf_attr { * limited to five). * * Each time the helper is called, it appends a line to the trace. + * Lines are discarded while *\/sys/kernel/debug/tracing/trace* is + * open, use *\/sys/kernel/debug/tracing/trace_pipe* to avoid this. * The format of the trace is customizable, and the exact output * one will get depends on the options set in * *\/sys/kernel/debug/tracing/trace_options* (see also the @@ -571,7 +819,7 @@ union bpf_attr { * * Also, note that **bpf_trace_printk**\ () is slow, and should * only be used for debugging purposes. For this reason, a notice - * bloc (spanning several lines) is printed to kernel logs and + * block (spanning several lines) is printed to kernel logs and * states that the helper should not be used "for production use" * the first time this helper is used (or more precisely, when * **trace_printk**\ () buffers are allocated). For passing values @@ -601,7 +849,7 @@ union bpf_attr { * Return * The SMP id of the processor running the program. * - * int bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags) + * long bpf_skb_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len, u64 flags) * Description * Store *len* bytes from address *from* into the packet * associated to *skb*, at *offset*. *flags* are a combination of @@ -610,7 +858,7 @@ union bpf_attr { * **BPF_F_INVALIDATE_HASH** (set *skb*\ **->hash**, *skb*\ * **->swhash** and *skb*\ **->l4hash** to 0). * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -618,7 +866,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_l3_csum_replace(struct sk_buff *skb, u32 offset, u64 from, u64 to, u64 size) + * long bpf_l3_csum_replace(struct sk_buff *skb, u32 offset, u64 from, u64 to, u64 size) * Description * Recompute the layer 3 (e.g. IP) checksum for the packet * associated to *skb*. Computation is incremental, so the helper @@ -635,7 +883,7 @@ union bpf_attr { * flexibility and can handle sizes larger than 2 or 4 for the * checksum to update. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -643,7 +891,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_l4_csum_replace(struct sk_buff *skb, u32 offset, u64 from, u64 to, u64 flags) + * long bpf_l4_csum_replace(struct sk_buff *skb, u32 offset, u64 from, u64 to, u64 flags) * Description * Recompute the layer 4 (e.g. TCP, UDP or ICMP) checksum for the * packet associated to *skb*. Computation is incremental, so the @@ -667,7 +915,7 @@ union bpf_attr { * flexibility and can handle sizes larger than 2 or 4 for the * checksum to update. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -675,7 +923,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_tail_call(void *ctx, struct bpf_map *prog_array_map, u32 index) + * long bpf_tail_call(void *ctx, struct bpf_map *prog_array_map, u32 index) * Description * This special helper is used to trigger a "tail call", or in * other words, to jump into another eBPF program. The same stack @@ -706,7 +954,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_clone_redirect(struct sk_buff *skb, u32 ifindex, u64 flags) + * long bpf_clone_redirect(struct sk_buff *skb, u32 ifindex, u64 flags) * Description * Clone and redirect the packet associated to *skb* to another * net device of index *ifindex*. Both ingress and egress @@ -722,7 +970,7 @@ union bpf_attr { * efficient, but it is handled through an action code where the * redirection happens only after the eBPF program has returned. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -742,7 +990,7 @@ union bpf_attr { * A 64-bit integer containing the current GID and UID, and * created as such: *current_gid* **<< 32 \|** *current_uid*. * - * int bpf_get_current_comm(char *buf, u32 size_of_buf) + * long bpf_get_current_comm(void *buf, u32 size_of_buf) * Description * Copy the **comm** attribute of the current task into *buf* of * *size_of_buf*. The **comm** attribute contains the name of @@ -764,7 +1012,7 @@ union bpf_attr { * based on a user-provided identifier for all traffic coming from * the tasks belonging to the related cgroup. See also the related * kernel documentation, available from the Linux sources in file - * *Documentation/cgroup-v1/net_cls.txt*. + * *Documentation/admin-guide/cgroup-v1/net_cls.rst*. * * The Linux kernel has two versions for cgroups: there are * cgroups v1 and cgroups v2. Both are available to users, who can @@ -779,7 +1027,7 @@ union bpf_attr { * Return * The classid, or 0 for the default unconfigured classid. * - * int bpf_skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci) + * long bpf_skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci) * Description * Push a *vlan_tci* (VLAN tag control information) of protocol * *vlan_proto* to the packet associated to *skb*, then update @@ -787,7 +1035,7 @@ union bpf_attr { * **ETH_P_8021Q** and **ETH_P_8021AD**, it is considered to * be **ETH_P_8021Q**. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -795,11 +1043,11 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_vlan_pop(struct sk_buff *skb) + * long bpf_skb_vlan_pop(struct sk_buff *skb) * Description * Pop a VLAN header from the packet associated to *skb*. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -807,7 +1055,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_get_tunnel_key(struct sk_buff *skb, struct bpf_tunnel_key *key, u32 size, u64 flags) + * long bpf_skb_get_tunnel_key(struct sk_buff *skb, struct bpf_tunnel_key *key, u32 size, u64 flags) * Description * Get tunnel metadata. This helper takes a pointer *key* to an * empty **struct bpf_tunnel_key** of **size**, that will be @@ -837,14 +1085,14 @@ union bpf_attr { * * int ret; * struct bpf_tunnel_key key = {}; - * + * * ret = bpf_skb_get_tunnel_key(skb, &key, sizeof(key), 0); * if (ret < 0) * return TC_ACT_SHOT; // drop packet - * + * * if (key.remote_ipv4 != 0x0a000001) * return TC_ACT_SHOT; // drop packet - * + * * return TC_ACT_OK; // accept packet * * This interface can also be used with all encapsulation devices @@ -858,7 +1106,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_set_tunnel_key(struct sk_buff *skb, struct bpf_tunnel_key *key, u32 size, u64 flags) + * long bpf_skb_set_tunnel_key(struct sk_buff *skb, struct bpf_tunnel_key *key, u32 size, u64 flags) * Description * Populate tunnel metadata for packet associated to *skb.* The * tunnel metadata is set to the contents of *key*, of *size*. The @@ -924,7 +1172,7 @@ union bpf_attr { * The value of the perf event counter read from the map, or a * negative error code in case of failure. * - * int bpf_redirect(u32 ifindex, u64 flags) + * long bpf_redirect(u32 ifindex, u64 flags) * Description * Redirect the packet to another net device of index *ifindex*. * This helper is somewhat similar to **bpf_clone_redirect**\ @@ -938,9 +1186,9 @@ union bpf_attr { * supports redirection to the egress interface, and accepts no * flag at all. * - * The same effect can be attained with the more generic - * **bpf_redirect_map**\ (), which requires specific maps to be - * used but offers better performance. + * The same effect can also be attained with the more generic + * **bpf_redirect_map**\ (), which uses a BPF map to store the + * redirect target instead of providing it directly to the helper. * Return * For XDP, the helper returns **XDP_REDIRECT** on success or * **XDP_ABORTED** on error. For other program types, the values @@ -971,7 +1219,7 @@ union bpf_attr { * The realm of the route for the packet associated to *skb*, or 0 * if none was found. * - * int bpf_perf_event_output(struct pt_reg *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) + * long bpf_perf_event_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) * Description * Write raw *data* blob into a special BPF perf event held by * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf @@ -1016,7 +1264,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_load_bytes(const struct sk_buff *skb, u32 offset, void *to, u32 len) + * long bpf_skb_load_bytes(const void *skb, u32 offset, void *to, u32 len) * Description * This helper was provided as an easy way to load data from a * packet. It can be used to load *len* bytes from *offset* from @@ -1033,7 +1281,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_get_stackid(struct pt_reg *ctx, struct bpf_map *map, u64 flags) + * long bpf_get_stackid(void *ctx, struct bpf_map *map, u64 flags) * Description * Walk a user or a kernel stack and return its id. To achieve * this, the helper needs *ctx*, which is a pointer to the context @@ -1102,7 +1350,7 @@ union bpf_attr { * The checksum result, or a negative error code in case of * failure. * - * int bpf_skb_get_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size) + * long bpf_skb_get_tunnel_opt(struct sk_buff *skb, void *opt, u32 size) * Description * Retrieve tunnel options metadata for the packet associated to * *skb*, and store the raw tunnel option data to the buffer *opt* @@ -1120,7 +1368,7 @@ union bpf_attr { * Return * The size of the option data retrieved. * - * int bpf_skb_set_tunnel_opt(struct sk_buff *skb, u8 *opt, u32 size) + * long bpf_skb_set_tunnel_opt(struct sk_buff *skb, void *opt, u32 size) * Description * Set tunnel options metadata for the packet associated to *skb* * to the option data contained in the raw buffer *opt* of *size*. @@ -1130,7 +1378,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_change_proto(struct sk_buff *skb, __be16 proto, u64 flags) + * long bpf_skb_change_proto(struct sk_buff *skb, __be16 proto, u64 flags) * Description * Change the protocol of the *skb* to *proto*. Currently * supported are transition from IPv4 to IPv6, and from IPv6 to @@ -1149,7 +1397,7 @@ union bpf_attr { * All values for *flags* are reserved for future usage, and must * be left at zero. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1157,7 +1405,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_change_type(struct sk_buff *skb, u32 type) + * long bpf_skb_change_type(struct sk_buff *skb, u32 type) * Description * Change the packet type for the packet associated to *skb*. This * comes down to setting *skb*\ **->pkt_type** to *type*, except @@ -1184,7 +1432,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_under_cgroup(struct sk_buff *skb, struct bpf_map *map, u32 index) + * long bpf_skb_under_cgroup(struct sk_buff *skb, struct bpf_map *map, u32 index) * Description * Check whether *skb* is a descendant of the cgroup2 held by * *map* of type **BPF_MAP_TYPE_CGROUP_ARRAY**, at *index*. @@ -1215,7 +1463,7 @@ union bpf_attr { * Return * A pointer to the current task struct. * - * int bpf_probe_write_user(void *dst, const void *src, u32 len) + * long bpf_probe_write_user(void *dst, const void *src, u32 len) * Description * Attempt in a safe way to write *len* bytes from the buffer * *src* to *dst* in memory. It only works for threads that are in @@ -1234,7 +1482,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_current_task_under_cgroup(struct bpf_map *map, u32 index) + * long bpf_current_task_under_cgroup(struct bpf_map *map, u32 index) * Description * Check whether the probe is being run is the context of a given * subset of the cgroup2 hierarchy. The cgroup2 to test is held by @@ -1242,11 +1490,11 @@ union bpf_attr { * Return * The return value depends on the result of the test, and can be: * - * * 0, if the *skb* task belongs to the cgroup2. - * * 1, if the *skb* task does not belong to the cgroup2. + * * 0, if current task belongs to the cgroup2. + * * 1, if current task does not belong to the cgroup2. * * A negative error code, if an error occurred. * - * int bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) + * long bpf_skb_change_tail(struct sk_buff *skb, u32 len, u64 flags) * Description * Resize (trim or grow) the packet associated to *skb* to the * new *len*. The *flags* are reserved for future usage, and must @@ -1262,7 +1510,7 @@ union bpf_attr { * implicitly linearizes, unclones and drops offloads from the * *skb*. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1270,7 +1518,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_pull_data(struct sk_buff *skb, u32 len) + * long bpf_skb_pull_data(struct sk_buff *skb, u32 len) * Description * Pull in non-linear data in case the *skb* is non-linear and not * all of *len* are part of the linear section. Make *len* bytes @@ -1298,7 +1546,7 @@ union bpf_attr { * **bpf_skb_pull_data()** to effectively unclone the *skb* from * the very beginning in case it is indeed cloned. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1326,7 +1574,7 @@ union bpf_attr { * recalculation the next time the kernel tries to access this * hash or when the **bpf_get_hash_recalc**\ () helper is called. * - * int bpf_get_numa_node_id(void) + * long bpf_get_numa_node_id(void) * Description * Return the id of the current NUMA node. The primary use case * for this helper is the selection of sockets for the local NUMA @@ -1337,7 +1585,7 @@ union bpf_attr { * Return * The id of current NUMA node. * - * int bpf_skb_change_head(struct sk_buff *skb, u32 len, u64 flags) + * long bpf_skb_change_head(struct sk_buff *skb, u32 len, u64 flags) * Description * Grows headroom of packet associated to *skb* and adjusts the * offset of the MAC header accordingly, adding *len* bytes of @@ -1350,7 +1598,7 @@ union bpf_attr { * All values for *flags* are reserved for future usage, and must * be left at zero. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1358,14 +1606,14 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_xdp_adjust_head(struct xdp_buff *xdp_md, int delta) + * long bpf_xdp_adjust_head(struct xdp_buff *xdp_md, int delta) * Description * Adjust (move) *xdp_md*\ **->data** by *delta* bytes. Note that * it is possible to use a negative value for *delta*. This helper * can be used to prepare the packet for pushing or popping * headers. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1373,45 +1621,14 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_probe_read_str(void *dst, int size, const void *unsafe_ptr) + * long bpf_probe_read_str(void *dst, u32 size, const void *unsafe_ptr) * Description - * Copy a NUL terminated string from an unsafe address - * *unsafe_ptr* to *dst*. The *size* should include the - * terminating NUL byte. In case the string length is smaller than - * *size*, the target is not padded with further NUL bytes. If the - * string length is larger than *size*, just *size*-1 bytes are - * copied and the last byte is set to NUL. + * Copy a NUL terminated string from an unsafe kernel address + * *unsafe_ptr* to *dst*. See **bpf_probe_read_kernel_str**\ () for + * more details. * - * On success, the length of the copied string is returned. This - * makes this helper useful in tracing programs for reading - * strings, and more importantly to get its length at runtime. See - * the following snippet: - * - * :: - * - * SEC("kprobe/sys_open") - * void bpf_sys_open(struct pt_regs *ctx) - * { - * char buf[PATHLEN]; // PATHLEN is defined to 256 - * int res = bpf_probe_read_str(buf, sizeof(buf), - * ctx->di); - * - * // Consume buf, for example push it to - * // userspace via bpf_perf_event_output(); we - * // can use res (the string length) as event - * // size, after checking its boundaries. - * } - * - * In comparison, using **bpf_probe_read()** helper here instead - * to read the string would require to estimate the length at - * compile time, and would often result in copying more memory - * than necessary. - * - * Another useful use case is when parsing individual process - * arguments or individual environment variables navigating - * *current*\ **->mm->arg_start** and *current*\ - * **->mm->env_start**: using this helper and the return value, - * one can quickly iterate at the right offset of the memory area. + * Generally, use **bpf_probe_read_user_str**\ () or + * **bpf_probe_read_kernel_str**\ () instead. * Return * On success, the strictly positive length of the string, * including the trailing NUL character. On error, a negative @@ -1424,8 +1641,8 @@ union bpf_attr { * If no cookie has been set yet, generate a new cookie. Once * generated, the socket cookie remains stable for the life of the * socket. This helper can be useful for monitoring per socket - * networking traffic statistics as it provides a unique socket - * identifier per namespace. + * networking traffic statistics as it provides a global socket + * identifier that can be assumed unique. * Return * A 8-byte long non-decreasing number on success, or 0 if the * socket field is missing inside *skb*. @@ -1433,14 +1650,14 @@ union bpf_attr { * u64 bpf_get_socket_cookie(struct bpf_sock_addr *ctx) * Description * Equivalent to bpf_get_socket_cookie() helper that accepts - * *skb*, but gets socket from **struct bpf_sock_addr** contex. + * *skb*, but gets socket from **struct bpf_sock_addr** context. * Return * A 8-byte long non-decreasing number. * * u64 bpf_get_socket_cookie(struct bpf_sock_ops *ctx) * Description - * Equivalent to bpf_get_socket_cookie() helper that accepts - * *skb*, but gets socket from **struct bpf_sock_ops** contex. + * Equivalent to **bpf_get_socket_cookie**\ () helper that accepts + * *skb*, but gets socket from **struct bpf_sock_ops** context. * Return * A 8-byte long non-decreasing number. * @@ -1452,14 +1669,14 @@ union bpf_attr { * is returned (note that **overflowuid** might also be the actual * UID value for the socket). * - * u32 bpf_set_hash(struct sk_buff *skb, u32 hash) + * long bpf_set_hash(struct sk_buff *skb, u32 hash) * Description * Set the full hash for *skb* (set the field *skb*\ **->hash**) * to value *hash*. * Return * 0 * - * int bpf_setsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen) + * long bpf_setsockopt(void *bpf_socket, int level, int optname, void *optval, int optlen) * Description * Emulate a call to **setsockopt()** on the socket associated to * *bpf_socket*, which must be a full socket. The *level* at @@ -1467,34 +1684,68 @@ union bpf_attr { * must be specified, see **setsockopt(2)** for more information. * The option value of length *optlen* is pointed by *optval*. * + * *bpf_socket* should be one of the following: + * + * * **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**. + * * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT** + * and **BPF_CGROUP_INET6_CONNECT**. + * * This helper actually implements a subset of **setsockopt()**. * It supports the following *level*\ s: * * * **SOL_SOCKET**, which supports the following *optname*\ s: * **SO_RCVBUF**, **SO_SNDBUF**, **SO_MAX_PACING_RATE**, - * **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**. + * **SO_PRIORITY**, **SO_RCVLOWAT**, **SO_MARK**, + * **SO_BINDTODEVICE**, **SO_KEEPALIVE**. * * **IPPROTO_TCP**, which supports the following *optname*\ s: * **TCP_CONGESTION**, **TCP_BPF_IW**, - * **TCP_BPF_SNDCWND_CLAMP**. + * **TCP_BPF_SNDCWND_CLAMP**, **TCP_SAVE_SYN**, + * **TCP_KEEPIDLE**, **TCP_KEEPINTVL**, **TCP_KEEPCNT**, + * **TCP_SYNCNT**, **TCP_USER_TIMEOUT**, **TCP_NOTSENT_LOWAT**. * * **IPPROTO_IP**, which supports *optname* **IP_TOS**. * * **IPPROTO_IPV6**, which supports *optname* **IPV6_TCLASS**. * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags) + * long bpf_skb_adjust_room(struct sk_buff *skb, s32 len_diff, u32 mode, u64 flags) * Description * Grow or shrink the room for data in the packet associated to * *skb* by *len_diff*, and according to the selected *mode*. * - * There is a single supported mode at this time: + * By default, the helper will reset any offloaded checksum + * indicator of the skb to CHECKSUM_NONE. This can be avoided + * by the following flag: + * + * * **BPF_F_ADJ_ROOM_NO_CSUM_RESET**: Do not reset offloaded + * checksum data of the skb to CHECKSUM_NONE. + * + * There are two supported modes at this time: + * + * * **BPF_ADJ_ROOM_MAC**: Adjust room at the mac layer + * (room space is added or removed below the layer 2 header). * * * **BPF_ADJ_ROOM_NET**: Adjust room at the network layer * (room space is added or removed below the layer 3 header). * - * All values for *flags* are reserved for future usage, and must - * be left at zero. + * The following flags are supported at this time: * - * A call to this helper is susceptible to change the underlaying + * * **BPF_F_ADJ_ROOM_FIXED_GSO**: Do not adjust gso_size. + * Adjusting mss in this way is not allowed for datagrams. + * + * * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV4**, + * **BPF_F_ADJ_ROOM_ENCAP_L3_IPV6**: + * Any new space is reserved to hold a tunnel header. + * Configure skb offsets and other fields accordingly. + * + * * **BPF_F_ADJ_ROOM_ENCAP_L4_GRE**, + * **BPF_F_ADJ_ROOM_ENCAP_L4_UDP**: + * Use with ENCAP_L3 flags to further specify the tunnel type. + * + * * **BPF_F_ADJ_ROOM_ENCAP_L2**\ (*len*): + * Use with ENCAP_L3/L4 flags to further specify the tunnel + * type; *len* is the length of the inner MAC header. + * + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1502,7 +1753,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags) + * long bpf_redirect_map(struct bpf_map *map, u32 key, u64 flags) * Description * Redirect the packet to the endpoint referenced by *map* at * index *key*. Depending on its type, this *map* can contain @@ -1511,18 +1762,19 @@ union bpf_attr { * but this is only implemented for native XDP (with driver * support) as of this writing). * - * All values for *flags* are reserved for future usage, and must - * be left at zero. + * The lower two bits of *flags* are used as the return code if + * the map lookup fails. This is so that the return value can be + * one of the XDP program return codes up to **XDP_TX**, as chosen + * by the caller. Any higher bits in the *flags* argument must be + * unset. * - * When used to redirect packets to net devices, this helper - * provides a high performance increase over **bpf_redirect**\ (). - * This is due to various implementation details of the underlying - * mechanisms, one of which is the fact that **bpf_redirect_map**\ - * () tries to send packet as a "bulk" to the device. + * See also **bpf_redirect**\ (), which only supports redirecting + * to an ifindex, but doesn't require a map to do so. * Return - * **XDP_REDIRECT** on success, or **XDP_ABORTED** on error. + * **XDP_REDIRECT** on success, or the value of the two lower bits + * of the *flags* argument on error. * - * int bpf_sk_redirect_map(struct bpf_map *map, u32 key, u64 flags) + * long bpf_sk_redirect_map(struct sk_buff *skb, struct bpf_map *map, u32 key, u64 flags) * Description * Redirect the packet to the socket referenced by *map* (of type * **BPF_MAP_TYPE_SOCKMAP**) at index *key*. Both ingress and @@ -1533,7 +1785,7 @@ union bpf_attr { * Return * **SK_PASS** on success, or **SK_DROP** on error. * - * int bpf_sock_map_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags) + * long bpf_sock_map_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags) * Description * Add an entry to, or update a *map* referencing sockets. The * *skops* is used as a new value for the entry associated to @@ -1552,7 +1804,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_xdp_adjust_meta(struct xdp_buff *xdp_md, int delta) + * long bpf_xdp_adjust_meta(struct xdp_buff *xdp_md, int delta) * Description * Adjust the address pointed by *xdp_md*\ **->data_meta** by * *delta* (which can be positive or negative). Note that this @@ -1573,7 +1825,7 @@ union bpf_attr { * more flexibility as the user is free to store whatever meta * data they need. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1581,7 +1833,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_perf_event_read_value(struct bpf_map *map, u64 flags, struct bpf_perf_event_value *buf, u32 buf_size) + * long bpf_perf_event_read_value(struct bpf_map *map, u64 flags, struct bpf_perf_event_value *buf, u32 buf_size) * Description * Read the value of a perf event counter, and store it into *buf* * of size *buf_size*. This helper relies on a *map* of type @@ -1625,13 +1877,13 @@ union bpf_attr { * the time running for event since last normalization. The * enabled and running times are accumulated since the perf event * open. To achieve scaling factor between two invocations of an - * eBPF program, users can can use CPU id as the key (which is + * eBPF program, users can use CPU id as the key (which is * typical for perf array usage model) to remember the previous * value and do the calculation inside the eBPF program. * Return * 0 on success, or a negative error in case of failure. * - * int bpf_perf_prog_read_value(struct bpf_perf_event_data *ctx, struct bpf_perf_event_value *buf, u32 buf_size) + * long bpf_perf_prog_read_value(struct bpf_perf_event_data *ctx, struct bpf_perf_event_value *buf, u32 buf_size) * Description * For en eBPF program attached to a perf event, retrieve the * value of the event counter associated to *ctx* and store it in @@ -1642,7 +1894,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_getsockopt(struct bpf_sock_ops *bpf_socket, int level, int optname, char *optval, int optlen) + * long bpf_getsockopt(void *bpf_socket, int level, int optname, void *optval, int optlen) * Description * Emulate a call to **getsockopt()** on the socket associated to * *bpf_socket*, which must be a full socket. The *level* at @@ -1651,6 +1903,12 @@ union bpf_attr { * The retrieved value is stored in the structure pointed by * *opval* and of length *optlen*. * + * *bpf_socket* should be one of the following: + * + * * **struct bpf_sock_ops** for **BPF_PROG_TYPE_SOCK_OPS**. + * * **struct bpf_sock_addr** for **BPF_CGROUP_INET4_CONNECT** + * and **BPF_CGROUP_INET6_CONNECT**. + * * This helper actually implements a subset of **getsockopt()**. * It supports the following *level*\ s: * @@ -1661,14 +1919,14 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_override_return(struct pt_reg *regs, u64 rc) + * long bpf_override_return(struct pt_regs *regs, u64 rc) * Description * Used for error injection, this helper uses kprobes to override * the return value of the probed function, and to set it to *rc*. * The first argument is the context *regs* on which the kprobe * works. * - * This helper works by setting setting the PC (program counter) + * This helper works by setting the PC (program counter) * to an override function which is run in place of the original * probed function. This means the probed function is not run at * all. The replacement function just returns with the required @@ -1686,7 +1944,7 @@ union bpf_attr { * Return * 0 * - * int bpf_sock_ops_cb_flags_set(struct bpf_sock_ops *bpf_sock, int argval) + * long bpf_sock_ops_cb_flags_set(struct bpf_sock_ops *bpf_sock, int argval) * Description * Attempt to set the value of the **bpf_sock_ops_cb_flags** field * for the full TCP socket associated to *bpf_sock_ops* to @@ -1702,11 +1960,19 @@ union bpf_attr { * error if an eBPF program tries to set a callback that is not * supported in the current kernel. * - * The supported callback values that *argval* can combine are: + * *argval* is a flag array which can combine these flags: * * * **BPF_SOCK_OPS_RTO_CB_FLAG** (retransmission time out) * * **BPF_SOCK_OPS_RETRANS_CB_FLAG** (retransmission) * * **BPF_SOCK_OPS_STATE_CB_FLAG** (TCP state change) + * * **BPF_SOCK_OPS_RTT_CB_FLAG** (every RTT) + * + * Therefore, this function can be used to clear a callback flag by + * setting the appropriate bit to zero. e.g. to disable the RTO + * callback: + * + * **bpf_sock_ops_cb_flags_set(bpf_sock,** + * **bpf_sock->bpf_sock_ops_cb_flags & ~BPF_SOCK_OPS_RTO_CB_FLAG)** * * Here are some examples of where one could call such eBPF * program: @@ -1722,7 +1988,7 @@ union bpf_attr { * be set is returned (which comes down to 0 if all bits were set * as required). * - * int bpf_msg_redirect_map(struct sk_msg_buff *msg, struct bpf_map *map, u32 key, u64 flags) + * long bpf_msg_redirect_map(struct sk_msg_buff *msg, struct bpf_map *map, u32 key, u64 flags) * Description * This helper is used in programs implementing policies at the * socket level. If the message *msg* is allowed to pass (i.e. if @@ -1736,7 +2002,7 @@ union bpf_attr { * Return * **SK_PASS** on success, or **SK_DROP** on error. * - * int bpf_msg_apply_bytes(struct sk_msg_buff *msg, u32 bytes) + * long bpf_msg_apply_bytes(struct sk_msg_buff *msg, u32 bytes) * Description * For socket policies, apply the verdict of the eBPF program to * the next *bytes* (number of bytes) of message *msg*. @@ -1770,7 +2036,7 @@ union bpf_attr { * Return * 0 * - * int bpf_msg_cork_bytes(struct sk_msg_buff *msg, u32 bytes) + * long bpf_msg_cork_bytes(struct sk_msg_buff *msg, u32 bytes) * Description * For socket policies, prevent the execution of the verdict eBPF * program for message *msg* until *bytes* (byte number) have been @@ -1788,7 +2054,7 @@ union bpf_attr { * Return * 0 * - * int bpf_msg_pull_data(struct sk_msg_buff *msg, u32 start, u32 end, u64 flags) + * long bpf_msg_pull_data(struct sk_msg_buff *msg, u32 start, u32 end, u64 flags) * Description * For socket policies, pull in non-linear data from user space * for *msg* and set pointers *msg*\ **->data** and *msg*\ @@ -1808,7 +2074,7 @@ union bpf_attr { * copied if necessary (i.e. if data was not linear and if start * and end pointers do not point to the same chunk). * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1819,7 +2085,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_bind(struct bpf_sock_addr *ctx, struct sockaddr *addr, int addr_len) + * long bpf_bind(struct bpf_sock_addr *ctx, struct sockaddr *addr, int addr_len) * Description * Bind the socket associated to *ctx* to the address pointed by * *addr*, of length *addr_len*. This allows for making outgoing @@ -1829,20 +2095,21 @@ union bpf_attr { * * This helper works for IPv4 and IPv6, TCP and UDP sockets. The * domain (*addr*\ **->sa_family**) must be **AF_INET** (or - * **AF_INET6**). Looking for a free port to bind to can be - * expensive, therefore binding to port is not permitted by the - * helper: *addr*\ **->sin_port** (or **sin6_port**, respectively) - * must be set to zero. + * **AF_INET6**). It's advised to pass zero port (**sin_port** + * or **sin6_port**) which triggers IP_BIND_ADDRESS_NO_PORT-like + * behavior and lets the kernel efficiently pick up an unused + * port as long as 4-tuple is unique. Passing non-zero port might + * lead to degraded performance. * Return * 0 on success, or a negative error in case of failure. * - * int bpf_xdp_adjust_tail(struct xdp_buff *xdp_md, int delta) + * long bpf_xdp_adjust_tail(struct xdp_buff *xdp_md, int delta) * Description * Adjust (move) *xdp_md*\ **->data_end** by *delta* bytes. It is - * only possible to shrink the packet as of this writing, - * therefore *delta* must be a negative integer. + * possible to both shrink and grow the packet tail. + * Shrink done via *delta* being a negative integer. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -1850,7 +2117,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_skb_get_xfrm_state(struct sk_buff *skb, u32 index, struct bpf_xfrm_state *xfrm_state, u32 size, u64 flags) + * long bpf_skb_get_xfrm_state(struct sk_buff *skb, u32 index, struct bpf_xfrm_state *xfrm_state, u32 size, u64 flags) * Description * Retrieve the XFRM state (IP transform framework, see also * **ip-xfrm(8)**) at *index* in XFRM "security path" for *skb*. @@ -1866,7 +2133,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_get_stack(struct pt_regs *regs, void *buf, u32 size, u64 flags) + * long bpf_get_stack(void *ctx, void *buf, u32 size, u64 flags) * Description * Return a user or a kernel stack in bpf program provided buffer. * To achieve this, the helper needs *ctx*, which is a pointer @@ -1899,7 +2166,7 @@ union bpf_attr { * A non-negative value equal to or less than *size* on success, * or a negative error in case of failure. * - * int bpf_skb_load_bytes_relative(const struct sk_buff *skb, u32 offset, void *to, u32 len, u32 start_header) + * long bpf_skb_load_bytes_relative(const void *skb, u32 offset, void *to, u32 len, u32 start_header) * Description * This helper is similar to **bpf_skb_load_bytes**\ () in that * it provides an easy way to load *len* bytes from *offset* @@ -1921,7 +2188,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_fib_lookup(void *ctx, struct bpf_fib_lookup *params, int plen, u32 flags) + * long bpf_fib_lookup(void *ctx, struct bpf_fib_lookup *params, int plen, u32 flags) * Description * Do FIB lookup in kernel tables using parameters in *params*. * If lookup is successful and result shows packet is to be @@ -1952,7 +2219,7 @@ union bpf_attr { * * > 0 one of **BPF_FIB_LKUP_RET_** codes explaining why the * packet is not forwarded or needs assist from full stack * - * int bpf_sock_hash_update(struct bpf_sock_ops_kern *skops, struct bpf_map *map, void *key, u64 flags) + * long bpf_sock_hash_update(struct bpf_sock_ops *skops, struct bpf_map *map, void *key, u64 flags) * Description * Add an entry to, or update a sockhash *map* referencing sockets. * The *skops* is used as a new value for the entry associated to @@ -1971,7 +2238,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_redirect_hash(struct sk_msg_buff *msg, struct bpf_map *map, void *key, u64 flags) + * long bpf_msg_redirect_hash(struct sk_msg_buff *msg, struct bpf_map *map, void *key, u64 flags) * Description * This helper is used in programs implementing policies at the * socket level. If the message *msg* is allowed to pass (i.e. if @@ -1985,11 +2252,11 @@ union bpf_attr { * Return * **SK_PASS** on success, or **SK_DROP** on error. * - * int bpf_sk_redirect_hash(struct sk_buff *skb, struct bpf_map *map, void *key, u64 flags) + * long bpf_sk_redirect_hash(struct sk_buff *skb, struct bpf_map *map, void *key, u64 flags) * Description * This helper is used in programs implementing policies at the * skb socket level. If the sk_buff *skb* is allowed to pass (i.e. - * if the verdeict eBPF program returns **SK_PASS**), redirect it + * if the verdict eBPF program returns **SK_PASS**), redirect it * to the socket referenced by *map* (of type * **BPF_MAP_TYPE_SOCKHASH**) using hash *key*. Both ingress and * egress interfaces can be used for redirection. The @@ -1999,7 +2266,7 @@ union bpf_attr { * Return * **SK_PASS** on success, or **SK_DROP** on error. * - * int bpf_lwt_push_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len) + * long bpf_lwt_push_encap(struct sk_buff *skb, u32 type, void *hdr, u32 len) * Description * Encapsulate the packet associated to *skb* within a Layer 3 * protocol header. This header is provided in the buffer at @@ -2014,8 +2281,21 @@ union bpf_attr { * Only works if *skb* contains an IPv6 packet. Insert a * Segment Routing Header (**struct ipv6_sr_hdr**) inside * the IPv6 header. + * **BPF_LWT_ENCAP_IP** + * IP encapsulation (GRE/GUE/IPIP/etc). The outer header + * must be IPv4 or IPv6, followed by zero or more + * additional headers, up to **LWT_BPF_MAX_HEADROOM** + * total bytes in all prepended headers. Please note that + * if **skb_is_gso**\ (*skb*) is true, no more than two + * headers can be prepended, and the inner header, if + * present, should be either GRE or UDP/GUE. * - * A call to this helper is susceptible to change the underlaying + * **BPF_LWT_ENCAP_SEG6**\ \* types can be called by BPF programs + * of type **BPF_PROG_TYPE_LWT_IN**; **BPF_LWT_ENCAP_IP** type can + * be called by bpf programs of types **BPF_PROG_TYPE_LWT_IN** and + * **BPF_PROG_TYPE_LWT_XMIT**. + * + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -2023,14 +2303,14 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_lwt_seg6_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len) + * long bpf_lwt_seg6_store_bytes(struct sk_buff *skb, u32 offset, const void *from, u32 len) * Description * Store *len* bytes from address *from* into the packet * associated to *skb*, at *offset*. Only the flags, tag and TLVs * inside the outermost IPv6 Segment Routing Header can be * modified through this helper. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -2038,7 +2318,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_lwt_seg6_adjust_srh(struct sk_buff *skb, u32 offset, s32 delta) + * long bpf_lwt_seg6_adjust_srh(struct sk_buff *skb, u32 offset, s32 delta) * Description * Adjust the size allocated to TLVs in the outermost IPv6 * Segment Routing Header contained in the packet associated to @@ -2046,7 +2326,7 @@ union bpf_attr { * after the segments are accepted. *delta* can be as well * positive (growing) as negative (shrinking). * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -2054,7 +2334,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_lwt_seg6_action(struct sk_buff *skb, u32 action, void *param, u32 param_len) + * long bpf_lwt_seg6_action(struct sk_buff *skb, u32 action, void *param, u32 param_len) * Description * Apply an IPv6 Segment Routing action of type *action* to the * packet associated to *skb*. Each action takes a parameter @@ -2069,13 +2349,13 @@ union bpf_attr { * Type of *param*: **int**. * **SEG6_LOCAL_ACTION_END_B6** * End.B6 action: Endpoint bound to an SRv6 policy. - * Type of param: **struct ipv6_sr_hdr**. + * Type of *param*: **struct ipv6_sr_hdr**. * **SEG6_LOCAL_ACTION_END_B6_ENCAP** * End.B6.Encap action: Endpoint bound to an SRv6 * encapsulation policy. - * Type of param: **struct ipv6_sr_hdr**. + * Type of *param*: **struct ipv6_sr_hdr**. * - * A call to this helper is susceptible to change the underlaying + * A call to this helper is susceptible to change the underlying * packet buffer. Therefore, at load time, all checks on pointers * previously done by the verifier are invalidated and must be * performed again, if the helper is used in combination with @@ -2083,33 +2363,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_rc_keydown(void *ctx, u32 protocol, u64 scancode, u32 toggle) - * Description - * This helper is used in programs implementing IR decoding, to - * report a successfully decoded key press with *scancode*, - * *toggle* value in the given *protocol*. The scancode will be - * translated to a keycode using the rc keymap, and reported as - * an input key down event. After a period a key up event is - * generated. This period can be extended by calling either - * **bpf_rc_keydown**\ () again with the same values, or calling - * **bpf_rc_repeat**\ (). - * - * Some protocols include a toggle bit, in case the button was - * released and pressed again between consecutive scancodes. - * - * The *ctx* should point to the lirc sample as passed into - * the program. - * - * The *protocol* is the decoded protocol number (see - * **enum rc_proto** for some predefined values). - * - * This helper is only available is the kernel was compiled with - * the **CONFIG_BPF_LIRC_MODE2** configuration option set to - * "**y**". - * Return - * 0 - * - * int bpf_rc_repeat(void *ctx) + * long bpf_rc_repeat(void *ctx) * Description * This helper is used in programs implementing IR decoding, to * report a successfully decoded repeat key message. This delays @@ -2128,7 +2382,33 @@ union bpf_attr { * Return * 0 * - * uint64_t bpf_skb_cgroup_id(struct sk_buff *skb) + * long bpf_rc_keydown(void *ctx, u32 protocol, u64 scancode, u32 toggle) + * Description + * This helper is used in programs implementing IR decoding, to + * report a successfully decoded key press with *scancode*, + * *toggle* value in the given *protocol*. The scancode will be + * translated to a keycode using the rc keymap, and reported as + * an input key down event. After a period a key up event is + * generated. This period can be extended by calling either + * **bpf_rc_keydown**\ () again with the same values, or calling + * **bpf_rc_repeat**\ (). + * + * Some protocols include a toggle bit, in case the button was + * released and pressed again between consecutive scancodes. + * + * The *ctx* should point to the lirc sample as passed into + * the program. + * + * The *protocol* is the decoded protocol number (see + * **enum rc_proto** for some predefined values). + * + * This helper is only available is the kernel was compiled with + * the **CONFIG_BPF_LIRC_MODE2** configuration option set to + * "**y**". + * Return + * 0 + * + * u64 bpf_skb_cgroup_id(struct sk_buff *skb) * Description * Return the cgroup v2 id of the socket associated with the *skb*. * This is roughly similar to the **bpf_get_cgroup_classid**\ () @@ -2144,6 +2424,38 @@ union bpf_attr { * Return * The id is returned or 0 in case the id could not be retrieved. * + * u64 bpf_get_current_cgroup_id(void) + * Return + * A 64-bit integer containing the current cgroup id based + * on the cgroup within which the current task is running. + * + * void *bpf_get_local_storage(void *map, u64 flags) + * Description + * Get the pointer to the local storage area. + * The type and the size of the local storage is defined + * by the *map* argument. + * The *flags* meaning is specific for each map type, + * and has to be 0 for cgroup local storage. + * + * Depending on the BPF program type, a local storage area + * can be shared between multiple instances of the BPF program, + * running simultaneously. + * + * A user should care about the synchronization by himself. + * For example, by using the **BPF_STX_XADD** instruction to alter + * the shared data. + * Return + * A pointer to the local storage area. + * + * long bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags) + * Description + * Select a **SO_REUSEPORT** socket from a + * **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*. + * It checks the selected socket is matching the incoming + * request in the socket buffer. + * Return + * 0 on success, or a negative error in case of failure. + * * u64 bpf_skb_ancestor_cgroup_id(struct sk_buff *skb, int ancestor_level) * Description * Return id of cgroup v2 that is ancestor of cgroup associated @@ -2162,38 +2474,6 @@ union bpf_attr { * Return * The id is returned or 0 in case the id could not be retrieved. * - * u64 bpf_get_current_cgroup_id(void) - * Return - * A 64-bit integer containing the current cgroup id based - * on the cgroup within which the current task is running. - * - * void* get_local_storage(void *map, u64 flags) - * Description - * Get the pointer to the local storage area. - * The type and the size of the local storage is defined - * by the *map* argument. - * The *flags* meaning is specific for each map type, - * and has to be 0 for cgroup local storage. - * - * Depending on the BPF program type, a local storage area - * can be shared between multiple instances of the BPF program, - * running simultaneously. - * - * A user should care about the synchronization by himself. - * For example, by using the **BPF_STX_XADD** instruction to alter - * the shared data. - * Return - * A pointer to the local storage area. - * - * int bpf_sk_select_reuseport(struct sk_reuseport_md *reuse, struct bpf_map *map, void *key, u64 flags) - * Description - * Select a **SO_REUSEPORT** socket from a - * **BPF_MAP_TYPE_REUSEPORT_ARRAY** *map*. - * It checks the selected socket is matching the incoming - * request in the socket buffer. - * Return - * 0 on success, or a negative error in case of failure. - * * struct bpf_sock *bpf_sk_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags) * Description * Look for TCP socket matching *tuple*, optionally in a child @@ -2212,7 +2492,7 @@ union bpf_attr { * Look for an IPv6 socket. * * If the *netns* is a negative signed 32-bit integer, then the - * socket lookup table in the netns associated with the *ctx* will + * socket lookup table in the netns associated with the *ctx* * will be used. For the TC hooks, this is the netns of the device * in the skb. For socket hooks, this is the netns of the socket. * If *netns* is any other signed 32-bit value greater than or @@ -2228,7 +2508,8 @@ union bpf_attr { * Return * Pointer to **struct bpf_sock**, or **NULL** in case of failure. * For sockets with reuseport option, the **struct bpf_sock** - * result is from **reuse->socks**\ [] using the hash of the tuple. + * result is from *reuse*\ **->socks**\ [] using the hash of the + * tuple. * * struct bpf_sock *bpf_sk_lookup_udp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags) * Description @@ -2248,7 +2529,7 @@ union bpf_attr { * Look for an IPv6 socket. * * If the *netns* is a negative signed 32-bit integer, then the - * socket lookup table in the netns associated with the *ctx* will + * socket lookup table in the netns associated with the *ctx* * will be used. For the TC hooks, this is the netns of the device * in the skb. For socket hooks, this is the netns of the socket. * If *netns* is any other signed 32-bit value greater than or @@ -2264,9 +2545,10 @@ union bpf_attr { * Return * Pointer to **struct bpf_sock**, or **NULL** in case of failure. * For sockets with reuseport option, the **struct bpf_sock** - * result is from **reuse->socks**\ [] using the hash of the tuple. + * result is from *reuse*\ **->socks**\ [] using the hash of the + * tuple. * - * int bpf_sk_release(struct bpf_sock *sock) + * long bpf_sk_release(void *sock) * Description * Release the reference held by *sock*. *sock* must be a * non-**NULL** pointer that was returned from @@ -2274,19 +2556,29 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_map_pop_elem(struct bpf_map *map, void *value) + * long bpf_map_push_elem(struct bpf_map *map, const void *value, u64 flags) + * Description + * Push an element *value* in *map*. *flags* is one of: + * + * **BPF_EXIST** + * If the queue/stack is full, the oldest element is + * removed to make room for this. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_map_pop_elem(struct bpf_map *map, void *value) * Description * Pop an element from *map*. * Return * 0 on success, or a negative error in case of failure. * - * int bpf_map_peek_elem(struct bpf_map *map, void *value) + * long bpf_map_peek_elem(struct bpf_map *map, void *value) * Description * Get an element from *map* without removing it. * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_push_data(struct sk_buff *skb, u32 start, u32 len, u64 flags) + * long bpf_msg_push_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags) * Description * For socket policies, insert *len* bytes into *msg* at offset * *start*. @@ -2302,9 +2594,9 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 pop, u64 flags) + * long bpf_msg_pop_data(struct sk_msg_buff *msg, u32 start, u32 len, u64 flags) * Description - * Will remove *pop* bytes from a *msg* starting at byte *start*. + * Will remove *len* bytes from a *msg* starting at byte *start*. * This may result in **ENOMEM** errors under certain situations if * an allocation and copy are required due to a full ring buffer. * However, the helper will try to avoid doing the allocation @@ -2314,7 +2606,7 @@ union bpf_attr { * Return * 0 on success, or a negative error in case of failure. * - * int bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y) + * long bpf_rc_pointer_rel(void *ctx, s32 rel_x, s32 rel_y) * Description * This helper is used in programs implementing IR decoding, to * report a successfully decoded pointer movement. @@ -2327,6 +2619,1129 @@ union bpf_attr { * "**y**". * Return * 0 + * + * long bpf_spin_lock(struct bpf_spin_lock *lock) + * Description + * Acquire a spinlock represented by the pointer *lock*, which is + * stored as part of a value of a map. Taking the lock allows to + * safely update the rest of the fields in that value. The + * spinlock can (and must) later be released with a call to + * **bpf_spin_unlock**\ (\ *lock*\ ). + * + * Spinlocks in BPF programs come with a number of restrictions + * and constraints: + * + * * **bpf_spin_lock** objects are only allowed inside maps of + * types **BPF_MAP_TYPE_HASH** and **BPF_MAP_TYPE_ARRAY** (this + * list could be extended in the future). + * * BTF description of the map is mandatory. + * * The BPF program can take ONE lock at a time, since taking two + * or more could cause dead locks. + * * Only one **struct bpf_spin_lock** is allowed per map element. + * * When the lock is taken, calls (either BPF to BPF or helpers) + * are not allowed. + * * The **BPF_LD_ABS** and **BPF_LD_IND** instructions are not + * allowed inside a spinlock-ed region. + * * The BPF program MUST call **bpf_spin_unlock**\ () to release + * the lock, on all execution paths, before it returns. + * * The BPF program can access **struct bpf_spin_lock** only via + * the **bpf_spin_lock**\ () and **bpf_spin_unlock**\ () + * helpers. Loading or storing data into the **struct + * bpf_spin_lock** *lock*\ **;** field of a map is not allowed. + * * To use the **bpf_spin_lock**\ () helper, the BTF description + * of the map value must be a struct and have **struct + * bpf_spin_lock** *anyname*\ **;** field at the top level. + * Nested lock inside another struct is not allowed. + * * The **struct bpf_spin_lock** *lock* field in a map value must + * be aligned on a multiple of 4 bytes in that value. + * * Syscall with command **BPF_MAP_LOOKUP_ELEM** does not copy + * the **bpf_spin_lock** field to user space. + * * Syscall with command **BPF_MAP_UPDATE_ELEM**, or update from + * a BPF program, do not update the **bpf_spin_lock** field. + * * **bpf_spin_lock** cannot be on the stack or inside a + * networking packet (it can only be inside of a map values). + * * **bpf_spin_lock** is available to root only. + * * Tracing programs and socket filter programs cannot use + * **bpf_spin_lock**\ () due to insufficient preemption checks + * (but this may change in the future). + * * **bpf_spin_lock** is not allowed in inner maps of map-in-map. + * Return + * 0 + * + * long bpf_spin_unlock(struct bpf_spin_lock *lock) + * Description + * Release the *lock* previously locked by a call to + * **bpf_spin_lock**\ (\ *lock*\ ). + * Return + * 0 + * + * struct bpf_sock *bpf_sk_fullsock(struct bpf_sock *sk) + * Description + * This helper gets a **struct bpf_sock** pointer such + * that all the fields in this **bpf_sock** can be accessed. + * Return + * A **struct bpf_sock** pointer on success, or **NULL** in + * case of failure. + * + * struct bpf_tcp_sock *bpf_tcp_sock(struct bpf_sock *sk) + * Description + * This helper gets a **struct bpf_tcp_sock** pointer from a + * **struct bpf_sock** pointer. + * Return + * A **struct bpf_tcp_sock** pointer on success, or **NULL** in + * case of failure. + * + * long bpf_skb_ecn_set_ce(struct sk_buff *skb) + * Description + * Set ECN (Explicit Congestion Notification) field of IP header + * to **CE** (Congestion Encountered) if current value is **ECT** + * (ECN Capable Transport). Otherwise, do nothing. Works with IPv6 + * and IPv4. + * Return + * 1 if the **CE** flag is set (either by the current helper call + * or because it was already present), 0 if it is not set. + * + * struct bpf_sock *bpf_get_listener_sock(struct bpf_sock *sk) + * Description + * Return a **struct bpf_sock** pointer in **TCP_LISTEN** state. + * **bpf_sk_release**\ () is unnecessary and not allowed. + * Return + * A **struct bpf_sock** pointer on success, or **NULL** in + * case of failure. + * + * struct bpf_sock *bpf_skc_lookup_tcp(void *ctx, struct bpf_sock_tuple *tuple, u32 tuple_size, u64 netns, u64 flags) + * Description + * Look for TCP socket matching *tuple*, optionally in a child + * network namespace *netns*. The return value must be checked, + * and if non-**NULL**, released via **bpf_sk_release**\ (). + * + * This function is identical to **bpf_sk_lookup_tcp**\ (), except + * that it also returns timewait or request sockets. Use + * **bpf_sk_fullsock**\ () or **bpf_tcp_sock**\ () to access the + * full structure. + * + * This helper is available only if the kernel was compiled with + * **CONFIG_NET** configuration option. + * Return + * Pointer to **struct bpf_sock**, or **NULL** in case of failure. + * For sockets with reuseport option, the **struct bpf_sock** + * result is from *reuse*\ **->socks**\ [] using the hash of the + * tuple. + * + * long bpf_tcp_check_syncookie(void *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len) + * Description + * Check whether *iph* and *th* contain a valid SYN cookie ACK for + * the listening socket in *sk*. + * + * *iph* points to the start of the IPv4 or IPv6 header, while + * *iph_len* contains **sizeof**\ (**struct iphdr**) or + * **sizeof**\ (**struct ip6hdr**). + * + * *th* points to the start of the TCP header, while *th_len* + * contains **sizeof**\ (**struct tcphdr**). + * Return + * 0 if *iph* and *th* are a valid SYN cookie ACK, or a negative + * error otherwise. + * + * long bpf_sysctl_get_name(struct bpf_sysctl *ctx, char *buf, size_t buf_len, u64 flags) + * Description + * Get name of sysctl in /proc/sys/ and copy it into provided by + * program buffer *buf* of size *buf_len*. + * + * The buffer is always NUL terminated, unless it's zero-sized. + * + * If *flags* is zero, full name (e.g. "net/ipv4/tcp_mem") is + * copied. Use **BPF_F_SYSCTL_BASE_NAME** flag to copy base name + * only (e.g. "tcp_mem"). + * Return + * Number of character copied (not including the trailing NUL). + * + * **-E2BIG** if the buffer wasn't big enough (*buf* will contain + * truncated name in this case). + * + * long bpf_sysctl_get_current_value(struct bpf_sysctl *ctx, char *buf, size_t buf_len) + * Description + * Get current value of sysctl as it is presented in /proc/sys + * (incl. newline, etc), and copy it as a string into provided + * by program buffer *buf* of size *buf_len*. + * + * The whole value is copied, no matter what file position user + * space issued e.g. sys_read at. + * + * The buffer is always NUL terminated, unless it's zero-sized. + * Return + * Number of character copied (not including the trailing NUL). + * + * **-E2BIG** if the buffer wasn't big enough (*buf* will contain + * truncated name in this case). + * + * **-EINVAL** if current value was unavailable, e.g. because + * sysctl is uninitialized and read returns -EIO for it. + * + * long bpf_sysctl_get_new_value(struct bpf_sysctl *ctx, char *buf, size_t buf_len) + * Description + * Get new value being written by user space to sysctl (before + * the actual write happens) and copy it as a string into + * provided by program buffer *buf* of size *buf_len*. + * + * User space may write new value at file position > 0. + * + * The buffer is always NUL terminated, unless it's zero-sized. + * Return + * Number of character copied (not including the trailing NUL). + * + * **-E2BIG** if the buffer wasn't big enough (*buf* will contain + * truncated name in this case). + * + * **-EINVAL** if sysctl is being read. + * + * long bpf_sysctl_set_new_value(struct bpf_sysctl *ctx, const char *buf, size_t buf_len) + * Description + * Override new value being written by user space to sysctl with + * value provided by program in buffer *buf* of size *buf_len*. + * + * *buf* should contain a string in same form as provided by user + * space on sysctl write. + * + * User space may write new value at file position > 0. To override + * the whole sysctl value file position should be set to zero. + * Return + * 0 on success. + * + * **-E2BIG** if the *buf_len* is too big. + * + * **-EINVAL** if sysctl is being read. + * + * long bpf_strtol(const char *buf, size_t buf_len, u64 flags, long *res) + * Description + * Convert the initial part of the string from buffer *buf* of + * size *buf_len* to a long integer according to the given base + * and save the result in *res*. + * + * The string may begin with an arbitrary amount of white space + * (as determined by **isspace**\ (3)) followed by a single + * optional '**-**' sign. + * + * Five least significant bits of *flags* encode base, other bits + * are currently unused. + * + * Base must be either 8, 10, 16 or 0 to detect it automatically + * similar to user space **strtol**\ (3). + * Return + * Number of characters consumed on success. Must be positive but + * no more than *buf_len*. + * + * **-EINVAL** if no valid digits were found or unsupported base + * was provided. + * + * **-ERANGE** if resulting value was out of range. + * + * long bpf_strtoul(const char *buf, size_t buf_len, u64 flags, unsigned long *res) + * Description + * Convert the initial part of the string from buffer *buf* of + * size *buf_len* to an unsigned long integer according to the + * given base and save the result in *res*. + * + * The string may begin with an arbitrary amount of white space + * (as determined by **isspace**\ (3)). + * + * Five least significant bits of *flags* encode base, other bits + * are currently unused. + * + * Base must be either 8, 10, 16 or 0 to detect it automatically + * similar to user space **strtoul**\ (3). + * Return + * Number of characters consumed on success. Must be positive but + * no more than *buf_len*. + * + * **-EINVAL** if no valid digits were found or unsupported base + * was provided. + * + * **-ERANGE** if resulting value was out of range. + * + * void *bpf_sk_storage_get(struct bpf_map *map, void *sk, void *value, u64 flags) + * Description + * Get a bpf-local-storage from a *sk*. + * + * Logically, it could be thought of getting the value from + * a *map* with *sk* as the **key**. From this + * perspective, the usage is not much different from + * **bpf_map_lookup_elem**\ (*map*, **&**\ *sk*) except this + * helper enforces the key must be a full socket and the map must + * be a **BPF_MAP_TYPE_SK_STORAGE** also. + * + * Underneath, the value is stored locally at *sk* instead of + * the *map*. The *map* is used as the bpf-local-storage + * "type". The bpf-local-storage "type" (i.e. the *map*) is + * searched against all bpf-local-storages residing at *sk*. + * + * *sk* is a kernel **struct sock** pointer for LSM program. + * *sk* is a **struct bpf_sock** pointer for other program types. + * + * An optional *flags* (**BPF_SK_STORAGE_GET_F_CREATE**) can be + * used such that a new bpf-local-storage will be + * created if one does not exist. *value* can be used + * together with **BPF_SK_STORAGE_GET_F_CREATE** to specify + * the initial value of a bpf-local-storage. If *value* is + * **NULL**, the new bpf-local-storage will be zero initialized. + * Return + * A bpf-local-storage pointer is returned on success. + * + * **NULL** if not found or there was an error in adding + * a new bpf-local-storage. + * + * long bpf_sk_storage_delete(struct bpf_map *map, void *sk) + * Description + * Delete a bpf-local-storage from a *sk*. + * Return + * 0 on success. + * + * **-ENOENT** if the bpf-local-storage cannot be found. + * **-EINVAL** if sk is not a fullsock (e.g. a request_sock). + * + * long bpf_send_signal(u32 sig) + * Description + * Send signal *sig* to the process of the current task. + * The signal may be delivered to any of this process's threads. + * Return + * 0 on success or successfully queued. + * + * **-EBUSY** if work queue under nmi is full. + * + * **-EINVAL** if *sig* is invalid. + * + * **-EPERM** if no permission to send the *sig*. + * + * **-EAGAIN** if bpf program can try again. + * + * s64 bpf_tcp_gen_syncookie(void *sk, void *iph, u32 iph_len, struct tcphdr *th, u32 th_len) + * Description + * Try to issue a SYN cookie for the packet with corresponding + * IP/TCP headers, *iph* and *th*, on the listening socket in *sk*. + * + * *iph* points to the start of the IPv4 or IPv6 header, while + * *iph_len* contains **sizeof**\ (**struct iphdr**) or + * **sizeof**\ (**struct ip6hdr**). + * + * *th* points to the start of the TCP header, while *th_len* + * contains the length of the TCP header. + * Return + * On success, lower 32 bits hold the generated SYN cookie in + * followed by 16 bits which hold the MSS value for that cookie, + * and the top 16 bits are unused. + * + * On failure, the returned value is one of the following: + * + * **-EINVAL** SYN cookie cannot be issued due to error + * + * **-ENOENT** SYN cookie should not be issued (no SYN flood) + * + * **-EOPNOTSUPP** kernel configuration does not enable SYN cookies + * + * **-EPROTONOSUPPORT** IP packet version is not 4 or 6 + * + * long bpf_skb_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) + * Description + * Write raw *data* blob into a special BPF perf event held by + * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf + * event must have the following attributes: **PERF_SAMPLE_RAW** + * as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and + * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. + * + * The *flags* are used to indicate the index in *map* for which + * the value must be put, masked with **BPF_F_INDEX_MASK**. + * Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU** + * to indicate that the index of the current CPU core should be + * used. + * + * The value to write, of *size*, is passed through eBPF stack and + * pointed by *data*. + * + * *ctx* is a pointer to in-kernel struct sk_buff. + * + * This helper is similar to **bpf_perf_event_output**\ () but + * restricted to raw_tracepoint bpf programs. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_probe_read_user(void *dst, u32 size, const void *unsafe_ptr) + * Description + * Safely attempt to read *size* bytes from user space address + * *unsafe_ptr* and store the data in *dst*. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_probe_read_kernel(void *dst, u32 size, const void *unsafe_ptr) + * Description + * Safely attempt to read *size* bytes from kernel space address + * *unsafe_ptr* and store the data in *dst*. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_probe_read_user_str(void *dst, u32 size, const void *unsafe_ptr) + * Description + * Copy a NUL terminated string from an unsafe user address + * *unsafe_ptr* to *dst*. The *size* should include the + * terminating NUL byte. In case the string length is smaller than + * *size*, the target is not padded with further NUL bytes. If the + * string length is larger than *size*, just *size*-1 bytes are + * copied and the last byte is set to NUL. + * + * On success, the length of the copied string is returned. This + * makes this helper useful in tracing programs for reading + * strings, and more importantly to get its length at runtime. See + * the following snippet: + * + * :: + * + * SEC("kprobe/sys_open") + * void bpf_sys_open(struct pt_regs *ctx) + * { + * char buf[PATHLEN]; // PATHLEN is defined to 256 + * int res = bpf_probe_read_user_str(buf, sizeof(buf), + * ctx->di); + * + * // Consume buf, for example push it to + * // userspace via bpf_perf_event_output(); we + * // can use res (the string length) as event + * // size, after checking its boundaries. + * } + * + * In comparison, using **bpf_probe_read_user**\ () helper here + * instead to read the string would require to estimate the length + * at compile time, and would often result in copying more memory + * than necessary. + * + * Another useful use case is when parsing individual process + * arguments or individual environment variables navigating + * *current*\ **->mm->arg_start** and *current*\ + * **->mm->env_start**: using this helper and the return value, + * one can quickly iterate at the right offset of the memory area. + * Return + * On success, the strictly positive length of the string, + * including the trailing NUL character. On error, a negative + * value. + * + * long bpf_probe_read_kernel_str(void *dst, u32 size, const void *unsafe_ptr) + * Description + * Copy a NUL terminated string from an unsafe kernel address *unsafe_ptr* + * to *dst*. Same semantics as with **bpf_probe_read_user_str**\ () apply. + * Return + * On success, the strictly positive length of the string, including + * the trailing NUL character. On error, a negative value. + * + * long bpf_tcp_send_ack(void *tp, u32 rcv_nxt) + * Description + * Send out a tcp-ack. *tp* is the in-kernel struct **tcp_sock**. + * *rcv_nxt* is the ack_seq to be sent out. + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_send_signal_thread(u32 sig) + * Description + * Send signal *sig* to the thread corresponding to the current task. + * Return + * 0 on success or successfully queued. + * + * **-EBUSY** if work queue under nmi is full. + * + * **-EINVAL** if *sig* is invalid. + * + * **-EPERM** if no permission to send the *sig*. + * + * **-EAGAIN** if bpf program can try again. + * + * u64 bpf_jiffies64(void) + * Description + * Obtain the 64bit jiffies + * Return + * The 64 bit jiffies + * + * long bpf_read_branch_records(struct bpf_perf_event_data *ctx, void *buf, u32 size, u64 flags) + * Description + * For an eBPF program attached to a perf event, retrieve the + * branch records (**struct perf_branch_entry**) associated to *ctx* + * and store it in the buffer pointed by *buf* up to size + * *size* bytes. + * Return + * On success, number of bytes written to *buf*. On error, a + * negative value. + * + * The *flags* can be set to **BPF_F_GET_BRANCH_RECORDS_SIZE** to + * instead return the number of bytes required to store all the + * branch entries. If this flag is set, *buf* may be NULL. + * + * **-EINVAL** if arguments invalid or **size** not a multiple + * of **sizeof**\ (**struct perf_branch_entry**\ ). + * + * **-ENOENT** if architecture does not support branch records. + * + * long bpf_get_ns_current_pid_tgid(u64 dev, u64 ino, struct bpf_pidns_info *nsdata, u32 size) + * Description + * Returns 0 on success, values for *pid* and *tgid* as seen from the current + * *namespace* will be returned in *nsdata*. + * Return + * 0 on success, or one of the following in case of failure: + * + * **-EINVAL** if dev and inum supplied don't match dev_t and inode number + * with nsfs of current task, or if dev conversion to dev_t lost high bits. + * + * **-ENOENT** if pidns does not exists for the current task. + * + * long bpf_xdp_output(void *ctx, struct bpf_map *map, u64 flags, void *data, u64 size) + * Description + * Write raw *data* blob into a special BPF perf event held by + * *map* of type **BPF_MAP_TYPE_PERF_EVENT_ARRAY**. This perf + * event must have the following attributes: **PERF_SAMPLE_RAW** + * as **sample_type**, **PERF_TYPE_SOFTWARE** as **type**, and + * **PERF_COUNT_SW_BPF_OUTPUT** as **config**. + * + * The *flags* are used to indicate the index in *map* for which + * the value must be put, masked with **BPF_F_INDEX_MASK**. + * Alternatively, *flags* can be set to **BPF_F_CURRENT_CPU** + * to indicate that the index of the current CPU core should be + * used. + * + * The value to write, of *size*, is passed through eBPF stack and + * pointed by *data*. + * + * *ctx* is a pointer to in-kernel struct xdp_buff. + * + * This helper is similar to **bpf_perf_eventoutput**\ () but + * restricted to raw_tracepoint bpf programs. + * Return + * 0 on success, or a negative error in case of failure. + * + * u64 bpf_get_netns_cookie(void *ctx) + * Description + * Retrieve the cookie (generated by the kernel) of the network + * namespace the input *ctx* is associated with. The network + * namespace cookie remains stable for its lifetime and provides + * a global identifier that can be assumed unique. If *ctx* is + * NULL, then the helper returns the cookie for the initial + * network namespace. The cookie itself is very similar to that + * of **bpf_get_socket_cookie**\ () helper, but for network + * namespaces instead of sockets. + * Return + * A 8-byte long opaque number. + * + * u64 bpf_get_current_ancestor_cgroup_id(int ancestor_level) + * Description + * Return id of cgroup v2 that is ancestor of the cgroup associated + * with the current task at the *ancestor_level*. The root cgroup + * is at *ancestor_level* zero and each step down the hierarchy + * increments the level. If *ancestor_level* == level of cgroup + * associated with the current task, then return value will be the + * same as that of **bpf_get_current_cgroup_id**\ (). + * + * The helper is useful to implement policies based on cgroups + * that are upper in hierarchy than immediate cgroup associated + * with the current task. + * + * The format of returned id and helper limitations are same as in + * **bpf_get_current_cgroup_id**\ (). + * Return + * The id is returned or 0 in case the id could not be retrieved. + * + * long bpf_sk_assign(struct sk_buff *skb, void *sk, u64 flags) + * Description + * Helper is overloaded depending on BPF program type. This + * description applies to **BPF_PROG_TYPE_SCHED_CLS** and + * **BPF_PROG_TYPE_SCHED_ACT** programs. + * + * Assign the *sk* to the *skb*. When combined with appropriate + * routing configuration to receive the packet towards the socket, + * will cause *skb* to be delivered to the specified socket. + * Subsequent redirection of *skb* via **bpf_redirect**\ (), + * **bpf_clone_redirect**\ () or other methods outside of BPF may + * interfere with successful delivery to the socket. + * + * This operation is only valid from TC ingress path. + * + * The *flags* argument must be zero. + * Return + * 0 on success, or a negative error in case of failure: + * + * **-EINVAL** if specified *flags* are not supported. + * + * **-ENOENT** if the socket is unavailable for assignment. + * + * **-ENETUNREACH** if the socket is unreachable (wrong netns). + * + * **-EOPNOTSUPP** if the operation is not supported, for example + * a call from outside of TC ingress. + * + * **-ESOCKTNOSUPPORT** if the socket type is not supported + * (reuseport). + * + * long bpf_sk_assign(struct bpf_sk_lookup *ctx, struct bpf_sock *sk, u64 flags) + * Description + * Helper is overloaded depending on BPF program type. This + * description applies to **BPF_PROG_TYPE_SK_LOOKUP** programs. + * + * Select the *sk* as a result of a socket lookup. + * + * For the operation to succeed passed socket must be compatible + * with the packet description provided by the *ctx* object. + * + * L4 protocol (**IPPROTO_TCP** or **IPPROTO_UDP**) must + * be an exact match. While IP family (**AF_INET** or + * **AF_INET6**) must be compatible, that is IPv6 sockets + * that are not v6-only can be selected for IPv4 packets. + * + * Only TCP listeners and UDP unconnected sockets can be + * selected. *sk* can also be NULL to reset any previous + * selection. + * + * *flags* argument can combination of following values: + * + * * **BPF_SK_LOOKUP_F_REPLACE** to override the previous + * socket selection, potentially done by a BPF program + * that ran before us. + * + * * **BPF_SK_LOOKUP_F_NO_REUSEPORT** to skip + * load-balancing within reuseport group for the socket + * being selected. + * + * On success *ctx->sk* will point to the selected socket. + * + * Return + * 0 on success, or a negative errno in case of failure. + * + * * **-EAFNOSUPPORT** if socket family (*sk->family*) is + * not compatible with packet family (*ctx->family*). + * + * * **-EEXIST** if socket has been already selected, + * potentially by another program, and + * **BPF_SK_LOOKUP_F_REPLACE** flag was not specified. + * + * * **-EINVAL** if unsupported flags were specified. + * + * * **-EPROTOTYPE** if socket L4 protocol + * (*sk->protocol*) doesn't match packet protocol + * (*ctx->protocol*). + * + * * **-ESOCKTNOSUPPORT** if socket is not in allowed + * state (TCP listening or UDP unconnected). + * + * u64 bpf_ktime_get_boot_ns(void) + * Description + * Return the time elapsed since system boot, in nanoseconds. + * Does include the time the system was suspended. + * See: **clock_gettime**\ (**CLOCK_BOOTTIME**) + * Return + * Current *ktime*. + * + * long bpf_seq_printf(struct seq_file *m, const char *fmt, u32 fmt_size, const void *data, u32 data_len) + * Description + * **bpf_seq_printf**\ () uses seq_file **seq_printf**\ () to print + * out the format string. + * The *m* represents the seq_file. The *fmt* and *fmt_size* are for + * the format string itself. The *data* and *data_len* are format string + * arguments. The *data* are a **u64** array and corresponding format string + * values are stored in the array. For strings and pointers where pointees + * are accessed, only the pointer values are stored in the *data* array. + * The *data_len* is the size of *data* in bytes. + * + * Formats **%s**, **%p{i,I}{4,6}** requires to read kernel memory. + * Reading kernel memory may fail due to either invalid address or + * valid address but requiring a major memory fault. If reading kernel memory + * fails, the string for **%s** will be an empty string, and the ip + * address for **%p{i,I}{4,6}** will be 0. Not returning error to + * bpf program is consistent with what **bpf_trace_printk**\ () does for now. + * Return + * 0 on success, or a negative error in case of failure: + * + * **-EBUSY** if per-CPU memory copy buffer is busy, can try again + * by returning 1 from bpf program. + * + * **-EINVAL** if arguments are invalid, or if *fmt* is invalid/unsupported. + * + * **-E2BIG** if *fmt* contains too many format specifiers. + * + * **-EOVERFLOW** if an overflow happened: The same object will be tried again. + * + * long bpf_seq_write(struct seq_file *m, const void *data, u32 len) + * Description + * **bpf_seq_write**\ () uses seq_file **seq_write**\ () to write the data. + * The *m* represents the seq_file. The *data* and *len* represent the + * data to write in bytes. + * Return + * 0 on success, or a negative error in case of failure: + * + * **-EOVERFLOW** if an overflow happened: The same object will be tried again. + * + * u64 bpf_sk_cgroup_id(void *sk) + * Description + * Return the cgroup v2 id of the socket *sk*. + * + * *sk* must be a non-**NULL** pointer to a socket, e.g. one + * returned from **bpf_sk_lookup_xxx**\ (), + * **bpf_sk_fullsock**\ (), etc. The format of returned id is + * same as in **bpf_skb_cgroup_id**\ (). + * + * This helper is available only if the kernel was compiled with + * the **CONFIG_SOCK_CGROUP_DATA** configuration option. + * Return + * The id is returned or 0 in case the id could not be retrieved. + * + * u64 bpf_sk_ancestor_cgroup_id(void *sk, int ancestor_level) + * Description + * Return id of cgroup v2 that is ancestor of cgroup associated + * with the *sk* at the *ancestor_level*. The root cgroup is at + * *ancestor_level* zero and each step down the hierarchy + * increments the level. If *ancestor_level* == level of cgroup + * associated with *sk*, then return value will be same as that + * of **bpf_sk_cgroup_id**\ (). + * + * The helper is useful to implement policies based on cgroups + * that are upper in hierarchy than immediate cgroup associated + * with *sk*. + * + * The format of returned id and helper limitations are same as in + * **bpf_sk_cgroup_id**\ (). + * Return + * The id is returned or 0 in case the id could not be retrieved. + * + * long bpf_ringbuf_output(void *ringbuf, void *data, u64 size, u64 flags) + * Description + * Copy *size* bytes from *data* into a ring buffer *ringbuf*. + * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification + * of new data availability is sent. + * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification + * of new data availability is sent unconditionally. + * Return + * 0 on success, or a negative error in case of failure. + * + * void *bpf_ringbuf_reserve(void *ringbuf, u64 size, u64 flags) + * Description + * Reserve *size* bytes of payload in a ring buffer *ringbuf*. + * Return + * Valid pointer with *size* bytes of memory available; NULL, + * otherwise. + * + * void bpf_ringbuf_submit(void *data, u64 flags) + * Description + * Submit reserved ring buffer sample, pointed to by *data*. + * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification + * of new data availability is sent. + * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification + * of new data availability is sent unconditionally. + * Return + * Nothing. Always succeeds. + * + * void bpf_ringbuf_discard(void *data, u64 flags) + * Description + * Discard reserved ring buffer sample, pointed to by *data*. + * If **BPF_RB_NO_WAKEUP** is specified in *flags*, no notification + * of new data availability is sent. + * If **BPF_RB_FORCE_WAKEUP** is specified in *flags*, notification + * of new data availability is sent unconditionally. + * Return + * Nothing. Always succeeds. + * + * u64 bpf_ringbuf_query(void *ringbuf, u64 flags) + * Description + * Query various characteristics of provided ring buffer. What + * exactly is queries is determined by *flags*: + * + * * **BPF_RB_AVAIL_DATA**: Amount of data not yet consumed. + * * **BPF_RB_RING_SIZE**: The size of ring buffer. + * * **BPF_RB_CONS_POS**: Consumer position (can wrap around). + * * **BPF_RB_PROD_POS**: Producer(s) position (can wrap around). + * + * Data returned is just a momentary snapshot of actual values + * and could be inaccurate, so this facility should be used to + * power heuristics and for reporting, not to make 100% correct + * calculation. + * Return + * Requested value, or 0, if *flags* are not recognized. + * + * long bpf_csum_level(struct sk_buff *skb, u64 level) + * Description + * Change the skbs checksum level by one layer up or down, or + * reset it entirely to none in order to have the stack perform + * checksum validation. The level is applicable to the following + * protocols: TCP, UDP, GRE, SCTP, FCOE. For example, a decap of + * | ETH | IP | UDP | GUE | IP | TCP | into | ETH | IP | TCP | + * through **bpf_skb_adjust_room**\ () helper with passing in + * **BPF_F_ADJ_ROOM_NO_CSUM_RESET** flag would require one call + * to **bpf_csum_level**\ () with **BPF_CSUM_LEVEL_DEC** since + * the UDP header is removed. Similarly, an encap of the latter + * into the former could be accompanied by a helper call to + * **bpf_csum_level**\ () with **BPF_CSUM_LEVEL_INC** if the + * skb is still intended to be processed in higher layers of the + * stack instead of just egressing at tc. + * + * There are three supported level settings at this time: + * + * * **BPF_CSUM_LEVEL_INC**: Increases skb->csum_level for skbs + * with CHECKSUM_UNNECESSARY. + * * **BPF_CSUM_LEVEL_DEC**: Decreases skb->csum_level for skbs + * with CHECKSUM_UNNECESSARY. + * * **BPF_CSUM_LEVEL_RESET**: Resets skb->csum_level to 0 and + * sets CHECKSUM_NONE to force checksum validation by the stack. + * * **BPF_CSUM_LEVEL_QUERY**: No-op, returns the current + * skb->csum_level. + * Return + * 0 on success, or a negative error in case of failure. In the + * case of **BPF_CSUM_LEVEL_QUERY**, the current skb->csum_level + * is returned or the error code -EACCES in case the skb is not + * subject to CHECKSUM_UNNECESSARY. + * + * struct tcp6_sock *bpf_skc_to_tcp6_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *tcp6_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. + * + * struct tcp_sock *bpf_skc_to_tcp_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *tcp_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. + * + * struct tcp_timewait_sock *bpf_skc_to_tcp_timewait_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *tcp_timewait_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. + * + * struct tcp_request_sock *bpf_skc_to_tcp_request_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *tcp_request_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. + * + * struct udp6_sock *bpf_skc_to_udp6_sock(void *sk) + * Description + * Dynamically cast a *sk* pointer to a *udp6_sock* pointer. + * Return + * *sk* if casting is valid, or **NULL** otherwise. + * + * long bpf_get_task_stack(struct task_struct *task, void *buf, u32 size, u64 flags) + * Description + * Return a user or a kernel stack in bpf program provided buffer. + * To achieve this, the helper needs *task*, which is a valid + * pointer to **struct task_struct**. To store the stacktrace, the + * bpf program provides *buf* with a nonnegative *size*. + * + * The last argument, *flags*, holds the number of stack frames to + * skip (from 0 to 255), masked with + * **BPF_F_SKIP_FIELD_MASK**. The next bits can be used to set + * the following flags: + * + * **BPF_F_USER_STACK** + * Collect a user space stack instead of a kernel stack. + * **BPF_F_USER_BUILD_ID** + * Collect buildid+offset instead of ips for user stack, + * only valid if **BPF_F_USER_STACK** is also specified. + * + * **bpf_get_task_stack**\ () can collect up to + * **PERF_MAX_STACK_DEPTH** both kernel and user frames, subject + * to sufficient large buffer size. Note that + * this limit can be controlled with the **sysctl** program, and + * that it should be manually increased in order to profile long + * user stacks (such as stacks for Java programs). To do so, use: + * + * :: + * + * # sysctl kernel.perf_event_max_stack= + * Return + * A non-negative value equal to or less than *size* on success, + * or a negative error in case of failure. + * + * long bpf_load_hdr_opt(struct bpf_sock_ops *skops, void *searchby_res, u32 len, u64 flags) + * Description + * Load header option. Support reading a particular TCP header + * option for bpf program (**BPF_PROG_TYPE_SOCK_OPS**). + * + * If *flags* is 0, it will search the option from the + * *skops*\ **->skb_data**. The comment in **struct bpf_sock_ops** + * has details on what skb_data contains under different + * *skops*\ **->op**. + * + * The first byte of the *searchby_res* specifies the + * kind that it wants to search. + * + * If the searching kind is an experimental kind + * (i.e. 253 or 254 according to RFC6994). It also + * needs to specify the "magic" which is either + * 2 bytes or 4 bytes. It then also needs to + * specify the size of the magic by using + * the 2nd byte which is "kind-length" of a TCP + * header option and the "kind-length" also + * includes the first 2 bytes "kind" and "kind-length" + * itself as a normal TCP header option also does. + * + * For example, to search experimental kind 254 with + * 2 byte magic 0xeB9F, the searchby_res should be + * [ 254, 4, 0xeB, 0x9F, 0, 0, .... 0 ]. + * + * To search for the standard window scale option (3), + * the *searchby_res* should be [ 3, 0, 0, .... 0 ]. + * Note, kind-length must be 0 for regular option. + * + * Searching for No-Op (0) and End-of-Option-List (1) are + * not supported. + * + * *len* must be at least 2 bytes which is the minimal size + * of a header option. + * + * Supported flags: + * + * * **BPF_LOAD_HDR_OPT_TCP_SYN** to search from the + * saved_syn packet or the just-received syn packet. + * + * Return + * > 0 when found, the header option is copied to *searchby_res*. + * The return value is the total length copied. On failure, a + * negative error code is returned: + * + * **-EINVAL** if a parameter is invalid. + * + * **-ENOMSG** if the option is not found. + * + * **-ENOENT** if no syn packet is available when + * **BPF_LOAD_HDR_OPT_TCP_SYN** is used. + * + * **-ENOSPC** if there is not enough space. Only *len* number of + * bytes are copied. + * + * **-EFAULT** on failure to parse the header options in the + * packet. + * + * **-EPERM** if the helper cannot be used under the current + * *skops*\ **->op**. + * + * long bpf_store_hdr_opt(struct bpf_sock_ops *skops, const void *from, u32 len, u64 flags) + * Description + * Store header option. The data will be copied + * from buffer *from* with length *len* to the TCP header. + * + * The buffer *from* should have the whole option that + * includes the kind, kind-length, and the actual + * option data. The *len* must be at least kind-length + * long. The kind-length does not have to be 4 byte + * aligned. The kernel will take care of the padding + * and setting the 4 bytes aligned value to th->doff. + * + * This helper will check for duplicated option + * by searching the same option in the outgoing skb. + * + * This helper can only be called during + * **BPF_SOCK_OPS_WRITE_HDR_OPT_CB**. + * + * Return + * 0 on success, or negative error in case of failure: + * + * **-EINVAL** If param is invalid. + * + * **-ENOSPC** if there is not enough space in the header. + * Nothing has been written + * + * **-EEXIST** if the option already exists. + * + * **-EFAULT** on failrue to parse the existing header options. + * + * **-EPERM** if the helper cannot be used under the current + * *skops*\ **->op**. + * + * long bpf_reserve_hdr_opt(struct bpf_sock_ops *skops, u32 len, u64 flags) + * Description + * Reserve *len* bytes for the bpf header option. The + * space will be used by **bpf_store_hdr_opt**\ () later in + * **BPF_SOCK_OPS_WRITE_HDR_OPT_CB**. + * + * If **bpf_reserve_hdr_opt**\ () is called multiple times, + * the total number of bytes will be reserved. + * + * This helper can only be called during + * **BPF_SOCK_OPS_HDR_OPT_LEN_CB**. + * + * Return + * 0 on success, or negative error in case of failure: + * + * **-EINVAL** if a parameter is invalid. + * + * **-ENOSPC** if there is not enough space in the header. + * + * **-EPERM** if the helper cannot be used under the current + * *skops*\ **->op**. + * + * void *bpf_inode_storage_get(struct bpf_map *map, void *inode, void *value, u64 flags) + * Description + * Get a bpf_local_storage from an *inode*. + * + * Logically, it could be thought of as getting the value from + * a *map* with *inode* as the **key**. From this + * perspective, the usage is not much different from + * **bpf_map_lookup_elem**\ (*map*, **&**\ *inode*) except this + * helper enforces the key must be an inode and the map must also + * be a **BPF_MAP_TYPE_INODE_STORAGE**. + * + * Underneath, the value is stored locally at *inode* instead of + * the *map*. The *map* is used as the bpf-local-storage + * "type". The bpf-local-storage "type" (i.e. the *map*) is + * searched against all bpf_local_storage residing at *inode*. + * + * An optional *flags* (**BPF_LOCAL_STORAGE_GET_F_CREATE**) can be + * used such that a new bpf_local_storage will be + * created if one does not exist. *value* can be used + * together with **BPF_LOCAL_STORAGE_GET_F_CREATE** to specify + * the initial value of a bpf_local_storage. If *value* is + * **NULL**, the new bpf_local_storage will be zero initialized. + * Return + * A bpf_local_storage pointer is returned on success. + * + * **NULL** if not found or there was an error in adding + * a new bpf_local_storage. + * + * int bpf_inode_storage_delete(struct bpf_map *map, void *inode) + * Description + * Delete a bpf_local_storage from an *inode*. + * Return + * 0 on success. + * + * **-ENOENT** if the bpf_local_storage cannot be found. + * + * long bpf_d_path(struct path *path, char *buf, u32 sz) + * Description + * Return full path for given **struct path** object, which + * needs to be the kernel BTF *path* object. The path is + * returned in the provided buffer *buf* of size *sz* and + * is zero terminated. + * + * Return + * On success, the strictly positive length of the string, + * including the trailing NUL character. On error, a negative + * value. + * + * long bpf_copy_from_user(void *dst, u32 size, const void *user_ptr) + * Description + * Read *size* bytes from user space address *user_ptr* and store + * the data in *dst*. This is a wrapper of **copy_from_user**\ (). + * Return + * 0 on success, or a negative error in case of failure. + * + * long bpf_snprintf_btf(char *str, u32 str_size, struct btf_ptr *ptr, u32 btf_ptr_size, u64 flags) + * Description + * Use BTF to store a string representation of *ptr*->ptr in *str*, + * using *ptr*->type_id. This value should specify the type + * that *ptr*->ptr points to. LLVM __builtin_btf_type_id(type, 1) + * can be used to look up vmlinux BTF type ids. Traversing the + * data structure using BTF, the type information and values are + * stored in the first *str_size* - 1 bytes of *str*. Safe copy of + * the pointer data is carried out to avoid kernel crashes during + * operation. Smaller types can use string space on the stack; + * larger programs can use map data to store the string + * representation. + * + * The string can be subsequently shared with userspace via + * bpf_perf_event_output() or ring buffer interfaces. + * bpf_trace_printk() is to be avoided as it places too small + * a limit on string size to be useful. + * + * *flags* is a combination of + * + * **BTF_F_COMPACT** + * no formatting around type information + * **BTF_F_NONAME** + * no struct/union member names/types + * **BTF_F_PTR_RAW** + * show raw (unobfuscated) pointer values; + * equivalent to printk specifier %px. + * **BTF_F_ZERO** + * show zero-valued struct/union members; they + * are not displayed by default + * + * Return + * The number of bytes that were written (or would have been + * written if output had to be truncated due to string size), + * or a negative error in cases of failure. + * + * long bpf_seq_printf_btf(struct seq_file *m, struct btf_ptr *ptr, u32 ptr_size, u64 flags) + * Description + * Use BTF to write to seq_write a string representation of + * *ptr*->ptr, using *ptr*->type_id as per bpf_snprintf_btf(). + * *flags* are identical to those used for bpf_snprintf_btf. + * Return + * 0 on success or a negative error in case of failure. + * + * u64 bpf_skb_cgroup_classid(struct sk_buff *skb) + * Description + * See **bpf_get_cgroup_classid**\ () for the main description. + * This helper differs from **bpf_get_cgroup_classid**\ () in that + * the cgroup v1 net_cls class is retrieved only from the *skb*'s + * associated socket instead of the current process. + * Return + * The id is returned or 0 in case the id could not be retrieved. + * + * long bpf_redirect_neigh(u32 ifindex, struct bpf_redir_neigh *params, int plen, u64 flags) + * Description + * Redirect the packet to another net device of index *ifindex* + * and fill in L2 addresses from neighboring subsystem. This helper + * is somewhat similar to **bpf_redirect**\ (), except that it + * populates L2 addresses as well, meaning, internally, the helper + * relies on the neighbor lookup for the L2 address of the nexthop. + * + * The helper will perform a FIB lookup based on the skb's + * networking header to get the address of the next hop, unless + * this is supplied by the caller in the *params* argument. The + * *plen* argument indicates the len of *params* and should be set + * to 0 if *params* is NULL. + * + * The *flags* argument is reserved and must be 0. The helper is + * currently only supported for tc BPF program types, and enabled + * for IPv4 and IPv6 protocols. + * Return + * The helper returns **TC_ACT_REDIRECT** on success or + * **TC_ACT_SHOT** on error. + * + * void *bpf_per_cpu_ptr(const void *percpu_ptr, u32 cpu) + * Description + * Take a pointer to a percpu ksym, *percpu_ptr*, and return a + * pointer to the percpu kernel variable on *cpu*. A ksym is an + * extern variable decorated with '__ksym'. For ksym, there is a + * global var (either static or global) defined of the same name + * in the kernel. The ksym is percpu if the global var is percpu. + * The returned pointer points to the global percpu var on *cpu*. + * + * bpf_per_cpu_ptr() has the same semantic as per_cpu_ptr() in the + * kernel, except that bpf_per_cpu_ptr() may return NULL. This + * happens if *cpu* is larger than nr_cpu_ids. The caller of + * bpf_per_cpu_ptr() must check the returned value. + * Return + * A pointer pointing to the kernel percpu variable on *cpu*, or + * NULL, if *cpu* is invalid. + * + * void *bpf_this_cpu_ptr(const void *percpu_ptr) + * Description + * Take a pointer to a percpu ksym, *percpu_ptr*, and return a + * pointer to the percpu kernel variable on this cpu. See the + * description of 'ksym' in **bpf_per_cpu_ptr**\ (). + * + * bpf_this_cpu_ptr() has the same semantic as this_cpu_ptr() in + * the kernel. Different from **bpf_per_cpu_ptr**\ (), it would + * never return NULL. + * Return + * A pointer pointing to the kernel percpu variable on this cpu. + * + * long bpf_redirect_peer(u32 ifindex, u64 flags) + * Description + * Redirect the packet to another net device of index *ifindex*. + * This helper is somewhat similar to **bpf_redirect**\ (), except + * that the redirection happens to the *ifindex*' peer device and + * the netns switch takes place from ingress to ingress without + * going through the CPU's backlog queue. + * + * The *flags* argument is reserved and must be 0. The helper is + * currently only supported for tc BPF program types at the ingress + * hook and for veth device types. The peer device must reside in a + * different network namespace. + * Return + * The helper returns **TC_ACT_REDIRECT** on success or + * **TC_ACT_SHOT** on error. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -2421,7 +3836,71 @@ union bpf_attr { FN(map_peek_elem), \ FN(msg_push_data), \ FN(msg_pop_data), \ - FN(rc_pointer_rel), + FN(rc_pointer_rel), \ + FN(spin_lock), \ + FN(spin_unlock), \ + FN(sk_fullsock), \ + FN(tcp_sock), \ + FN(skb_ecn_set_ce), \ + FN(get_listener_sock), \ + FN(skc_lookup_tcp), \ + FN(tcp_check_syncookie), \ + FN(sysctl_get_name), \ + FN(sysctl_get_current_value), \ + FN(sysctl_get_new_value), \ + FN(sysctl_set_new_value), \ + FN(strtol), \ + FN(strtoul), \ + FN(sk_storage_get), \ + FN(sk_storage_delete), \ + FN(send_signal), \ + FN(tcp_gen_syncookie), \ + FN(skb_output), \ + FN(probe_read_user), \ + FN(probe_read_kernel), \ + FN(probe_read_user_str), \ + FN(probe_read_kernel_str), \ + FN(tcp_send_ack), \ + FN(send_signal_thread), \ + FN(jiffies64), \ + FN(read_branch_records), \ + FN(get_ns_current_pid_tgid), \ + FN(xdp_output), \ + FN(get_netns_cookie), \ + FN(get_current_ancestor_cgroup_id), \ + FN(sk_assign), \ + FN(ktime_get_boot_ns), \ + FN(seq_printf), \ + FN(seq_write), \ + FN(sk_cgroup_id), \ + FN(sk_ancestor_cgroup_id), \ + FN(ringbuf_output), \ + FN(ringbuf_reserve), \ + FN(ringbuf_submit), \ + FN(ringbuf_discard), \ + FN(ringbuf_query), \ + FN(csum_level), \ + FN(skc_to_tcp6_sock), \ + FN(skc_to_tcp_sock), \ + FN(skc_to_tcp_timewait_sock), \ + FN(skc_to_tcp_request_sock), \ + FN(skc_to_udp6_sock), \ + FN(get_task_stack), \ + FN(load_hdr_opt), \ + FN(store_hdr_opt), \ + FN(reserve_hdr_opt), \ + FN(inode_storage_get), \ + FN(inode_storage_delete), \ + FN(d_path), \ + FN(copy_from_user), \ + FN(snprintf_btf), \ + FN(seq_printf_btf), \ + FN(skb_cgroup_classid), \ + FN(redirect_neigh), \ + FN(bpf_per_cpu_ptr), \ + FN(bpf_this_cpu_ptr), \ + FN(redirect_peer), \ + /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call @@ -2436,53 +3915,147 @@ enum bpf_func_id { /* All flags used by eBPF helper functions, placed here. */ /* BPF_FUNC_skb_store_bytes flags. */ -#define BPF_F_RECOMPUTE_CSUM (1ULL << 0) -#define BPF_F_INVALIDATE_HASH (1ULL << 1) +enum { + BPF_F_RECOMPUTE_CSUM = (1ULL << 0), + BPF_F_INVALIDATE_HASH = (1ULL << 1), +}; /* BPF_FUNC_l3_csum_replace and BPF_FUNC_l4_csum_replace flags. * First 4 bits are for passing the header field size. */ -#define BPF_F_HDR_FIELD_MASK 0xfULL +enum { + BPF_F_HDR_FIELD_MASK = 0xfULL, +}; /* BPF_FUNC_l4_csum_replace flags. */ -#define BPF_F_PSEUDO_HDR (1ULL << 4) -#define BPF_F_MARK_MANGLED_0 (1ULL << 5) -#define BPF_F_MARK_ENFORCE (1ULL << 6) +enum { + BPF_F_PSEUDO_HDR = (1ULL << 4), + BPF_F_MARK_MANGLED_0 = (1ULL << 5), + BPF_F_MARK_ENFORCE = (1ULL << 6), +}; /* BPF_FUNC_clone_redirect and BPF_FUNC_redirect flags. */ -#define BPF_F_INGRESS (1ULL << 0) +enum { + BPF_F_INGRESS = (1ULL << 0), +}; /* BPF_FUNC_skb_set_tunnel_key and BPF_FUNC_skb_get_tunnel_key flags. */ -#define BPF_F_TUNINFO_IPV6 (1ULL << 0) +enum { + BPF_F_TUNINFO_IPV6 = (1ULL << 0), +}; /* flags for both BPF_FUNC_get_stackid and BPF_FUNC_get_stack. */ -#define BPF_F_SKIP_FIELD_MASK 0xffULL -#define BPF_F_USER_STACK (1ULL << 8) +enum { + BPF_F_SKIP_FIELD_MASK = 0xffULL, + BPF_F_USER_STACK = (1ULL << 8), /* flags used by BPF_FUNC_get_stackid only. */ -#define BPF_F_FAST_STACK_CMP (1ULL << 9) -#define BPF_F_REUSE_STACKID (1ULL << 10) + BPF_F_FAST_STACK_CMP = (1ULL << 9), + BPF_F_REUSE_STACKID = (1ULL << 10), /* flags used by BPF_FUNC_get_stack only. */ -#define BPF_F_USER_BUILD_ID (1ULL << 11) + BPF_F_USER_BUILD_ID = (1ULL << 11), +}; /* BPF_FUNC_skb_set_tunnel_key flags. */ -#define BPF_F_ZERO_CSUM_TX (1ULL << 1) -#define BPF_F_DONT_FRAGMENT (1ULL << 2) -#define BPF_F_SEQ_NUMBER (1ULL << 3) +enum { + BPF_F_ZERO_CSUM_TX = (1ULL << 1), + BPF_F_DONT_FRAGMENT = (1ULL << 2), + BPF_F_SEQ_NUMBER = (1ULL << 3), +}; /* BPF_FUNC_perf_event_output, BPF_FUNC_perf_event_read and * BPF_FUNC_perf_event_read_value flags. */ -#define BPF_F_INDEX_MASK 0xffffffffULL -#define BPF_F_CURRENT_CPU BPF_F_INDEX_MASK +enum { + BPF_F_INDEX_MASK = 0xffffffffULL, + BPF_F_CURRENT_CPU = BPF_F_INDEX_MASK, /* BPF_FUNC_perf_event_output for sk_buff input context. */ -#define BPF_F_CTXLEN_MASK (0xfffffULL << 32) + BPF_F_CTXLEN_MASK = (0xfffffULL << 32), +}; /* Current network namespace */ -#define BPF_F_CURRENT_NETNS (-1L) +enum { + BPF_F_CURRENT_NETNS = (-1L), +}; + +/* BPF_FUNC_csum_level level values. */ +enum { + BPF_CSUM_LEVEL_QUERY, + BPF_CSUM_LEVEL_INC, + BPF_CSUM_LEVEL_DEC, + BPF_CSUM_LEVEL_RESET, +}; + +/* BPF_FUNC_skb_adjust_room flags. */ +enum { + BPF_F_ADJ_ROOM_FIXED_GSO = (1ULL << 0), + BPF_F_ADJ_ROOM_ENCAP_L3_IPV4 = (1ULL << 1), + BPF_F_ADJ_ROOM_ENCAP_L3_IPV6 = (1ULL << 2), + BPF_F_ADJ_ROOM_ENCAP_L4_GRE = (1ULL << 3), + BPF_F_ADJ_ROOM_ENCAP_L4_UDP = (1ULL << 4), + BPF_F_ADJ_ROOM_NO_CSUM_RESET = (1ULL << 5), +}; + +enum { + BPF_ADJ_ROOM_ENCAP_L2_MASK = 0xff, + BPF_ADJ_ROOM_ENCAP_L2_SHIFT = 56, +}; + +#define BPF_F_ADJ_ROOM_ENCAP_L2(len) (((__u64)len & \ + BPF_ADJ_ROOM_ENCAP_L2_MASK) \ + << BPF_ADJ_ROOM_ENCAP_L2_SHIFT) + +/* BPF_FUNC_sysctl_get_name flags. */ +enum { + BPF_F_SYSCTL_BASE_NAME = (1ULL << 0), +}; + +/* BPF_FUNC__storage_get flags */ +enum { + BPF_LOCAL_STORAGE_GET_F_CREATE = (1ULL << 0), + /* BPF_SK_STORAGE_GET_F_CREATE is only kept for backward compatibility + * and BPF_LOCAL_STORAGE_GET_F_CREATE must be used instead. + */ + BPF_SK_STORAGE_GET_F_CREATE = BPF_LOCAL_STORAGE_GET_F_CREATE, +}; + +/* BPF_FUNC_read_branch_records flags. */ +enum { + BPF_F_GET_BRANCH_RECORDS_SIZE = (1ULL << 0), +}; + +/* BPF_FUNC_bpf_ringbuf_commit, BPF_FUNC_bpf_ringbuf_discard, and + * BPF_FUNC_bpf_ringbuf_output flags. + */ +enum { + BPF_RB_NO_WAKEUP = (1ULL << 0), + BPF_RB_FORCE_WAKEUP = (1ULL << 1), +}; + +/* BPF_FUNC_bpf_ringbuf_query flags */ +enum { + BPF_RB_AVAIL_DATA = 0, + BPF_RB_RING_SIZE = 1, + BPF_RB_CONS_POS = 2, + BPF_RB_PROD_POS = 3, +}; + +/* BPF ring buffer constants */ +enum { + BPF_RINGBUF_BUSY_BIT = (1U << 31), + BPF_RINGBUF_DISCARD_BIT = (1U << 30), + BPF_RINGBUF_HDR_SZ = 8, +}; + +/* BPF_FUNC_sk_assign flags in bpf_sk_lookup context. */ +enum { + BPF_SK_LOOKUP_F_REPLACE = (1ULL << 0), + BPF_SK_LOOKUP_F_NO_REUSEPORT = (1ULL << 1), +}; /* Mode for BPF_FUNC_skb_adjust_room helper. */ enum bpf_adj_room_mode { BPF_ADJ_ROOM_NET, + BPF_ADJ_ROOM_MAC, }; /* Mode for BPF_FUNC_skb_load_bytes_relative helper. */ @@ -2494,7 +4067,8 @@ enum bpf_hdr_start_off { /* Encapsulation type for BPF_FUNC_lwt_push_encap helper. */ enum bpf_lwt_encap_mode { BPF_LWT_ENCAP_SEG6, - BPF_LWT_ENCAP_SEG6_INLINE + BPF_LWT_ENCAP_SEG6_INLINE, + BPF_LWT_ENCAP_IP, }; #define __bpf_md_ptr(type, name) \ @@ -2540,6 +4114,9 @@ struct __sk_buff { __bpf_md_ptr(struct bpf_flow_keys *, flow_keys); __u64 tstamp; __u32 wire_len; + __u32 gso_segs; + __bpf_md_ptr(struct bpf_sock *, sk); + __u32 gso_size; }; struct bpf_tunnel_key { @@ -2581,7 +4158,15 @@ enum bpf_ret_code { BPF_DROP = 2, /* 3-6 reserved */ BPF_REDIRECT = 7, - /* >127 are reserved for prog type specific return codes */ + /* >127 are reserved for prog type specific return codes. + * + * BPF_LWT_REROUTE: used by BPF_PROG_TYPE_LWT_IN and + * BPF_PROG_TYPE_LWT_XMIT to indicate that skb had been + * changed and should be routed based on its new L3 header. + * (This is an L3 redirect, as opposed to L2 redirect + * represented by BPF_REDIRECT above). + */ + BPF_LWT_REROUTE = 128, }; struct bpf_sock { @@ -2591,15 +4176,60 @@ struct bpf_sock { __u32 protocol; __u32 mark; __u32 priority; - __u32 src_ip4; /* Allows 1,2,4-byte read. - * Stored in network byte order. + /* IP address also allows 1 and 2 bytes access */ + __u32 src_ip4; + __u32 src_ip6[4]; + __u32 src_port; /* host byte order */ + __u32 dst_port; /* network byte order */ + __u32 dst_ip4; + __u32 dst_ip6[4]; + __u32 state; + __s32 rx_queue_mapping; +}; + +struct bpf_tcp_sock { + __u32 snd_cwnd; /* Sending congestion window */ + __u32 srtt_us; /* smoothed round trip time << 3 in usecs */ + __u32 rtt_min; + __u32 snd_ssthresh; /* Slow start size threshold */ + __u32 rcv_nxt; /* What we want to receive next */ + __u32 snd_nxt; /* Next sequence we send */ + __u32 snd_una; /* First byte we want an ack for */ + __u32 mss_cache; /* Cached effective mss, not including SACKS */ + __u32 ecn_flags; /* ECN status bits. */ + __u32 rate_delivered; /* saved rate sample: packets delivered */ + __u32 rate_interval_us; /* saved rate sample: time elapsed */ + __u32 packets_out; /* Packets which are "in flight" */ + __u32 retrans_out; /* Retransmitted packets out */ + __u32 total_retrans; /* Total retransmits for entire connection */ + __u32 segs_in; /* RFC4898 tcpEStatsPerfSegsIn + * total number of segments in. */ - __u32 src_ip6[4]; /* Allows 1,2,4-byte read. - * Stored in network byte order. + __u32 data_segs_in; /* RFC4898 tcpEStatsPerfDataSegsIn + * total number of data segments in. */ - __u32 src_port; /* Allows 4-byte read. - * Stored in host byte order + __u32 segs_out; /* RFC4898 tcpEStatsPerfSegsOut + * The total number of segments sent. */ + __u32 data_segs_out; /* RFC4898 tcpEStatsPerfDataSegsOut + * total number of data segments sent. + */ + __u32 lost_out; /* Lost packets */ + __u32 sacked_out; /* SACK'd packets */ + __u64 bytes_received; /* RFC4898 tcpEStatsAppHCThruOctetsReceived + * sum(delta(rcv_nxt)), or how many bytes + * were acked. + */ + __u64 bytes_acked; /* RFC4898 tcpEStatsAppHCThruOctetsAcked + * sum(delta(snd_una)), or how many bytes + * were acked. + */ + __u32 dsack_dups; /* RFC4898 tcpEStatsStackDSACKDups + * total number of DSACK blocks received + */ + __u32 delivered; /* Total data packets delivered incl. rexmits */ + __u32 delivered_ce; /* Like the above but only ECE marked packets */ + __u32 icsk_retransmits; /* Number of unrecovered [RTO] timeouts */ }; struct bpf_sock_tuple { @@ -2619,6 +4249,10 @@ struct bpf_sock_tuple { }; }; +struct bpf_xdp_sock { + __u32 queue_id; +}; + #define XDP_PACKET_HEADROOM 256 /* User return codes for XDP prog type. @@ -2644,6 +4278,34 @@ struct xdp_md { /* Below access go through struct xdp_rxq_info */ __u32 ingress_ifindex; /* rxq->dev->ifindex */ __u32 rx_queue_index; /* rxq->queue_index */ + + __u32 egress_ifindex; /* txq->dev->ifindex */ +}; + +/* DEVMAP map-value layout + * + * The struct data-layout of map-value is a configuration interface. + * New members can only be added to the end of this structure. + */ +struct bpf_devmap_val { + __u32 ifindex; /* device index */ + union { + int fd; /* prog fd on map write */ + __u32 id; /* prog id on map read */ + } bpf_prog; +}; + +/* CPUMAP map-value layout + * + * The struct data-layout of map-value is a configuration interface. + * New members can only be added to the end of this structure. + */ +struct bpf_cpumap_val { + __u32 qsize; /* queue size to remote target CPU */ + union { + int fd; /* prog fd on map write */ + __u32 id; /* prog id on map read */ + } bpf_prog; }; enum sk_action { @@ -2666,6 +4328,8 @@ struct sk_msg_md { __u32 remote_port; /* Stored in network byte order */ __u32 local_port; /* stored in host byte order */ __u32 size; /* Total size of sk_msg */ + + __bpf_md_ptr(struct bpf_sock *, sk); /* current socket */ }; struct sk_reuseport_md { @@ -2710,6 +4374,7 @@ struct bpf_prog_info { char name[BPF_OBJ_NAME_LEN]; __u32 ifindex; __u32 gpl_compatible:1; + __u32 :31; /* alignment pad */ __u64 netns_dev; __u64 netns_ino; __u32 nr_jited_ksyms; @@ -2728,6 +4393,8 @@ struct bpf_prog_info { __u32 jited_line_info_rec_size; __u32 nr_prog_tags; __aligned_u64 prog_tags; + __u64 run_time_ns; + __u64 run_cnt; } __attribute__((aligned(8))); struct bpf_map_info { @@ -2739,7 +4406,7 @@ struct bpf_map_info { __u32 map_flags; char name[BPF_OBJ_NAME_LEN]; __u32 ifindex; - __u32 :32; + __u32 btf_vmlinux_value_type_id; __u64 netns_dev; __u64 netns_ino; __u32 btf_id; @@ -2753,30 +4420,66 @@ struct bpf_btf_info { __u32 id; } __attribute__((aligned(8))); +struct bpf_link_info { + __u32 type; + __u32 id; + __u32 prog_id; + union { + struct { + __aligned_u64 tp_name; /* in/out: tp_name buffer ptr */ + __u32 tp_name_len; /* in/out: tp_name buffer len */ + } raw_tracepoint; + struct { + __u32 attach_type; + } tracing; + struct { + __u64 cgroup_id; + __u32 attach_type; + } cgroup; + struct { + __aligned_u64 target_name; /* in/out: target_name buffer ptr */ + __u32 target_name_len; /* in/out: target_name buffer len */ + union { + struct { + __u32 map_id; + } map; + }; + } iter; + struct { + __u32 netns_ino; + __u32 attach_type; + } netns; + struct { + __u32 ifindex; + } xdp; + }; +} __attribute__((aligned(8))); + /* User bpf_sock_addr struct to access socket fields and sockaddr struct passed * by user and intended to be used by socket (e.g. to bind to, depends on - * attach attach type). + * attach type). */ struct bpf_sock_addr { __u32 user_family; /* Allows 4-byte read, but no write. */ __u32 user_ip4; /* Allows 1,2,4-byte read and 4-byte write. * Stored in network byte order. */ - __u32 user_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. + __u32 user_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write. * Stored in network byte order. */ - __u32 user_port; /* Allows 4-byte read and write. + __u32 user_port; /* Allows 1,2,4-byte read and 4-byte write. * Stored in network byte order */ __u32 family; /* Allows 4-byte read, but no write */ __u32 type; /* Allows 4-byte read, but no write */ __u32 protocol; /* Allows 4-byte read, but no write */ - __u32 msg_src_ip4; /* Allows 1,2,4-byte read an 4-byte write. + __u32 msg_src_ip4; /* Allows 1,2,4-byte read and 4-byte write. * Stored in network byte order. */ - __u32 msg_src_ip6[4]; /* Allows 1,2,4-byte read an 4-byte write. + __u32 msg_src_ip6[4]; /* Allows 1,2,4,8-byte read and 4,8-byte write. * Stored in network byte order. */ + __bpf_md_ptr(struct bpf_sock *, sk); }; /* User bpf_sock_ops struct to access socket values and specify request ops @@ -2828,15 +4531,91 @@ struct bpf_sock_ops { __u32 sk_txhash; __u64 bytes_received; __u64 bytes_acked; + __bpf_md_ptr(struct bpf_sock *, sk); + /* [skb_data, skb_data_end) covers the whole TCP header. + * + * BPF_SOCK_OPS_PARSE_HDR_OPT_CB: The packet received + * BPF_SOCK_OPS_HDR_OPT_LEN_CB: Not useful because the + * header has not been written. + * BPF_SOCK_OPS_WRITE_HDR_OPT_CB: The header and options have + * been written so far. + * BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB: The SYNACK that concludes + * the 3WHS. + * BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB: The ACK that concludes + * the 3WHS. + * + * bpf_load_hdr_opt() can also be used to read a particular option. + */ + __bpf_md_ptr(void *, skb_data); + __bpf_md_ptr(void *, skb_data_end); + __u32 skb_len; /* The total length of a packet. + * It includes the header, options, + * and payload. + */ + __u32 skb_tcp_flags; /* tcp_flags of the header. It provides + * an easy way to check for tcp_flags + * without parsing skb_data. + * + * In particular, the skb_tcp_flags + * will still be available in + * BPF_SOCK_OPS_HDR_OPT_LEN even though + * the outgoing header has not + * been written yet. + */ }; /* Definitions for bpf_sock_ops_cb_flags */ -#define BPF_SOCK_OPS_RTO_CB_FLAG (1<<0) -#define BPF_SOCK_OPS_RETRANS_CB_FLAG (1<<1) -#define BPF_SOCK_OPS_STATE_CB_FLAG (1<<2) -#define BPF_SOCK_OPS_ALL_CB_FLAGS 0x7 /* Mask of all currently - * supported cb flags - */ +enum { + BPF_SOCK_OPS_RTO_CB_FLAG = (1<<0), + BPF_SOCK_OPS_RETRANS_CB_FLAG = (1<<1), + BPF_SOCK_OPS_STATE_CB_FLAG = (1<<2), + BPF_SOCK_OPS_RTT_CB_FLAG = (1<<3), + /* Call bpf for all received TCP headers. The bpf prog will be + * called under sock_ops->op == BPF_SOCK_OPS_PARSE_HDR_OPT_CB + * + * Please refer to the comment in BPF_SOCK_OPS_PARSE_HDR_OPT_CB + * for the header option related helpers that will be useful + * to the bpf programs. + * + * It could be used at the client/active side (i.e. connect() side) + * when the server told it that the server was in syncookie + * mode and required the active side to resend the bpf-written + * options. The active side can keep writing the bpf-options until + * it received a valid packet from the server side to confirm + * the earlier packet (and options) has been received. The later + * example patch is using it like this at the active side when the + * server is in syncookie mode. + * + * The bpf prog will usually turn this off in the common cases. + */ + BPF_SOCK_OPS_PARSE_ALL_HDR_OPT_CB_FLAG = (1<<4), + /* Call bpf when kernel has received a header option that + * the kernel cannot handle. The bpf prog will be called under + * sock_ops->op == BPF_SOCK_OPS_PARSE_HDR_OPT_CB. + * + * Please refer to the comment in BPF_SOCK_OPS_PARSE_HDR_OPT_CB + * for the header option related helpers that will be useful + * to the bpf programs. + */ + BPF_SOCK_OPS_PARSE_UNKNOWN_HDR_OPT_CB_FLAG = (1<<5), + /* Call bpf when the kernel is writing header options for the + * outgoing packet. The bpf prog will first be called + * to reserve space in a skb under + * sock_ops->op == BPF_SOCK_OPS_HDR_OPT_LEN_CB. Then + * the bpf prog will be called to write the header option(s) + * under sock_ops->op == BPF_SOCK_OPS_WRITE_HDR_OPT_CB. + * + * Please refer to the comment in BPF_SOCK_OPS_HDR_OPT_LEN_CB + * and BPF_SOCK_OPS_WRITE_HDR_OPT_CB for the header option + * related helpers that will be useful to the bpf programs. + * + * The kernel gets its chance to reserve space and write + * options first before the BPF program does. + */ + BPF_SOCK_OPS_WRITE_HDR_OPT_CB_FLAG = (1<<6), +/* Mask of all currently supported cb flags */ + BPF_SOCK_OPS_ALL_CB_FLAGS = 0x7F, +}; /* List of known BPF sock_ops operators. * New entries can only be added at the end @@ -2889,6 +4668,65 @@ enum { BPF_SOCK_OPS_TCP_LISTEN_CB, /* Called on listen(2), right after * socket transition to LISTEN state. */ + BPF_SOCK_OPS_RTT_CB, /* Called on every RTT. + */ + BPF_SOCK_OPS_PARSE_HDR_OPT_CB, /* Parse the header option. + * It will be called to handle + * the packets received at + * an already established + * connection. + * + * sock_ops->skb_data: + * Referring to the received skb. + * It covers the TCP header only. + * + * bpf_load_hdr_opt() can also + * be used to search for a + * particular option. + */ + BPF_SOCK_OPS_HDR_OPT_LEN_CB, /* Reserve space for writing the + * header option later in + * BPF_SOCK_OPS_WRITE_HDR_OPT_CB. + * Arg1: bool want_cookie. (in + * writing SYNACK only) + * + * sock_ops->skb_data: + * Not available because no header has + * been written yet. + * + * sock_ops->skb_tcp_flags: + * The tcp_flags of the + * outgoing skb. (e.g. SYN, ACK, FIN). + * + * bpf_reserve_hdr_opt() should + * be used to reserve space. + */ + BPF_SOCK_OPS_WRITE_HDR_OPT_CB, /* Write the header options + * Arg1: bool want_cookie. (in + * writing SYNACK only) + * + * sock_ops->skb_data: + * Referring to the outgoing skb. + * It covers the TCP header + * that has already been written + * by the kernel and the + * earlier bpf-progs. + * + * sock_ops->skb_tcp_flags: + * The tcp_flags of the outgoing + * skb. (e.g. SYN, ACK, FIN). + * + * bpf_store_hdr_opt() should + * be used to write the + * option. + * + * bpf_load_hdr_opt() can also + * be used to search for a + * particular option that + * has already been written + * by the kernel or the + * earlier bpf-progs. + */ }; /* List of TCP states. There is a build check in net/ipv4/tcp.c to detect @@ -2913,8 +4751,67 @@ enum { BPF_TCP_MAX_STATES /* Leave at the end! */ }; -#define TCP_BPF_IW 1001 /* Set TCP initial congestion window */ -#define TCP_BPF_SNDCWND_CLAMP 1002 /* Set sndcwnd_clamp */ +enum { + TCP_BPF_IW = 1001, /* Set TCP initial congestion window */ + TCP_BPF_SNDCWND_CLAMP = 1002, /* Set sndcwnd_clamp */ + TCP_BPF_DELACK_MAX = 1003, /* Max delay ack in usecs */ + TCP_BPF_RTO_MIN = 1004, /* Min delay ack in usecs */ + /* Copy the SYN pkt to optval + * + * BPF_PROG_TYPE_SOCK_OPS only. It is similar to the + * bpf_getsockopt(TCP_SAVED_SYN) but it does not limit + * to only getting from the saved_syn. It can either get the + * syn packet from: + * + * 1. the just-received SYN packet (only available when writing the + * SYNACK). It will be useful when it is not necessary to + * save the SYN packet for latter use. It is also the only way + * to get the SYN during syncookie mode because the syn + * packet cannot be saved during syncookie. + * + * OR + * + * 2. the earlier saved syn which was done by + * bpf_setsockopt(TCP_SAVE_SYN). + * + * The bpf_getsockopt(TCP_BPF_SYN*) option will hide where the + * SYN packet is obtained. + * + * If the bpf-prog does not need the IP[46] header, the + * bpf-prog can avoid parsing the IP header by using + * TCP_BPF_SYN. Otherwise, the bpf-prog can get both + * IP[46] and TCP header by using TCP_BPF_SYN_IP. + * + * >0: Total number of bytes copied + * -ENOSPC: Not enough space in optval. Only optlen number of + * bytes is copied. + * -ENOENT: The SYN skb is not available now and the earlier SYN pkt + * is not saved by setsockopt(TCP_SAVE_SYN). + */ + TCP_BPF_SYN = 1005, /* Copy the TCP header */ + TCP_BPF_SYN_IP = 1006, /* Copy the IP[46] and TCP header */ + TCP_BPF_SYN_MAC = 1007, /* Copy the MAC, IP[46], and TCP header */ +}; + +enum { + BPF_LOAD_HDR_OPT_TCP_SYN = (1ULL << 0), +}; + +/* args[0] value during BPF_SOCK_OPS_HDR_OPT_LEN_CB and + * BPF_SOCK_OPS_WRITE_HDR_OPT_CB. + */ +enum { + BPF_WRITE_HDR_TCP_CURRENT_MSS = 1, /* Kernel is finding the + * total option spaces + * required for an established + * sk in order to calculate the + * MSS. No skb is actually + * sent. + */ + BPF_WRITE_HDR_TCP_SYNACK_COOKIE = 2, /* Kernel is in syncookie mode + * when sending a SYN. + */ +}; struct bpf_perf_event_value { __u64 counter; @@ -2922,12 +4819,16 @@ struct bpf_perf_event_value { __u64 running; }; -#define BPF_DEVCG_ACC_MKNOD (1ULL << 0) -#define BPF_DEVCG_ACC_READ (1ULL << 1) -#define BPF_DEVCG_ACC_WRITE (1ULL << 2) +enum { + BPF_DEVCG_ACC_MKNOD = (1ULL << 0), + BPF_DEVCG_ACC_READ = (1ULL << 1), + BPF_DEVCG_ACC_WRITE = (1ULL << 2), +}; -#define BPF_DEVCG_DEV_BLOCK (1ULL << 0) -#define BPF_DEVCG_DEV_CHAR (1ULL << 1) +enum { + BPF_DEVCG_DEV_BLOCK = (1ULL << 0), + BPF_DEVCG_DEV_CHAR = (1ULL << 1), +}; struct bpf_cgroup_dev_ctx { /* access_type encoded as (BPF_DEVCG_ACC_* << 16) | BPF_DEVCG_DEV_* */ @@ -2943,8 +4844,10 @@ struct bpf_raw_tracepoint_args { /* DIRECT: Skip the FIB rules and go to FIB table associated with device * OUTPUT: Do lookup from egress perspective; default is ingress */ -#define BPF_FIB_LOOKUP_DIRECT BIT(0) -#define BPF_FIB_LOOKUP_OUTPUT BIT(1) +enum { + BPF_FIB_LOOKUP_DIRECT = (1U << 0), + BPF_FIB_LOOKUP_OUTPUT = (1U << 1), +}; enum { BPF_FIB_LKUP_RET_SUCCESS, /* lookup successful */ @@ -3007,6 +4910,16 @@ struct bpf_fib_lookup { __u8 dmac[6]; /* ETH_ALEN */ }; +struct bpf_redir_neigh { + /* network family for lookup (AF_INET, AF_INET6) */ + __u32 nh_family; + /* network address of nexthop; skips fib lookup to find gateway */ + union { + __be32 ipv4_nh; + __u32 ipv6_nh[4]; /* in6_addr; network order */ + }; +}; + enum bpf_task_fd_type { BPF_FD_TYPE_RAW_TRACEPOINT, /* tp name */ BPF_FD_TYPE_TRACEPOINT, /* tp name */ @@ -3016,6 +4929,12 @@ enum bpf_task_fd_type { BPF_FD_TYPE_URETPROBE, /* filename + offset */ }; +enum { + BPF_FLOW_DISSECTOR_F_PARSE_1ST_FRAG = (1U << 0), + BPF_FLOW_DISSECTOR_F_STOP_AT_FLOW_LABEL = (1U << 1), + BPF_FLOW_DISSECTOR_F_STOP_AT_ENCAP = (1U << 2), +}; + struct bpf_flow_keys { __u16 nhoff; __u16 thoff; @@ -3037,6 +4956,8 @@ struct bpf_flow_keys { __u32 ipv6_dst[4]; /* in6_addr; network order */ }; }; + __u32 flags; + __be32 flow_label; }; struct bpf_func_info { @@ -3054,4 +4975,77 @@ struct bpf_line_info { __u32 line_col; }; +struct bpf_spin_lock { + __u32 val; +}; + +struct bpf_sysctl { + __u32 write; /* Sysctl is being read (= 0) or written (= 1). + * Allows 1,2,4-byte read, but no write. + */ + __u32 file_pos; /* Sysctl file position to read from, write to. + * Allows 1,2,4-byte read an 4-byte write. + */ +}; + +struct bpf_sockopt { + __bpf_md_ptr(struct bpf_sock *, sk); + __bpf_md_ptr(void *, optval); + __bpf_md_ptr(void *, optval_end); + + __s32 level; + __s32 optname; + __s32 optlen; + __s32 retval; +}; + +struct bpf_pidns_info { + __u32 pid; + __u32 tgid; +}; + +/* User accessible data for SK_LOOKUP programs. Add new fields at the end. */ +struct bpf_sk_lookup { + __bpf_md_ptr(struct bpf_sock *, sk); /* Selected socket */ + + __u32 family; /* Protocol family (AF_INET, AF_INET6) */ + __u32 protocol; /* IP protocol (IPPROTO_TCP, IPPROTO_UDP) */ + __u32 remote_ip4; /* Network byte order */ + __u32 remote_ip6[4]; /* Network byte order */ + __u32 remote_port; /* Network byte order */ + __u32 local_ip4; /* Network byte order */ + __u32 local_ip6[4]; /* Network byte order */ + __u32 local_port; /* Host byte order */ +}; + +/* + * struct btf_ptr is used for typed pointer representation; the + * type id is used to render the pointer data as the appropriate type + * via the bpf_snprintf_btf() helper described above. A flags field - + * potentially to specify additional details about the BTF pointer + * (rather than its mode of display) - is included for future use. + * Display flags - BTF_F_* - are passed to bpf_snprintf_btf separately. + */ +struct btf_ptr { + void *ptr; + __u32 type_id; + __u32 flags; /* BTF ptr flags; unused at present. */ +}; + +/* + * Flags to control bpf_snprintf_btf() behaviour. + * - BTF_F_COMPACT: no formatting around type information + * - BTF_F_NONAME: no struct/union member names/types + * - BTF_F_PTR_RAW: show raw (unobfuscated) pointer values; + * equivalent to %px. + * - BTF_F_ZERO: show zero-valued struct/union members; they + * are not displayed by default + */ +enum { + BTF_F_COMPACT = (1ULL << 0), + BTF_F_NONAME = (1ULL << 1), + BTF_F_PTR_RAW = (1ULL << 2), + BTF_F_ZERO = (1ULL << 3), +}; + #endif /* _UAPI__LINUX_BPF_H__ */ diff --git a/src/shared/linux/dm-ioctl.h b/src/shared/linux/dm-ioctl.h index b3aeec70f..ab312e13f 100644 --- a/src/shared/linux/dm-ioctl.h +++ b/src/shared/linux/dm-ioctl.h @@ -243,6 +243,7 @@ enum { DM_TARGET_MSG_CMD, DM_DEV_SET_GEOMETRY_CMD, DM_DEV_ARM_POLL_CMD, + DM_GET_TARGET_VERSION_CMD, }; #define DM_IOCTL 0xfd @@ -265,6 +266,7 @@ enum { #define DM_TABLE_STATUS _IOWR(DM_IOCTL, DM_TABLE_STATUS_CMD, struct dm_ioctl) #define DM_LIST_VERSIONS _IOWR(DM_IOCTL, DM_LIST_VERSIONS_CMD, struct dm_ioctl) +#define DM_GET_TARGET_VERSION _IOWR(DM_IOCTL, DM_GET_TARGET_VERSION_CMD, struct dm_ioctl) #define DM_TARGET_MSG _IOWR(DM_IOCTL, DM_TARGET_MSG_CMD, struct dm_ioctl) #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) @@ -272,7 +274,7 @@ enum { #define DM_VERSION_MAJOR 4 #define DM_VERSION_MINOR 27 #define DM_VERSION_PATCHLEVEL 0 -#define DM_VERSION_EXTRA "-ioctl (2019-01-18)" +#define DM_VERSION_EXTRA "-ioctl (2020-10-01)" /* Status bits */ #define DM_READONLY_FLAG (1 << 0) /* In/Out */ diff --git a/src/shared/linux/ethtool.h b/src/shared/linux/ethtool.h index b06c6302f..974d4292e 100644 --- a/src/shared/linux/ethtool.h +++ b/src/shared/linux/ethtool.h @@ -1621,6 +1621,8 @@ enum ethtool_link_mode_bit_indices { ETHTOOL_LINK_MODE_400000baseLR4_ER4_FR4_Full_BIT = 87, ETHTOOL_LINK_MODE_400000baseDR4_Full_BIT = 88, ETHTOOL_LINK_MODE_400000baseCR4_Full_BIT = 89, + ETHTOOL_LINK_MODE_100baseFX_Half_BIT = 90, + ETHTOOL_LINK_MODE_100baseFX_Full_BIT = 91, /* must be last entry */ __ETHTOOL_LINK_MODE_MASK_NBITS }; diff --git a/src/shared/local-addresses.c b/src/shared/local-addresses.c index 2c860f76d..1de890f14 100644 --- a/src/shared/local-addresses.c +++ b/src/shared/local-addresses.c @@ -204,7 +204,7 @@ int local_gateways(sd_netlink *context, int ifindex, int af, struct local_addres union in_addr_union gateway; uint16_t type; unsigned char dst_len, src_len, table; - uint32_t ifi, metric = 0; + uint32_t ifi = 0, metric = 0; size_t rta_len; int family; RouteVia via; diff --git a/src/shared/log-link.h b/src/shared/log-link.h index bb692e051..3a4dcaa26 100644 --- a/src/shared/log-link.h +++ b/src/shared/log-link.h @@ -3,6 +3,13 @@ #include "log.h" +#define log_interface_full_errno(ifname, level, error, ...) \ + ({ \ + const char *_ifname = (ifname); \ + _ifname ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, "INTERFACE=", _ifname, NULL, NULL, ##__VA_ARGS__) : \ + log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \ + }) + /* * The following macros append INTERFACE= to the message. * The macros require a struct named 'Link' which contains 'char *ifname': @@ -17,9 +24,8 @@ #define log_link_full_errno(link, level, error, ...) \ ({ \ const Link *_l = (link); \ - (_l && _l->ifname) ? log_object_internal(level, error, PROJECT_FILE, __LINE__, __func__, "INTERFACE=", _l->ifname, NULL, NULL, ##__VA_ARGS__) : \ - log_internal(level, error, PROJECT_FILE, __LINE__, __func__, ##__VA_ARGS__); \ - }) \ + log_interface_full_errno(_l ? _l->ifname : NULL, level, error, ##__VA_ARGS__); \ + }) #define log_link_full(link, level, ...) (void) log_link_full_errno(link, level, 0, __VA_ARGS__) diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 840f221ff..706a00c7f 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -66,26 +66,17 @@ static int print_catalog(FILE *f, sd_journal *j) { else prefix = "--"; - if (colors_enabled()) - newline = strjoina(ANSI_NORMAL "\n" ANSI_GREY, prefix, ANSI_NORMAL " " ANSI_GREEN); - else - newline = strjoina("\n", prefix, " "); + newline = strjoina(ansi_normal(), "\n", ansi_grey(), prefix, ansi_normal(), " ", ansi_green()); z = strreplace(strstrip(t), "\n", newline); if (!z) return log_oom(); - if (colors_enabled()) - fprintf(f, ANSI_GREY "%s" ANSI_NORMAL " " ANSI_GREEN, prefix); - else - fprintf(f, "%s ", prefix); + fprintf(f, "%s%s %s%s", ansi_grey(), prefix, ansi_normal(), ansi_green()); fputs(z, f); - if (colors_enabled()) - fputs(ANSI_NORMAL "\n", f); - else - fputc('\n', f); + fprintf(f, "%s\n", ansi_normal()); return 1; } @@ -1332,7 +1323,7 @@ int show_journal( assert(mode >= 0); assert(mode < _OUTPUT_MODE_MAX); - if (how_many == (unsigned) -1) + if (how_many == UINT_MAX) need_seek = true; else { /* Seek to end */ @@ -1405,9 +1396,9 @@ int show_journal( bool noaccess = journal_access_blocked(j); if (line == 0 && noaccess) - fprintf(f, "Warning: some journal files were not opened due to insufficient permissions."); + fprintf(f, "Warning: some journal files were not opened due to insufficient permissions.\n"); else if (!noaccess) - fprintf(f, "Warning: journal has been rotated since unit was started, output may be incomplete.\n"); + fprintf(f, "Notice: journal has been rotated since unit was started, output may be incomplete.\n"); else fprintf(f, "Warning: journal has been rotated since unit was started and some journal " "files were not opened due to insufficient permissions, output may be incomplete.\n"); @@ -1531,9 +1522,6 @@ static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) { assert(machine); assert(boot_id); - if (!machine_name_is_valid(machine)) - return -EINVAL; - r = container_get_leader(machine, &pid); if (r < 0) return r; @@ -1647,10 +1635,6 @@ int show_journal_by_unit( if (r < 0) return log_error_errno(r, "Failed to open journal: %m"); - r = add_match_this_boot(j, NULL); - if (r < 0) - return r; - if (system_unit) r = add_matches_for_unit(j, unit); else @@ -1658,6 +1642,14 @@ int show_journal_by_unit( if (r < 0) return log_error_errno(r, "Failed to add unit matches: %m"); + r = sd_journal_add_conjunction(j); + if (r < 0) + return log_error_errno(r, "Failed to add conjunction: %m"); + + r = add_match_this_boot(j, NULL); + if (r < 0) + return r; + if (DEBUG_LOGGING) { _cleanup_free_ char *filter; diff --git a/src/core/loopback-setup.c b/src/shared/loopback-setup.c similarity index 100% rename from src/core/loopback-setup.c rename to src/shared/loopback-setup.c diff --git a/src/core/loopback-setup.h b/src/shared/loopback-setup.h similarity index 100% rename from src/core/loopback-setup.h rename to src/shared/loopback-setup.h diff --git a/src/core/machine-id-setup.c b/src/shared/machine-id-setup.c similarity index 100% rename from src/core/machine-id-setup.c rename to src/shared/machine-id-setup.c diff --git a/src/core/machine-id-setup.h b/src/shared/machine-id-setup.h similarity index 100% rename from src/core/machine-id-setup.h rename to src/shared/machine-id-setup.h diff --git a/src/shared/macvlan-util.h b/src/shared/macvlan-util.h index 0d3a5f405..0705ecb6d 100644 --- a/src/shared/macvlan-util.h +++ b/src/shared/macvlan-util.h @@ -10,7 +10,7 @@ typedef enum MacVlanMode { NETDEV_MACVLAN_MODE_PASSTHRU = MACVLAN_MODE_PASSTHRU, NETDEV_MACVLAN_MODE_SOURCE = MACVLAN_MODE_SOURCE, _NETDEV_MACVLAN_MODE_MAX, - _NETDEV_MACVLAN_MODE_INVALID = -1 + _NETDEV_MACVLAN_MODE_INVALID = -EINVAL, } MacVlanMode; const char *macvlan_mode_to_string(MacVlanMode d) _const_; diff --git a/src/shared/meson.build b/src/shared/meson.build index f30fe4499..a2e4958fd 100644 --- a/src/shared/meson.build +++ b/src/shared/meson.build @@ -78,6 +78,9 @@ shared_sources = files(''' daemon-util.h dev-setup.c dev-setup.h + devnode-acl.h + discover-image.c + discover-image.h dissect-image.c dissect-image.h dm-util.c @@ -97,10 +100,15 @@ shared_sources = files(''' exec-util.h exit-status.c exit-status.h + extension-release.c + extension-release.h fdset.c fdset.h fileio-label.c fileio-label.h + firewall-util-nft.c + firewall-util-private.h + firewall-util.c firewall-util.h format-table.c format-table.h @@ -115,6 +123,8 @@ shared_sources = files(''' gpt.h group-record.c group-record.h + hostname-setup.c + hostname-setup.h id128-print.c id128-print.h idn-util.c @@ -139,8 +149,14 @@ shared_sources = files(''' json-internal.h json.c json.h + kbd-util.c + kbd-util.h + killall.c + killall.h libcrypt-util.c libcrypt-util.h + libfido2-util.c + libfido2-util.h libmount-util.h linux/auto_dev-ioctl.h linux/bpf.h @@ -157,8 +173,10 @@ shared_sources = files(''' logs-show.h loop-util.c loop-util.h - machine-image.c - machine-image.h + loopback-setup.c + loopback-setup.h + machine-id-setup.c + machine-id-setup.h machine-pool.c machine-pool.h macvlan-util.c @@ -167,23 +185,27 @@ shared_sources = files(''' mkfs-util.c mkfs-util.h module-util.h + mount-setup.c + mount-setup.h mount-util.c mount-util.h + net-condition.c + net-condition.h netif-naming-scheme.c netif-naming-scheme.h - nscd-flush.c nscd-flush.h nsflags.c nsflags.h numa-util.c numa-util.h + openssl-util.c openssl-util.h - os-util.c - os-util.h output-mode.c output-mode.h pager.c pager.h + parse-argument.c + parse-argument.h pe-header.h pkcs11-util.c pkcs11-util.h @@ -222,18 +244,16 @@ shared_sources = files(''' specifier.h switch-root.c switch-root.h - sysctl-util.c - sysctl-util.h tmpfile-util-label.c tmpfile-util-label.h tomoyo-util.c tomoyo-util.h + tpm2-util.c + tpm2-util.h udev-util.c udev-util.h uid-range.c uid-range.h - unit-file.c - unit-file.h user-record-nss.c user-record-nss.h user-record-show.c @@ -262,24 +282,28 @@ shared_sources = files(''' '''.split()) if get_option('tests') != 'false' - shared_sources += files('tests.c', 'tests.h') + shared_sources += files(''' + test-tables.h + tests.c + tests.h + '''.split()) endif -test_tables_h = files('test-tables.h') -shared_sources += test_tables_h - generate_syscall_list = find_program('generate-syscall-list.py') fname = 'syscall-list.h' syscall_list_h = custom_target( fname, - input : 'syscall-names.text', + input : syscall_list_txt, output : fname, command : [generate_syscall_list, '@INPUT@'], capture : true) if conf.get('HAVE_ACL') == 1 - shared_sources += files('acl-util.c') + shared_sources += files(''' + acl-util.c + devnode-acl.c + '''.split()) endif if conf.get('ENABLE_UTMP') == 1 @@ -292,7 +316,7 @@ if conf.get('HAVE_SECCOMP') == 1 endif if conf.get('HAVE_LIBIPTC') == 1 - shared_sources += files('firewall-util.c') + shared_sources += files('firewall-util-iptables.c') endif if conf.get('HAVE_KMOD') == 1 @@ -300,10 +324,13 @@ if conf.get('HAVE_KMOD') == 1 endif if conf.get('HAVE_PAM') == 1 - shared_sources += files(''' - pam-util.c - pam-util.h -'''.split()) + shared_sources += files( + 'pam-util.c', + 'pam-util.h') +endif + +if conf.get('ENABLE_NSCD') == 1 + shared_sources += files('nscd-flush.c') endif generate_ip_protocol_list = find_program('generate-ip-protocol-list.sh') @@ -378,22 +405,14 @@ libshared_static = static_library( libshared = shared_library( libshared_name, - libudev_sources, include_directories : includes, link_args : ['-shared', '-Wl,--version-script=' + libshared_sym_path], link_whole : [libshared_static, libbasic, libbasic_gcrypt, - libsystemd_static, - libjournal_client], + libsystemd_static], c_args : ['-fvisibility=default'], dependencies : libshared_deps, install : true, install_dir : rootlibexecdir) - -############################################################ - -run_target( - 'syscall-names-update', - command : [syscall_names_update_sh, meson.current_source_dir()]) diff --git a/src/shared/module-util.h b/src/shared/module-util.h index 4db8c5f04..8ca6a06a0 100644 --- a/src/shared/module-util.h +++ b/src/shared/module-util.h @@ -7,6 +7,6 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_ctx*, kmod_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_module*, kmod_module_unref); -DEFINE_TRIVIAL_CLEANUP_FUNC(struct kmod_list*, kmod_module_unref_list); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct kmod_list*, kmod_module_unref_list, NULL); int module_load_and_warn(struct kmod_ctx *ctx, const char *module, bool verbose); diff --git a/src/core/mount-setup.c b/src/shared/mount-setup.c similarity index 99% rename from src/core/mount-setup.c rename to src/shared/mount-setup.c index 915b1016b..1e4bbfb1a 100644 --- a/src/core/mount-setup.c +++ b/src/shared/mount-setup.c @@ -66,7 +66,7 @@ static const MountPoint mount_table[] = { NULL, MNT_FATAL|MNT_IN_CONTAINER|MNT_FOLLOW_SYMLINK }, { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL, MNT_FATAL|MNT_IN_CONTAINER }, - { "devtmpfs", "/dev", "devtmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_NOEXEC|MS_STRICTATIME, + { "devtmpfs", "/dev", "devtmpfs", "mode=755" TMPFS_LIMITS_DEV, MS_NOSUID|MS_STRICTATIME, NULL, MNT_FATAL|MNT_IN_CONTAINER }, { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, NULL, MNT_NONE }, diff --git a/src/core/mount-setup.h b/src/shared/mount-setup.h similarity index 100% rename from src/core/mount-setup.h rename to src/shared/mount-setup.h diff --git a/src/shared/mount-util.c b/src/shared/mount-util.c index b19b3849a..576e4054c 100644 --- a/src/shared/mount-util.c +++ b/src/shared/mount-util.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include #include @@ -8,21 +9,27 @@ #include #include "alloc-util.h" +#include "dissect-image.h" #include "extract-word.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" #include "hashmap.h" #include "libmount-util.h" +#include "mkdir.h" #include "mount-util.h" #include "mountpoint-util.h" +#include "namespace-util.h" #include "parse-util.h" #include "path-util.h" +#include "process-util.h" #include "set.h" #include "stat-util.h" #include "stdio-util.h" #include "string-util.h" #include "strv.h" +#include "tmpfile-util.h" +#include "user-util.h" int mount_fd(const char *source, int target_fd, @@ -203,13 +210,14 @@ int bind_remount_recursive_with_mountinfo( assert(prefix); assert(proc_self_mountinfo); - /* Recursively remount a directory (and all its submounts) read-only or read-write. If the directory is already - * mounted, we reuse the mount and simply mark it MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write - * operation). If it isn't we first make it one. Afterwards we apply MS_BIND|MS_RDONLY (or remove MS_RDONLY) to - * all submounts we can access, too. When mounts are stacked on the same mount point we only care for each - * individual "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We - * do not have any effect on future submounts that might get propagated, they might be writable. This includes - * future submounts that have been triggered via autofs. + /* Recursively remount a directory (and all its submounts) with desired flags (MS_READONLY, + * MS_NOSUID, MS_NOEXEC). If the directory is already mounted, we reuse the mount and simply mark it + * MS_BIND|MS_RDONLY (or remove the MS_RDONLY for read-write operation), ditto for other flags. If it + * isn't we first make it one. Afterwards we apply (or remove) the flags to all submounts we can + * access, too. When mounts are stacked on the same mount point we only care for each individual + * "top-level" mount on each point, as we cannot influence/access the underlying mounts anyway. We do + * not have any effect on future submounts that might get propagated, they might be writable + * etc. This includes future submounts that have been triggered via autofs. * * If the "deny_list" parameter is specified it may contain a list of subtrees to exclude from the * remount operation. Note that we'll ignore the deny list for the top-level path. */ @@ -733,7 +741,7 @@ int mount_option_mangle( } /* If 'word' is not a mount flag, then store it in '*ret_remaining_options'. */ - if (!ent->name && !strextend_with_separator(&ret, ",", word, NULL)) + if (!ent->name && !strextend_with_separator(&ret, ",", word)) return -ENOMEM; } @@ -742,3 +750,262 @@ int mount_option_mangle( return 0; } + +static int mount_in_namespace( + pid_t target, + const char *propagate_path, + const char *incoming_path, + const char *src, + const char *dest, + bool read_only, + bool make_file_or_directory, + const MountOptions *options, + bool is_image) { + + _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 }; + _cleanup_close_ int self_mntns_fd = -1, mntns_fd = -1, root_fd = -1, pidns_fd = -1, chased_src_fd = -1; + char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p, + chased_src[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + bool mount_slave_created = false, mount_slave_mounted = false, + mount_tmp_created = false, mount_tmp_mounted = false, + mount_outside_created = false, mount_outside_mounted = false; + struct stat st, self_mntns_st; + pid_t child; + int r; + + assert(target > 0); + assert(propagate_path); + assert(incoming_path); + assert(src); + assert(dest); + assert(!options || is_image); + + r = namespace_open(target, &pidns_fd, &mntns_fd, NULL, NULL, &root_fd); + if (r < 0) + return log_debug_errno(r, "Failed to retrieve FDs of the target process' namespace: %m"); + + if (fstat(mntns_fd, &st) < 0) + return log_debug_errno(errno, "Failed to fstat mount namespace FD of target process: %m"); + + r = namespace_open(0, NULL, &self_mntns_fd, NULL, NULL, NULL); + if (r < 0) + return log_debug_errno(r, "Failed to retrieve FDs of systemd's namespace: %m"); + + if (fstat(self_mntns_fd, &self_mntns_st) < 0) + return log_debug_errno(errno, "Failed to fstat mount namespace FD of systemd: %m"); + + /* We can't add new mounts at runtime if the process wasn't started in a namespace */ + if (st.st_ino == self_mntns_st.st_ino && st.st_dev == self_mntns_st.st_dev) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to activate bind mount in target, not running in a mount namespace"); + + /* One day, when bind mounting /proc/self/fd/n works across + * namespace boundaries we should rework this logic to make + * use of it... */ + + p = strjoina(propagate_path, "/"); + r = laccess(p, F_OK); + if (r < 0) + return log_debug_errno(r == -ENOENT ? SYNTHETIC_ERRNO(EOPNOTSUPP) : r, "Target does not allow propagation of mount points"); + + r = chase_symlinks(src, NULL, CHASE_TRAIL_SLASH, NULL, &chased_src_fd); + if (r < 0) + return log_debug_errno(r, "Failed to resolve source path of %s: %m", src); + xsprintf(chased_src, "/proc/self/fd/%i", chased_src_fd); + + if (fstat(chased_src_fd, &st) < 0) + return log_debug_errno(errno, "Failed to stat() resolved source path %s: %m", src); + if (S_ISLNK(st.st_mode)) /* This shouldn't really happen, given that we just chased the symlinks above, but let's better be safe… */ + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Source directory %s can't be a symbolic link", src); + + /* Our goal is to install a new bind mount into the container, + possibly read-only. This is irritatingly complex + unfortunately, currently. + + First, we start by creating a private playground in /tmp, + that we can mount MS_SLAVE. (Which is necessary, since + MS_MOVE cannot be applied to mounts with MS_SHARED parent + mounts.) */ + + if (!mkdtemp(mount_slave)) + return log_debug_errno(errno, "Failed to create playground %s: %m", mount_slave); + + mount_slave_created = true; + + r = mount_nofollow_verbose(LOG_DEBUG, mount_slave, mount_slave, NULL, MS_BIND, NULL); + if (r < 0) + goto finish; + + mount_slave_mounted = true; + + r = mount_nofollow_verbose(LOG_DEBUG, NULL, mount_slave, NULL, MS_SLAVE, NULL); + if (r < 0) + goto finish; + + /* Second, we mount the source file or directory to a directory inside of our MS_SLAVE playground. */ + mount_tmp = strjoina(mount_slave, "/mount"); + if (is_image) + r = mkdir_p(mount_tmp, 0700); + else + r = make_mount_point_inode_from_stat(&st, mount_tmp, 0700); + if (r < 0) { + log_debug_errno(r, "Failed to create temporary mount point %s: %m", mount_tmp); + goto finish; + } + + mount_tmp_created = true; + + if (is_image) + r = verity_dissect_and_mount(chased_src, mount_tmp, options, NULL, NULL, NULL); + else + r = mount_follow_verbose(LOG_DEBUG, chased_src, mount_tmp, NULL, MS_BIND, NULL); + if (r < 0) + goto finish; + + mount_tmp_mounted = true; + + /* Third, we remount the new bind mount read-only if requested. */ + if (read_only) { + r = mount_nofollow_verbose(LOG_DEBUG, NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL); + if (r < 0) + goto finish; + } + + /* Fourth, we move the new bind mount into the propagation directory. This way it will appear there read-only + * right-away. */ + + mount_outside = strjoina(propagate_path, "/XXXXXX"); + if (is_image || S_ISDIR(st.st_mode)) + r = mkdtemp(mount_outside) ? 0 : -errno; + else { + r = mkostemp_safe(mount_outside); + safe_close(r); + } + if (r < 0) { + log_debug_errno(r, "Cannot create propagation file or directory %s: %m", mount_outside); + goto finish; + } + + mount_outside_created = true; + + r = mount_nofollow_verbose(LOG_DEBUG, mount_tmp, mount_outside, NULL, MS_MOVE, NULL); + if (r < 0) + goto finish; + + mount_outside_mounted = true; + mount_tmp_mounted = false; + + if (is_image || S_ISDIR(st.st_mode)) + (void) rmdir(mount_tmp); + else + (void) unlink(mount_tmp); + mount_tmp_created = false; + + (void) umount_verbose(LOG_DEBUG, mount_slave, UMOUNT_NOFOLLOW); + mount_slave_mounted = false; + + (void) rmdir(mount_slave); + mount_slave_created = false; + + if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) { + log_debug_errno(errno, "Failed to create pipe: %m"); + goto finish; + } + + r = namespace_fork("(sd-bindmnt)", "(sd-bindmnt-inner)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG, + pidns_fd, mntns_fd, -1, -1, root_fd, &child); + if (r < 0) + goto finish; + if (r == 0) { + const char *mount_inside; + + errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]); + + if (make_file_or_directory) { + if (!is_image) { + (void) mkdir_parents(dest, 0755); + (void) make_mount_point_inode_from_stat(&st, dest, 0700); + } else + (void) mkdir_p(dest, 0755); + } + + /* Fifth, move the mount to the right place inside */ + mount_inside = strjoina(incoming_path, basename(mount_outside)); + r = mount_nofollow_verbose(LOG_ERR, mount_inside, dest, NULL, MS_MOVE, NULL); + if (r < 0) + goto child_fail; + + _exit(EXIT_SUCCESS); + + child_fail: + (void) write(errno_pipe_fd[1], &r, sizeof(r)); + errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); + + _exit(EXIT_FAILURE); + } + + errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]); + + r = wait_for_terminate_and_check("(sd-bindmnt)", child, 0); + if (r < 0) { + log_debug_errno(r, "Failed to wait for child: %m"); + goto finish; + } + if (r != EXIT_SUCCESS) { + if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r)) + log_debug_errno(r, "Failed to mount: %m"); + else + log_debug("Child failed."); + goto finish; + } + +finish: + if (mount_outside_mounted) + (void) umount_verbose(LOG_DEBUG, mount_outside, UMOUNT_NOFOLLOW); + if (mount_outside_created) { + if (is_image || S_ISDIR(st.st_mode)) + (void) rmdir(mount_outside); + else + (void) unlink(mount_outside); + } + + if (mount_tmp_mounted) + (void) umount_verbose(LOG_DEBUG, mount_tmp, UMOUNT_NOFOLLOW); + if (mount_tmp_created) { + if (is_image || S_ISDIR(st.st_mode)) + (void) rmdir(mount_tmp); + else + (void) unlink(mount_tmp); + } + + if (mount_slave_mounted) + (void) umount_verbose(LOG_DEBUG, mount_slave, UMOUNT_NOFOLLOW); + if (mount_slave_created) + (void) rmdir(mount_slave); + + return r; +} + +int bind_mount_in_namespace( + pid_t target, + const char *propagate_path, + const char *incoming_path, + const char *src, + const char *dest, + bool read_only, + bool make_file_or_directory) { + + return mount_in_namespace(target, propagate_path, incoming_path, src, dest, read_only, make_file_or_directory, NULL, false); +} + +int mount_image_in_namespace( + pid_t target, + const char *propagate_path, + const char *incoming_path, + const char *src, + const char *dest, + bool read_only, + bool make_file_or_directory, + const MountOptions *options) { + + return mount_in_namespace(target, propagate_path, incoming_path, src, dest, read_only, make_file_or_directory, options, true); +} diff --git a/src/shared/mount-util.h b/src/shared/mount-util.h index 6202008a8..718389768 100644 --- a/src/shared/mount-util.h +++ b/src/shared/mount-util.h @@ -5,6 +5,8 @@ #include #include +#include "alloc-util.h" +#include "dissect-image.h" #include "errno-util.h" #include "macro.h" @@ -21,7 +23,7 @@ * PID1 because 16MB of free space is required. */ #define TMPFS_LIMITS_RUN ",size=20%,nr_inodes=800k" -/* The limit used for various nested tmpfs mounts, in paricular for guests started by systemd-nspawn. +/* The limit used for various nested tmpfs mounts, in particular for guests started by systemd-nspawn. * 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25% * translates to 1M inodes. * (On the host, /tmp is configured through a .mount unit file.) */ @@ -43,7 +45,7 @@ int bind_remount_one_with_mountinfo(const char *path, unsigned long new_flags, u int mount_move_root(const char *path); -DEFINE_TRIVIAL_CLEANUP_FUNC(FILE*, endmntent); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, endmntent, NULL); #define _cleanup_endmntent_ _cleanup_(endmntentp) int mount_verbose_full( @@ -93,7 +95,9 @@ static inline char* umount_and_rmdir_and_free(char *p) { PROTECT_ERRNO; (void) umount_recursive(p, 0); (void) rmdir(p); - free(p); - return NULL; + return mfree(p); } DEFINE_TRIVIAL_CLEANUP_FUNC(char*, umount_and_rmdir_and_free); + +int bind_mount_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory); +int mount_image_in_namespace(pid_t target, const char *propagate_path, const char *incoming_path, const char *src, const char *dest, bool read_only, bool make_file_or_directory, const MountOptions *options); diff --git a/src/shared/net-condition.c b/src/shared/net-condition.c new file mode 100644 index 000000000..174bb2a7e --- /dev/null +++ b/src/shared/net-condition.c @@ -0,0 +1,428 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "condition.h" +#include "env-util.h" +#include "log.h" +#include "net-condition.h" +#include "network-util.h" +#include "socket-util.h" +#include "string-table.h" +#include "strv.h" + +void net_match_clear(NetMatch *match) { + if (!match) + return; + + match->mac = set_free_free(match->mac); + match->permanent_mac = set_free_free(match->permanent_mac); + match->path = strv_free(match->path); + match->driver = strv_free(match->driver); + match->iftype = strv_free(match->iftype); + match->ifname = strv_free(match->ifname); + match->property = strv_free(match->property); + match->wifi_iftype = strv_free(match->wifi_iftype); + match->ssid = strv_free(match->ssid); + match->bssid = set_free_free(match->bssid); +} + +bool net_match_is_empty(const NetMatch *match) { + assert(match); + + return + set_isempty(match->mac) && + set_isempty(match->permanent_mac) && + strv_isempty(match->path) && + strv_isempty(match->driver) && + strv_isempty(match->iftype) && + strv_isempty(match->ifname) && + strv_isempty(match->property) && + strv_isempty(match->wifi_iftype) && + strv_isempty(match->ssid) && + set_isempty(match->bssid); +} + +static bool net_condition_test_strv(char * const *patterns, const char *string) { + char * const *p; + bool match = false, has_positive_rule = false; + + if (strv_isempty(patterns)) + return true; + + STRV_FOREACH(p, patterns) { + const char *q = *p; + bool invert; + + invert = *q == '!'; + q += invert; + + if (!invert) + has_positive_rule = true; + + if (string && fnmatch(q, string, 0) == 0) { + if (invert) + return false; + else + match = true; + } + } + + return has_positive_rule ? match : true; +} + +static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { + if (net_condition_test_strv(patterns, ifname)) + return true; + + char * const *p; + STRV_FOREACH(p, alternative_names) + if (net_condition_test_strv(patterns, *p)) + return true; + + return false; +} + +static int net_condition_test_property(char * const *match_property, sd_device *device) { + char * const *p; + + if (strv_isempty(match_property)) + return true; + + STRV_FOREACH(p, match_property) { + _cleanup_free_ char *key = NULL; + const char *val, *dev_val; + bool invert, v; + + invert = **p == '!'; + + val = strchr(*p + invert, '='); + if (!val) + return -EINVAL; + + key = strndup(*p + invert, val - *p - invert); + if (!key) + return -ENOMEM; + + val++; + + v = device && + sd_device_get_property_value(device, key, &dev_val) >= 0 && + fnmatch(val, dev_val, 0) == 0; + + if (invert ? v : !v) + return false; + } + + return true; +} + +static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = { + [NL80211_IFTYPE_ADHOC] = "ad-hoc", + [NL80211_IFTYPE_STATION] = "station", + [NL80211_IFTYPE_AP] = "ap", + [NL80211_IFTYPE_AP_VLAN] = "ap-vlan", + [NL80211_IFTYPE_WDS] = "wds", + [NL80211_IFTYPE_MONITOR] = "monitor", + [NL80211_IFTYPE_MESH_POINT] = "mesh-point", + [NL80211_IFTYPE_P2P_CLIENT] = "p2p-client", + [NL80211_IFTYPE_P2P_GO] = "p2p-go", + [NL80211_IFTYPE_P2P_DEVICE] = "p2p-device", + [NL80211_IFTYPE_OCB] = "ocb", + [NL80211_IFTYPE_NAN] = "nan", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype); + +bool net_match_config( + const NetMatch *match, + sd_device *device, + const struct ether_addr *mac, + const struct ether_addr *permanent_mac, + const char *driver, + unsigned short iftype, + const char *ifname, + char * const *alternative_names, + enum nl80211_iftype wifi_iftype, + const char *ssid, + const struct ether_addr *bssid) { + + _cleanup_free_ char *iftype_str; + const char *path = NULL; + + assert(match); + + iftype_str = link_get_type_string(device, iftype); + + if (device) { + const char *mac_str; + + (void) sd_device_get_property_value(device, "ID_PATH", &path); + if (!driver) + (void) sd_device_get_property_value(device, "ID_NET_DRIVER", &driver); + if (!ifname) + (void) sd_device_get_sysname(device, &ifname); + if (!mac && + sd_device_get_sysattr_value(device, "address", &mac_str) >= 0) + mac = ether_aton(mac_str); + } + + if (match->mac && (!mac || !set_contains(match->mac, mac))) + return false; + + if (match->permanent_mac && + (!permanent_mac || + ether_addr_is_null(permanent_mac) || + !set_contains(match->permanent_mac, permanent_mac))) + return false; + + if (!net_condition_test_strv(match->path, path)) + return false; + + if (!net_condition_test_strv(match->driver, driver)) + return false; + + if (!net_condition_test_strv(match->iftype, iftype_str)) + return false; + + if (!net_condition_test_ifname(match->ifname, ifname, alternative_names)) + return false; + + if (!net_condition_test_property(match->property, device)) + return false; + + if (!net_condition_test_strv(match->wifi_iftype, wifi_iftype_to_string(wifi_iftype))) + return false; + + if (!net_condition_test_strv(match->ssid, ssid)) + return false; + + if (match->bssid && (!bssid || !set_contains(match->bssid, bssid))) + return false; + + return true; +} + +int config_parse_net_condition( + 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) { + + ConditionType cond = ltype; + Condition **list = data, *c; + bool negate; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *list = condition_free_list_type(*list, cond); + return 0; + } + + negate = rvalue[0] == '!'; + if (negate) + rvalue++; + + c = condition_new(cond, rvalue, false, negate); + if (!c) + return log_oom(); + + /* Drop previous assignment. */ + *list = condition_free_list_type(*list, cond); + + LIST_PREPEND(conditions, *list, c); + return 0; +} + +int config_parse_match_strv( + 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) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} + +int config_parse_match_ifnames( + 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) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, 0); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to parse interface name list, ignoring: %s", rvalue); + return 0; + } + + if (!ifname_valid_full(word, ltype)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Interface name is not valid or too long, ignoring assignment: %s", word); + continue; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} + +int config_parse_match_property( + 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) { + + const char *p = rvalue; + char ***sv = data; + bool invert; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (isempty(rvalue)) { + *sv = strv_free(*sv); + return 0; + } + + invert = *p == '!'; + p += invert; + + for (;;) { + _cleanup_free_ char *word = NULL, *k = NULL; + + r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); + if (r == 0) + return 0; + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + if (!env_assignment_is_valid(word)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid property or value, ignoring assignment: %s", word); + continue; + } + + if (invert) { + k = strjoin("!", word); + if (!k) + return log_oom(); + } else + k = TAKE_PTR(word); + + r = strv_consume(sv, TAKE_PTR(k)); + if (r < 0) + return log_oom(); + } +} diff --git a/src/shared/net-condition.h b/src/shared/net-condition.h new file mode 100644 index 000000000..8d85fc8a7 --- /dev/null +++ b/src/shared/net-condition.h @@ -0,0 +1,45 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +#include "sd-device.h" + +#include "conf-parser.h" +#include "ether-addr-util.h" +#include "set.h" + +typedef struct NetMatch { + Set *mac; + Set *permanent_mac; + char **path; + char **driver; + char **iftype; + char **ifname; + char **property; + char **wifi_iftype; + char **ssid; + Set *bssid; +} NetMatch; + +void net_match_clear(NetMatch *match); +bool net_match_is_empty(const NetMatch *match); + +bool net_match_config( + const NetMatch *match, + sd_device *device, + const struct ether_addr *mac, + const struct ether_addr *permanent_mac, + const char *driver, + unsigned short iftype, + const char *ifname, + char * const *alternative_names, + enum nl80211_iftype wifi_iftype, + const char *ssid, + const struct ether_addr *bssid); + +CONFIG_PARSER_PROTOTYPE(config_parse_net_condition); +CONFIG_PARSER_PROTOTYPE(config_parse_match_strv); +CONFIG_PARSER_PROTOTYPE(config_parse_match_ifnames); +CONFIG_PARSER_PROTOTYPE(config_parse_match_property); diff --git a/src/shared/netif-naming-scheme.h b/src/shared/netif-naming-scheme.h index 503a74ea3..28cd4e41f 100644 --- a/src/shared/netif-naming-scheme.h +++ b/src/shared/netif-naming-scheme.h @@ -42,7 +42,7 @@ typedef enum NamingSchemeFlags { NAMING_V245 = NAMING_V243 | NAMING_NSPAWN_LONG_HASH, NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT, - _NAMING_SCHEME_FLAGS_INVALID = -1, + _NAMING_SCHEME_FLAGS_INVALID = -EINVAL, } NamingSchemeFlags; typedef struct NamingScheme { diff --git a/src/shared/nscd-flush.h b/src/shared/nscd-flush.h index 5aafa9a24..dac223e65 100644 --- a/src/shared/nscd-flush.h +++ b/src/shared/nscd-flush.h @@ -1,4 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#if ENABLE_NSCD int nscd_flush_cache(char **databases); +#else +static inline void nscd_flush_cache(char **databases) {} +#endif diff --git a/src/shared/nsflags.c b/src/shared/nsflags.c index 2845041cf..b5bba8091 100644 --- a/src/shared/nsflags.c +++ b/src/shared/nsflags.c @@ -61,7 +61,7 @@ int namespace_flags_to_string(unsigned long flags, char **ret) { if ((flags & namespace_flag_map[i].flag) != namespace_flag_map[i].flag) continue; - if (!strextend_with_separator(&s, " ", namespace_flag_map[i].name, NULL)) + if (!strextend_with_separator(&s, " ", namespace_flag_map[i].name)) return -ENOMEM; } @@ -69,3 +69,11 @@ int namespace_flags_to_string(unsigned long flags, char **ret) { return 0; } + +const char *namespace_single_flag_to_string(unsigned long flag) { + for (unsigned i = 0; namespace_flag_map[i].name; i++) + if (namespace_flag_map[i].flag == flag) + return namespace_flag_map[i].name; + + return NULL; +} diff --git a/src/shared/nsflags.h b/src/shared/nsflags.h index 3d774c755..a35332dd9 100644 --- a/src/shared/nsflags.h +++ b/src/shared/nsflags.h @@ -16,10 +16,11 @@ CLONE_NEWUSER| \ CLONE_NEWUTS)) -#define NAMESPACE_FLAGS_INITIAL ((unsigned long) -1) +#define NAMESPACE_FLAGS_INITIAL ULONG_MAX int namespace_flags_from_string(const char *name, unsigned long *ret); int namespace_flags_to_string(unsigned long flags, char **ret); +const char *namespace_single_flag_to_string(unsigned long flag); struct namespace_flag_map { unsigned long flag; diff --git a/src/shared/openssl-util.c b/src/shared/openssl-util.c new file mode 100644 index 000000000..4ea72a8b2 --- /dev/null +++ b/src/shared/openssl-util.c @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "openssl-util.h" +#include "alloc-util.h" + +#if HAVE_OPENSSL +int rsa_encrypt_bytes( + EVP_PKEY *pkey, + const void *decrypted_key, + size_t decrypted_key_size, + void **ret_encrypt_key, + size_t *ret_encrypt_key_size) { + + _cleanup_(EVP_PKEY_CTX_freep) EVP_PKEY_CTX *ctx = NULL; + _cleanup_free_ void *b = NULL; + size_t l; + + ctx = EVP_PKEY_CTX_new(pkey, NULL); + if (!ctx) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to allocate public key context"); + + if (EVP_PKEY_encrypt_init(ctx) <= 0) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to initialize public key context"); + + if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to configure PKCS#1 padding"); + + if (EVP_PKEY_encrypt(ctx, NULL, &l, decrypted_key, decrypted_key_size) <= 0) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine encrypted key size"); + + b = malloc(l); + if (!b) + return -ENOMEM; + + if (EVP_PKEY_encrypt(ctx, b, &l, decrypted_key, decrypted_key_size) <= 0) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to determine encrypted key size"); + + *ret_encrypt_key = TAKE_PTR(b); + *ret_encrypt_key_size = l; + + return 0; +} + +int rsa_pkey_to_suitable_key_size( + EVP_PKEY *pkey, + size_t *ret_suitable_key_size) { + + size_t suitable_key_size; + RSA *rsa; + int bits; + + assert_se(pkey); + assert_se(ret_suitable_key_size); + + /* Analyzes the specified public key and that it is RSA. If so, will return a suitable size for a + * disk encryption key to encrypt with RSA for use in PKCS#11 security token schemes. */ + + if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) + return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "X.509 certificate does not refer to RSA key."); + + rsa = EVP_PKEY_get0_RSA(pkey); + if (!rsa) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Failed to acquire RSA public key from X.509 certificate."); + + bits = RSA_bits(rsa); + log_debug("Bits in RSA key: %i", bits); + + /* We use PKCS#1 padding for the RSA cleartext, hence let's leave some extra space for it, hence only + * generate a random key half the size of the RSA length */ + suitable_key_size = bits / 8 / 2; + + if (suitable_key_size < 1) + return log_debug_errno(SYNTHETIC_ERRNO(EIO), "Uh, RSA key size too short?"); + + *ret_suitable_key_size = suitable_key_size; + return 0; +} +#endif diff --git a/src/shared/openssl-util.h b/src/shared/openssl-util.h index 1b49834dd..0f527e74c 100644 --- a/src/shared/openssl-util.h +++ b/src/shared/openssl-util.h @@ -1,12 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include "macro.h" + #if HAVE_OPENSSL # include -DEFINE_TRIVIAL_CLEANUP_FUNC(X509*, X509_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(X509_NAME*, X509_NAME_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_PKEY_CTX*, EVP_PKEY_CTX_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(EVP_CIPHER_CTX*, EVP_CIPHER_CTX_free); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509*, X509_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(X509_NAME*, X509_NAME_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_PKEY_CTX*, EVP_PKEY_CTX_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(EVP_CIPHER_CTX*, EVP_CIPHER_CTX_free, NULL); + +int rsa_encrypt_bytes(EVP_PKEY *pkey, const void *decrypted_key, size_t decrypted_key_size, void **ret_encrypt_key, size_t *ret_encrypt_key_size); + +int rsa_pkey_to_suitable_key_size(EVP_PKEY *pkey, size_t *ret_suitable_key_size); #endif diff --git a/src/shared/os-util.h b/src/shared/os-util.h deleted file mode 100644 index 1d9b0b146..000000000 --- a/src/shared/os-util.h +++ /dev/null @@ -1,13 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include - -int path_is_os_tree(const char *path); - -int open_os_release(const char *root, char **ret_path, int *ret_fd); -int fopen_os_release(const char *root, char **ret_path, FILE **ret_file); - -int parse_os_release(const char *root, ...) _sentinel_; -int load_os_release_pairs(const char *root, char ***ret); -int load_os_release_pairs_with_prefix(const char *root, const char *prefix, char ***ret); diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h index a879054b6..ba067c9f9 100644 --- a/src/shared/output-mode.h +++ b/src/shared/output-mode.h @@ -21,7 +21,7 @@ typedef enum OutputMode { OUTPUT_CAT, OUTPUT_WITH_UNIT, _OUTPUT_MODE_MAX, - _OUTPUT_MODE_INVALID = -1 + _OUTPUT_MODE_INVALID = -EINVAL, } OutputMode; static inline bool OUTPUT_MODE_IS_JSON(OutputMode m) { diff --git a/src/shared/pager.c b/src/shared/pager.c index f689d9f28..4bbad7e37 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -37,7 +37,7 @@ static bool stderr_redirected = false; _noreturn_ static void pager_fallback(void) { int r; - r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, (uint64_t) -1, 0); + r = copy_bytes(STDIN_FILENO, STDOUT_FILENO, UINT64_MAX, 0); if (r < 0) { log_error_errno(r, "Internal pager failed: %m"); _exit(EXIT_FAILURE); @@ -262,7 +262,7 @@ int pager_open(PagerFlags flags) { if (r < 0) return r; if (r > 0) - (void) ignore_signals(SIGINT, -1); + (void) ignore_signals(SIGINT); return 1; } diff --git a/src/shared/parse-argument.c b/src/shared/parse-argument.c new file mode 100644 index 000000000..68c55a54c --- /dev/null +++ b/src/shared/parse-argument.c @@ -0,0 +1,123 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "format-table.h" +#include "parse-argument.h" +#include "path-util.h" +#include "signal-util.h" +#include "stdio-util.h" +#include "string-table.h" +#include "string-util.h" + +/* All functions in this file emit warnings. */ + +int parse_boolean_argument(const char *optname, const char *s, bool *ret) { + int r; + + /* Returns the result through *ret and the return value. */ + + if (s) { + r = parse_boolean(s); + if (r < 0) + return log_error_errno(r, "Failed to parse boolean argument to %s: %s.", optname, s); + + if (ret) + *ret = r; + return r; + } else { + /* s may be NULL. This is controlled by getopt_long() parameters. */ + if (ret) + *ret = true; + return true; + } +} + +int parse_json_argument(const char *s, JsonFormatFlags *ret) { + assert(s); + assert(ret); + + if (streq(s, "pretty")) + *ret = JSON_FORMAT_PRETTY|JSON_FORMAT_COLOR_AUTO; + else if (streq(s, "short")) + *ret = JSON_FORMAT_NEWLINE; + else if (streq(s, "off")) + *ret = JSON_FORMAT_OFF; + else if (streq(s, "help")) { + puts("pretty\n" + "short\n" + "off"); + return 0; /* 0 means → we showed a brief help, exit now */ + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown argument to --json= switch: %s", s); + + return 1; /* 1 means → properly parsed */ +} + +int parse_path_argument(const char *path, bool suppress_root, char **arg) { + char *p; + int r; + + /* + * This function is intended to be used in command line parsers, to handle paths that are passed + * in. It makes the path absolute, and reduces it to NULL if omitted or root (the latter optionally). + * + * NOTE THAT THIS WILL FREE THE PREVIOUS ARGUMENT POINTER ON SUCCESS! + * Hence, do not pass in uninitialized pointers. + */ + + if (isempty(path)) { + *arg = mfree(*arg); + return 0; + } + + r = path_make_absolute_cwd(path, &p); + if (r < 0) + return log_error_errno(r, "Failed to parse path \"%s\" and make it absolute: %m", path); + + path_simplify(p, false); + if (suppress_root && empty_or_root(p)) + p = mfree(p); + + return free_and_replace(*arg, p); +} + +int parse_signal_argument(const char *s, int *ret) { + int r; + + assert(s); + assert(ret); + + if (streq(s, "help")) { + DUMP_STRING_TABLE(signal, int, _NSIG); + return 0; + } + + if (streq(s, "list")) { + _cleanup_(table_unrefp) Table *table = NULL; + + table = table_new("signal", "name"); + if (!table) + return log_oom(); + + for (int i = 1; i < _NSIG; i++) { + r = table_add_many( + table, + TABLE_INT, i, + TABLE_SIGNAL, i); + if (r < 0) + return table_log_add_error(r); + } + + r = table_print(table, NULL); + if (r < 0) + return table_log_print_error(r); + + return 0; + } + + r = signal_from_string(s); + if (r < 0) + return log_error_errno(r, "Failed to parse signal string \"%s\".", s); + + *ret = r; + return 1; /* work to do */ +} diff --git a/src/shared/parse-argument.h b/src/shared/parse-argument.h new file mode 100644 index 000000000..adad65e90 --- /dev/null +++ b/src/shared/parse-argument.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "json.h" + +int parse_boolean_argument(const char *optname, const char *s, bool *ret); +int parse_json_argument(const char *s, JsonFormatFlags *ret); +int parse_path_argument(const char *path, bool suppress_root, char **arg); +int parse_signal_argument(const char *s, int *ret); diff --git a/src/shared/pkcs11-util.c b/src/shared/pkcs11-util.c index e74f0be26..27c209cdf 100644 --- a/src/shared/pkcs11-util.c +++ b/src/shared/pkcs11-util.c @@ -5,6 +5,7 @@ #include "ask-password-api.h" #include "escape.h" #include "fd-util.h" +#include "format-table.h" #include "io-util.h" #include "memory-util.h" #if HAVE_OPENSSL @@ -671,7 +672,6 @@ int pkcs11_token_acquire_rng( CK_SESSION_HANDLE session) { _cleanup_free_ void *buffer = NULL; - _cleanup_close_ int fd = -1; size_t rps; CK_RV rv; int r; @@ -696,11 +696,7 @@ int pkcs11_token_acquire_rng( return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Failed to generate RNG data on security token: %s", p11_kit_strerror(rv)); - fd = open("/dev/urandom", O_WRONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return log_debug_errno(errno, "Failed to open /dev/urandom for writing: %m"); - - r = loop_write(fd, buffer, rps, false); + r = random_write_entropy(-1, buffer, rps, false); if (r < 0) return log_debug_errno(r, "Failed to write PKCS#11 acquired random data to /dev/urandom: %m"); @@ -929,4 +925,229 @@ int pkcs11_find_token( return -EAGAIN; } +#if HAVE_OPENSSL +struct pkcs11_acquire_certificate_callback_data { + char *pin_used; + X509 *cert; + const char *askpw_friendly_name, *askpw_icon_name; +}; + +static void pkcs11_acquire_certificate_callback_data_release(struct pkcs11_acquire_certificate_callback_data *data) { + erase_and_free(data->pin_used); + X509_free(data->cert); +} + +static int pkcs11_acquire_certificate_callback( + CK_FUNCTION_LIST *m, + CK_SESSION_HANDLE session, + CK_SLOT_ID slot_id, + const CK_SLOT_INFO *slot_info, + const CK_TOKEN_INFO *token_info, + P11KitUri *uri, + void *userdata) { + + _cleanup_(erase_and_freep) char *pin_used = NULL; + struct pkcs11_acquire_certificate_callback_data *data = userdata; + CK_OBJECT_HANDLE object; + int r; + + assert(m); + assert(slot_info); + assert(token_info); + assert(uri); + assert(data); + + /* Called for every token matching our URI */ + + r = pkcs11_token_login(m, session, slot_id, token_info, data->askpw_friendly_name, data->askpw_icon_name, "pkcs11-pin", UINT64_MAX, &pin_used); + if (r < 0) + return r; + + r = pkcs11_token_find_x509_certificate(m, session, uri, &object); + if (r < 0) + return r; + + r = pkcs11_token_read_x509_certificate(m, session, object, &data->cert); + if (r < 0) + return r; + + /* Let's read some random data off the token and write it to the kernel pool before we generate our + * random key from it. This way we can claim the quality of the RNG is at least as good as the + * kernel's and the token's pool */ + (void) pkcs11_token_acquire_rng(m, session); + + data->pin_used = TAKE_PTR(pin_used); + return 1; +} + +int pkcs11_acquire_certificate( + const char *uri, + const char *askpw_friendly_name, + const char *askpw_icon_name, + X509 **ret_cert, + char **ret_pin_used) { + + _cleanup_(pkcs11_acquire_certificate_callback_data_release) struct pkcs11_acquire_certificate_callback_data data = { + .askpw_friendly_name = askpw_friendly_name, + .askpw_icon_name = askpw_icon_name, + }; + int r; + + assert(uri); + assert(ret_cert); + + r = pkcs11_find_token(uri, pkcs11_acquire_certificate_callback, &data); + if (r == -EAGAIN) /* pkcs11_find_token() doesn't log about this error, but all others */ + return log_error_errno(SYNTHETIC_ERRNO(ENXIO), + "Specified PKCS#11 token with URI '%s' not found.", + uri); + if (r < 0) + return r; + + *ret_cert = TAKE_PTR(data.cert); + + if (ret_pin_used) + *ret_pin_used = TAKE_PTR(data.pin_used); + + return 0; +} #endif + +static int list_callback( + CK_FUNCTION_LIST *m, + CK_SESSION_HANDLE session, + CK_SLOT_ID slot_id, + const CK_SLOT_INFO *slot_info, + const CK_TOKEN_INFO *token_info, + P11KitUri *uri, + void *userdata) { + + _cleanup_free_ char *token_uri_string = NULL, *token_label = NULL, *token_manufacturer_id = NULL, *token_model = NULL; + _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; + Table *t = userdata; + int uri_result, r; + + assert(slot_info); + assert(token_info); + + /* We only care about hardware devices here with a token inserted. Let's filter everything else + * out. (Note that the user can explicitly specify non-hardware tokens if they like, but during + * enumeration we'll filter those, since software tokens are typically the system certificate store + * and such, and it's typically not what people want to bind their home directories to.) */ + if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT)) + return -EAGAIN; + + token_label = pkcs11_token_label(token_info); + if (!token_label) + return log_oom(); + + token_manufacturer_id = pkcs11_token_manufacturer_id(token_info); + if (!token_manufacturer_id) + return log_oom(); + + token_model = pkcs11_token_model(token_info); + if (!token_model) + return log_oom(); + + token_uri = uri_from_token_info(token_info); + if (!token_uri) + return log_oom(); + + uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, &token_uri_string); + if (uri_result != P11_KIT_URI_OK) + return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result)); + + r = table_add_many( + t, + TABLE_STRING, token_uri_string, + TABLE_STRING, token_label, + TABLE_STRING, token_manufacturer_id, + TABLE_STRING, token_model); + if (r < 0) + return table_log_add_error(r); + + return -EAGAIN; /* keep scanning */ +} +#endif + +int pkcs11_list_tokens(void) { +#if HAVE_P11KIT + _cleanup_(table_unrefp) Table *t = NULL; + int r; + + t = table_new("uri", "label", "manufacturer", "model"); + if (!t) + return log_oom(); + + r = pkcs11_find_token(NULL, list_callback, t); + if (r < 0 && r != -EAGAIN) + return r; + + if (table_get_rows(t) <= 1) { + log_info("No suitable PKCS#11 tokens found."); + return 0; + } + + r = table_print(t, stdout); + if (r < 0) + return log_error_errno(r, "Failed to show device table: %m"); + + return 0; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PKCS#11 tokens not supported on this build."); +#endif +} + +#if HAVE_P11KIT +static int auto_callback( + CK_FUNCTION_LIST *m, + CK_SESSION_HANDLE session, + CK_SLOT_ID slot_id, + const CK_SLOT_INFO *slot_info, + const CK_TOKEN_INFO *token_info, + P11KitUri *uri, + void *userdata) { + + _cleanup_(p11_kit_uri_freep) P11KitUri *token_uri = NULL; + char **t = userdata; + int uri_result; + + assert(slot_info); + assert(token_info); + + if (!FLAGS_SET(token_info->flags, CKF_HW_SLOT|CKF_TOKEN_PRESENT)) + return -EAGAIN; + + if (*t) + return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), + "More than one suitable PKCS#11 token found."); + + token_uri = uri_from_token_info(token_info); + if (!token_uri) + return log_oom(); + + uri_result = p11_kit_uri_format(token_uri, P11_KIT_URI_FOR_ANY, t); + if (uri_result != P11_KIT_URI_OK) + return log_warning_errno(SYNTHETIC_ERRNO(EAGAIN), "Failed to format slot URI: %s", p11_kit_uri_message(uri_result)); + + return 0; +} +#endif + +int pkcs11_find_token_auto(char **ret) { +#if HAVE_P11KIT + int r; + + r = pkcs11_find_token(NULL, auto_callback, ret); + if (r == -EAGAIN) + return log_error_errno(SYNTHETIC_ERRNO(ENODEV), "No suitable PKCS#11 tokens found."); + if (r < 0) + return r; + + return 0; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "PKCS#11 tokens not supported on this build."); +#endif +} diff --git a/src/shared/pkcs11-util.h b/src/shared/pkcs11-util.h index f14607de8..f32ab3042 100644 --- a/src/shared/pkcs11-util.h +++ b/src/shared/pkcs11-util.h @@ -21,8 +21,8 @@ P11KitUri *uri_from_module_info(const CK_INFO *info); P11KitUri *uri_from_slot_info(const CK_SLOT_INFO *slot_info); P11KitUri *uri_from_token_info(const CK_TOKEN_INFO *token_info); -DEFINE_TRIVIAL_CLEANUP_FUNC(P11KitUri*, p11_kit_uri_free); -DEFINE_TRIVIAL_CLEANUP_FUNC(CK_FUNCTION_LIST**, p11_kit_modules_finalize_and_release); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(P11KitUri*, p11_kit_uri_free, NULL); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(CK_FUNCTION_LIST**, p11_kit_modules_finalize_and_release, NULL); CK_RV pkcs11_get_slot_list_malloc(CK_FUNCTION_LIST *m, CK_SLOT_ID **ret_slotids, CK_ULONG *ret_n_slotids); @@ -44,4 +44,12 @@ int pkcs11_token_acquire_rng(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session); typedef int (*pkcs11_find_token_callback_t)(CK_FUNCTION_LIST *m, CK_SESSION_HANDLE session, CK_SLOT_ID slotid, const CK_SLOT_INFO *slot_info, const CK_TOKEN_INFO *token_info, P11KitUri *uri, void *userdata); int pkcs11_find_token(const char *pkcs11_uri, pkcs11_find_token_callback_t callback, void *userdata); + +#if HAVE_OPENSSL +int pkcs11_acquire_certificate(const char *uri, const char *askpw_friendly_name, const char *askpw_icon_name, X509 **ret_cert, char **ret_pin_used); #endif + +#endif + +int pkcs11_list_tokens(void); +int pkcs11_find_token_auto(char **ret); diff --git a/src/shared/pretty-print.c b/src/shared/pretty-print.c index ca5b25a7a..0f02f3276 100644 --- a/src/shared/pretty-print.c +++ b/src/shared/pretty-print.c @@ -21,10 +21,6 @@ bool urlify_enabled(void) { static int cached_urlify_enabled = -1; - /* Unfortunately 'less' doesn't support links like this yet 😭, hence let's disable this as long as there's a - * pager in effect. Let's drop this check as soon as less got fixed a and enough time passed so that it's safe - * to assume that a link-enabled 'less' version has hit most installations. */ - if (cached_urlify_enabled < 0) { int val; @@ -32,7 +28,7 @@ bool urlify_enabled(void) { if (val >= 0) cached_urlify_enabled = val; else - cached_urlify_enabled = colors_enabled() && !pager_have(); + cached_urlify_enabled = colors_enabled(); } return cached_urlify_enabled; diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 754b4f5a9..4c309f925 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -646,24 +646,24 @@ int pty_forward_set_width_height(PTYForward *f, unsigned width, unsigned height) assert(f); - if (width == (unsigned) -1 && height == (unsigned) -1) + if (width == UINT_MAX && height == UINT_MAX) return 0; /* noop */ - if (width != (unsigned) -1 && + if (width != UINT_MAX && (width == 0 || width > USHRT_MAX)) return -ERANGE; - if (height != (unsigned) -1 && + if (height != UINT_MAX && (height == 0 || height > USHRT_MAX)) return -ERANGE; - if (width == (unsigned) -1 || height == (unsigned) -1) { + if (width == UINT_MAX || height == UINT_MAX) { if (ioctl(f->master, TIOCGWINSZ, &ws) < 0) return -errno; - if (width != (unsigned) -1) + if (width != UINT_MAX) ws.ws_col = width; - if (height != (unsigned) -1) + if (height != UINT_MAX) ws.ws_row = height; } else ws = (struct winsize) { diff --git a/src/shared/pwquality-util.c b/src/shared/pwquality-util.c index 4000bef89..5bd33eee4 100644 --- a/src/shared/pwquality-util.c +++ b/src/shared/pwquality-util.c @@ -38,14 +38,14 @@ int dlopen_pwquality(void) { r = dlsym_many_and_warn( dl, LOG_DEBUG, - &sym_pwquality_check, "pwquality_check", - &sym_pwquality_default_settings, "pwquality_default_settings", - &sym_pwquality_free_settings, "pwquality_free_settings", - &sym_pwquality_generate, "pwquality_generate", - &sym_pwquality_get_str_value, "pwquality_get_str_value", - &sym_pwquality_read_config, "pwquality_read_config", - &sym_pwquality_set_int_value, "pwquality_set_int_value", - &sym_pwquality_strerror, "pwquality_strerror", + DLSYM_ARG(pwquality_check), + DLSYM_ARG(pwquality_default_settings), + DLSYM_ARG(pwquality_free_settings), + DLSYM_ARG(pwquality_generate), + DLSYM_ARG(pwquality_get_str_value), + DLSYM_ARG(pwquality_read_config), + DLSYM_ARG(pwquality_set_int_value), + DLSYM_ARG(pwquality_strerror), NULL); if (r < 0) return r; diff --git a/src/shared/pwquality-util.h b/src/shared/pwquality-util.h index de288bb01..877f439d1 100644 --- a/src/shared/pwquality-util.h +++ b/src/shared/pwquality-util.h @@ -19,7 +19,7 @@ extern const char* (*sym_pwquality_strerror)(char *buf, size_t len, int errcode, int dlopen_pwquality(void); -DEFINE_TRIVIAL_CLEANUP_FUNC(pwquality_settings_t*, sym_pwquality_free_settings); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(pwquality_settings_t*, sym_pwquality_free_settings, NULL); void pwq_maybe_disable_dictionary(pwquality_settings_t *pwq); int pwq_allocate_context(pwquality_settings_t **ret); diff --git a/src/shared/qrcode-util.c b/src/shared/qrcode-util.c index 7050e186b..6b9ff8531 100644 --- a/src/shared/qrcode-util.c +++ b/src/shared/qrcode-util.c @@ -5,12 +5,45 @@ #if HAVE_QRENCODE #include +#include "alloc-util.h" #include "dlfcn-util.h" #include "locale-util.h" #include "terminal-util.h" #define ANSI_WHITE_ON_BLACK "\033[40;37;1m" +static void *qrcode_dl = NULL; + +static QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) = NULL; +static void (*sym_QRcode_free)(QRcode *qrcode) = NULL; + +int dlopen_qrencode(void) { + _cleanup_(dlclosep) void *dl = NULL; + int r; + + if (qrcode_dl) + return 0; /* Already loaded */ + + dl = dlopen("libqrencode.so.4", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "libqrcode support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + DLSYM_ARG(QRcode_encodeString), + DLSYM_ARG(QRcode_free), + NULL); + if (r < 0) + return r; + + /* Note that we never release the reference here, because there's no real reason to, after all this + * was traditionally a regular shared library dependency which lives forever too. */ + qrcode_dl = TAKE_PTR(dl); + return 1; +} + static void print_border(FILE *output, unsigned width) { /* Four rows of border */ for (unsigned y = 0; y < 4; y += 2) { @@ -65,9 +98,6 @@ static void write_qrcode(FILE *output, QRcode *qr) { } int print_qrcode(FILE *out, const char *header, const char *string) { - QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive); - void (*sym_QRcode_free)(QRcode *qrcode); - _cleanup_(dlclosep) void *dl = NULL; QRcode* qr; int r; @@ -76,17 +106,7 @@ int print_qrcode(FILE *out, const char *header, const char *string) { if (!is_locale_utf8() || !colors_enabled()) return -EOPNOTSUPP; - dl = dlopen("libqrencode.so.4", RTLD_LAZY); - if (!dl) - return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), - "QRCODE support is not installed: %s", dlerror()); - - r = dlsym_many_and_warn( - dl, - LOG_DEBUG, - &sym_QRcode_encodeString, "QRcode_encodeString", - &sym_QRcode_free, "QRcode_free", - NULL); + r = dlopen_qrencode(); if (r < 0) return r; diff --git a/src/shared/qrcode-util.h b/src/shared/qrcode-util.h index 6fc45c93d..b64ecce80 100644 --- a/src/shared/qrcode-util.h +++ b/src/shared/qrcode-util.h @@ -5,6 +5,8 @@ #include #if HAVE_QRENCODE +int dlopen_qrencode(void); + int print_qrcode(FILE *out, const char *header, const char *string); #else static inline int print_qrcode(FILE *out, const char *header, const char *string) { diff --git a/src/shared/resolve-util.c b/src/shared/resolve-util.c index 1023b6249..6541d231e 100644 --- a/src/shared/resolve-util.c +++ b/src/shared/resolve-util.c @@ -33,7 +33,7 @@ bool dns_server_address_valid(int family, const union in_addr_union *sa) { /* Refuses the 0 IP addresses as well as 127.0.0.53 (which is our own DNS stub) */ - if (in_addr_is_null(family, sa)) + if (!in_addr_is_set(family, sa)) return false; if (family == AF_INET && sa->in.s_addr == htobe32(INADDR_DNS_STUB)) diff --git a/src/shared/resolve-util.h b/src/shared/resolve-util.h index 4ea24a60b..c4d927536 100644 --- a/src/shared/resolve-util.h +++ b/src/shared/resolve-util.h @@ -15,7 +15,7 @@ enum DnsCacheMode { DNS_CACHE_MODE_YES, DNS_CACHE_MODE_NO_NEGATIVE, _DNS_CACHE_MODE_MAX, - _DNS_CACHE_MODE_INVALID = 1 + _DNS_CACHE_MODE_INVALID = -EINVAL, }; typedef enum ResolveSupport ResolveSupport; @@ -27,7 +27,7 @@ enum ResolveSupport { RESOLVE_SUPPORT_YES, RESOLVE_SUPPORT_RESOLVE, _RESOLVE_SUPPORT_MAX, - _RESOLVE_SUPPORT_INVALID = -1 + _RESOLVE_SUPPORT_INVALID = -EINVAL, }; enum DnssecMode { @@ -45,7 +45,7 @@ enum DnssecMode { DNSSEC_YES, _DNSSEC_MODE_MAX, - _DNSSEC_MODE_INVALID = -1 + _DNSSEC_MODE_INVALID = -EINVAL, }; enum DnsOverTlsMode { @@ -60,7 +60,7 @@ enum DnsOverTlsMode { DNS_OVER_TLS_YES, _DNS_OVER_TLS_MODE_MAX, - _DNS_OVER_TLS_MODE_INVALID = -1 + _DNS_OVER_TLS_MODE_INVALID = -EINVAL, }; CONFIG_PARSER_PROTOTYPE(config_parse_resolve_support); diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index ccae9d4f1..9813d82f9 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -23,7 +23,8 @@ #include "string-util.h" #include "strv.h" -const uint32_t seccomp_local_archs[] = { +/* This array will be modified at runtime as seccomp_restrict_archs is called. */ +uint32_t seccomp_local_archs[] = { /* Note: always list the native arch we are compiled as last, so that users can deny-list seccomp(), but our own calls to it still succeed */ @@ -94,7 +95,7 @@ const uint32_t seccomp_local_archs[] = { #elif defined(__s390__) SCMP_ARCH_S390, #endif - (uint32_t) -1 + SECCOMP_LOCAL_ARCH_END }; const char* seccomp_arch_to_string(uint32_t c) { @@ -1058,14 +1059,14 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter return 0; } -int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action, bool log_missing) { +int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* filter, uint32_t action, bool log_missing) { uint32_t arch; int r; - /* Similar to seccomp_load_syscall_filter_set(), but takes a raw Set* of syscalls, instead of a - * SyscallFilterSet* table. */ + /* Similar to seccomp_load_syscall_filter_set(), but takes a raw Hashmap* of syscalls, instead + * of a SyscallFilterSet* table. */ - if (hashmap_isempty(set) && default_action == SCMP_ACT_ALLOW) + if (hashmap_isempty(filter) && default_action == SCMP_ACT_ALLOW) return 0; SECCOMP_FOREACH_LOCAL_ARCH(arch) { @@ -1078,7 +1079,7 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u if (r < 0) return r; - HASHMAP_FOREACH_KEY(val, syscall_id, set) { + HASHMAP_FOREACH_KEY(val, syscall_id, filter) { uint32_t a = action; int id = PTR_TO_INT(syscall_id) - 1; int error = PTR_TO_INT(val); @@ -1089,12 +1090,13 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u else if (action == SCMP_ACT_LOG) a = SCMP_ACT_LOG; #endif - else if (action != SCMP_ACT_ALLOW && error >= 0) + else if (error >= 0) a = SCMP_ACT_ERRNO(error); r = seccomp_rule_add_exact(seccomp, a, id, 0); if (r < 0) { - /* If the system call is not known on this architecture, then that's fine, let's ignore it */ + /* If the system call is not known on this architecture, then that's + * fine, let's ignore it */ _cleanup_free_ char *n = NULL; bool ignore; @@ -1112,7 +1114,8 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, u if (ERRNO_IS_SECCOMP_FATAL(r)) return r; if (r < 0) - log_debug_errno(r, "Failed to install filter set for architecture %s, skipping: %m", seccomp_arch_to_string(arch)); + log_debug_errno(r, "Failed to install systemc call filter for architecture %s, skipping: %m", + seccomp_arch_to_string(arch)); } return 0; @@ -1132,16 +1135,19 @@ int seccomp_parse_syscall_filter( assert(name); assert(filter); + if (!FLAGS_SET(flags, SECCOMP_PARSE_INVERT) && errno_num >= 0) + return -EINVAL; + if (name[0] == '@') { const SyscallFilterSet *set; const char *i; set = syscall_filter_set_find(name); if (!set) { - if (!(flags & SECCOMP_PARSE_PERMISSIVE)) + if (!FLAGS_SET(flags, SECCOMP_PARSE_PERMISSIVE)) return -EINVAL; - log_syntax(unit, flags & SECCOMP_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0, + log_syntax(unit, FLAGS_SET(flags, SECCOMP_PARSE_LOG) ? LOG_WARNING : LOG_DEBUG, filename, line, 0, "Unknown system call group, ignoring: %s", name); return 0; } @@ -1160,22 +1166,24 @@ int seccomp_parse_syscall_filter( id = seccomp_syscall_resolve_name(name); if (id == __NR_SCMP_ERROR) { - if (!(flags & SECCOMP_PARSE_PERMISSIVE)) + if (!FLAGS_SET(flags, SECCOMP_PARSE_PERMISSIVE)) return -EINVAL; - log_syntax(unit, flags & SECCOMP_PARSE_LOG ? LOG_WARNING : LOG_DEBUG, filename, line, 0, + log_syntax(unit, FLAGS_SET(flags, SECCOMP_PARSE_LOG) ? LOG_WARNING : LOG_DEBUG, filename, line, 0, "Failed to parse system call, ignoring: %s", name); return 0; } - /* If we previously wanted to forbid a syscall and now - * we want to allow it, then remove it from the list. */ - if (!(flags & SECCOMP_PARSE_INVERT) == !!(flags & SECCOMP_PARSE_ALLOW_LIST)) { + /* If we previously wanted to forbid a syscall and now we want to allow it, then remove + * it from the list. The entries in allow-list with non-negative error value will be + * handled with SCMP_ACT_ERRNO() instead of the default action. */ + if (!FLAGS_SET(flags, SECCOMP_PARSE_INVERT) == FLAGS_SET(flags, SECCOMP_PARSE_ALLOW_LIST) || + (FLAGS_SET(flags, SECCOMP_PARSE_INVERT | SECCOMP_PARSE_ALLOW_LIST) && errno_num >= 0)) { r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num)); if (r < 0) switch (r) { case -ENOMEM: - return flags & SECCOMP_PARSE_LOG ? log_oom() : -ENOMEM; + return FLAGS_SET(flags, SECCOMP_PARSE_LOG) ? log_oom() : -ENOMEM; case -EEXIST: assert_se(hashmap_update(filter, INT_TO_PTR(id + 1), INT_TO_PTR(errno_num)) == 0); break; @@ -1758,8 +1766,8 @@ int seccomp_memory_deny_write_execute(void) { int seccomp_restrict_archs(Set *archs) { _cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL; - void *id; int r; + bool blocked_new = false; /* This installs a filter with no rules, but that restricts the system call architectures to the specified * list. @@ -1775,24 +1783,36 @@ int seccomp_restrict_archs(Set *archs) { if (!seccomp) return -ENOMEM; - SET_FOREACH(id, archs) { - r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1); - if (r < 0 && r != -EEXIST) - return r; + for (unsigned i = 0; seccomp_local_archs[i] != SECCOMP_LOCAL_ARCH_END; ++i) { + uint32_t arch = seccomp_local_archs[i]; + + /* That architecture might have already been blocked by a previous call to seccomp_restrict_archs. */ + if (arch == SECCOMP_LOCAL_ARCH_BLOCKED) + continue; + + bool block = !set_contains(archs, UINT32_TO_PTR(arch + 1)); + + /* The vdso for x32 assumes that x86-64 syscalls are available. Let's allow them, since x32 + * x32 syscalls should basically match x86-64 for everything except the pointer type. + * The important thing is that you can block the old 32-bit x86 syscalls. + * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850047 */ + if (block && arch == SCMP_ARCH_X86_64 && seccomp_arch_native() == SCMP_ARCH_X32) + block = !set_contains(archs, UINT32_TO_PTR(SCMP_ARCH_X32 + 1)); + + if (block) { + seccomp_local_archs[i] = SECCOMP_LOCAL_ARCH_BLOCKED; + blocked_new = true; + } else { + r = seccomp_arch_add(seccomp, arch); + if (r < 0 && r != -EEXIST) + return r; + } } - /* The vdso for x32 assumes that x86-64 syscalls are available. Let's allow them, since x32 - * x32 syscalls should basically match x86-64 for everything except the pointer type. - * The important thing is that you can block the old 32-bit x86 syscalls. - * https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=850047 */ - - if (seccomp_arch_native() == SCMP_ARCH_X32 || - set_contains(archs, UINT32_TO_PTR(SCMP_ARCH_X32 + 1))) { - - r = seccomp_arch_add(seccomp, SCMP_ARCH_X86_64); - if (r < 0 && r != -EEXIST) - return r; - } + /* All architectures that will be blocked by the seccomp program were + * already blocked. */ + if (!blocked_new) + return 0; r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0); if (r < 0) @@ -2066,10 +2086,12 @@ static int seccomp_restrict_sxid(scmp_filter_ctx seccomp, mode_t m) { /* The new openat2() system call can't be filtered sensibly, since it moves the flags parameter into * an indirect structure. Let's block it entirely for now. That should be a reasonably OK thing to do * for now, since openat2() is very new and code generally needs fallback logic anyway to be - * compatible with kernels that are not absolutely recent. */ + * compatible with kernels that are not absolutely recent. We would normally return EPERM for a + * policy check, but this isn't strictly a policy check. Instead, we return ENOSYS to force programs + * to call open() or openat() instead. We can properly enforce policy for those functions. */ r = seccomp_rule_add_exact( seccomp, - SCMP_ACT_ERRNO(EPERM), + SCMP_ACT_ERRNO(ENOSYS), SCMP_SYS(openat2), 0); if (r < 0) @@ -2138,3 +2160,41 @@ uint32_t scmp_act_kill_process(void) { return SCMP_ACT_KILL; /* same as SCMP_ACT_KILL_THREAD */ } + +int parse_syscall_and_errno(const char *in, char **name, int *error) { + _cleanup_free_ char *n = NULL; + char *p; + int e = -1; + + assert(in); + assert(name); + assert(error); + + /* + * This parse "syscall:errno" like "uname:EILSEQ", "@sync:255". + * If errno is omitted, then error is set to -1. + * Empty syscall name is not allowed. + * Here, we do not check that the syscall name is valid or not. + */ + + p = strchr(in, ':'); + if (p) { + e = seccomp_parse_errno_or_action(p + 1); + if (e < 0) + return e; + + n = strndup(in, p - in); + } else + n = strdup(in); + + if (!n) + return -ENOMEM; + + if (isempty(n)) + return -EINVAL; + + *error = e; + *name = TAKE_PTR(n); + + return 0; +} diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 610597127..b3d25c9f3 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -100,12 +100,20 @@ int seccomp_lock_personality(unsigned long personality); int seccomp_protect_hostname(void); int seccomp_restrict_suid_sgid(void); -extern const uint32_t seccomp_local_archs[]; +extern uint32_t seccomp_local_archs[]; + +#define SECCOMP_LOCAL_ARCH_END UINT32_MAX + +/* Note: 0 is safe to use here because although SCMP_ARCH_NATIVE is 0, it would + * never be in the seccomp_local_archs array anyway so we can use it as a + * marker. */ +#define SECCOMP_LOCAL_ARCH_BLOCKED 0 #define SECCOMP_FOREACH_LOCAL_ARCH(arch) \ for (unsigned _i = ({ (arch) = seccomp_local_archs[0]; 0; }); \ - seccomp_local_archs[_i] != (uint32_t) -1; \ - (arch) = seccomp_local_archs[++_i]) + (arch) != SECCOMP_LOCAL_ARCH_END; \ + (arch) = seccomp_local_archs[++_i]) \ + if ((arch) != SECCOMP_LOCAL_ARCH_BLOCKED) /* EACCES: does not have the CAP_SYS_ADMIN or no_new_privs == 1 * ENOMEM: out of memory, failed to allocate space for a libseccomp structure, or would exceed a defined constant @@ -113,7 +121,7 @@ extern const uint32_t seccomp_local_archs[]; #define ERRNO_IS_SECCOMP_FATAL(r) \ IN_SET(abs(r), EPERM, EACCES, ENOMEM, EFAULT) -DEFINE_TRIVIAL_CLEANUP_FUNC(scmp_filter_ctx, seccomp_release); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(scmp_filter_ctx, seccomp_release, NULL); int parse_syscall_archs(char **l, Set **ret_archs); @@ -140,3 +148,5 @@ static inline const char *seccomp_errno_or_action_to_string(int num) { return "kill"; return errno_to_name(num); } + +int parse_syscall_and_errno(const char *in, char **name, int *error); diff --git a/src/shared/serialize.c b/src/shared/serialize.c index 45f57d6a5..23aac3ef5 100644 --- a/src/shared/serialize.c +++ b/src/shared/serialize.c @@ -187,11 +187,10 @@ int deserialize_environment(const char *value, char ***list) { if (r < 0) return log_error_errno(r, "Failed to unescape: %m"); - r = strv_env_replace(list, unescaped); + r = strv_env_replace_consume(list, TAKE_PTR(unescaped)); if (r < 0) return log_error_errno(r, "Failed to append environment variable: %m"); - unescaped = NULL; /* now part of 'list' */ return 0; } diff --git a/src/shared/specifier.c b/src/shared/specifier.c index 86731f8cd..24e878180 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -203,7 +203,7 @@ static int specifier_os_release_common(const char *field, char **ret) { char *t = NULL; int r; - r = parse_os_release(NULL, field, &t, NULL); + r = parse_os_release(NULL, field, &t); if (r < 0) return r; if (!t) { diff --git a/src/shared/test-tables.h b/src/shared/test-tables.h index bb8177b64..3f20318db 100644 --- a/src/shared/test-tables.h +++ b/src/shared/test-tables.h @@ -1,44 +1,43 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once +#include +#include #include #include #include -typedef const char* (*lookup_t)(int); -typedef int (*reverse_t)(const char*); +#include "string-util.h" -static inline void _test_table(const char *name, - lookup_t lookup, - reverse_t reverse, - int size, - bool sparse) { - int i, boring = 0; - - for (i = -1; i < size + 1; i++) { - const char* val = lookup(i); - int rev; - - if (val) { - rev = reverse(val); - boring = 0; - } else { - rev = reverse("--no-such--value----"); - boring += i >= 0; - } - - if (boring < 1 || i == size) - printf("%s: %d → %s → %d\n", name, i, val, rev); - else if (boring == 1) - printf("%*s ...\n", (int) strlen(name), ""); - - assert_se(!(i >= 0 && i < size ? - sparse ? rev != i && rev != -1 : val == NULL || rev != i : - val != NULL || rev != -1)); +#define _test_table(name, lookup, reverse, size, sparse) \ + for (int64_t _i = -EINVAL, _boring = 0; _i < size + 1; _i++) { \ + const char* _val; \ + int64_t _rev; \ + \ + _val = lookup(_i); \ + if (_val) { \ + _rev = reverse(_val); \ + _boring = 0; \ + } else { \ + _rev = reverse("--no-such--value----"); \ + _boring += _i >= 0; \ + } \ + if (_boring == 0 || _i == size) \ + printf("%s: %" PRIi64 " → %s → %" PRIi64 "\n", name, _i, strnull(_val), _rev); \ + else if (_boring == 1) \ + printf("%*s ...\n", (int) strlen(name), ""); \ + \ + if (_i >= 0 && _i < size) { \ + if (sparse) \ + assert_se(_rev == _i || _rev == -EINVAL); \ + else \ + assert_se(_val && _rev == _i); \ + } else \ + assert_se(!_val && _rev == -EINVAL); \ } -} -#define test_table(lower, upper) \ +#define test_table(lower, upper) \ _test_table(STRINGIFY(lower), lower##_to_string, lower##_from_string, _##upper##_MAX, false) -#define test_table_sparse(lower, upper) \ +#define test_table_sparse(lower, upper) \ _test_table(STRINGIFY(lower), lower##_to_string, lower##_from_string, _##upper##_MAX, true) diff --git a/src/shared/tpm2-util.c b/src/shared/tpm2-util.c new file mode 100644 index 000000000..8a0f45c2d --- /dev/null +++ b/src/shared/tpm2-util.c @@ -0,0 +1,998 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "extract-word.h" +#include "parse-util.h" +#include "tpm2-util.h" + +#if HAVE_TPM2 +#include "alloc-util.h" +#include "dirent-util.h" +#include "dlfcn-util.h" +#include "fd-util.h" +#include "format-table.h" +#include "fs-util.h" +#include "hexdecoct.h" +#include "memory-util.h" +#include "random-util.h" +#include "time-util.h" + +static void *libtss2_esys_dl = NULL; +static void *libtss2_rc_dl = NULL; +static void *libtss2_mu_dl = NULL; + +TSS2_RC (*sym_Esys_Create)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_PUBLIC *inPublic, const TPM2B_DATA *outsideInfo, const TPML_PCR_SELECTION *creationPCR, TPM2B_PRIVATE **outPrivate, TPM2B_PUBLIC **outPublic, TPM2B_CREATION_DATA **creationData, TPM2B_DIGEST **creationHash, TPMT_TK_CREATION **creationTicket) = NULL; +TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR primaryHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_PUBLIC *inPublic, const TPM2B_DATA *outsideInfo, const TPML_PCR_SELECTION *creationPCR, ESYS_TR *objectHandle, TPM2B_PUBLIC **outPublic, TPM2B_CREATION_DATA **creationData, TPM2B_DIGEST **creationHash, TPMT_TK_CREATION **creationTicket) = NULL; +void (*sym_Esys_Finalize)(ESYS_CONTEXT **context) = NULL; +TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle) = NULL; +void (*sym_Esys_Free)(void *ptr) = NULL; +TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes) = NULL; +TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion) = NULL; +TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle) = NULL; +TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest) = NULL; +TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs) = NULL; +TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle) = NULL; +TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType) = NULL; +TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData) = NULL; + +const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc) = NULL; + +TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Marshal)(TPM2B_PRIVATE const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL; +TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PRIVATE *dest) = NULL; +TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal)(TPM2B_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset) = NULL; +TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PUBLIC *dest) = NULL; + +int dlopen_tpm2(void) { + int r, k = 0; + + if (!libtss2_esys_dl) { + _cleanup_(dlclosep) void *dl = NULL; + + dl = dlopen("libtss2-esys.so.0", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + DLSYM_ARG(Esys_Create), + DLSYM_ARG(Esys_CreatePrimary), + DLSYM_ARG(Esys_Finalize), + DLSYM_ARG(Esys_FlushContext), + DLSYM_ARG(Esys_Free), + DLSYM_ARG(Esys_GetRandom), + DLSYM_ARG(Esys_Initialize), + DLSYM_ARG(Esys_Load), + DLSYM_ARG(Esys_PolicyGetDigest), + DLSYM_ARG(Esys_PolicyPCR), + DLSYM_ARG(Esys_StartAuthSession), + DLSYM_ARG(Esys_Startup), + DLSYM_ARG(Esys_Unseal), + NULL); + if (r < 0) + return r; + + libtss2_esys_dl = TAKE_PTR(dl); + k++; + } + + if (!libtss2_rc_dl) { + _cleanup_(dlclosep) void *dl = NULL; + + dl = dlopen("libtss2-rc.so.0", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + DLSYM_ARG(Tss2_RC_Decode), + NULL); + if (r < 0) + return r; + + libtss2_rc_dl = TAKE_PTR(dl); + k++; + } + + if (!libtss2_mu_dl) { + _cleanup_(dlclosep) void *dl = NULL; + + dl = dlopen("libtss2-mu.so.0", RTLD_LAZY); + if (!dl) + return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 support is not installed: %s", dlerror()); + + r = dlsym_many_and_warn( + dl, + LOG_DEBUG, + DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Marshal), + DLSYM_ARG(Tss2_MU_TPM2B_PRIVATE_Unmarshal), + DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Marshal), + DLSYM_ARG(Tss2_MU_TPM2B_PUBLIC_Unmarshal), + NULL); + if (r < 0) + return r; + + libtss2_mu_dl = TAKE_PTR(dl); + k++; + } + + return k; +} + +struct tpm2_context { + ESYS_CONTEXT *esys_context; + void *tcti_dl; + TSS2_TCTI_CONTEXT *tcti_context; +}; + +static void tpm2_context_destroy(struct tpm2_context *c) { + assert(c); + + if (c->esys_context) + sym_Esys_Finalize(&c->esys_context); + + c->tcti_context = mfree(c->tcti_context); + + if (c->tcti_dl) { + dlclose(c->tcti_dl); + c->tcti_dl = NULL; + } +} + +static inline void Esys_Finalize_wrapper(ESYS_CONTEXT **c) { + /* A wrapper around Esys_Finalize() for use with _cleanup_(). Only reasons we need this wrapper is + * because the function itself warn logs if we'd pass a pointer to NULL, and we don't want that. */ + if (*c) + sym_Esys_Finalize(c); +} + +static inline void Esys_Freep(void *p) { + if (*(void**) p) + sym_Esys_Free(*(void**) p); +} + +static ESYS_TR flush_context_verbose(ESYS_CONTEXT *c, ESYS_TR handle) { + TSS2_RC rc; + + if (!c || handle == ESYS_TR_NONE) + return ESYS_TR_NONE; + + rc = sym_Esys_FlushContext(c, handle); + if (rc != TSS2_RC_SUCCESS) /* We ignore failures here (besides debug logging), since this is called + * in error paths, where we cannot do anything about failures anymore. And + * when it is called in successful codepaths by this time we already did + * what we wanted to do, and got the results we wanted so there's no + * reason to make this fail more loudly than necessary. */ + log_debug("Failed to get flush context of TPM, ignoring: %s", sym_Tss2_RC_Decode(rc)); + + return ESYS_TR_NONE; +} + +static int tpm2_init(const char *device, struct tpm2_context *ret) { + _cleanup_(Esys_Finalize_wrapper) ESYS_CONTEXT *c = NULL; + _cleanup_free_ TSS2_TCTI_CONTEXT *tcti = NULL; + _cleanup_(dlclosep) void *dl = NULL; + TSS2_RC rc; + int r; + + r = dlopen_tpm2(); + if (r < 0) + return log_error_errno(r, "TPM2 support not installed: %m"); + + if (!device) + device = secure_getenv("SYSTEMD_TPM2_DEVICE"); + + if (device) { + const char *param, *driver, *fn; + const TSS2_TCTI_INFO* info; + TSS2_TCTI_INFO_FUNC func; + size_t sz = 0; + + param = strchr(device, ':'); + if (param) { + driver = strndupa(device, param - device); + param++; + } else { + driver = "device"; + param = device; + } + + fn = strjoina("libtss2-tcti-", driver, ".so.0"); + + dl = dlopen(fn, RTLD_NOW); + if (!dl) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Failed to load %s: %s", fn, dlerror()); + + func = dlsym(dl, TSS2_TCTI_INFO_SYMBOL); + if (!func) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to find TCTI info symbol " TSS2_TCTI_INFO_SYMBOL ": %s", + dlerror()); + + info = func(); + if (!info) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), "Unable to get TCTI info data."); + + + log_debug("Loaded TCTI module '%s' (%s) [Version %" PRIu32 "]", info->name, info->description, info->version); + + rc = info->init(NULL, &sz, NULL); + if (rc != TPM2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc)); + + tcti = malloc0(sz); + if (!tcti) + return log_oom(); + + rc = info->init(tcti, &sz, device); + if (rc != TPM2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to initialize TCTI context: %s", sym_Tss2_RC_Decode(rc)); + } + + rc = sym_Esys_Initialize(&c, tcti, NULL); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to initialize TPM context: %s", sym_Tss2_RC_Decode(rc)); + + rc = sym_Esys_Startup(c, TPM2_SU_CLEAR); + if (rc == TPM2_RC_INITIALIZE) + log_debug("TPM already started up."); + else if (rc == TSS2_RC_SUCCESS) + log_debug("TPM successfully started up."); + else + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to start up TPM: %s", sym_Tss2_RC_Decode(rc)); + + *ret = (struct tpm2_context) { + .esys_context = TAKE_PTR(c), + .tcti_context = TAKE_PTR(tcti), + .tcti_dl = TAKE_PTR(dl), + }; + + return 0; +} + +static int tpm2_credit_random(ESYS_CONTEXT *c) { + size_t rps, done = 0; + TSS2_RC rc; + int r; + + assert(c); + + /* Pulls some entropy from the TPM and adds it into the kernel RNG pool. That way we can say that the + * key we will ultimately generate with the kernel random pool is at least as good as the TPM's RNG, + * but likely better. Note that we don't trust the TPM RNG very much, hence do not actually credit + * any entropy. */ + + for (rps = random_pool_size(); rps > 0;) { + _cleanup_(Esys_Freep) TPM2B_DIGEST *buffer = NULL; + + rc = sym_Esys_GetRandom( + c, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + MIN(rps, 32U), /* 32 is supposedly a safe choice, given that AES 256bit keys are this long, and TPM2 baseline requires support for those. */ + &buffer); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to acquire entropy from TPM: %s", sym_Tss2_RC_Decode(rc)); + + if (buffer->size == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Zero-sized entropy returned from TPM."); + + r = random_write_entropy(-1, buffer->buffer, buffer->size, false); + if (r < 0) + return log_error_errno(r, "Failed wo write entropy to kernel: %m"); + + done += buffer->size; + rps = LESS_BY(rps, buffer->size); + } + + log_debug("Added %zu bytes of entropy to the kernel random pool.", done); + return 0; +} + +static int tpm2_make_primary( + ESYS_CONTEXT *c, + ESYS_TR *ret_primary) { + + static const TPM2B_SENSITIVE_CREATE primary_sensitive = {}; + static const TPM2B_PUBLIC primary_template = { + .size = sizeof(TPMT_PUBLIC), + .publicArea = { + .type = TPM2_ALG_ECC, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = TPMA_OBJECT_RESTRICTED|TPMA_OBJECT_DECRYPT|TPMA_OBJECT_FIXEDTPM|TPMA_OBJECT_FIXEDPARENT|TPMA_OBJECT_SENSITIVEDATAORIGIN|TPMA_OBJECT_USERWITHAUTH, + .parameters = { + .eccDetail = { + .symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits.aes = 128, + .mode.aes = TPM2_ALG_CFB, + }, + .scheme.scheme = TPM2_ALG_NULL, + .curveID = TPM2_ECC_NIST_P256, + .kdf.scheme = TPM2_ALG_NULL, + }, + }, + }, + }; + static const TPML_PCR_SELECTION creation_pcr = {}; + ESYS_TR primary = ESYS_TR_NONE; + TSS2_RC rc; + + log_debug("Creating primary key on TPM."); + + rc = sym_Esys_CreatePrimary( + c, + ESYS_TR_RH_OWNER, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + &primary_sensitive, + &primary_template, + NULL, + &creation_pcr, + &primary, + NULL, + NULL, + NULL, + NULL); + + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to generate primary key in TPM: %s", sym_Tss2_RC_Decode(rc)); + + log_debug("Successfully created primary key on TPM."); + + *ret_primary = primary; + return 0; +} + +static int tpm2_make_pcr_session( + ESYS_CONTEXT *c, + uint32_t pcr_mask, + ESYS_TR *ret_session, + TPM2B_DIGEST **ret_policy_digest) { + + static const TPMT_SYM_DEF symmetric = { + .algorithm = TPM2_ALG_AES, + .keyBits = { + .aes = 128 + }, + .mode = { + .aes = TPM2_ALG_CFB, + } + }; + TPML_PCR_SELECTION pcr_selection = { + .count = 1, + .pcrSelections[0].hash = TPM2_ALG_SHA256, + .pcrSelections[0].sizeofSelect = 3, + .pcrSelections[0].pcrSelect[0] = pcr_mask & 0xFF, + .pcrSelections[0].pcrSelect[1] = (pcr_mask >> 8) & 0xFF, + .pcrSelections[0].pcrSelect[2] = (pcr_mask >> 16) & 0xFF, + }; + _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; + ESYS_TR session = ESYS_TR_NONE; + TSS2_RC rc; + int r; + + assert(c); + + log_debug("Starting authentication session."); + + rc = sym_Esys_StartAuthSession( + c, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + NULL, + TPM2_SE_POLICY, + &symmetric, + TPM2_ALG_SHA256, + &session); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to open session in TPM: %s", sym_Tss2_RC_Decode(rc)); + + log_debug("Configuring PCR policy."); + + rc = sym_Esys_PolicyPCR( + c, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + NULL, + &pcr_selection); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to add PCR policy to TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } + + if (DEBUG_LOGGING || ret_policy_digest) { + log_debug("Acquiring policy digest."); + + rc = sym_Esys_PolicyGetDigest( + c, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + ESYS_TR_NONE, + &policy_digest); + + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to get policy digest from TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } + + if (DEBUG_LOGGING) { + _cleanup_free_ char *h = NULL; + + h = hexmem(policy_digest->buffer, policy_digest->size); + if (!h) { + r = log_oom(); + goto finish; + } + + log_debug("Session policy digest: %s", h); + } + } + + if (ret_session) { + *ret_session = session; + session = ESYS_TR_NONE; + } + + if (ret_policy_digest) + *ret_policy_digest = TAKE_PTR(policy_digest); + + r = 0; + +finish: + session = flush_context_verbose(c, session); + return r; +} + +int tpm2_seal( + const char *device, + uint32_t pcr_mask, + void **ret_secret, + size_t *ret_secret_size, + void **ret_blob, + size_t *ret_blob_size, + void **ret_pcr_hash, + size_t *ret_pcr_hash_size) { + + _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; + _cleanup_(Esys_Freep) TPM2B_PRIVATE *private = NULL; + _cleanup_(Esys_Freep) TPM2B_PUBLIC *public = NULL; + static const TPML_PCR_SELECTION creation_pcr = {}; + _cleanup_(erase_and_freep) void *secret = NULL; + _cleanup_free_ void *blob = NULL, *hash = NULL; + TPM2B_SENSITIVE_CREATE hmac_sensitive; + ESYS_TR primary = ESYS_TR_NONE; + TPM2B_PUBLIC hmac_template; + size_t k, blob_size; + usec_t start; + TSS2_RC rc; + int r; + + assert(ret_secret); + assert(ret_secret_size); + assert(ret_blob); + assert(ret_blob_size); + assert(ret_pcr_hash); + assert(ret_pcr_hash_size); + + assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */ + + /* So here's what we do here: we connect to the TPM2 chip. It persistently contains a "seed" key that + * is randomized when the TPM2 is first initialized or reset and remains stable across boots. We + * generate a "primary" key pair derived from that (RSA). Given the seed remains fixed this will + * result in the same key pair whenever we specify the exact same parameters for it. We then create a + * PCR-bound policy session, which calculates a hash on the current PCR values of the indexes we + * specify. We then generate a randomized key on the host (which is the key we actually enroll in the + * LUKS2 keyslots), which we upload into the TPM2, where it is encrypted with the "primary" key, + * taking the PCR policy session into account. We then download the encrypted key from the TPM2 + * ("sealing") and marshall it into binary form, which is ultimately placed in the LUKS2 JSON header. + * + * The TPM2 "seed" key and "primary" keys never leave the TPM2 chip (and cannot be extracted at + * all). The random key we enroll in LUKS2 we generate on the host using the Linux random device. It + * is stored in the LUKS2 JSON only in encrypted form with the "primary" key of the TPM2 chip, thus + * binding the unlocking to the TPM2 chip. */ + + start = now(CLOCK_MONOTONIC); + + r = tpm2_init(device, &c); + if (r < 0) + return r; + + r = tpm2_make_primary(c.esys_context, &primary); + if (r < 0) + return r; + + r = tpm2_make_pcr_session(c.esys_context, pcr_mask, NULL, &policy_digest); + if (r < 0) + goto finish; + + /* We use a keyed hash object (i.e. HMAC) to store the secret key we want to use for unlocking the + * LUKS2 volume with. We don't ever use for HMAC/keyed hash operations however, we just use it + * because it's a key type that is universally supported and suitable for symmetric binary blobs. */ + hmac_template = (TPM2B_PUBLIC) { + .size = sizeof(TPMT_PUBLIC), + .publicArea = { + .type = TPM2_ALG_KEYEDHASH, + .nameAlg = TPM2_ALG_SHA256, + .objectAttributes = TPMA_OBJECT_FIXEDTPM | TPMA_OBJECT_FIXEDPARENT, + .parameters = { + .keyedHashDetail = { + .scheme.scheme = TPM2_ALG_NULL, + }, + }, + .unique = { + .keyedHash = { + .size = 32, + }, + }, + .authPolicy = *policy_digest, + }, + }; + + hmac_sensitive = (TPM2B_SENSITIVE_CREATE) { + .size = sizeof(hmac_sensitive.sensitive), + .sensitive.data.size = 32, + }; + assert(sizeof(hmac_sensitive.sensitive.data.buffer) >= hmac_sensitive.sensitive.data.size); + + (void) tpm2_credit_random(c.esys_context); + + log_debug("Generating secret key data."); + + r = genuine_random_bytes(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size, RANDOM_BLOCK); + if (r < 0) { + log_error_errno(r, "Failed to generate secret key: %m"); + goto finish; + } + + log_debug("Creating HMAC key."); + + rc = sym_Esys_Create( + c.esys_context, + primary, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + &hmac_sensitive, + &hmac_template, + NULL, + &creation_pcr, + &private, + &public, + NULL, + NULL, + NULL); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to generate HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } + + secret = memdup(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size); + explicit_bzero_safe(hmac_sensitive.sensitive.data.buffer, hmac_sensitive.sensitive.data.size); + if (!secret) { + r = log_oom(); + goto finish; + } + + log_debug("Marshalling private and public part of HMAC key."); + + k = ALIGN8(sizeof(*private)) + ALIGN8(sizeof(*public)); /* Some roughly sensible start value */ + for (;;) { + _cleanup_free_ void *buf = NULL; + size_t offset = 0; + + buf = malloc(k); + if (!buf) { + r = log_oom(); + goto finish; + } + + rc = sym_Tss2_MU_TPM2B_PRIVATE_Marshal(private, buf, k, &offset); + if (rc == TSS2_RC_SUCCESS) { + rc = sym_Tss2_MU_TPM2B_PUBLIC_Marshal(public, buf, k, &offset); + if (rc == TSS2_RC_SUCCESS) { + blob = TAKE_PTR(buf); + blob_size = offset; + break; + } + } + if (rc != TSS2_MU_RC_INSUFFICIENT_BUFFER) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to marshal private/public key: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } + + if (k > SIZE_MAX / 2) { + r = log_oom(); + goto finish; + } + + k *= 2; + } + + hash = memdup(policy_digest->buffer, policy_digest->size); + if (!hash) + return log_oom(); + + if (DEBUG_LOGGING) { + char buf[FORMAT_TIMESPAN_MAX]; + log_debug("Completed TPM2 key sealing in %s.", format_timespan(buf, sizeof(buf), now(CLOCK_MONOTONIC) - start, 1)); + } + + *ret_secret = TAKE_PTR(secret); + *ret_secret_size = hmac_sensitive.sensitive.data.size; + *ret_blob = TAKE_PTR(blob); + *ret_blob_size = blob_size; + *ret_pcr_hash = TAKE_PTR(hash); + *ret_pcr_hash_size = policy_digest->size; + + r = 0; + +finish: + primary = flush_context_verbose(c.esys_context, primary); + return r; +} + +int tpm2_unseal( + const char *device, + uint32_t pcr_mask, + const void *blob, + size_t blob_size, + const void *known_policy_hash, + size_t known_policy_hash_size, + void **ret_secret, + size_t *ret_secret_size) { + + _cleanup_(tpm2_context_destroy) struct tpm2_context c = {}; + ESYS_TR primary = ESYS_TR_NONE, session = ESYS_TR_NONE, hmac_key = ESYS_TR_NONE; + _cleanup_(Esys_Freep) TPM2B_SENSITIVE_DATA* unsealed = NULL; + _cleanup_(Esys_Freep) TPM2B_DIGEST *policy_digest = NULL; + _cleanup_(erase_and_freep) char *secret = NULL; + TPM2B_PRIVATE private = {}; + TPM2B_PUBLIC public = {}; + size_t offset = 0; + TSS2_RC rc; + usec_t start; + int r; + + assert(blob); + assert(blob_size > 0); + assert(known_policy_hash_size == 0 || known_policy_hash); + assert(ret_secret); + assert(ret_secret_size); + + assert(pcr_mask < (UINT32_C(1) << TPM2_PCRS_MAX)); /* Support 24 PCR banks */ + + /* So here's what we do here: We connect to the TPM2 chip. As we do when sealing we generate a + * "primary" key on the TPM2 chip, with the same parameters as well as a PCR-bound policy + * session. Given we pass the same parameters, this will result in the same "primary" key, and same + * policy hash (the latter of course, only if the PCR values didn't change in between). We unmarshal + * the encrypted key we stored in the LUKS2 JSON token header and upload it into the TPM2, where it + * is decrypted if the seed and the PCR policy were right ("unsealing"). We then download the result, + * and use it to unlock the LUKS2 volume. */ + + start = now(CLOCK_MONOTONIC); + + log_debug("Unmarshalling private part of HMAC key."); + + rc = sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal(blob, blob_size, &offset, &private); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to unmarshal private key: %s", sym_Tss2_RC_Decode(rc)); + + log_debug("Unmarshalling public part of HMAC key."); + + rc = sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal(blob, blob_size, &offset, &public); + if (rc != TSS2_RC_SUCCESS) + return log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to unmarshal public key: %s", sym_Tss2_RC_Decode(rc)); + + r = tpm2_init(device, &c); + if (r < 0) + return r; + + r = tpm2_make_pcr_session(c.esys_context, pcr_mask, &session, &policy_digest); + if (r < 0) + goto finish; + + /* If we know the policy hash to expect, and it doesn't match, we can shortcut things here, and not + * wait until the TPM2 tells us to go away. */ + if (known_policy_hash_size > 0 && + memcmp_nn(policy_digest->buffer, policy_digest->size, known_policy_hash, known_policy_hash_size) != 0) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), + "Current policy digest does not match stored policy digest, cancelling TPM2 authentication attempt."); + + r = tpm2_make_primary(c.esys_context, &primary); + if (r < 0) + return r; + + log_debug("Loading HMAC key into TPM."); + + rc = sym_Esys_Load( + c.esys_context, + primary, + ESYS_TR_PASSWORD, + ESYS_TR_NONE, + ESYS_TR_NONE, + &private, + &public, + &hmac_key); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to load HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } + + log_debug("Unsealing HMAC key."); + + rc = sym_Esys_Unseal( + c.esys_context, + hmac_key, + session, + ESYS_TR_NONE, + ESYS_TR_NONE, + &unsealed); + if (rc != TSS2_RC_SUCCESS) { + r = log_error_errno(SYNTHETIC_ERRNO(ENOTRECOVERABLE), + "Failed to unseal HMAC key in TPM: %s", sym_Tss2_RC_Decode(rc)); + goto finish; + } + + secret = memdup(unsealed->buffer, unsealed->size); + explicit_bzero_safe(unsealed->buffer, unsealed->size); + if (!secret) { + r = log_oom(); + goto finish; + } + + if (DEBUG_LOGGING) { + char buf[FORMAT_TIMESPAN_MAX]; + log_debug("Completed TPM2 key unsealing in %s.", format_timespan(buf, sizeof(buf), now(CLOCK_MONOTONIC) - start, 1)); + } + + *ret_secret = TAKE_PTR(secret); + *ret_secret_size = unsealed->size; + + r = 0; + +finish: + primary = flush_context_verbose(c.esys_context, primary); + session = flush_context_verbose(c.esys_context, session); + hmac_key = flush_context_verbose(c.esys_context, hmac_key); + return r; +} + +#endif + +int tpm2_list_devices(void) { +#if HAVE_TPM2 + _cleanup_(table_unrefp) Table *t = NULL; + _cleanup_(closedirp) DIR *d = NULL; + int r; + + r = dlopen_tpm2(); + if (r < 0) + return log_error_errno(r, "TPM2 support is not installed."); + + t = table_new("path", "device", "driver"); + if (!t) + return log_oom(); + + d = opendir("/sys/class/tpmrm"); + if (!d) { + log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, "Failed to open /sys/class/tpmrm: %m"); + if (errno != ENOENT) + return -errno; + } else { + for (;;) { + _cleanup_free_ char *device_path = NULL, *device = NULL, *driver_path = NULL, *driver = NULL, *node = NULL; + struct dirent *de; + + de = readdir_no_dot(d); + if (!de) + break; + + device_path = path_join("/sys/class/tpmrm", de->d_name, "device"); + if (!device_path) + return log_oom(); + + r = readlink_malloc(device_path, &device); + if (r < 0) + log_debug_errno(r, "Failed to read device symlink %s, ignoring: %m", device_path); + else { + driver_path = path_join(device_path, "driver"); + if (!driver_path) + return log_oom(); + + r = readlink_malloc(driver_path, &driver); + if (r < 0) + log_debug_errno(r, "Failed to read driver symlink %s, ignoring: %m", driver_path); + } + + node = path_join("/dev", de->d_name); + if (!node) + return log_oom(); + + r = table_add_many( + t, + TABLE_PATH, node, + TABLE_STRING, device ? last_path_component(device) : NULL, + TABLE_STRING, driver ? last_path_component(driver) : NULL); + if (r < 0) + return table_log_add_error(r); + } + } + + if (table_get_rows(t) <= 1) { + log_info("No suitable TPM2 devices found."); + return 0; + } + + r = table_print(t, stdout); + if (r < 0) + return log_error_errno(r, "Failed to show device table: %m"); + + return 0; +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 not supported on this build."); +#endif +} + +int tpm2_find_device_auto( + int log_level, /* log level when no device is found */ + char **ret) { +#if HAVE_TPM2 + _cleanup_(closedirp) DIR *d = NULL; + int r; + + r = dlopen_tpm2(); + if (r < 0) + return log_error_errno(r, "TPM2 support is not installed."); + + d = opendir("/sys/class/tpmrm"); + if (!d) { + log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_ERR, errno, + "Failed to open /sys/class/tpmrm: %m"); + if (errno != ENOENT) + return -errno; + } else { + _cleanup_free_ char *node = NULL; + + for (;;) { + struct dirent *de; + + de = readdir_no_dot(d); + if (!de) + break; + + if (node) + return log_error_errno(SYNTHETIC_ERRNO(ENOTUNIQ), + "More than one TPM2 (tpmrm) device found."); + + node = path_join("/dev", de->d_name); + if (!node) + return log_oom(); + } + + if (node) { + *ret = TAKE_PTR(node); + return 0; + } + } + + return log_full_errno(log_level, SYNTHETIC_ERRNO(ENODEV), "No TPM2 (tpmrm) device found."); +#else + return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), + "TPM2 not supported on this build."); +#endif +} + +int tpm2_parse_pcrs(const char *s, uint32_t *ret) { + const char *p = s; + uint32_t mask = 0; + int r; + + /* Parses a comma-separated list of PCR indexes */ + + for (;;) { + _cleanup_free_ char *pcr = NULL; + unsigned n; + + r = extract_first_word(&p, &pcr, ",", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r == 0) + break; + if (r < 0) + return log_error_errno(r, "Failed to parse PCR list: %s", s); + + r = safe_atou(pcr, &n); + if (r < 0) + return log_error_errno(r, "Failed to parse PCR number: %s", pcr); + if (n >= TPM2_PCRS_MAX) + return log_error_errno(SYNTHETIC_ERRNO(ERANGE), + "PCR number out of range (valid range 0…23): %u", n); + + mask |= UINT32_C(1) << n; + } + + *ret = mask; + return 0; +} + +int tpm2_make_luks2_json( + int keyslot, + uint32_t pcr_mask, + const void *blob, + size_t blob_size, + const void *policy_hash, + size_t policy_hash_size, + JsonVariant **ret) { + + _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *a = NULL; + _cleanup_free_ char *keyslot_as_string = NULL; + JsonVariant* pcr_array[TPM2_PCRS_MAX]; + unsigned n_pcrs = 0; + int r; + + assert(blob || blob_size == 0); + assert(policy_hash || policy_hash_size == 0); + + if (asprintf(&keyslot_as_string, "%i", keyslot) < 0) + return -ENOMEM; + + for (unsigned i = 0; i < ELEMENTSOF(pcr_array); i++) { + if ((pcr_mask & (UINT32_C(1) << i)) == 0) + continue; + + r = json_variant_new_integer(pcr_array + n_pcrs, i); + if (r < 0) { + json_variant_unref_many(pcr_array, n_pcrs); + return -ENOMEM; + } + + n_pcrs++; + } + + r = json_variant_new_array(&a, pcr_array, n_pcrs); + json_variant_unref_many(pcr_array, n_pcrs); + if (r < 0) + return -ENOMEM; + + r = json_build(&v, + JSON_BUILD_OBJECT( + JSON_BUILD_PAIR("type", JSON_BUILD_STRING("systemd-tpm2")), + JSON_BUILD_PAIR("keyslots", JSON_BUILD_ARRAY(JSON_BUILD_STRING(keyslot_as_string))), + JSON_BUILD_PAIR("tpm2-blob", JSON_BUILD_BASE64(blob, blob_size)), + JSON_BUILD_PAIR("tpm2-pcrs", JSON_BUILD_VARIANT(a)), + JSON_BUILD_PAIR("tpm2-policy-hash", JSON_BUILD_HEX(policy_hash, policy_hash_size)))); + if (r < 0) + return r; + + if (ret) + *ret = TAKE_PTR(v); + + return keyslot; +} diff --git a/src/shared/tpm2-util.h b/src/shared/tpm2-util.h new file mode 100644 index 000000000..82cd186e1 --- /dev/null +++ b/src/shared/tpm2-util.h @@ -0,0 +1,51 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "json.h" +#include "macro.h" + +#if HAVE_TPM2 + +#include +#include +#include + +extern TSS2_RC (*sym_Esys_Create)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_PUBLIC *inPublic, const TPM2B_DATA *outsideInfo, const TPML_PCR_SELECTION *creationPCR, TPM2B_PRIVATE **outPrivate, TPM2B_PUBLIC **outPublic, TPM2B_CREATION_DATA **creationData, TPM2B_DIGEST **creationHash, TPMT_TK_CREATION **creationTicket); +extern TSS2_RC (*sym_Esys_CreatePrimary)(ESYS_CONTEXT *esysContext, ESYS_TR primaryHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_SENSITIVE_CREATE *inSensitive, const TPM2B_PUBLIC *inPublic, const TPM2B_DATA *outsideInfo, const TPML_PCR_SELECTION *creationPCR, ESYS_TR *objectHandle, TPM2B_PUBLIC **outPublic, TPM2B_CREATION_DATA **creationData, TPM2B_DIGEST **creationHash, TPMT_TK_CREATION **creationTicket); +extern void (*sym_Esys_Finalize)(ESYS_CONTEXT **context); +extern TSS2_RC (*sym_Esys_FlushContext)(ESYS_CONTEXT *esysContext, ESYS_TR flushHandle); +extern void (*sym_Esys_Free)(void *ptr); +extern TSS2_RC (*sym_Esys_GetRandom)(ESYS_CONTEXT *esysContext, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, UINT16 bytesRequested, TPM2B_DIGEST **randomBytes); +extern TSS2_RC (*sym_Esys_Initialize)(ESYS_CONTEXT **esys_context, TSS2_TCTI_CONTEXT *tcti, TSS2_ABI_VERSION *abiVersion); +extern TSS2_RC (*sym_Esys_Load)(ESYS_CONTEXT *esysContext, ESYS_TR parentHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_PRIVATE *inPrivate, const TPM2B_PUBLIC *inPublic, ESYS_TR *objectHandle); +extern TSS2_RC (*sym_Esys_PolicyGetDigest)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_DIGEST **policyDigest); +extern TSS2_RC (*sym_Esys_PolicyPCR)(ESYS_CONTEXT *esysContext, ESYS_TR policySession, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_DIGEST *pcrDigest, const TPML_PCR_SELECTION *pcrs); +extern TSS2_RC (*sym_Esys_StartAuthSession)(ESYS_CONTEXT *esysContext, ESYS_TR tpmKey, ESYS_TR bind, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, const TPM2B_NONCE *nonceCaller, TPM2_SE sessionType, const TPMT_SYM_DEF *symmetric, TPMI_ALG_HASH authHash, ESYS_TR *sessionHandle); +extern TSS2_RC (*sym_Esys_Startup)(ESYS_CONTEXT *esysContext, TPM2_SU startupType); +extern TSS2_RC (*sym_Esys_Unseal)(ESYS_CONTEXT *esysContext, ESYS_TR itemHandle, ESYS_TR shandle1, ESYS_TR shandle2, ESYS_TR shandle3, TPM2B_SENSITIVE_DATA **outData); + +extern const char* (*sym_Tss2_RC_Decode)(TSS2_RC rc); + +extern TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Marshal)(TPM2B_PRIVATE const *src, uint8_t buffer[], size_t buffer_size, size_t *offset); +extern TSS2_RC (*sym_Tss2_MU_TPM2B_PRIVATE_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PRIVATE *dest); +extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Marshal)(TPM2B_PUBLIC const *src, uint8_t buffer[], size_t buffer_size, size_t *offset); +extern TSS2_RC (*sym_Tss2_MU_TPM2B_PUBLIC_Unmarshal)(uint8_t const buffer[], size_t buffer_size, size_t *offset, TPM2B_PUBLIC *dest); + +int dlopen_tpm2(void); + +int tpm2_seal(const char *device, uint32_t pcr_mask, void **ret_secret, size_t *ret_secret_size, void **ret_blob, size_t *ret_blob_size, void **ret_pcr_hash, size_t *ret_pcr_hash_size); +int tpm2_unseal(const char *device, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *pcr_hash, size_t pcr_hash_size, void **ret_secret, size_t *ret_secret_size); + +#endif + +int tpm2_list_devices(void); +int tpm2_find_device_auto(int log_level, char **ret); + +int tpm2_parse_pcrs(const char *s, uint32_t *ret); + +int tpm2_make_luks2_json(int keyslot, uint32_t pcr_mask, const void *blob, size_t blob_size, const void *policy_hash, size_t policy_hash_size, JsonVariant **ret); + +#define TPM2_PCRS_MAX 24 + +/* Default to PCR 7 only */ +#define TPM2_PCR_MASK_DEFAULT (UINT32_C(1) << 7) diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c index 030922eca..06aede9d3 100644 --- a/src/shared/udev-util.c +++ b/src/shared/udev-util.c @@ -1,12 +1,18 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include #include +#include #include #include "alloc-util.h" +#include "device-nodes.h" +#include "device-private.h" #include "device-util.h" #include "env-file.h" +#include "errno-util.h" #include "escape.h" +#include "fd-util.h" #include "log.h" #include "macro.h" #include "parse-util.h" @@ -14,6 +20,7 @@ #include "signal-util.h" #include "string-table.h" #include "string-util.h" +#include "strxcpyx.h" #include "udev-util.h" #include "utf8.h" @@ -63,7 +70,7 @@ int udev_parse_config_full( /* we set the udev log level here explicitly, this is supposed * to regulate the code in libudev/ and udev/. */ - r = log_set_max_level_from_string_realm(LOG_REALM_UDEV, log); + r = log_set_max_level_from_string(log); if (r < 0) log_syntax(NULL, LOG_WARNING, "/etc/udev/udev.conf", 0, r, "failed to set udev log level '%s', ignoring: %m", log); @@ -129,7 +136,7 @@ static int device_new_from_dev_path(const char *devlink, sd_device **ret_device) return log_error_errno(SYNTHETIC_ERRNO(ENOTBLK), "%s does not point to a block device: %m", devlink); - r = sd_device_new_from_devnum(ret_device, 'b', st.st_rdev); + r = sd_device_new_from_stat_rdev(ret_device, &st); if (r < 0) return log_error_errno(r, "Failed to initialize device from %s: %m", devlink); @@ -170,7 +177,7 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, * (And yes, we only need to special case REMOVE. It's the only "negative" event type, where a device * ceases to exist. All other event types are "positive": the device exists and is registered in the * udev database, thus whenever we see the event, we can consider it initialized.) */ - if (device_for_action(device, DEVICE_ACTION_REMOVE)) + if (device_for_action(device, SD_DEVICE_REMOVE)) return 0; if (data->sysname && sd_device_get_sysname(device, &sysname) >= 0 && streq(sysname, data->sysname)) @@ -313,15 +320,32 @@ int device_is_renaming(sd_device *dev) { return true; } -bool device_for_action(sd_device *dev, DeviceAction action) { - DeviceAction a; +bool device_for_action(sd_device *dev, sd_device_action_t a) { + sd_device_action_t b; assert(dev); - if (device_get_action(dev, &a) < 0) + if (a < 0) return false; - return a == action; + if (sd_device_get_action(dev, &b) < 0) + return false; + + return a == b; +} + +void log_device_uevent(sd_device *device, const char *str) { + sd_device_action_t action = _SD_DEVICE_ACTION_INVALID; + uint64_t seqnum = 0; + + if (!DEBUG_LOGGING) + return; + + (void) sd_device_get_seqnum(device, &seqnum); + (void) sd_device_get_action(device, &action); + log_device_debug(device, "%s%s(SEQNUM=%"PRIu64", ACTION=%s)", + strempty(str), isempty(str) ? "" : " ", + seqnum, strna(device_action_to_string(action))); } int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { @@ -369,3 +393,171 @@ int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos) { *ret_endpos = i + 1; return 0; } + +size_t udev_replace_whitespace(const char *str, char *to, size_t len) { + bool is_space = false; + size_t i, j; + + assert(str); + assert(to); + + /* Copy from 'str' to 'to', while removing all leading and trailing whitespace, and replacing + * each run of consecutive whitespace with a single underscore. The chars from 'str' are copied + * up to the \0 at the end of the string, or at most 'len' chars. This appends \0 to 'to', at + * the end of the copied characters. + * + * If 'len' chars are copied into 'to', the final \0 is placed at len+1 (i.e. 'to[len] = \0'), + * so the 'to' buffer must have at least len+1 chars available. + * + * Note this may be called with 'str' == 'to', i.e. to replace whitespace in-place in a buffer. + * This function can handle that situation. + * + * Note that only 'len' characters are read from 'str'. */ + + i = strspn(str, WHITESPACE); + + for (j = 0; j < len && i < len && str[i] != '\0'; i++) { + if (isspace(str[i])) { + is_space = true; + continue; + } + + if (is_space) { + if (j + 1 >= len) + break; + + to[j++] = '_'; + is_space = false; + } + to[j++] = str[i]; + } + + to[j] = '\0'; + return j; +} + +size_t udev_replace_chars(char *str, const char *allow) { + size_t i = 0, replaced = 0; + + assert(str); + + /* allow chars in allow list, plain ascii, hex-escaping and valid utf8. */ + + while (str[i] != '\0') { + int len; + + if (allow_listed_char_for_devnode(str[i], allow)) { + i++; + continue; + } + + /* accept hex encoding */ + if (str[i] == '\\' && str[i+1] == 'x') { + i += 2; + continue; + } + + /* accept valid utf8 */ + len = utf8_encoded_valid_unichar(str + i, SIZE_MAX); + if (len > 1) { + i += len; + continue; + } + + /* if space is allowed, replace whitespace with ordinary space */ + if (isspace(str[i]) && allow && strchr(allow, ' ')) { + str[i] = ' '; + i++; + replaced++; + continue; + } + + /* everything else is replaced with '_' */ + str[i] = '_'; + i++; + replaced++; + } + return replaced; +} + +int udev_resolve_subsys_kernel(const char *string, char *result, size_t maxsize, bool read_value) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + _cleanup_free_ char *temp = NULL; + char *subsys, *sysname, *attr; + const char *val; + int r; + + assert(string); + assert(result); + + /* handle "[/]" format */ + + if (string[0] != '[') + return -EINVAL; + + temp = strdup(string); + if (!temp) + return -ENOMEM; + + subsys = &temp[1]; + + sysname = strchr(subsys, '/'); + if (!sysname) + return -EINVAL; + sysname[0] = '\0'; + sysname = &sysname[1]; + + attr = strchr(sysname, ']'); + if (!attr) + return -EINVAL; + attr[0] = '\0'; + attr = &attr[1]; + if (attr[0] == '/') + attr = &attr[1]; + if (attr[0] == '\0') + attr = NULL; + + if (read_value && !attr) + return -EINVAL; + + r = sd_device_new_from_subsystem_sysname(&dev, subsys, sysname); + if (r < 0) + return r; + + if (read_value) { + r = sd_device_get_sysattr_value(dev, attr, &val); + if (r < 0 && !ERRNO_IS_PRIVILEGE(r) && r != -ENOENT) + return r; + if (r >= 0) + strscpy(result, maxsize, val); + else + result[0] = '\0'; + log_debug("value '[%s/%s]%s' is '%s'", subsys, sysname, attr, result); + } else { + r = sd_device_get_syspath(dev, &val); + if (r < 0) + return r; + + strscpyl(result, maxsize, val, attr ? "/" : NULL, attr ?: NULL, NULL); + log_debug("path '[%s/%s]%s' is '%s'", subsys, sysname, strempty(attr), result); + } + return 0; +} + +int udev_queue_is_empty(void) { + return access("/run/udev/queue", F_OK) < 0 ? + (errno == ENOENT ? true : -errno) : false; +} + +int udev_queue_init(void) { + _cleanup_close_ int fd = -1; + + fd = inotify_init1(IN_CLOEXEC); + if (fd < 0) + return -errno; + + if (inotify_add_watch(fd, "/run/udev" , IN_DELETE) < 0) + return -errno; + + return TAKE_FD(fd); +} diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h index 270861e55..c2cf7caa6 100644 --- a/src/shared/udev-util.h +++ b/src/shared/udev-util.h @@ -3,15 +3,18 @@ #include "sd-device.h" -#include "device-private.h" #include "time-util.h" +#define UDEV_NAME_SIZE 512 +#define UDEV_PATH_SIZE 1024 +#define UDEV_LINE_SIZE 16384 + typedef enum ResolveNameTiming { RESOLVE_NAME_NEVER, RESOLVE_NAME_LATE, RESOLVE_NAME_EARLY, _RESOLVE_NAME_TIMING_MAX, - _RESOLVE_NAME_TIMING_INVALID = -1, + _RESOLVE_NAME_TIMING_INVALID = -EINVAL, } ResolveNameTiming; ResolveNameTiming resolve_name_timing_from_string(const char *s) _pure_; @@ -31,6 +34,15 @@ static inline int udev_parse_config(void) { int device_wait_for_initialization(sd_device *device, const char *subsystem, usec_t deadline, sd_device **ret); int device_wait_for_devlink(const char *path, const char *subsystem, usec_t deadline, sd_device **ret); int device_is_renaming(sd_device *dev); -bool device_for_action(sd_device *dev, DeviceAction action); + +bool device_for_action(sd_device *dev, sd_device_action_t action); + +void log_device_uevent(sd_device *device, const char *str); int udev_rule_parse_value(char *str, char **ret_value, char **ret_endpos); +size_t udev_replace_whitespace(const char *str, char *to, size_t len); +size_t udev_replace_chars(char *str, const char *allow); +int udev_resolve_subsys_kernel(const char *string, char *result, size_t maxsize, bool read_value); + +int udev_queue_is_empty(void); +int udev_queue_init(void); diff --git a/src/shared/user-record.c b/src/shared/user-record.c index 6c48c56a2..bc35edd72 100644 --- a/src/shared/user-record.c +++ b/src/shared/user-record.c @@ -427,11 +427,11 @@ static int json_dispatch_rlimits(const char *name, JsonVariant *variant, JsonDis p = startswith(key, "RLIMIT_"); if (!p) - l = -1; + l = -SYNTHETIC_ERRNO(EINVAL); else l = rlimit_from_string(p); if (l < 0) - return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' not known.", key); + return json_log(variant, flags, l, "Resource limit '%s' not known.", key); if (!json_variant_is_object(value)) return json_log(value, flags, SYNTHETIC_ERRNO(EINVAL), "Resource limit '%s' has invalid value.", key); @@ -570,7 +570,7 @@ static int json_dispatch_umask(const char *name, JsonVariant *variant, JsonDispa uintmax_t k; if (json_variant_is_null(variant)) { - *m = (mode_t) -1; + *m = MODE_INVALID; return 0; } @@ -590,7 +590,7 @@ static int json_dispatch_access_mode(const char *name, JsonVariant *variant, Jso uintmax_t k; if (json_variant_is_null(variant)) { - *m = (mode_t) -1; + *m = MODE_INVALID; return 0; } @@ -608,7 +608,6 @@ static int json_dispatch_access_mode(const char *name, JsonVariant *variant, Jso static int json_dispatch_environment(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { _cleanup_strv_free_ char **n = NULL; char ***l = userdata; - size_t i; int r; if (json_variant_is_null(variant)) { @@ -619,8 +618,7 @@ static int json_dispatch_environment(const char *name, JsonVariant *variant, Jso if (!json_variant_is_array(variant)) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name)); - for (i = 0; i < json_variant_elements(variant); i++) { - _cleanup_free_ char *c = NULL; + for (size_t i = 0; i < json_variant_elements(variant); i++) { JsonVariant *e; const char *a; @@ -633,19 +631,12 @@ static int json_dispatch_environment(const char *name, JsonVariant *variant, Jso if (!env_assignment_is_valid(a)) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array of environment variables.", strna(name)); - c = strdup(a); - if (!c) - return json_log_oom(variant, flags); - - r = strv_env_replace(&n, c); + r = strv_env_replace_strdup(&n, a); if (r < 0) return json_log_oom(variant, flags); - - c = NULL; } - strv_free_and_replace(*l, n); - return 0; + return strv_free_and_replace(*l, n); } int json_dispatch_user_disposition(const char *name, JsonVariant *variant, JsonDispatchFlags flags, void *userdata) { @@ -661,7 +652,7 @@ int json_dispatch_user_disposition(const char *name, JsonVariant *variant, JsonD k = user_disposition_from_string(json_variant_string(variant)); if (k < 0) - return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Disposition type '%s' not known.", json_variant_string(variant)); + return json_log(variant, flags, k, "Disposition type '%s' not known.", json_variant_string(variant)); *disposition = k; return 0; @@ -680,7 +671,7 @@ static int json_dispatch_storage(const char *name, JsonVariant *variant, JsonDis k = user_storage_from_string(json_variant_string(variant)); if (k < 0) - return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Storage type '%s' not known.", json_variant_string(variant)); + return json_log(variant, flags, k, "Storage type '%s' not known.", json_variant_string(variant)); *storage = k; return 0; @@ -875,7 +866,7 @@ static int dispatch_pkcs11_key_data(const char *name, JsonVariant *variant, Json if (!json_variant_is_string(variant)) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); - r = unbase64mem(json_variant_string(variant), (size_t) -1, &b, &l); + r = unbase64mem(json_variant_string(variant), SIZE_MAX, &b, &l); if (r < 0) return json_log(variant, flags, r, "Failed to decode encrypted PKCS#11 key: %m"); @@ -942,7 +933,7 @@ static int dispatch_fido2_hmac_credential(const char *name, JsonVariant *variant if (!json_variant_is_string(variant)) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); - r = unbase64mem(json_variant_string(variant), (size_t) -1, &b, &l); + r = unbase64mem(json_variant_string(variant), SIZE_MAX, &b, &l); if (r < 0) return json_log(variant, flags, r, "Failed to decode FIDO2 credential ID: %m"); @@ -972,7 +963,7 @@ static int dispatch_fido2_hmac_credential_array(const char *name, JsonVariant *v if (!array) return log_oom(); - r = unbase64mem(json_variant_string(e), (size_t) -1, &b, &l); + r = unbase64mem(json_variant_string(e), SIZE_MAX, &b, &l); if (r < 0) return json_log(variant, flags, r, "Failed to decode FIDO2 credential ID: %m"); @@ -1002,7 +993,7 @@ static int dispatch_fido2_hmac_salt_value(const char *name, JsonVariant *variant if (!json_variant_is_string(variant)) return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a string.", strna(name)); - r = unbase64mem(json_variant_string(variant), (size_t) -1, &b, &l); + r = unbase64mem(json_variant_string(variant), SIZE_MAX, &b, &l); if (r < 0) return json_log(variant, flags, r, "Failed to decode FIDO2 salt: %m"); @@ -1471,7 +1462,7 @@ int user_group_record_mangle( JsonDispatchFlags json_flags = USER_RECORD_LOAD_FLAGS_TO_JSON_DISPATCH_FLAGS(load_flags); _cleanup_(json_variant_unrefp) JsonVariant *w = NULL; JsonVariant *array[ELEMENTSOF(mask_field) * 2]; - size_t n_retain = 0, i; + size_t n_retain = 0; UserRecordMask m = 0; int r; @@ -1496,7 +1487,7 @@ int user_group_record_mangle( return json_log(v, json_flags, SYNTHETIC_ERRNO(EINVAL), "Stripping everything from record, refusing."); /* Check if we have the special sections and if they match our flags set */ - for (i = 0; i < ELEMENTSOF(mask_field); i++) { + for (size_t i = 0; i < ELEMENTSOF(mask_field); i++) { JsonVariant *e, *k; if (FLAGS_SET(USER_RECORD_STRIP_MASK(load_flags), mask_field[i].mask)) { @@ -1535,16 +1526,15 @@ int user_group_record_mangle( r = json_variant_new_object(&w, array, n_retain); if (r < 0) return json_log(v, json_flags, r, "Failed to allocate new object: %m"); - } else { + } else /* And now check if there's anything else in the record */ - for (i = 0; i < json_variant_elements(v); i += 2) { + for (size_t i = 0; i < json_variant_elements(v); i += 2) { const char *f; bool special = false; - size_t j; assert_se(f = json_variant_string(json_variant_by_index(v, i))); - for (j = 0; j < ELEMENTSOF(mask_field); j++) + for (size_t j = 0; j < ELEMENTSOF(mask_field); j++) if (streq(f, mask_field[j].name)) { /* already covered in the loop above */ special = true; continue; @@ -1558,7 +1548,6 @@ int user_group_record_mangle( break; } } - } if (FLAGS_SET(load_flags, USER_RECORD_REQUIRE_REGULAR) && !FLAGS_SET(m, USER_RECORD_REGULAR)) return json_log(v, json_flags, SYNTHETIC_ERRNO(EBADMSG), "Record lacks basic identity fields, which are required."); @@ -1765,7 +1754,7 @@ const char *user_record_skeleton_directory(UserRecord *h) { mode_t user_record_access_mode(UserRecord *h) { assert(h); - return h->access_mode != (mode_t) -1 ? h->access_mode : 0700; + return h->access_mode != MODE_INVALID ? h->access_mode : 0700; } const char* user_record_home_directory(UserRecord *h) { diff --git a/src/shared/user-record.h b/src/shared/user-record.h index 542a0dc84..623f7bc9e 100644 --- a/src/shared/user-record.h +++ b/src/shared/user-record.h @@ -54,7 +54,7 @@ typedef enum UserDisposition { USER_CONTAINER, /* UID ranges allocated for container uses */ USER_RESERVED, /* Range above 2^31 */ _USER_DISPOSITION_MAX, - _USER_DISPOSITION_INVALID = -1, + _USER_DISPOSITION_INVALID = -EINVAL, } UserDisposition; typedef enum UserHomeStorage { @@ -65,7 +65,7 @@ typedef enum UserHomeStorage { USER_FSCRYPT, USER_CIFS, _USER_STORAGE_MAX, - _USER_STORAGE_INVALID = -1 + _USER_STORAGE_INVALID = -EINVAL, } UserStorage; typedef enum UserRecordMask { diff --git a/src/shared/userdb.c b/src/shared/userdb.c index 2d480283d..0d471a2f9 100644 --- a/src/shared/userdb.c +++ b/src/shared/userdb.c @@ -1241,7 +1241,7 @@ int userdb_block_nss_systemd(int b) { 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 */ + /* If the file 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()); diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index b36bc2051..3eeee2469 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -38,18 +38,10 @@ int utmp_get_runlevel(int *runlevel, int *previous) { * very new and not apply to the current script being executed. */ e = getenv("RUNLEVEL"); - if (e && e[0] > 0) { + if (!isempty(e)) { *runlevel = e[0]; - - if (previous) { - /* $PREVLEVEL seems to be an Upstart thing */ - - e = getenv("PREVLEVEL"); - if (e && e[0] > 0) - *previous = e[0]; - else - *previous = 0; - } + if (previous) + *previous = 0; return 0; } diff --git a/src/shared/varlink.c b/src/shared/varlink.c index e7be33ca7..6ed72075b 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -54,7 +54,7 @@ typedef enum VarlinkState { VARLINK_DISCONNECTED, _VARLINK_STATE_MAX, - _VARLINK_STATE_INVALID = -1 + _VARLINK_STATE_INVALID = -EINVAL, } VarlinkState; /* Tests whether we are not yet disconnected. Note that this is true during all states where the connection @@ -281,22 +281,22 @@ int varlink_connect_address(Varlink **ret, const char *address) { r = sockaddr_un_set_path(&sockaddr.un, address); if (r < 0) - return r; + return log_debug_errno(r, "Failed to set socket address '%s': %m", address); sockaddr_len = r; r = varlink_new(&v); if (r < 0) - return r; + return log_debug_errno(r, "Failed to create varlink object: %m"); v->fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); if (v->fd < 0) - return -errno; + return log_debug_errno(errno, "Failed to create AF_UNIX socket: %m"); v->fd = fd_move_above_stdio(v->fd); if (connect(v->fd, &sockaddr.sa, sockaddr_len) < 0) { if (!IN_SET(errno, EAGAIN, EINPROGRESS)) - return -errno; + return log_debug_errno(errno, "Failed to connect to %s: %m", address); v->connecting = true; /* We are asynchronously connecting, i.e. the connect() is being * processed in the background. As long as that's the case the socket @@ -312,7 +312,7 @@ int varlink_connect_address(Varlink **ret, const char *address) { varlink_set_state(v, VARLINK_IDLE_CLIENT); *ret = TAKE_PTR(v); - return r; + return 0; } int varlink_connect_fd(Varlink **ret, int fd) { @@ -324,11 +324,11 @@ int varlink_connect_fd(Varlink **ret, int fd) { r = fd_nonblock(fd, true); if (r < 0) - return r; + return log_debug_errno(r, "Failed to make fd %d nonblocking: %m", fd); r = varlink_new(&v); if (r < 0) - return r; + return log_debug_errno(r, "Failed to create varlink object: %m"); v->fd = fd; varlink_set_state(v, VARLINK_IDLE_CLIENT); @@ -927,43 +927,57 @@ int varlink_process(Varlink *v) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); varlink_ref(v); r = varlink_write(v); + if (r < 0) + varlink_log_errno(v, r, "Write failed: %m"); if (r != 0) goto finish; r = varlink_dispatch_reply(v); + if (r < 0) + varlink_log_errno(v, r, "Reply dispatch failed: %m"); if (r != 0) goto finish; r = varlink_dispatch_method(v); + if (r < 0) + varlink_log_errno(v, r, "Method dispatch failed: %m"); if (r != 0) goto finish; r = varlink_parse_message(v); + if (r < 0) + varlink_log_errno(v, r, "Message parsing failed: %m"); if (r != 0) goto finish; r = varlink_read(v); + if (r < 0) + varlink_log_errno(v, r, "Read failed: %m"); if (r != 0) goto finish; r = varlink_test_disconnect(v); + assert(r >= 0); if (r != 0) goto finish; r = varlink_dispatch_disconnect(v); + assert(r >= 0); if (r != 0) goto finish; r = varlink_test_timeout(v); + assert(r >= 0); if (r != 0) goto finish; r = varlink_dispatch_timeout(v); + assert(r >= 0); if (r != 0) goto finish; @@ -974,7 +988,7 @@ finish: /* If we did some processing, make sure we are called again soon */ q = sd_event_source_set_enabled(v->defer_event_source, r > 0 ? SD_EVENT_ON : SD_EVENT_OFF); if (q < 0) - r = q; + r = varlink_log_errno(v, q, "Failed to enable deferred event source: %m"); } if (r < 0) { @@ -1022,7 +1036,7 @@ int varlink_wait(Varlink *v, usec_t timeout) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); r = varlink_get_timeout(v, &t); if (r < 0) @@ -1062,9 +1076,9 @@ int varlink_get_fd(Varlink *v) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); if (v->fd < 0) - return -EBADF; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBADF), "No valid fd."); return v->fd; } @@ -1075,7 +1089,7 @@ int varlink_get_events(Varlink *v) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); if (v->connecting) /* When processing an asynchronous connect(), we only wait for EPOLLOUT, which * tells us that the connection is now complete. Before that we should neither @@ -1099,7 +1113,7 @@ int varlink_get_timeout(Varlink *v, usec_t *ret) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); if (IN_SET(v->state, VARLINK_AWAITING_REPLY, VARLINK_AWAITING_REPLY_MORE, VARLINK_CALLING) && v->timeout != USEC_INFINITY) { @@ -1119,7 +1133,7 @@ int varlink_flush(Varlink *v) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); for (;;) { if (v->output_buffer_size == 0) @@ -1137,7 +1151,7 @@ int varlink_flush(Varlink *v) { r = fd_wait_for_event(v->fd, POLLOUT, USEC_INFINITY); if (r < 0) - return r; + return varlink_log_errno(v, r, "Poll failed on fd: %m"); assert(r != 0); @@ -1185,7 +1199,6 @@ static void varlink_detach_server(Varlink *v) { } int varlink_close(Varlink *v) { - assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) @@ -1193,8 +1206,9 @@ int varlink_close(Varlink *v) { varlink_set_state(v, VARLINK_DISCONNECTED); - /* Let's take a reference first, since varlink_detach_server() might drop the final (dangling) ref - * which would destroy us before we can call varlink_clear() */ + /* Let's take a reference first, since varlink_detach_server() might drop the final ref from the + * disconnect callback, which would invalidate the pointer we are holding before we can call + * varlink_clear(). */ varlink_ref(v); varlink_detach_server(v); varlink_clear(v); @@ -1204,22 +1218,36 @@ int varlink_close(Varlink *v) { } Varlink* varlink_close_unref(Varlink *v) { - if (!v) return NULL; - (void) varlink_close(v); + /* A reference is given to us to be destroyed. But when calling varlink_close(), a callback might + * also drop a reference. We allow this, and will hold a temporary reference to the object to make + * sure that the object still exists when control returns to us. If there's just one reference + * remaining after varlink_close(), even though there were at least two right before, we'll handle + * that gracefully instead of crashing. + * + * In other words, this call drops the donated reference, but if the internal call to varlink_close() + * dropped a reference to, we don't drop the reference afain. This allows the caller to say: + * global_object->varlink = varlink_close_unref(global_object->varlink); + * even though there is some callback which has access to global_object and may drop the reference + * stored in global_object->varlink. Without this step, the same code would have to be written as: + * Varlink *t = TAKE_PTR(global_object->varlink); + * varlink_close_unref(t); + */ + /* n_ref >= 1 */ + varlink_ref(v); /* n_ref >= 2 */ + varlink_close(v); /* n_ref >= 1 */ + if (v->n_ref > 1) + v->n_ref--; /* n_ref >= 1 */ return varlink_unref(v); } Varlink* varlink_flush_close_unref(Varlink *v) { + if (v) + varlink_flush(v); - if (!v) - return NULL; - - (void) varlink_flush(v); - (void) varlink_close(v); - return varlink_unref(v); + return varlink_close_unref(v); } static int varlink_enqueue_json(Varlink *v, JsonVariant *m) { @@ -1280,26 +1308,26 @@ int varlink_send(Varlink *v, const char *method, JsonVariant *parameters) { assert_return(method, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); /* We allow enqueuing multiple method calls at once! */ if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY)) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)), JSON_BUILD_PAIR("oneway", JSON_BUILD_BOOLEAN(true)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); /* No state change here, this is one-way only after all */ v->timestamp = now(CLOCK_MONOTONIC); @@ -1318,7 +1346,7 @@ int varlink_sendb(Varlink *v, const char *method, ...) { va_end(ap); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); return varlink_send(v, method, parameters); } @@ -1331,25 +1359,25 @@ int varlink_invoke(Varlink *v, const char *method, JsonVariant *parameters) { assert_return(method, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); /* We allow enqueuing multiple method calls at once! */ if (!IN_SET(v->state, VARLINK_IDLE_CLIENT, VARLINK_AWAITING_REPLY)) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); varlink_set_state(v, VARLINK_AWAITING_REPLY); v->n_pending++; @@ -1370,7 +1398,7 @@ int varlink_invokeb(Varlink *v, const char *method, ...) { va_end(ap); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); return varlink_invoke(v, method, parameters); } @@ -1383,27 +1411,27 @@ int varlink_observe(Varlink *v, const char *method, JsonVariant *parameters) { assert_return(method, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); + /* Note that we don't allow enqueuing multiple method calls when we are in more/continues mode! We * thus insist on an idle client here. */ if (v->state != VARLINK_IDLE_CLIENT) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)), JSON_BUILD_PAIR("more", JSON_BUILD_BOOLEAN(true)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; - + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); varlink_set_state(v, VARLINK_AWAITING_REPLY_MORE); v->n_pending++; @@ -1424,7 +1452,7 @@ int varlink_observeb(Varlink *v, const char *method, ...) { va_end(ap); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); return varlink_observe(v, method, parameters); } @@ -1444,25 +1472,25 @@ int varlink_call( assert_return(method, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); if (!IN_SET(v->state, VARLINK_IDLE_CLIENT)) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); assert(v->n_pending == 0); /* n_pending can't be > 0 if we are in VARLINK_IDLE_CLIENT state */ r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("method", JSON_BUILD_STRING(method)), JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); varlink_set_state(v, VARLINK_CALLING); v->n_pending++; @@ -1504,10 +1532,10 @@ int varlink_call( case VARLINK_PENDING_DISCONNECT: case VARLINK_DISCONNECTED: - return -ECONNRESET; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ECONNRESET), "Connection was closed."); case VARLINK_PENDING_TIMEOUT: - return -ETIME; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ETIME), "Connection timed out."); default: assert_not_reached("Unexpected state after method call."); @@ -1532,7 +1560,7 @@ int varlink_callb( va_end(ap); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); return varlink_call(v, method, parameters, ret_parameters, ret_error_id, ret_flags); } @@ -1552,15 +1580,15 @@ int varlink_reply(Varlink *v, JsonVariant *parameters) { r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) { /* We just replied to a method call that was let hanging for a while (i.e. we were outside of @@ -1601,25 +1629,25 @@ int varlink_error(Varlink *v, const char *error_id, JsonVariant *parameters) { assert_return(error_id, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); if (!IN_SET(v->state, VARLINK_PROCESSING_METHOD, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("error", JSON_BUILD_STRING(error_id)), JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); if (IN_SET(v->state, VARLINK_PENDING_METHOD, VARLINK_PENDING_METHOD_MORE)) { v->current = json_variant_unref(v->current); @@ -1643,7 +1671,7 @@ int varlink_errorb(Varlink *v, const char *error_id, ...) { va_end(ap); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); return varlink_error(v, error_id, parameters); } @@ -1683,23 +1711,23 @@ int varlink_notify(Varlink *v, JsonVariant *parameters) { assert_return(v, -EINVAL); if (v->state == VARLINK_DISCONNECTED) - return -ENOTCONN; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENOTCONN), "Not connected."); if (!IN_SET(v->state, VARLINK_PROCESSING_METHOD_MORE, VARLINK_PENDING_METHOD_MORE)) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "Connection busy."); r = varlink_sanitize_parameters(¶meters); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to sanitize parameters: %m"); r = json_build(&m, JSON_BUILD_OBJECT( JSON_BUILD_PAIR("parameters", JSON_BUILD_VARIANT(parameters)), JSON_BUILD_PAIR("continues", JSON_BUILD_BOOLEAN(true)))); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); r = varlink_enqueue_json(v, m); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enqueue json message: %m"); /* No state change, as more is coming */ return 1; @@ -1717,7 +1745,7 @@ int varlink_notifyb(Varlink *v, ...) { va_end(ap); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to build json message: %m"); return varlink_notify(v, parameters); } @@ -1726,7 +1754,7 @@ int varlink_bind_reply(Varlink *v, VarlinkReply callback) { assert_return(v, -EINVAL); if (callback && v->reply_callback && callback != v->reply_callback) - return -EBUSY; + return varlink_log_errno(v, SYNTHETIC_ERRNO(EBUSY), "A different callback was already set."); v->reply_callback = callback; @@ -1774,10 +1802,10 @@ int varlink_get_peer_uid(Varlink *v, uid_t *ret) { r = varlink_acquire_ucred(v); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to acquire credentials: %m"); if (!uid_is_valid(v->ucred.uid)) - return -ENODATA; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENODATA), "Peer uid is invalid."); *ret = v->ucred.uid; return 0; @@ -1791,10 +1819,10 @@ int varlink_get_peer_pid(Varlink *v, pid_t *ret) { r = varlink_acquire_ucred(v); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to acquire credentials: %m"); if (!pid_is_valid(v->ucred.pid)) - return -ENODATA; + return varlink_log_errno(v, SYNTHETIC_ERRNO(ENODATA), "Peer uid is invalid."); *ret = v->ucred.pid; return 0; @@ -1867,7 +1895,7 @@ static int prepare_callback(sd_event_source *s, void *userdata) { r = sd_event_source_set_io_events(v->io_event_source, e); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to set source events: %m"); r = varlink_get_timeout(v, &until); if (r < 0) @@ -1877,12 +1905,12 @@ static int prepare_callback(sd_event_source *s, void *userdata) { if (have_timeout) { r = sd_event_source_set_time(v->time_event_source, until); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to set source time: %m"); } r = sd_event_source_set_enabled(v->time_event_source, have_timeout ? SD_EVENT_ON : SD_EVENT_OFF); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to enable event source: %m"); return 1; } @@ -1910,7 +1938,7 @@ int varlink_attach_event(Varlink *v, sd_event *e, int64_t priority) { else { r = sd_event_default(&v->event); if (r < 0) - return r; + return varlink_log_errno(v, r, "Failed to create event source: %m"); } r = sd_event_add_time(v->event, &v->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, v); @@ -1960,6 +1988,7 @@ int varlink_attach_event(Varlink *v, sd_event *e, int64_t priority) { return 0; fail: + varlink_log_errno(v, r, "Failed to setup event source: %m"); varlink_detach_event(v); return r; } @@ -1987,7 +2016,7 @@ int varlink_server_new(VarlinkServer **ret, VarlinkServerFlags flags) { s = new(VarlinkServer, 1); if (!s) - return -ENOMEM; + return log_oom_debug(); *s = (VarlinkServer) { .n_ref = 1, @@ -2125,7 +2154,9 @@ int varlink_server_add_connection(VarlinkServer *server, int fd, Varlink **ret) return r; v->fd = fd; - v->userdata = server->userdata; + if (server->flags & VARLINK_SERVER_INHERIT_USERDATA) + v->userdata = server->userdata; + if (ucred_acquired) { v->ucred = ucred; v->ucred_acquired = true; @@ -2207,7 +2238,7 @@ int varlink_server_listen_fd(VarlinkServer *s, int fd) { ss = new(VarlinkServerSocket, 1); if (!ss) - return -ENOMEM; + return log_oom_debug(); *ss = (VarlinkServerSocket) { .server = s, @@ -2369,7 +2400,7 @@ sd_event *varlink_server_get_event(VarlinkServer *s) { } int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMethod callback) { - char *m; + _cleanup_free_ char *m = NULL; int r; assert_return(s, -EINVAL); @@ -2377,21 +2408,19 @@ int varlink_server_bind_method(VarlinkServer *s, const char *method, VarlinkMeth assert_return(callback, -EINVAL); if (startswith(method, "org.varlink.service.")) - return -EEXIST; - - r = hashmap_ensure_allocated(&s->methods, &string_hash_ops); - if (r < 0) - return r; + return log_debug_errno(SYNTHETIC_ERRNO(EEXIST), "Cannot bind server to '%s'.", method); m = strdup(method); if (!m) - return -ENOMEM; + return log_oom_debug(); - r = hashmap_put(s->methods, m, callback); - if (r < 0) { - free(m); - return r; - } + r = hashmap_ensure_put(&s->methods, &string_hash_ops, m, callback); + if (r == -ENOMEM) + return log_oom_debug(); + if (r < 0) + return log_debug_errno(r, "Failed to register callback: %m"); + if (r > 0) + TAKE_PTR(m); return 0; } @@ -2426,7 +2455,7 @@ int varlink_server_bind_connect(VarlinkServer *s, VarlinkConnect callback) { assert_return(s, -EINVAL); if (callback && s->connect_callback && callback != s->connect_callback) - return -EBUSY; + return log_debug_errno(SYNTHETIC_ERRNO(EBUSY), "A different callback was already set."); s->connect_callback = callback; return 0; @@ -2436,7 +2465,7 @@ int varlink_server_bind_disconnect(VarlinkServer *s, VarlinkDisconnect callback) assert_return(s, -EINVAL); if (callback && s->disconnect_callback && callback != s->disconnect_callback) - return -EBUSY; + return log_debug_errno(SYNTHETIC_ERRNO(EBUSY), "A different callback was already set."); s->disconnect_callback = callback; return 0; diff --git a/src/shared/varlink.h b/src/shared/varlink.h index 7ea1f9113..66a1ff630 100644 --- a/src/shared/varlink.h +++ b/src/shared/varlink.h @@ -41,11 +41,12 @@ typedef enum VarlinkMethodFlags { } VarlinkMethodFlags; typedef enum VarlinkServerFlags { - VARLINK_SERVER_ROOT_ONLY = 1 << 0, /* Only accessible by root */ - VARLINK_SERVER_MYSELF_ONLY = 1 << 1, /* Only accessible by our own UID */ - VARLINK_SERVER_ACCOUNT_UID = 1 << 2, /* Do per user accounting */ + VARLINK_SERVER_ROOT_ONLY = 1 << 0, /* Only accessible by root */ + VARLINK_SERVER_MYSELF_ONLY = 1 << 1, /* Only accessible by our own UID */ + VARLINK_SERVER_ACCOUNT_UID = 1 << 2, /* Do per user accounting */ + VARLINK_SERVER_INHERIT_USERDATA = 1 << 3, /* Initialize Varlink connection userdata from VarlinkServer userdata */ - _VARLINK_SERVER_FLAGS_ALL = (1 << 3) - 1, + _VARLINK_SERVER_FLAGS_ALL = (1 << 4) - 1, } VarlinkServerFlags; typedef int (*VarlinkMethod)(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata); diff --git a/src/shared/verbs.h b/src/shared/verbs.h index 245bb37ae..03819e38c 100644 --- a/src/shared/verbs.h +++ b/src/shared/verbs.h @@ -3,7 +3,7 @@ #include -#define VERB_ANY ((unsigned) -1) +#define VERB_ANY (UINT_MAX) typedef enum VerbFlags { VERB_DEFAULT = 1 << 0, /* The verb to run if no verb is specified */ diff --git a/src/shared/volatile-util.c b/src/shared/volatile-util.c index 3323897a4..5138edbd1 100644 --- a/src/shared/volatile-util.c +++ b/src/shared/volatile-util.c @@ -27,7 +27,7 @@ int query_volatile_mode(VolatileMode *ret) { m = volatile_mode_from_string(mode); if (m < 0) - return -EINVAL; + return m; *ret = m; } else diff --git a/src/shared/volatile-util.h b/src/shared/volatile-util.h index 9a1bb384e..6e0206d3a 100644 --- a/src/shared/volatile-util.h +++ b/src/shared/volatile-util.h @@ -7,7 +7,7 @@ typedef enum VolatileMode { VOLATILE_STATE, VOLATILE_OVERLAY, _VOLATILE_MODE_MAX, - _VOLATILE_MODE_INVALID = -1 + _VOLATILE_MODE_INVALID = -EINVAL, } VolatileMode; VolatileMode volatile_mode_from_string(const char *s); diff --git a/src/shared/wifi-util.c b/src/shared/wifi-util.c index 2ac884600..35940ad02 100644 --- a/src/shared/wifi-util.c +++ b/src/shared/wifi-util.c @@ -5,7 +5,7 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftype, char **ssid) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; - sd_genl_family family; + sd_genl_family_t family; int r; assert(genl); @@ -42,7 +42,7 @@ int wifi_get_interface(sd_netlink *genl, int ifindex, enum nl80211_iftype *iftyp if (r < 0) return log_debug_errno(r, "Failed to determine genl family: %m"); if (family != SD_GENL_NL80211) { - log_debug("Received message of unexpected genl family %u, ignoring.", family); + log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family); goto nodata; } @@ -75,7 +75,7 @@ nodata: int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL, *reply = NULL; - sd_genl_family family; + sd_genl_family_t family; int r; assert(genl); @@ -110,7 +110,7 @@ int wifi_get_station(sd_netlink *genl, int ifindex, struct ether_addr *bssid) { if (r < 0) return log_debug_errno(r, "Failed to determine genl family: %m"); if (family != SD_GENL_NL80211) { - log_debug("Received message of unexpected genl family %u, ignoring.", family); + log_debug("Received message of unexpected genl family %" PRIi64 ", ignoring.", family); goto nodata; } diff --git a/src/shutdown/meson.build b/src/shutdown/meson.build index ebf0bed24..e1348d95d 100644 --- a/src/shutdown/meson.build +++ b/src/shutdown/meson.build @@ -1,5 +1,15 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + systemd_shutdown_sources = files(''' shutdown.c umount.c umount.h '''.split()) + +tests += [ + [['src/shutdown/test-umount.c', + 'src/shutdown/umount.c', + 'src/shutdown/umount.h'], + [], + [libmount]], +] diff --git a/src/shutdown/shutdown.c b/src/shutdown/shutdown.c index 0d0786554..d2b162994 100644 --- a/src/shutdown/shutdown.c +++ b/src/shutdown/shutdown.c @@ -487,7 +487,7 @@ int main(int argc, char *argv[]) { /* There are things we cannot get rid of. Loop one more time * with LOG_ERR to inform the user. Note that we don't need * to do this if there is a initrd to switch to, because that - * one is likely to get rid of the remounting mounts. If not, + * one is likely to get rid of the remaining mounts. If not, * it will log about them. */ umount_log_level = LOG_ERR; continue; diff --git a/src/test/test-umount.c b/src/shutdown/test-umount.c similarity index 100% rename from src/test/test-umount.c rename to src/shutdown/test-umount.c diff --git a/src/shutdown/umount.c b/src/shutdown/umount.c index 3a72a13e1..906756292 100644 --- a/src/shutdown/umount.c +++ b/src/shutdown/umount.c @@ -96,13 +96,9 @@ int mount_points_list_get(const char *mountinfo, MountPoint **head) { * Even if there are duplicates later in mount_option_mangle() * they shouldn't hurt anyways as they override each other. */ - if (!strextend_with_separator(&options, ",", - mnt_fs_get_vfs_options(fs), - NULL)) + if (!strextend_with_separator(&options, ",", mnt_fs_get_vfs_options(fs))) return log_oom(); - if (!strextend_with_separator(&options, ",", - mnt_fs_get_fs_options(fs), - NULL)) + if (!strextend_with_separator(&options, ",", mnt_fs_get_fs_options(fs))) return log_oom(); /* Ignore mount points we can't unmount because they diff --git a/src/sleep/sleep.c b/src/sleep/sleep.c index 39ab55429..262d4cea6 100644 --- a/src/sleep/sleep.c +++ b/src/sleep/sleep.c @@ -169,7 +169,7 @@ static int lock_all_homes(void) { return log_debug("Successfully requested locking of all home directories."); } -static int execute(char **modes, char **states) { +static int execute(char **modes, char **states, const char *action) { char *arguments[] = { NULL, (char*) "pre", @@ -211,6 +211,10 @@ static int execute(char **modes, char **states) { return log_error_errno(r, "Failed to write mode to /sys/power/disk: %m");; } + r = setenv("SYSTEMD_SLEEP_ACTION", action, 1); + if (r != 0) + log_warning_errno(errno, "Error setting SYSTEMD_SLEEP_ACTION=%s: %m", action); + (void) execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL, NULL, arguments, NULL, EXEC_DIR_PARALLEL | EXEC_DIR_IGNORE_ERRORS); (void) lock_all_homes(); @@ -258,7 +262,7 @@ static int execute_s2h(const SleepConfig *sleep_config) { if (r < 0) return log_error_errno(errno, "Error setting hibernate timer: %m"); - r = execute(sleep_config->suspend_modes, sleep_config->suspend_states); + r = execute(sleep_config->suspend_modes, sleep_config->suspend_states, "suspend"); if (r < 0) return r; @@ -274,11 +278,11 @@ static int execute_s2h(const SleepConfig *sleep_config) { log_debug("Attempting to hibernate after waking from %s timer", format_timespan(buf, sizeof(buf), sleep_config->hibernate_delay_sec, USEC_PER_SEC)); - r = execute(sleep_config->hibernate_modes, sleep_config->hibernate_states); + r = execute(sleep_config->hibernate_modes, sleep_config->hibernate_states, "hibernate"); if (r < 0) { log_notice_errno(r, "Couldn't hibernate, will try to suspend again: %m"); - r = execute(sleep_config->suspend_modes, sleep_config->suspend_states); + r = execute(sleep_config->suspend_modes, sleep_config->suspend_states, "suspend-after-failed-hibernate"); if (r < 0) return log_error_errno(r, "Could neither hibernate nor suspend, giving up: %m"); } @@ -304,10 +308,9 @@ static int help(void) { " hybrid-sleep Both hibernate and suspend the system\n" " suspend-then-hibernate Initially suspend and then hibernate\n" " the system after a fixed period of time\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -365,7 +368,7 @@ static int run(int argc, char *argv[]) { _cleanup_(free_sleep_configp) SleepConfig *sleep_config = NULL; int r; - log_setup_service(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) @@ -387,7 +390,7 @@ static int run(int argc, char *argv[]) { if (streq(arg_verb, "suspend-then-hibernate")) return execute_s2h(sleep_config); else - return execute(modes, states); + return execute(modes, states, arg_verb); } DEFINE_MAIN_FUNCTION(run); diff --git a/src/sleep/sleep.conf b/src/sleep/sleep.conf index dc2ed37f7..7c04072d4 100644 --- a/src/sleep/sleep.conf +++ b/src/sleep/sleep.conf @@ -1,15 +1,16 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # -# See systemd-sleep.conf(5) for details +# See systemd-sleep.conf(5) for details. [Sleep] #AllowSuspend=yes diff --git a/src/socket-proxy/socket-proxyd.c b/src/socket-proxy/socket-proxyd.c index 4391d9f1f..6e3ee0d76 100644 --- a/src/socket-proxy/socket-proxyd.c +++ b/src/socket-proxy/socket-proxyd.c @@ -595,11 +595,10 @@ static int help(void) { " the %3$s for time span format\n" " -h --help Show this help\n" " --version Show package version\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - , time_link - ); + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + time_link); return 0; } diff --git a/src/stdio-bridge/stdio-bridge.c b/src/stdio-bridge/stdio-bridge.c index 81d50717b..217bd97ea 100644 --- a/src/stdio-bridge/stdio-bridge.c +++ b/src/stdio-bridge/stdio-bridge.c @@ -2,7 +2,6 @@ #include #include -#include #include #include #include @@ -15,6 +14,7 @@ #include "bus-internal.h" #include "bus-util.h" #include "errno-util.h" +#include "io-util.h" #include "log.h" #include "main-func.h" #include "util.h" @@ -23,6 +23,7 @@ static const char *arg_bus_path = DEFAULT_BUS_PATH; static BusTransport arg_transport = BUS_TRANSPORT_LOCAL; +static bool arg_user = false; static int help(void) { @@ -30,8 +31,10 @@ static int help(void) { "STDIO or socket-activatable proxy to a given DBus endpoint.\n\n" " -h --help Show this help\n" " --version Show package version\n" - " -p --bus-path=PATH Path to the kernel bus (default: %s)\n" - " -M --machine=MACHINE Name of machine to connect to\n", + " -p --bus-path=PATH Path to the bus address (default: %s)\n" + " --system Connect to system bus\n" + " --user Connect to user bus\n" + " -M --machine=CONTAINER Name of local container to connect to\n", program_invocation_short_name, DEFAULT_BUS_PATH); return 0; @@ -42,12 +45,16 @@ static int parse_argv(int argc, char *argv[]) { enum { ARG_VERSION = 0x100, ARG_MACHINE, + ARG_USER, + ARG_SYSTEM, }; static const struct option options[] = { { "help", no_argument, NULL, 'h' }, { "version", no_argument, NULL, ARG_VERSION }, { "bus-path", required_argument, NULL, 'p' }, + { "user", no_argument, NULL, ARG_USER }, + { "system", no_argument, NULL, ARG_SYSTEM }, { "machine", required_argument, NULL, 'M' }, {}, }; @@ -67,6 +74,14 @@ static int parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); + case ARG_USER: + arg_user = true; + break; + + case ARG_SYSTEM: + arg_user = false; + break; + case 'p': arg_bus_path = optarg; break; @@ -121,7 +136,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(r, "Failed to allocate bus: %m"); if (arg_transport == BUS_TRANSPORT_MACHINE) - r = bus_set_address_system_machine(a, arg_bus_path); + r = bus_set_address_machine(a, arg_user, arg_bus_path); else r = sd_bus_set_address(a, arg_bus_path); if (r < 0) @@ -166,8 +181,9 @@ static int run(int argc, char *argv[]) { for (;;) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; int events_a, events_b, fd; - uint64_t timeout_a, timeout_b, t; - struct timespec _ts, *ts; + usec_t timeout_a, timeout_b, t; + + assert_cc(sizeof(usec_t) == sizeof(uint64_t)); r = sd_bus_process(a, &m); if (r < 0) @@ -220,23 +236,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to get timeout: %m"); - t = timeout_a; - if (t == (uint64_t) -1 || (timeout_b != (uint64_t) -1 && timeout_b < timeout_a)) - t = timeout_b; - - if (t == (uint64_t) -1) - ts = NULL; - else { - usec_t nw; - - nw = now(CLOCK_MONOTONIC); - if (t > nw) - t -= nw; - else - t = 0; - - ts = timespec_store(&_ts, t); - } + t = usec_sub_unsigned(MIN(timeout_a, timeout_b), now(CLOCK_MONOTONIC)); struct pollfd p[3] = { { .fd = fd, .events = events_a }, @@ -244,13 +244,9 @@ static int run(int argc, char *argv[]) { { .fd = STDOUT_FILENO, .events = events_b & POLLOUT }, }; - r = ppoll(p, ELEMENTSOF(p), ts, NULL); + r = ppoll_usec(p, ELEMENTSOF(p), t); if (r < 0) - return log_error_errno(errno, "ppoll() failed: %m"); - if (p[0].revents & POLLNVAL || - p[1].revents & POLLNVAL || - p[2].revents & POLLNVAL) - return log_error_errno(SYNTHETIC_ERRNO(EBADF), "Invalid file descriptor to poll on?"); + return log_error_errno(r, "ppoll() failed: %m"); } return 0; diff --git a/src/sulogin-shell/sulogin-shell.c b/src/sulogin-shell/sulogin-shell.c index b0d71ff58..0207e85b7 100644 --- a/src/sulogin-shell/sulogin-shell.c +++ b/src/sulogin-shell/sulogin-shell.c @@ -100,7 +100,7 @@ int main(int argc, char *argv[]) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; - log_setup_service(); + log_setup(); print_mode(argc > 1 ? argv[1] : ""); diff --git a/src/sysctl/sysctl.c b/src/sysctl/sysctl.c index e263d459a..15b68b7d2 100644 --- a/src/sysctl/sysctl.c +++ b/src/sysctl/sysctl.c @@ -161,7 +161,7 @@ static int apply_all(OrderedHashmap *sysctl_options) { continue; if (ordered_hashmap_contains(sysctl_options, key)) { - log_info("Not setting %s (explicit setting exists).", key); + log_debug("Not setting %s (explicit setting exists).", key); continue; } @@ -294,10 +294,9 @@ static int help(void) { " --cat-config Show configuration files\n" " --prefix=PATH Only apply rules with the specified prefix\n" " --no-pager Do not pipe output into a pager\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -387,7 +386,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/sysext/meson.build b/src/sysext/meson.build new file mode 100644 index 000000000..1517df414 --- /dev/null +++ b/src/sysext/meson.build @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +systemd_sysext_sources = files(''' + sysext.c +'''.split()) diff --git a/src/sysext/sysext.c b/src/sysext/sysext.c new file mode 100644 index 000000000..9b1c4908a --- /dev/null +++ b/src/sysext/sysext.c @@ -0,0 +1,992 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include + +#include "capability-util.h" +#include "discover-image.h" +#include "dissect-image.h" +#include "env-util.h" +#include "escape.h" +#include "extension-release.h" +#include "fd-util.h" +#include "fileio.h" +#include "format-table.h" +#include "fs-util.h" +#include "hashmap.h" +#include "log.h" +#include "main-func.h" +#include "missing_magic.h" +#include "mkdir.h" +#include "mount-util.h" +#include "mountpoint-util.h" +#include "os-util.h" +#include "pager.h" +#include "parse-argument.h" +#include "parse-util.h" +#include "pretty-print.h" +#include "process-util.h" +#include "sort-util.h" +#include "stat-util.h" +#include "terminal-util.h" +#include "user-util.h" +#include "verbs.h" + +static char **arg_hierarchies = NULL; /* "/usr" + "/opt" by default */ +static char *arg_root = NULL; +static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF; +static PagerFlags arg_pager_flags = 0; +static bool arg_legend = true; +static bool arg_force = false; + +STATIC_DESTRUCTOR_REGISTER(arg_hierarchies, strv_freep); +STATIC_DESTRUCTOR_REGISTER(arg_root, freep); + +static int is_our_mount_point(const char *p) { + _cleanup_free_ char *buf = NULL, *f = NULL; + struct stat st; + dev_t dev; + int r; + + r = path_is_mount_point(p, NULL, 0); + if (r == -ENOENT) { + log_debug_errno(r, "Hierarchy '%s' doesn't exist.", p); + return false; + } + if (r < 0) + return log_error_errno(r, "Failed to determine whether '%s' is a mount point: %m", p); + if (r == 0) { + log_debug("Hierarchy '%s' is not a mount point, skipping.", p); + return false; + } + + /* So we know now that it's a mount point. Now let's check if it's one of ours, so that we don't + * accidentally unmount the user's own /usr/ but just the mounts we established ourselves. We do this + * check by looking into the metadata directory we place in merged mounts: if the file + * .systemd-sysext/dev contains the major/minor device pair of the mount we have a good reason to + * believe this is one of our mounts. This thorough check has the benefit that we aren't easily + * confused if people tar up one of our merged trees and untar them elsewhere where we might mistake + * them for a live sysext tree. */ + + f = path_join(p, ".systemd-sysext/dev"); + if (!f) + return log_oom(); + + r = read_one_line_file(f, &buf); + if (r == -ENOENT) { + log_debug("Hierarchy '%s' does not carry a .systemd-sysext/dev file, not a sysext merged tree.", p); + return false; + } + if (r < 0) + return log_error_errno(r, "Failed to determine whether hierarchy '%s' contains '.systemd-sysext/dev': %m", p); + + r = parse_dev(buf, &dev); + if (r < 0) + return log_error_errno(r, "Failed to parse device major/minor stored in '.systemd-sysext/dev' file on '%s': %m", p); + + if (lstat(p, &st) < 0) + return log_error_errno(r, "Failed to stat %s: %m", p); + + if (st.st_dev != dev) { + log_debug("Hierarchy '%s' reports a different device major/minor than what we are seeing, assuming offline copy.", p); + return false; + } + + return true; +} + +static int unmerge_hierarchy(const char *p) { + int r; + + for (;;) { + /* We only unmount /usr/ if it is a mount point and really one of ours, in order not to break + * systems where /usr/ is a mount point of its own already. */ + + r = is_our_mount_point(p); + if (r < 0) + return r; + if (r == 0) + break; + + r = umount_verbose(LOG_ERR, p, MNT_DETACH|UMOUNT_NOFOLLOW); + if (r < 0) + return log_error_errno(r, "Failed to unmount file system '%s': %m", p); + + log_info("Unmerged '%s'.", p); + } + + return 0; +} + +static int unmerge(void) { + int r, ret = 0; + char **p; + + STRV_FOREACH(p, arg_hierarchies) { + _cleanup_free_ char *resolved = NULL; + + r = chase_symlinks(*p, arg_root, CHASE_PREFIX_ROOT, &resolved, NULL); + if (r == -ENOENT) { + log_debug_errno(r, "Hierarchy '%s%s' does not exist, ignoring.", strempty(arg_root), *p); + continue; + } + if (r < 0) { + log_error_errno(r, "Failed to resolve path to hierarchy '%s%s': %m", strempty(arg_root), *p); + if (ret == 0) + ret = r; + + continue; + } + + r = unmerge_hierarchy(resolved); + if (r < 0 && ret == 0) + ret = r; + } + + return ret; +} + +static int verb_unmerge(int argc, char **argv, void *userdata) { + + if (!have_effective_cap(CAP_SYS_ADMIN)) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be privileged."); + + return unmerge(); +} + +static int verb_status(int argc, char **argv, void *userdata) { + _cleanup_(table_unrefp) Table *t = NULL; + int r, ret = 0; + char **p; + + t = table_new("hierarchy", "extensions", "since"); + if (!t) + return log_oom(); + + (void) table_set_empty_string(t, "-"); + + STRV_FOREACH(p, arg_hierarchies) { + _cleanup_free_ char *resolved = NULL, *f = NULL, *buf = NULL; + _cleanup_strv_free_ char **l = NULL; + struct stat st; + + r = chase_symlinks(*p, arg_root, CHASE_PREFIX_ROOT, &resolved, NULL); + if (r == -ENOENT) { + log_debug_errno(r, "Hierarchy '%s%s' does not exist, ignoring.", strempty(arg_root), *p); + continue; + } + if (r < 0) { + log_error_errno(r, "Failed to resolve path to hierarchy '%s%s': %m", strempty(arg_root), *p); + goto inner_fail; + } + + r = is_our_mount_point(resolved); + if (r < 0) + goto inner_fail; + if (r == 0) { + r = table_add_many( + t, + TABLE_PATH, *p, + TABLE_STRING, "none", + TABLE_SET_COLOR, ansi_grey(), + TABLE_EMPTY); + if (r < 0) + return table_log_add_error(r); + + continue; + } + + f = path_join(*p, ".systemd-sysext/extensions"); + if (!f) + return log_oom(); + + r = read_full_file(f, &buf, NULL); + if (r < 0) + return log_error_errno(r, "Failed to open '%s': %m", f); + + l = strv_split_newlines(buf); + if (!l) + return log_oom(); + + if (stat(*p, &st) < 0) + return log_error_errno(r, "Failed to stat() '%s': %m", *p); + + r = table_add_many( + t, + TABLE_PATH, *p, + TABLE_STRV, l, + TABLE_TIMESTAMP, timespec_load(&st.st_mtim)); + if (r < 0) + return table_log_add_error(r); + + continue; + + inner_fail: + if (ret == 0) + ret = r; + } + + (void) table_set_sort(t, (size_t) 0); + + r = table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); + if (r < 0) + return r; + + return ret; +} + +static int mount_overlayfs( + const char *where, + char **layers) { + + _cleanup_free_ char *options = NULL; + bool separator = false; + char **l; + int r; + + assert(where); + + options = strdup("lowerdir="); + if (!options) + return log_oom(); + + STRV_FOREACH(l, layers) { + _cleanup_free_ char *escaped = NULL; + + escaped = shell_escape(*l, ",:"); + if (!escaped) + return log_oom(); + + if (!strextend(&options, separator ? ":" : "", escaped)) + return log_oom(); + + separator = true; + } + + /* Now mount the actual overlayfs */ + r = mount_nofollow_verbose(LOG_ERR, "sysext", where, "overlay", MS_RDONLY, options); + if (r < 0) + return r; + + return 0; +} + +static int merge_hierarchy( + const char *hierarchy, + char **extensions, + char **paths, + const char *meta_path, + const char *overlay_path) { + + _cleanup_free_ char *resolved_hierarchy = NULL, *f = NULL, *buf = NULL; + _cleanup_strv_free_ char **layers = NULL; + struct stat st; + char **p; + int r; + + assert(hierarchy); + assert(meta_path); + assert(overlay_path); + + /* Resolve the path of the host's version of the hierarchy, i.e. what we want to use as lowest layer + * in the overlayfs stack. */ + r = chase_symlinks(hierarchy, arg_root, CHASE_PREFIX_ROOT, &resolved_hierarchy, NULL); + if (r == -ENOENT) + log_debug_errno(r, "Hierarchy '%s' on host doesn't exist, not merging.", hierarchy); + else if (r < 0) + return log_error_errno(r, "Failed to resolve host hierarchy '%s': %m", hierarchy); + else { + r = dir_is_empty(resolved_hierarchy); + if (r < 0) + return log_error_errno(r, "Failed to check if host hierarchy '%s' is empty: %m", resolved_hierarchy); + if (r > 0) { + log_debug("Host hierarchy '%s' is empty, not merging.", resolved_hierarchy); + resolved_hierarchy = mfree(resolved_hierarchy); + } + } + + /* Let's generate a metadata file that lists all extensions we took into account for this + * hierarchy. We include this in the final fs, to make things nicely discoverable and + * recognizable. */ + f = path_join(meta_path, ".systemd-sysext/extensions"); + if (!f) + return log_oom(); + + buf = strv_join(extensions, "\n"); + if (!buf) + return log_oom(); + + r = write_string_file(f, buf, WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_MKDIR_0755); + if (r < 0) + return log_error_errno(r, "Failed to write extension meta file '%s': %m", f); + + /* Put the meta path (i.e. our synthesized stuff) at the top of the layer stack */ + layers = strv_new(meta_path); + if (!layers) + return log_oom(); + + /* Put the extensions in the middle */ + STRV_FOREACH(p, paths) { + _cleanup_free_ char *resolved = NULL; + + r = chase_symlinks(hierarchy, *p, CHASE_PREFIX_ROOT, &resolved, NULL); + if (r == -ENOENT) { + log_debug_errno(r, "Hierarchy '%s' in extension '%s' doesn't exist, not merging.", hierarchy, *p); + continue; + } + if (r < 0) + return log_error_errno(r, "Failed to resolve hierarchy '%s' in extension '%s': %m", hierarchy, *p); + + r = dir_is_empty(resolved); + if (r < 0) + return log_error_errno(r, "Failed to check if hierarchy '%s' in extension '%s' is empty: %m", resolved, *p); + if (r > 0) { + log_debug("Hierarchy '%s' in extension '%s' is empty, not merging.", hierarchy, *p); + continue; + } + + r = strv_consume(&layers, TAKE_PTR(resolved)); + if (r < 0) + return log_oom(); + } + + if (!layers[1]) /* No extension with files in this hierarchy? Then don't do anything. */ + return 0; + + if (resolved_hierarchy) { + /* Add the host hierarchy as last (lowest) layer in the stack */ + r = strv_consume(&layers, TAKE_PTR(resolved_hierarchy)); + if (r < 0) + return log_oom(); + } + + r = mkdir_p(overlay_path, 0700); + if (r < 0) + return log_error_errno(r, "Failed to make directory '%s': %m", overlay_path); + + r = mount_overlayfs(overlay_path, layers); + if (r < 0) + return r; + + /* The overlayfs superblock is read-only. Let's also mark the bind mount read-only. Extra turbo safety 😎 */ + r = bind_remount_recursive(overlay_path, MS_RDONLY, MS_RDONLY, NULL); + if (r < 0) + return log_error_errno(r, "Failed to make bind mount '%s' read-only: %m", overlay_path); + + /* Now we have mounted the new file system. Let's now figure out its .st_dev field, and make that + * available in the metadata directory. This is useful to detect whether the metadata dir actually + * belongs to the fs it is found on: if .st_dev of the top-level mount matches it, it's pretty likely + * we are looking at a live sysext tree, and not an unpacked tar or so of one. */ + if (stat(overlay_path, &st) < 0) + return log_error_errno(r, "Failed to stat mount '%s': %m", overlay_path); + + free(f); + f = path_join(meta_path, ".systemd-sysext/dev"); + if (!f) + return log_oom(); + + r = write_string_filef(f, WRITE_STRING_FILE_CREATE, "%u:%u", major(st.st_dev), minor(st.st_dev)); + if (r < 0) + return log_error_errno(r, "Failed to write '%s': %m", f); + + /* Make sure the top-level dir has an mtime marking the point we established the merge */ + if (utimensat(AT_FDCWD, meta_path, NULL, AT_SYMLINK_NOFOLLOW) < 0) + return log_error_errno(r, "Failed fix mtime of '%s': %m", meta_path); + + return 1; +} + +static int strverscmp_improvedp(char *const* a, char *const* b) { + /* usable in qsort() for sorting a string array with strverscmp_improved() */ + return strverscmp_improved(*a, *b); +} + +static int validate_version( + const char *root, + const Image *img, + const char *host_os_release_id, + const char *host_os_release_version_id, + const char *host_os_release_sysext_level) { + + int r; + + assert(root); + assert(img); + + if (arg_force) { + log_debug("Force mode enabled, skipping version validation."); + return 1; + } + + /* Insist that extension images do not overwrite the underlying OS release file (it's fine if + * they place one in /etc/os-release, i.e. where things don't matter, as they aren't + * merged.) */ + r = chase_symlinks("/usr/lib/os-release", root, CHASE_PREFIX_ROOT, NULL, NULL); + if (r < 0) { + if (r != -ENOENT) + return log_error_errno(r, "Failed to determine whether /usr/lib/os-release exists in the extension image: %m"); + } else + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Extension image contains /usr/lib/os-release file, which is not allowed (it may carry /etc/os-release), refusing."); + + return extension_release_validate( + img->name, + host_os_release_id, + host_os_release_version_id, + host_os_release_sysext_level, + img->extension_release); +} + +static int merge_subprocess(Hashmap *images, const char *workspace) { + _cleanup_free_ char *host_os_release_id = NULL, *host_os_release_version_id = NULL, *host_os_release_sysext_level = NULL, + *buf = NULL; + _cleanup_strv_free_ char **extensions = NULL, **paths = NULL; + size_t n_extensions = 0; + unsigned n_ignored = 0; + Image *img; + char **h; + int r; + + /* Mark the whole of /run as MS_SLAVE, so that we can mount stuff below it that doesn't show up on + * the host otherwise. */ + r = mount_nofollow_verbose(LOG_ERR, NULL, "/run", NULL, MS_SLAVE|MS_REC, NULL); + if (r < 0) + return log_error_errno(r, "Failed to remount /run/ MS_SLAVE: %m"); + + /* Let's create the workspace if it's missing */ + r = mkdir_p(workspace, 0700); + if (r < 0) + return log_error_errno(r, "Failed to create /run/systemd/sysext: %m"); + + /* Let's mount a tmpfs to our workspace. This way we don't need to clean up the inodes we mount over, + * but let the kernel do that entirely automatically, once our namespace dies. Note that this file + * system won't be visible to anyone but us, since we opened our own namespace and then made the + * /run/ hierarchy (which our workspace is contained in) MS_SLAVE, see above. */ + r = mount_nofollow_verbose(LOG_ERR, "sysexit", workspace, "tmpfs", 0, "mode=0700"); + if (r < 0) + return r; + + /* Acquire host OS release info, so that we can compare it with the extension's data */ + r = parse_os_release( + arg_root, + "ID", &host_os_release_id, + "VERSION_ID", &host_os_release_version_id, + "SYSEXT_LEVEL", &host_os_release_sysext_level); + if (r < 0) + return log_error_errno(r, "Failed to acquire 'os-release' data of OS tree '%s': %m", empty_to_root(arg_root)); + + /* Let's now mount all images */ + HASHMAP_FOREACH(img, images) { + _cleanup_free_ char *p = NULL; + + p = path_join(workspace, "extensions", img->name); + if (!p) + return log_oom(); + + r = mkdir_p(p, 0700); + if (r < 0) + return log_error_errno(r, "Failed to create %s: %m", p); + + switch (img->type) { + case IMAGE_DIRECTORY: + case IMAGE_SUBVOLUME: + r = mount_nofollow_verbose(LOG_ERR, img->path, p, NULL, MS_BIND, NULL); + if (r < 0) + return r; + + /* Make this a read-only bind mount */ + r = bind_remount_recursive(p, MS_RDONLY, MS_RDONLY, NULL); + if (r < 0) + return log_error_errno(r, "Failed to make bind mount '%s' read-only: %m", p); + + break; + + case IMAGE_RAW: + case IMAGE_BLOCK: { + _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL; + _cleanup_(loop_device_unrefp) LoopDevice *d = NULL; + _cleanup_(decrypted_image_unrefp) DecryptedImage *di = NULL; + _cleanup_(verity_settings_done) VeritySettings verity_settings = VERITY_SETTINGS_DEFAULT; + DissectImageFlags flags = DISSECT_IMAGE_READ_ONLY|DISSECT_IMAGE_REQUIRE_ROOT|DISSECT_IMAGE_MOUNT_ROOT_ONLY; + + r = verity_settings_load(&verity_settings, img->path, NULL, NULL); + if (r < 0) + return log_error_errno(r, "Failed to read verity artifacts for %s: %m", img->path); + + if (verity_settings.data_path) + flags |= DISSECT_IMAGE_NO_PARTITION_TABLE; + + r = loop_device_make_by_path(img->path, O_RDONLY, 0, &d); + if (r < 0) + return log_error_errno(r, "Failed to set up loopback device: %m"); + + r = dissect_image_and_warn( + d->fd, + img->path, + &verity_settings, + NULL, + flags, + &m); + if (r < 0) + return r; + + r = dissected_image_decrypt_interactively( + m, NULL, + &verity_settings, + flags, + &di); + if (r < 0) + return r; + + r = dissected_image_mount_and_warn( + m, + p, + UID_INVALID, + flags); + if (r < 0) + return r; + + if (di) { + r = decrypted_image_relinquish(di); + if (r < 0) + return log_error_errno(r, "Failed to relinquish DM devices: %m"); + } + + loop_device_relinquish(d); + break; + } + default: + assert_not_reached("Unsupported image type"); + } + + r = validate_version( + p, + img, + host_os_release_id, + host_os_release_version_id, + host_os_release_sysext_level); + if (r < 0) + return r; + if (r == 0) { + n_ignored++; + continue; + } + + /* Noice! This one is an extension we want. */ + r = strv_extend(&extensions, img->name); + if (r < 0) + return log_oom(); + + n_extensions ++; + } + + /* Nothing left? Then shortcut things */ + if (n_extensions == 0) { + if (n_ignored > 0) + log_info("No suitable extensions found (%u ignored due to incompatible version).", n_ignored); + else + log_info("No extensions found."); + return 0; + } + + /* Order by version sort with strverscmp_improved() */ + typesafe_qsort(extensions, n_extensions, strverscmp_improvedp); + + buf = strv_join(extensions, "', '"); + if (!buf) + return log_oom(); + + log_info("Using extensions '%s'.", buf); + + /* Build table of extension paths (in reverse order) */ + paths = new0(char*, n_extensions + 1); + if (!paths) + return log_oom(); + + for (size_t k = 0; k < n_extensions; k++) { + _cleanup_free_ char *p = NULL; + + assert_se(img = hashmap_get(images, extensions[n_extensions - 1 - k])); + + p = path_join(workspace, "extensions", img->name); + if (!p) + return log_oom(); + + paths[k] = TAKE_PTR(p); + } + + /* Let's now unmerge the status quo ante, since to build the new overlayfs we need a reference to the + * underlying fs. */ + STRV_FOREACH(h, arg_hierarchies) { + _cleanup_free_ char *resolved = NULL; + + r = chase_symlinks(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL); + if (r < 0) + return log_error_errno(r, "Failed to resolve hierarchy '%s%s': %m", strempty(arg_root), *h); + + r = unmerge_hierarchy(resolved); + if (r < 0) + return r; + } + + /* Create overlayfs mounts for all hierarchies */ + STRV_FOREACH(h, arg_hierarchies) { + _cleanup_free_ char *meta_path = NULL, *overlay_path = NULL; + + meta_path = path_join(workspace, "meta", *h); /* The place where to store metadata about this instance */ + if (!meta_path) + return log_oom(); + + overlay_path = path_join(workspace, "overlay", *h); /* The resulting overlayfs instance */ + if (!overlay_path) + return log_oom(); + + r = merge_hierarchy(*h, extensions, paths, meta_path, overlay_path); + if (r < 0) + return r; + } + + /* And move them all into place. This is where things appear in the host namespace */ + STRV_FOREACH(h, arg_hierarchies) { + _cleanup_free_ char *p = NULL, *resolved = NULL; + + p = path_join(workspace, "overlay", *h); + if (!p) + return log_oom(); + + if (laccess(p, F_OK) < 0) { + if (errno != ENOENT) + return log_error_errno(errno, "Failed to check if '%s' exists: %m", p); + + /* Hierarchy apparently was empty in all extensions, and wasn't mounted, ignoring. */ + continue; + } + + r = chase_symlinks(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL); + if (r < 0) + return log_error_errno(r, "Failed to resolve hierarchy '%s%s': %m", strempty(arg_root), *h); + + r = mkdir_p(resolved, 0755); + if (r < 0) + return log_error_errno(r, "Failed to create hierarchy mount point '%s': %m", resolved); + + r = mount_nofollow_verbose(LOG_ERR, p, resolved, NULL, MS_BIND, NULL); + if (r < 0) + return r; + + log_info("Merged extensions into '%s'.", resolved); + } + + return 1; +} + +static int merge(Hashmap *images) { + pid_t pid; + int r; + + r = safe_fork("(sd-sysext)", FORK_DEATHSIG|FORK_LOG|FORK_NEW_MOUNTNS, &pid); + if (r < 0) + return log_error_errno(r, "Failed to fork off child: %m"); + if (r == 0) { + /* Child with its own mount namespace */ + + r = merge_subprocess(images, "/run/systemd/sysext"); + if (r < 0) + _exit(EXIT_FAILURE); + + /* Our namespace ceases to exist here, also implicitly detaching all temporary mounts we + * created below /run. Nice! */ + + _exit(r > 0 ? EXIT_SUCCESS : 123); /* 123 means: didn't find any extensions */ + } + + r = wait_for_terminate_and_check("(sd-sysext)", pid, WAIT_LOG_ABNORMAL); + if (r < 0) + return r; + + return r != 123; /* exit code 123 means: didn't do anything */ +} + +static int image_discover_and_read_metadata(Hashmap **ret_images) { + _cleanup_(hashmap_freep) Hashmap *images = NULL; + Image *img; + int r; + + assert(ret_images); + + images = hashmap_new(&image_hash_ops); + if (!images) + return log_oom(); + + r = image_discover(IMAGE_EXTENSION, arg_root, images); + if (r < 0) + return log_error_errno(r, "Failed to discover extension images: %m"); + + HASHMAP_FOREACH(img, images) { + r = image_read_metadata(img); + if (r < 0) + return log_error_errno(r, "Failed to read metadata for image %s: %m", img->name); + } + + *ret_images = TAKE_PTR(images); + + return 0; +} + +static int verb_merge(int argc, char **argv, void *userdata) { + _cleanup_(hashmap_freep) Hashmap *images = NULL; + char **p; + int r; + + if (!have_effective_cap(CAP_SYS_ADMIN)) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be privileged."); + + r = image_discover_and_read_metadata(&images); + if (r < 0) + return r; + + /* In merge mode fail if things are already merged. (In --refresh mode below we'll unmerge if we find + * things are already merged...) */ + STRV_FOREACH(p, arg_hierarchies) { + _cleanup_free_ char *resolved = NULL; + + r = chase_symlinks(*p, arg_root, CHASE_PREFIX_ROOT, &resolved, NULL); + if (r == -ENOENT) { + log_debug_errno(r, "Hierarchy '%s%s' does not exist, ignoring.", strempty(arg_root), *p); + continue; + } + if (r < 0) + return log_error_errno(r, "Failed to resolve path to hierarchy '%s%s': %m", strempty(arg_root), *p); + + r = is_our_mount_point(resolved); + if (r < 0) + return r; + if (r > 0) + return log_error_errno(SYNTHETIC_ERRNO(EBUSY), + "Hierarchy '%s' is already merged.", *p); + } + + return merge(images); +} + +static int verb_refresh(int argc, char **argv, void *userdata) { + _cleanup_(hashmap_freep) Hashmap *images = NULL; + int r; + + if (!have_effective_cap(CAP_SYS_ADMIN)) + return log_error_errno(SYNTHETIC_ERRNO(EPERM), "Need to be privileged."); + + r = image_discover_and_read_metadata(&images); + if (r < 0) + return r; + + r = merge(images); /* Returns > 0 if it did something, i.e. a new overlayfs is mounted now. When it + * does so it implicitly unmounts any overlayfs placed there before. Returns == 0 + * if it did nothing, i.e. no extension images found. In this case the old + * overlayfs remains in place if there was one. */ + if (r < 0) + return r; + if (r == 0) /* No images found? Then unmerge. The goal of --refresh is after all that after having + * called there's a guarantee that the merge status matches the installed extensions. */ + r = unmerge(); + + /* Net result here is that: + * + * 1. If an overlayfs was mounted before and no extensions exist anymore, we'll have unmerged things. + * + * 2. If an overlayfs was mounted before, and there are still extensions installed' we'll have + * unmerged and then merged things again. + * + * 3. If an overlayfs so far wasn't mounted, and there are extensions installed, we'll have it + * mounted now. + * + * 4. If there was no overlayfs mount so far, and no extensions installed, we implement a NOP. + */ + + return 0; +} + +static int verb_list(int argc, char **argv, void *userdata) { + _cleanup_(hashmap_freep) Hashmap *images = NULL; + _cleanup_(table_unrefp) Table *t = NULL; + Image *img; + int r; + + images = hashmap_new(&image_hash_ops); + if (!images) + return log_oom(); + + r = image_discover(IMAGE_EXTENSION, arg_root, images); + if (r < 0) + return log_error_errno(r, "Failed to discover extension images: %m"); + + if ((arg_json_format_flags & JSON_FORMAT_OFF) && hashmap_isempty(images)) { + log_info("No OS extensions found."); + return 0; + } + + t = table_new("name", "type", "path", "time"); + if (!t) + return log_oom(); + + HASHMAP_FOREACH(img, images) { + r = table_add_many( + t, + TABLE_STRING, img->name, + TABLE_STRING, image_type_to_string(img->type), + TABLE_PATH, img->path, + TABLE_TIMESTAMP, img->mtime != 0 ? img->mtime : img->crtime); + if (r < 0) + return table_log_add_error(r); + } + + (void) table_set_sort(t, (size_t) 0); + + return table_print_with_pager(t, arg_json_format_flags, arg_pager_flags, arg_legend); +} + +static int verb_help(int argc, char **argv, void *userdata) { + _cleanup_free_ char *link = NULL; + int r; + + r = terminal_urlify_man("systemd-sysext", "1", &link); + if (r < 0) + return log_oom(); + + printf("%1$s [OPTIONS...] [DEVICE]\n" + "\n%5$sMerge extension images into /usr/ and /opt/ hierarchies.%6$s\n" + "\n%3$sCommands:%4$s\n" + " status Show current merge status (default)\n" + " merge Merge extensions into /usr/ and /opt/\n" + " unmerge Unmerge extensions from /usr/ and /opt/\n" + " refresh Unmerge/merge extensions again\n" + " list List installed extensions\n" + " -h --help Show this help\n" + " --version Show package version\n" + "\n%3$sOptions:%4$s\n" + " --no-pager Do not pipe output into a pager\n" + " --no-legend Do not show the headers and footers\n" + " --root=PATH Operate relative to root path\n" + " --json=pretty|short|off\n" + " Generate JSON output\n" + " --force Ignore version incompatibilities\n" + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_NO_PAGER, + ARG_NO_LEGEND, + ARG_ROOT, + ARG_JSON, + ARG_FORCE, + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, ARG_VERSION }, + { "no-pager", no_argument, NULL, ARG_NO_PAGER }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "root", required_argument, NULL, ARG_ROOT }, + { "json", required_argument, NULL, ARG_JSON }, + { "force", no_argument, NULL, ARG_FORCE }, + {} + }; + + int c, r; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) + + switch (c) { + + case 'h': + return verb_help(argc, argv, NULL); + + case ARG_VERSION: + return version(); + + case ARG_NO_PAGER: + arg_pager_flags |= PAGER_DISABLE; + break; + + case ARG_NO_LEGEND: + arg_legend = false; + break; + + case ARG_ROOT: + r = parse_path_argument(optarg, false, &arg_root); + if (r < 0) + return r; + break; + + case ARG_JSON: + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; + + break; + + case ARG_FORCE: + arg_force = true; + break; + + case '?': + return -EINVAL; + + default: + assert_not_reached("Unhandled option"); + } + + return 1; +} + +static int sysext_main(int argc, char *argv[]) { + + static const Verb verbs[] = { + { "status", VERB_ANY, 1, VERB_DEFAULT, verb_status }, + { "merge", VERB_ANY, 1, 0, verb_merge }, + { "unmerge", VERB_ANY, 1, 0, verb_unmerge }, + { "refresh", VERB_ANY, 1, 0, verb_refresh }, + { "list", VERB_ANY, 1, 0, verb_list }, + { "help", VERB_ANY, 1, 0, verb_help }, + {} + }; + + return dispatch_verb(argc, argv, verbs, NULL); +} + +static int run(int argc, char *argv[]) { + int r; + + log_setup(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + /* For debugging purposes it might make sense to do this for other hierarchies than /usr/ and + * /opt/, but let's make that a hacker/debugging feature, i.e. env var instead of cmdline + * switch. */ + r = parse_env_extension_hierarchies(&arg_hierarchies); + if (r < 0) + return log_error_errno(r, "Failed to parse $SYSTEMD_SYSEXT_HIERARCHIES environment variable: %m"); + + return sysext_main(argc, argv); +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/systemctl/fuzz-systemctl-parse-argv.c b/src/systemctl/fuzz-systemctl-parse-argv.c new file mode 100644 index 000000000..66b48eee8 --- /dev/null +++ b/src/systemctl/fuzz-systemctl-parse-argv.c @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "env-util.h" +#include "fd-util.h" +#include "fuzz.h" +#include "selinux-util.h" +#include "static-destruct.h" +#include "stdio-util.h" +#include "strv.h" +#include "systemctl.h" +#include "systemctl-util.h" + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + _cleanup_strv_free_ char **argv = NULL; + _cleanup_close_ int orig_stdout_fd = -1; + int r; + + /* We don't want to fill the logs with messages about parse errors. + * Disable most logging if not running standalone */ + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); + + arg_pager_flags = PAGER_DISABLE; /* We shouldn't execute the pager */ + + argv = strv_parse_nulstr((const char *)data, size); + if (!argv) + return log_oom(); + + if (!argv[0]) + return 0; /* argv[0] should always be present, but may be zero-length. */ + + if (getenv_bool("SYSTEMD_FUZZ_OUTPUT") <= 0) { + orig_stdout_fd = fcntl(fileno(stdout), F_DUPFD_CLOEXEC, 3); + if (orig_stdout_fd < 0) + log_warning_errno(orig_stdout_fd, "Failed to duplicate fd 1: %m"); + else + assert_se(freopen("/dev/null", "w", stdout)); + + opterr = 0; /* do not print errors */ + } + + optind = 0; /* this tells the getopt machinery to reinitialize */ + + r = systemctl_dispatch_parse_argv(strv_length(argv), argv); + if (r < 0) + log_error_errno(r, "Failed to parse args: %m"); + else + log_info(r == 0 ? "Done!" : "Action!"); + + if (orig_stdout_fd >= 0) { + char path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + + xsprintf(path, "/proc/self/fd/%d", orig_stdout_fd); + assert_se(freopen(path, "w", stdout)); + } + + release_busses(); /* We open the bus for communication with logind. + * It needs to be closed to avoid apparent leaks. */ + + mac_selinux_finish(); + + /* Call static destructors to do global state cleanup. We do it here, and not in fuzz-main.c so that + * any global state is destroyed between fuzzer runs. */ + static_destruct(); + + return 0; +} diff --git a/src/systemctl/meson.build b/src/systemctl/meson.build new file mode 100644 index 000000000..38bf33d49 --- /dev/null +++ b/src/systemctl/meson.build @@ -0,0 +1,89 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +systemctl_sources = files( + 'systemctl-add-dependency.c', + 'systemctl-add-dependency.h', + 'systemctl-cancel-job.c', + 'systemctl-cancel-job.h', + 'systemctl-clean-or-freeze.c', + 'systemctl-clean-or-freeze.h', + 'systemctl-compat-halt.c', + 'systemctl-compat-halt.h', + 'systemctl-compat-runlevel.c', + 'systemctl-compat-runlevel.h', + 'systemctl-compat-shutdown.c', + 'systemctl-compat-shutdown.h', + 'systemctl-compat-telinit.c', + 'systemctl-compat-telinit.h', + 'systemctl-daemon-reload.c', + 'systemctl-daemon-reload.h', + 'systemctl-edit.c', + 'systemctl-edit.h', + 'systemctl-enable.c', + 'systemctl-enable.h', + 'systemctl-is-active.c', + 'systemctl-is-active.h', + 'systemctl-is-enabled.c', + 'systemctl-is-enabled.h', + 'systemctl-is-system-running.c', + 'systemctl-is-system-running.h', + 'systemctl-kill.c', + 'systemctl-kill.h', + 'systemctl-list-dependencies.c', + 'systemctl-list-dependencies.h', + 'systemctl-list-jobs.c', + 'systemctl-list-jobs.h', + 'systemctl-list-machines.c', + 'systemctl-list-machines.h', + 'systemctl-list-unit-files.c', + 'systemctl-list-unit-files.h', + 'systemctl-list-units.c', + 'systemctl-list-units.h', + 'systemctl-log-setting.c', + 'systemctl-log-setting.h', + 'systemctl-logind.c', + 'systemctl-logind.h', + 'systemctl-mount.c', + 'systemctl-mount.h', + 'systemctl-preset-all.c', + 'systemctl-preset-all.h', + 'systemctl-reset-failed.c', + 'systemctl-reset-failed.h', + 'systemctl-service-watchdogs.c', + 'systemctl-service-watchdogs.h', + 'systemctl-set-default.c', + 'systemctl-set-default.h', + 'systemctl-set-environment.c', + 'systemctl-set-environment.h', + 'systemctl-set-property.c', + 'systemctl-set-property.h', + 'systemctl-show.c', + 'systemctl-show.h', + 'systemctl-start-special.c', + 'systemctl-start-special.h', + 'systemctl-start-unit.c', + 'systemctl-start-unit.h', + 'systemctl-switch-root.c', + 'systemctl-switch-root.h', + 'systemctl-sysv-compat.c', + 'systemctl-sysv-compat.h', + 'systemctl-trivial-method.c', + 'systemctl-trivial-method.h', + 'systemctl-util.c', + 'systemctl-util.h', + 'systemctl.c', + 'systemctl.h') + +if get_option('link-systemctl-shared') + systemctl_link_with = [libshared] +else + systemctl_link_with = [libsystemd_static, + libshared_static, + libbasic_gcrypt] +endif + +fuzzers += [ + [['src/systemctl/fuzz-systemctl-parse-argv.c', + systemctl_sources], + systemctl_link_with, + [], [], ['-DFUZZ_SYSTEMCTL_PARSE_ARGV']]] diff --git a/src/systemctl/systemctl-compat-halt.c b/src/systemctl/systemctl-compat-halt.c index 8e41bd6cb..82cb3df6c 100644 --- a/src/systemctl/systemctl-compat-halt.c +++ b/src/systemctl/systemctl-compat-halt.c @@ -36,16 +36,15 @@ static int halt_help(void) { " -w --wtmp-only Don't halt/power-off/reboot, just write wtmp record\n" " -d --no-wtmp Don't write wtmp record\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , arg_action == ACTION_REBOOT ? " [ARG]" : "" - , ansi_highlight() - , arg_action == ACTION_REBOOT ? "Reboot" : - arg_action == ACTION_POWEROFF ? "Power off" : - "Halt" - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + arg_action == ACTION_REBOOT ? " [ARG]" : "", + ansi_highlight(), + arg_action == ACTION_REBOOT ? "Reboot" : + arg_action == ACTION_POWEROFF ? "Power off" : + "Halt", + ansi_normal(), + link); return 0; } diff --git a/src/systemctl/systemctl-compat-runlevel.c b/src/systemctl/systemctl-compat-runlevel.c index e05b1b470..ad6325bf3 100644 --- a/src/systemctl/systemctl-compat-runlevel.c +++ b/src/systemctl/systemctl-compat-runlevel.c @@ -21,11 +21,11 @@ static int runlevel_help(void) { "\n%sPrints the previous and current runlevel of the init system.%s\n" "\nOptions:\n" " --help Show this help\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } diff --git a/src/systemctl/systemctl-compat-shutdown.c b/src/systemctl/systemctl-compat-shutdown.c index 0c7d18b6d..11154f5f8 100644 --- a/src/systemctl/systemctl-compat-shutdown.c +++ b/src/systemctl/systemctl-compat-shutdown.c @@ -28,11 +28,11 @@ static int shutdown_help(void) { " -k Don't halt/power-off/reboot, just send warnings\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" " -c Cancel a pending shutdown\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -132,9 +132,10 @@ int shutdown_parse_argv(int argc, char *argv[]) { wall = argv + optind + 1; if (wall) { - arg_wall = strv_copy(wall); - if (!arg_wall) + char **copy = strv_copy(wall); + if (!copy) return log_oom(); + strv_free_and_replace(arg_wall, copy); } optind = argc; diff --git a/src/systemctl/systemctl-compat-telinit.c b/src/systemctl/systemctl-compat-telinit.c index 148574d52..f0e9ca8d7 100644 --- a/src/systemctl/systemctl-compat-telinit.c +++ b/src/systemctl/systemctl-compat-telinit.c @@ -1,9 +1,11 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include "alloc-util.h" #include "pretty-print.h" +#include "rlimit-util.h" #include "systemctl-compat-telinit.h" #include "systemctl-daemon-reload.h" #include "systemctl-start-unit.h" @@ -31,11 +33,11 @@ static int telinit_help(void) { "\nOptions:\n" " --help Show this help\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -150,3 +152,11 @@ int reload_with_fallback(void) { return 0; } + +int exec_telinit(char *argv[]) { + (void) rlimit_nofile_safe(); + execv(TELINIT, argv); + + return log_error_errno(SYNTHETIC_ERRNO(EIO), + "Couldn't find an alternative telinit implementation to spawn."); +} diff --git a/src/systemctl/systemctl-compat-telinit.h b/src/systemctl/systemctl-compat-telinit.h index 1a2bcd440..783c3878a 100644 --- a/src/systemctl/systemctl-compat-telinit.h +++ b/src/systemctl/systemctl-compat-telinit.h @@ -4,3 +4,4 @@ int telinit_parse_argv(int argc, char *argv[]); int start_with_fallback(void); int reload_with_fallback(void); +int exec_telinit(char *argv[]); diff --git a/src/systemctl/systemctl-edit.c b/src/systemctl/systemctl-edit.c index 4186ec3ae..314962ac6 100644 --- a/src/systemctl/systemctl-edit.c +++ b/src/systemctl/systemctl-edit.c @@ -146,7 +146,6 @@ static int create_edit_temp_file(const char *new_path, const char *original_path _cleanup_free_ char *new_contents = NULL; _cleanup_fclose_ FILE *f = NULL; char **path; - size_t size; r = mac_selinux_create_file_prepare(new_path, S_IFREG); if (r < 0) @@ -161,7 +160,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path if (r < 0) return log_error_errno(errno, "Failed to change mode of \"%s\": %m", t); - r = read_full_file(new_path, &new_contents, &size); + r = read_full_file(new_path, &new_contents, NULL); if (r < 0 && r != -ENOENT) return log_error_errno(r, "Failed to read \"%s\": %m", new_path); @@ -182,16 +181,18 @@ static int create_edit_temp_file(const char *new_path, const char *original_path if (path_equal(*path, new_path)) continue; - r = read_full_file(*path, &contents, &size); + r = read_full_file(*path, &contents, NULL); if (r < 0) return log_error_errno(r, "Failed to read \"%s\": %m", *path); fprintf(f, "\n\n### %s", *path); if (!isempty(contents)) { - contents = strreplace(strstrip(contents), "\n", "\n# "); - if (!contents) + _cleanup_free_ char *commented_contents = NULL; + + commented_contents = strreplace(strstrip(contents), "\n", "\n# "); + if (!commented_contents) return log_oom(); - fprintf(f, "\n# %s", contents); + fprintf(f, "\n# %s", commented_contents); } } @@ -468,10 +469,12 @@ static int trim_edit_markers(const char *path) { int r; /* Trim out the lines between the two markers */ - r = read_full_file(path, &contents, &size); + r = read_full_file(path, &contents, NULL); if (r < 0) return log_error_errno(r, "Failed to read temporary file \"%s\": %m", path); + size = strlen(contents); + contents_start = strstr(contents, EDIT_MARKER_START); if (contents_start) contents_start += strlen(EDIT_MARKER_START); diff --git a/src/systemctl/systemctl-is-active.c b/src/systemctl/systemctl-is-active.c index 3d99b0deb..d83736e94 100644 --- a/src/systemctl/systemctl-is-active.c +++ b/src/systemctl/systemctl-is-active.c @@ -14,7 +14,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int UnitActiveState active_state; sd_bus *bus; char **name; - int r, i; + int r; bool found = false; r = acquire_bus(BUS_MANAGER, &bus); @@ -33,7 +33,7 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int if (!arg_quiet) puts(unit_active_state_to_string(active_state)); - for (i = 0; i < nb_states; ++i) + for (int i = 0; i < nb_states; ++i) if (good_states[i] == active_state) found = true; } diff --git a/src/systemctl/systemctl-is-enabled.c b/src/systemctl/systemctl-is-enabled.c index babd5902c..e33dffaf2 100644 --- a/src/systemctl/systemctl-is-enabled.c +++ b/src/systemctl/systemctl-is-enabled.c @@ -9,7 +9,7 @@ static int show_installation_targets_client_side(const char *name) { UnitFileChange *changes = NULL; - size_t n_changes = 0, i; + size_t n_changes = 0; UnitFileFlags flags; char **p; int r; @@ -22,8 +22,8 @@ static int show_installation_targets_client_side(const char *name) { if (r < 0) return log_error_errno(r, "Failed to get file links for %s: %m", name); - for (i = 0; i < n_changes; i++) - if (changes[i].type == UNIT_FILE_UNLINK) + for (size_t i = 0; i < n_changes; i++) + if (changes[i].type_or_errno == UNIT_FILE_UNLINK) printf(" %s\n", changes[i].path); return 0; diff --git a/src/systemctl/systemctl-list-dependencies.c b/src/systemctl/systemctl-list-dependencies.c index 821998eb4..5d19f338d 100644 --- a/src/systemctl/systemctl-list-dependencies.c +++ b/src/systemctl/systemctl-list-dependencies.c @@ -12,11 +12,10 @@ static int list_dependencies_print(const char *name, int level, unsigned branche _cleanup_free_ char *n = NULL; size_t max_len = MAX(columns(),20u); size_t len = 0; - int i; if (!arg_plain) { - for (i = level - 1; i >= 0; i--) { + for (int i = level - 1; i >= 0; i--) { len += 2; if (len > max_len - 3 && !arg_full) { printf("%s...\n",max_len % 2 ? "" : " "); @@ -117,7 +116,7 @@ static int list_dependencies_one( break; } - printf("%s%s%s ", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), ansi_normal()); + printf("%s%s%s ", on, special_glyph(unit_active_state_to_glyph(active_state)), ansi_normal()); } r = list_dependencies_print(*c, level, branches, c[1] == NULL); diff --git a/src/systemctl/systemctl-list-jobs.c b/src/systemctl/systemctl-list-jobs.c index 8b028c013..7ac049638 100644 --- a/src/systemctl/systemctl-list-jobs.c +++ b/src/systemctl/systemctl-list-jobs.c @@ -58,14 +58,13 @@ struct job_info { static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n, bool skipped) { _cleanup_(table_unrefp) Table *table = NULL; - const struct job_info *j; const char *on, *off; int r; assert(n == 0 || jobs); if (n == 0) { - if (!arg_no_legend) { + if (arg_legend != 0) { on = ansi_highlight_green(); off = ansi_normal(); @@ -80,13 +79,13 @@ static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n if (!table) return log_oom(); - table_set_header(table, !arg_no_legend); + table_set_header(table, arg_legend != 0); if (arg_full) table_set_width(table, 0); (void) table_set_empty_string(table, "-"); - for (j = jobs; j < jobs + n; j++) { + for (const struct job_info *j = jobs; j < jobs + n; j++) { if (streq(j->state, "running")) on = ansi_highlight(); else @@ -112,7 +111,7 @@ static int output_jobs_list(sd_bus *bus, const struct job_info* jobs, unsigned n if (r < 0) return log_error_errno(r, "Failed to print the table: %m"); - if (!arg_no_legend) { + if (arg_legend != 0) { on = ansi_highlight(); off = ansi_normal(); diff --git a/src/systemctl/systemctl-list-machines.c b/src/systemctl/systemctl-list-machines.c index 48d0e8bde..2e891b103 100644 --- a/src/systemctl/systemctl-list-machines.c +++ b/src/systemctl/systemctl-list-machines.c @@ -33,12 +33,10 @@ void machine_info_clear(struct machine_info *info) { } static void free_machines_list(struct machine_info *machine_infos, int n) { - int i; - if (!machine_infos) return; - for (i = 0; i < n; i++) + for (int i = 0; i < n; i++) machine_info_clear(&machine_infos[i]); free(machine_infos); @@ -150,7 +148,6 @@ static int get_machine_list( static int output_machines_list(struct machine_info *machine_infos, unsigned n) { _cleanup_(table_unrefp) Table *table = NULL; - struct machine_info *m; bool state_missing = false; int r; @@ -160,7 +157,7 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n) if (!table) return log_oom(); - table_set_header(table, !arg_no_legend); + table_set_header(table, arg_legend != 0); if (arg_plain) { /* Hide the 'glyph' column when --plain is requested */ r = table_hide_column_from_display(table, 0); @@ -172,7 +169,7 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n) (void) table_set_empty_string(table, "-"); - for (m = machine_infos; m < machine_infos + n; m++) { + for (struct machine_info *m = machine_infos; m < machine_infos + n; m++) { _cleanup_free_ char *mname = NULL; const char *on_state = "", *on_failed = ""; bool circle = false; @@ -213,7 +210,7 @@ static int output_machines_list(struct machine_info *machine_infos, unsigned n) if (r < 0) return r; - if (!arg_no_legend) { + if (arg_legend != 0) { printf("\n"); if (state_missing && geteuid() != 0) printf("Notice: some information only available to privileged users was not shown.\n"); diff --git a/src/systemctl/systemctl-list-unit-files.c b/src/systemctl/systemctl-list-unit-files.c index e1bf87662..1bf2fc18f 100644 --- a/src/systemctl/systemctl-list-unit-files.c +++ b/src/systemctl/systemctl-list-unit-files.c @@ -58,7 +58,7 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) { if (!table) return log_oom(); - table_set_header(table, !arg_no_legend); + table_set_header(table, arg_legend != 0); if (arg_full) table_set_width(table, 0); @@ -127,7 +127,7 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) { if (r < 0) return r; - if (!arg_no_legend) + if (arg_legend != 0) printf("\n%u unit files listed.\n", c); return 0; @@ -136,7 +136,6 @@ static int output_unit_file_list(const UnitFileList *units, unsigned c) { int list_unit_files(int argc, char *argv[], void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ UnitFileList *units = NULL; - UnitFileList *unit; size_t size = 0; unsigned c = 0; const char *state; @@ -265,7 +264,7 @@ int list_unit_files(int argc, char *argv[], void *userdata) { return r; if (install_client_side()) - for (unit = units; unit < units + c; unit++) + for (UnitFileList *unit = units; unit < units + c; unit++) free(unit->path); if (c == 0) diff --git a/src/systemctl/systemctl-list-units.c b/src/systemctl/systemctl-list-units.c index c7a91ba4f..e02a7608f 100644 --- a/src/systemctl/systemctl-list-units.c +++ b/src/systemctl/systemctl-list-units.c @@ -97,7 +97,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { if (!table) return log_oom(); - table_set_header(table, !arg_no_legend); + table_set_header(table, arg_legend != 0); if (arg_plain) { /* Hide the 'glyph' column when --plain is requested */ r = table_hide_column_from_display(table, 0); @@ -109,7 +109,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { (void) table_set_empty_string(table, "-"); - for (const UnitInfo *u = unit_infos; unit_infos && u - unit_infos < c; u++) { + for (const UnitInfo *u = unit_infos; unit_infos && (size_t) (u - unit_infos) < c; u++) { _cleanup_free_ char *j = NULL; const char *on_underline = "", *on_loaded = "", *on_active = ""; const char *on_circle = "", *id; @@ -177,7 +177,7 @@ static int output_units_list(const UnitInfo *unit_infos, unsigned c) { if (r < 0) return r; - if (!arg_no_legend) { + if (arg_legend != 0) { const char *on, *off; size_t records = table_get_rows(table) - 1; @@ -351,7 +351,6 @@ static int socket_info_compare(const struct socket_info *a, const struct socket_ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { _cleanup_(table_unrefp) Table *table = NULL; - struct socket_info *s; const char *on, *off; int r; @@ -361,19 +360,19 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { if (!arg_show_types) { /* Hide the second (TYPE) column */ - r = table_set_display(table, (size_t) 0, (size_t) 2, (size_t) 3, (size_t) -1); + r = table_set_display(table, (size_t) 0, (size_t) 2, (size_t) 3); if (r < 0) return log_error_errno(r, "Failed to set columns to display: %m"); } - table_set_header(table, !arg_no_legend); + table_set_header(table, arg_legend != 0); if (arg_full) table_set_width(table, 0); (void) table_set_empty_string(table, "-"); if (cs) { - for (s = socket_infos; s < socket_infos + cs; s++) { + for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) { _cleanup_free_ char *j = NULL; const char *path; @@ -417,7 +416,7 @@ static int output_sockets_list(struct socket_info *socket_infos, unsigned cs) { if (r < 0) return r; - if (!arg_no_legend) { + if (arg_legend != 0) { printf("\n%s%u sockets listed.%s\n", on, cs, off); if (!arg_all) printf("Pass --all to see loaded but inactive sockets, too.\n"); @@ -432,8 +431,6 @@ int list_sockets(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **sockets_with_suffix = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; _cleanup_free_ struct socket_info *socket_infos = NULL; - const UnitInfo *u; - struct socket_info *s; unsigned cs = 0; size_t size = 0; int r, n; @@ -454,9 +451,9 @@ int list_sockets(int argc, char *argv[], void *userdata) { if (n < 0) return n; - for (u = unit_infos; u < unit_infos + n; u++) { + for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { _cleanup_strv_free_ char **listening = NULL, **triggered = NULL; - int i, c; + int c; if (!endswith(u->id, ".socket")) continue; @@ -476,7 +473,7 @@ int list_sockets(int argc, char *argv[], void *userdata) { goto cleanup; } - for (i = 0; i < c; i++) + for (int i = 0; i < c; i++) socket_infos[cs + i] = (struct socket_info) { .machine = u->machine, .id = u->id, @@ -499,7 +496,7 @@ int list_sockets(int argc, char *argv[], void *userdata) { cleanup: assert(cs == 0 || socket_infos); - for (s = socket_infos; s < socket_infos + cs; s++) { + for (struct socket_info *s = socket_infos; s < socket_infos + cs; s++) { free(s->type); free(s->path); if (s->own_triggered) @@ -604,7 +601,6 @@ static int timer_info_compare(const struct timer_info *a, const struct timer_inf static int output_timers_list(struct timer_info *timer_infos, unsigned n) { _cleanup_(table_unrefp) Table *table = NULL; - struct timer_info *t; const char *on, *off; int r; @@ -614,40 +610,40 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) { if (!table) return log_oom(); - table_set_header(table, !arg_no_legend); + table_set_header(table, arg_legend != 0); if (arg_full) table_set_width(table, 0); (void) table_set_empty_string(table, "-"); - if (n > 0) { - for (t = timer_infos; t < timer_infos + n; t++) { - _cleanup_free_ char *j = NULL, *activates = NULL; - const char *unit; + for (struct timer_info *t = timer_infos; t < timer_infos + n; t++) { + _cleanup_free_ char *j = NULL, *activates = NULL; + const char *unit; - if (t->machine) { - j = strjoin(t->machine, ":", t->id); - if (!j) - return log_oom(); - unit = j; - } else - unit = t->id; - - activates = strv_join(t->triggered, ", "); - if (!activates) + if (t->machine) { + j = strjoin(t->machine, ":", t->id); + if (!j) return log_oom(); + unit = j; + } else + unit = t->id; - r = table_add_many(table, - TABLE_TIMESTAMP, t->next_elapse, - TABLE_TIMESTAMP_RELATIVE, t->next_elapse, - TABLE_TIMESTAMP, t->last_trigger, - TABLE_TIMESTAMP_RELATIVE, t->last_trigger, - TABLE_STRING, unit, - TABLE_STRING, activates); - if (r < 0) - return table_log_add_error(r); - } + activates = strv_join(t->triggered, ", "); + if (!activates) + return log_oom(); + r = table_add_many(table, + TABLE_TIMESTAMP, t->next_elapse, + TABLE_TIMESTAMP_RELATIVE, t->next_elapse, + TABLE_TIMESTAMP, t->last_trigger, + TABLE_TIMESTAMP_RELATIVE, t->last_trigger, + TABLE_STRING, unit, + TABLE_STRING, activates); + if (r < 0) + return table_log_add_error(r); + } + + if (n > 0) { on = ansi_highlight(); off = ansi_normal(); } else { @@ -659,7 +655,7 @@ static int output_timers_list(struct timer_info *timer_infos, unsigned n) { if (r < 0) return r; - if (!arg_no_legend) { + if (arg_legend != 0) { printf("\n%s%u timers listed.%s\n", on, n, off); if (!arg_all) printf("Pass --all to see loaded but inactive timers, too.\n"); @@ -699,8 +695,6 @@ int list_timers(int argc, char *argv[], void *userdata) { _cleanup_strv_free_ char **timers_with_suffix = NULL; _cleanup_free_ struct timer_info *timer_infos = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; - struct timer_info *t; - const UnitInfo *u; size_t size = 0; int n, c = 0; dual_timestamp nw; @@ -724,7 +718,7 @@ int list_timers(int argc, char *argv[], void *userdata) { dual_timestamp_get(&nw); - for (u = unit_infos; u < unit_infos + n; u++) { + for (const UnitInfo *u = unit_infos; u < unit_infos + n; u++) { _cleanup_strv_free_ char **triggered = NULL; dual_timestamp next = DUAL_TIMESTAMP_NULL; usec_t m, last = 0; @@ -764,7 +758,7 @@ int list_timers(int argc, char *argv[], void *userdata) { output_timers_list(timer_infos, c); cleanup: - for (t = timer_infos; t < timer_infos + c; t++) + for (struct timer_info *t = timer_infos; t < timer_infos + c; t++) strv_free(t->triggered); return r; diff --git a/src/systemctl/systemctl-log-setting.c b/src/systemctl/systemctl-log-setting.c index 64984e4a8..9a95c7dab 100644 --- a/src/systemctl/systemctl-log-setting.c +++ b/src/systemctl/systemctl-log-setting.c @@ -30,9 +30,9 @@ static int log_setting_internal(sd_bus *bus, const BusLocator* bloc, const char if (value) { if (level) { - if (log_level_from_string(value) < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "\"%s\" is not a valid log level.", value); + r = log_level_from_string(value); + if (r < 0) + return log_error_errno(r, "\"%s\" is not a valid log level.", value); } r = bus_set_property(bus, bloc, diff --git a/src/systemctl/systemctl-logind.c b/src/systemctl/systemctl-logind.c index 405f12a33..103f81647 100644 --- a/src/systemctl/systemctl-logind.c +++ b/src/systemctl/systemctl-logind.c @@ -6,6 +6,7 @@ #include "bus-error.h" #include "bus-locator.h" +#include "login-util.h" #include "process-util.h" #include "systemctl-logind.h" #include "systemctl-start-unit.h" @@ -57,6 +58,8 @@ int logind_reboot(enum action a) { }; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *method_with_flags; + uint64_t flags = 0; sd_bus *bus; int r; @@ -75,6 +78,20 @@ int logind_reboot(enum action a) { if (arg_dry_run) return 0; + SET_FLAG(flags, SD_LOGIND_ROOT_CHECK_INHIBITORS, arg_check_inhibitors > 0); + + method_with_flags = strjoina(actions[a].method, "WithFlags"); + + r = bus_call_method(bus, bus_login_mgr, method_with_flags, &error, NULL, "t", flags); + if (r >= 0) + return 0; + if (!sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) + return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); + + /* Fallback to original methods in case there is older version of systemd-logind */ + log_debug("Method %s not available: %s. Falling back to %s", method_with_flags, bus_error_message(&error, r), actions[a].method); + sd_bus_error_free(&error); + r = bus_call_method(bus, bus_login_mgr, actions[a].method, &error, NULL, "b", arg_ask_password); if (r < 0) return log_error_errno(r, "Failed to %s via logind: %s", actions[a].description, bus_error_message(&error, r)); @@ -96,17 +113,19 @@ int logind_check_inhibitors(enum action a) { char **s; int r; - if (arg_ignore_inhibitors || arg_force > 0) + if (arg_check_inhibitors == 0 || arg_force > 0) return 0; if (arg_when > 0) return 0; - if (geteuid() == 0) - return 0; + if (arg_check_inhibitors < 0) { + if (geteuid() == 0) + return 0; - if (!on_tty()) - return 0; + if (!on_tty()) + return 0; + } if (arg_transport != BUS_TRANSPORT_LOCAL) return 0; diff --git a/src/systemctl/systemctl-mount.c b/src/systemctl/systemctl-mount.c new file mode 100644 index 000000000..04e626550 --- /dev/null +++ b/src/systemctl/systemctl-mount.c @@ -0,0 +1,116 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "bus-error.h" +#include "bus-locator.h" +#include "dissect-image.h" +#include "systemctl-mount.h" +#include "systemctl-util.h" +#include "systemctl.h" + +int mount_bind(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + _cleanup_free_ char *n = NULL; + sd_bus *bus; + int r; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + polkit_agent_open_maybe(); + + r = unit_name_mangle(argv[1], arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &n); + if (r < 0) + return log_error_errno(r, "Failed to mangle unit name: %m"); + + r = bus_call_method( + bus, + bus_systemd_mgr, + "BindMountUnit", + &error, + NULL, + "sssbb", + n, + argv[2], + argv[3], + arg_read_only, + arg_mkdir); + if (r < 0) + return log_error_errno(r, "Failed to bind mount: %s", bus_error_message(&error, r)); + + return 0; +} + +int mount_image(int argc, char *argv[], void *userdata) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + const char *unit = argv[1], *src = argv[2], *dest = argv[3]; + _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; + _cleanup_free_ char *n = NULL; + sd_bus *bus; + int r; + + r = acquire_bus(BUS_MANAGER, &bus); + if (r < 0) + return r; + + polkit_agent_open_maybe(); + + r = unit_name_mangle(unit, arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN, &n); + if (r < 0) + return log_error_errno(r, "Failed to mangle unit name: %m"); + + r = bus_message_new_method_call( + bus, + &m, + bus_systemd_mgr, + "MountImageUnit"); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_append( + m, + "sssbb", + n, + src, + dest, + arg_read_only, + arg_mkdir); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_message_open_container(m, 'a', "(ss)"); + if (r < 0) + return bus_log_create_error(r); + + if (argc > 4) { + _cleanup_free_ char *partition = NULL, *mount_options = NULL; + const char *options = argv[4]; + + r = extract_many_words(&options, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL); + if (r < 0) + return r; + /* Single set of options, applying to the root partition/single filesystem */ + if (r == 1) { + r = sd_bus_message_append(m, "(ss)", "root", partition); + if (r < 0) + return bus_log_create_error(r); + } else if (r > 1) { + if (partition_designator_from_string(partition) < 0) + return bus_log_create_error(-EINVAL); + + r = sd_bus_message_append(m, "(ss)", partition, mount_options); + if (r < 0) + return bus_log_create_error(r); + } + } + + r = sd_bus_message_close_container(m); + if (r < 0) + return bus_log_create_error(r); + + r = sd_bus_call(bus, m, -1, &error, NULL); + if (r < 0) + return log_error_errno(r, "Failed to mount image: %s", bus_error_message(&error, r)); + + return 0; +} diff --git a/src/systemctl/systemctl-mount.h b/src/systemctl/systemctl-mount.h new file mode 100644 index 000000000..60d6875d8 --- /dev/null +++ b/src/systemctl/systemctl-mount.h @@ -0,0 +1,5 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +int mount_bind(int argc, char *argv[], void *userdata); +int mount_image(int argc, char *argv[], void *userdata); diff --git a/src/systemctl/systemctl-set-environment.c b/src/systemctl/systemctl-set-environment.c index b37bd6f67..bfd87c0cd 100644 --- a/src/systemctl/systemctl-set-environment.c +++ b/src/systemctl/systemctl-set-environment.c @@ -119,9 +119,9 @@ int import_environment(int argc, char *argv[], void *userdata) { return bus_log_create_error(r); if (argc < 2) { - _cleanup_strv_free_ char **copy = NULL; + log_warning("Calling import-environment without a list of variable names is deprecated."); - copy = strv_copy(environ); + _cleanup_strv_free_ char **copy = strv_copy(environ); if (!copy) return log_oom(); diff --git a/src/systemctl/systemctl-show.c b/src/systemctl/systemctl-show.c index d5efecbe6..c3c81f03f 100644 --- a/src/systemctl/systemctl-show.c +++ b/src/systemctl/systemctl-show.c @@ -147,15 +147,14 @@ typedef struct UnitCondition { LIST_FIELDS(struct UnitCondition, conditions); } UnitCondition; -static void unit_condition_free(UnitCondition *c) { +static UnitCondition* unit_condition_free(UnitCondition *c) { if (!c) - return; + return NULL; free(c->name); free(c->param); - free(c); + return mfree(c); } - DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free); typedef struct UnitStatusInfo { @@ -314,7 +313,9 @@ static void print_status_info( format_active_state(i->active_state, &active_on, &active_off); - printf("%s%s%s %s", active_on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), active_off, strna(i->id)); + const SpecialGlyph glyph = unit_active_state_to_glyph(unit_active_state_from_string(i->active_state)); + + printf("%s%s%s %s", active_on, special_glyph(glyph), active_off, strna(i->id)); if (i->description && !streq_ptr(i->id, i->description)) printf(" - %s", i->description); @@ -433,7 +434,7 @@ static void print_status_info( printf("%s %s%s%s %s\n", t == i->triggered_by ? "TriggeredBy:" : " ", - on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, + on, special_glyph(unit_active_state_to_glyph(state)), off, *t); } @@ -647,7 +648,7 @@ static void print_status_info( if (i->status_errno > 0) printf(" Error: %i (%s)\n", i->status_errno, strerror_safe(i->status_errno)); - if (i->ip_ingress_bytes != (uint64_t) -1 && i->ip_egress_bytes != (uint64_t) -1) { + if (i->ip_ingress_bytes != UINT64_MAX && i->ip_egress_bytes != UINT64_MAX) { char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX]; printf(" IP: %s in, %s out\n", @@ -663,16 +664,16 @@ static void print_status_info( format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes)); } - if (i->tasks_current != (uint64_t) -1) { + if (i->tasks_current != UINT64_MAX) { printf(" Tasks: %" PRIu64, i->tasks_current); - if (i->tasks_max != (uint64_t) -1) + if (i->tasks_max != UINT64_MAX) printf(" (limit: %" PRIu64 ")\n", i->tasks_max); else printf("\n"); } - if (i->memory_current != (uint64_t) -1) { + if (i->memory_current != UINT64_MAX) { char buf[FORMAT_BYTES_MAX]; printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current)); @@ -713,7 +714,7 @@ static void print_status_info( printf("\n"); } - if (i->cpu_usage_nsec != (uint64_t) -1) { + if (i->cpu_usage_nsec != UINT64_MAX) { char buf[FORMAT_TIMESPAN_MAX]; printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC)); } @@ -1101,7 +1102,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) { const int32_t *status, *signal; - size_t n_status, n_signal, i; + size_t n_status, n_signal; r = sd_bus_message_enter_container(m, 'r', "aiai"); if (r < 0) @@ -1130,7 +1131,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m fputc('=', stdout); } - for (i = 0; i < n_status; i++) { + for (size_t i = 0; i < n_status; i++) { if (first) first = false; else @@ -1139,7 +1140,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m printf("%"PRIi32, status[i]); } - for (i = 0; i < n_signal; i++) { + for (size_t i = 0; i < n_signal; i++) { const char *str; str = signal_to_string((int) signal[i]); @@ -1473,10 +1474,10 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8) continue; - if (in_addr_prefix_to_string(family, (union in_addr_union *) ap, prefixlen, &str) < 0) + if (in_addr_prefix_to_string(family, (const union in_addr_union*) ap, prefixlen, &str) < 0) continue; - if (!strextend_with_separator(&addresses, " ", str, NULL)) + if (!strextend_with_separator(&addresses, " ", str)) return log_oom(); } @@ -1513,7 +1514,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m rbind == MS_REC ? ":rbind" : "") < 0) return log_oom(); - if (!strextend_with_separator(&paths, " ", str, NULL)) + if (!strextend_with_separator(&paths, " ", str)) return log_oom(); } if (r < 0) @@ -1545,7 +1546,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m if (asprintf(&str, "%s%s%s", target, isempty(option) ? "" : ":", strempty(option)) < 0) return log_oom(); - if (!strextend_with_separator(&paths, " ", str, NULL)) + if (!strextend_with_separator(&paths, " ", str)) return log_oom(); } if (r < 0) @@ -1593,7 +1594,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m if (!utf8_is_valid(str)) continue; - if (!strextend_with_separator(&fields, " ", str, NULL)) + if (!strextend_with_separator(&fields, " ", str)) return log_oom(); } if (r < 0) @@ -1670,7 +1671,7 @@ static int print_property(const char *name, const char *expected_value, sd_bus_m if (r < 0) return r; - if (!strextend_with_separator(&paths, " ", str, NULL)) + if (!strextend_with_separator(&paths, " ", str)) return log_oom(); r = sd_bus_message_exit_container(m); @@ -1706,7 +1707,7 @@ typedef enum SystemctlShowMode{ SYSTEMCTL_SHOW_STATUS, SYSTEMCTL_SHOW_HELP, _SYSTEMCTL_SHOW_MODE_MAX, - _SYSTEMCTL_SHOW_MODE_INVALID = -1, + _SYSTEMCTL_SHOW_MODE_INVALID = -EINVAL, } SystemctlShowMode; static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = { @@ -1822,16 +1823,16 @@ static int show_one( _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; _cleanup_set_free_ Set *found_properties = NULL; _cleanup_(unit_status_info_free) UnitStatusInfo info = { - .memory_current = (uint64_t) -1, + .memory_current = UINT64_MAX, .memory_high = CGROUP_LIMIT_MAX, .memory_max = CGROUP_LIMIT_MAX, .memory_swap_max = CGROUP_LIMIT_MAX, - .memory_limit = (uint64_t) -1, - .cpu_usage_nsec = (uint64_t) -1, - .tasks_current = (uint64_t) -1, - .tasks_max = (uint64_t) -1, - .ip_ingress_bytes = (uint64_t) -1, - .ip_egress_bytes = (uint64_t) -1, + .memory_limit = UINT64_MAX, + .cpu_usage_nsec = UINT64_MAX, + .tasks_current = UINT64_MAX, + .tasks_max = UINT64_MAX, + .ip_ingress_bytes = UINT64_MAX, + .ip_egress_bytes = UINT64_MAX, .io_read_bytes = UINT64_MAX, .io_write_bytes = UINT64_MAX, }; @@ -1931,7 +1932,6 @@ static int show_all( _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ UnitInfo *unit_infos = NULL; - const UnitInfo *u; unsigned c; int r, ret = 0; @@ -1945,7 +1945,7 @@ static int show_all( typesafe_qsort(unit_infos, c, unit_info_compare); - for (u = unit_infos; u < unit_infos + c; u++) { + for (const UnitInfo *u = unit_infos; u < unit_infos + c; u++) { _cleanup_free_ char *p = NULL; p = unit_dbus_path_from_name(u->id); @@ -2038,8 +2038,7 @@ int show(int argc, char *argv[], void *userdata) { show_mode = systemctl_show_mode_from_string(argv[0]); if (show_mode < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid argument."); + return log_error_errno(show_mode, "Invalid argument."); if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), diff --git a/src/systemctl/systemctl-start-unit.c b/src/systemctl/systemctl-start-unit.c index b398e77eb..c40e80721 100644 --- a/src/systemctl/systemctl-start-unit.c +++ b/src/systemctl/systemctl-start-unit.c @@ -36,9 +36,7 @@ static const struct { }; static const char *verb_to_method(const char *verb) { - size_t i; - - for (i = 0; i < ELEMENTSOF(unit_actions); i++) + for (size_t i = 0; i < ELEMENTSOF(unit_actions); i++) if (streq_ptr(unit_actions[i].verb, verb)) return unit_actions[i].method; @@ -46,9 +44,7 @@ static const char *verb_to_method(const char *verb) { } static const char *verb_to_job_type(const char *verb) { - size_t i; - - for (i = 0; i < ELEMENTSOF(unit_actions); i++) + for (size_t i = 0; i < ELEMENTSOF(unit_actions); i++) if (streq_ptr(unit_actions[i].verb, verb)) return unit_actions[i].job_type; @@ -180,6 +176,43 @@ fail: return r; } +static int enqueue_marked_jobs( + sd_bus *bus, + BusWaitForJobs *w) { + + _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + int r; + + log_debug("%s dbus call org.freedesktop.systemd1.Manager EnqueueMarkedJobs()", + arg_dry_run ? "Would execute" : "Executing"); + + if (arg_dry_run) + return 0; + + r = bus_call_method(bus, bus_systemd_mgr, "EnqueueMarkedJobs", &error, &reply, NULL); + if (r < 0) + return log_error_errno(r, "Failed to start jobs: %s", bus_error_message(&error, r)); + + _cleanup_strv_free_ char **paths = NULL; + r = sd_bus_message_read_strv(reply, &paths); + if (r < 0) + return bus_log_parse_error(r); + + if (w) { + char **path; + + STRV_FOREACH(path, paths) { + log_debug("Adding %s to the set", *path); + r = bus_wait_for_jobs_add(w, *path); + if (r < 0) + return log_error_errno(r, "Failed to watch job %s: %m", *path); + } + } + + return 0; +} + const struct action_metadata action_table[_ACTION_MAX] = { [ACTION_HALT] = { SPECIAL_HALT_TARGET, "halt", "replace-irreversibly" }, [ACTION_POWEROFF] = { SPECIAL_POWEROFF_TARGET, "poweroff", "replace-irreversibly" }, @@ -200,9 +233,7 @@ const struct action_metadata action_table[_ACTION_MAX] = { }; enum action verb_to_action(const char *verb) { - enum action i; - - for (i = 0; i < _ACTION_MAX; i++) + for (enum action i = 0; i < _ACTION_MAX; i++) if (streq_ptr(action_table[i].verb, verb)) return i; @@ -271,7 +302,7 @@ int start_unit(int argc, char *argv[], void *userdata) { job_type = "start"; mode = "isolate"; suffix = ".target"; - } else { + } else if (!arg_marked) { /* A command in style of "systemctl start …", "sysemctl stop …" and so on */ method = verb_to_method(argv[0]); job_type = verb_to_job_type(argv[0]); @@ -295,7 +326,7 @@ int start_unit(int argc, char *argv[], void *userdata) { names = strv_new(one_name); if (!names) return log_oom(); - } else { + } else if (!arg_marked) { bool expanded; r = expand_unit_names(bus, strv_skip(argv, 1), suffix, &names, &expanded); @@ -328,19 +359,23 @@ int start_unit(int argc, char *argv[], void *userdata) { return log_error_errno(r, "Failed to allocate unit watch context: %m"); } - STRV_FOREACH(name, names) { - _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; + if (arg_marked) + ret = enqueue_marked_jobs(bus, w); - r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu); - if (ret == EXIT_SUCCESS && r < 0) - ret = translate_bus_error_to_exit_status(r, &error); + else + STRV_FOREACH(name, names) { + _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; - if (r >= 0 && streq(method, "StopUnit")) { - r = strv_push(&stopped_units, *name); - if (r < 0) - return log_oom(); + r = start_unit_one(bus, method, job_type, *name, mode, &error, w, wu); + if (ret == EXIT_SUCCESS && r < 0) + ret = translate_bus_error_to_exit_status(r, &error); + + if (r >= 0 && streq(method, "StopUnit")) { + r = strv_push(&stopped_units, *name); + if (r < 0) + return log_oom(); + } } - } if (!arg_no_block) { const char* extra_args[4]; diff --git a/src/systemctl/systemctl-switch-root.c b/src/systemctl/systemctl-switch-root.c index 9ed40e6ec..b80126797 100644 --- a/src/systemctl/systemctl-switch-root.c +++ b/src/systemctl/systemctl-switch-root.c @@ -60,7 +60,7 @@ int switch_root(int argc, char *argv[], void *userdata) { /* If we are slow to exit after the root switch, the new systemd instance will send us a signal to * terminate. Just ignore it and exit normally. This way the unit does not end up as failed. */ - r = ignore_signals(SIGTERM, -1); + r = ignore_signals(SIGTERM); if (r < 0) log_warning_errno(r, "Failed to change disposition of SIGTERM to ignore: %m"); @@ -68,7 +68,7 @@ int switch_root(int argc, char *argv[], void *userdata) { r = bus_call_method(bus, bus_systemd_mgr, "SwitchRoot", &error, NULL, "ss", root, init); if (r < 0) { - (void) default_signals(SIGTERM, -1); + (void) default_signals(SIGTERM); return log_error_errno(r, "Failed to switch root: %s", bus_error_message(&error, r)); } diff --git a/src/systemctl/systemctl-util.c b/src/systemctl/systemctl-util.c index 9713fce7a..d1490c906 100644 --- a/src/systemctl/systemctl-util.c +++ b/src/systemctl/systemctl-util.c @@ -62,9 +62,7 @@ int acquire_bus(BusFocus focus, sd_bus **ret) { } void release_busses(void) { - BusFocus w; - - for (w = 0; w < _BUS_FOCUS_MAX; w++) + for (BusFocus w = 0; w < _BUS_FOCUS_MAX; w++) buses[w] = sd_bus_flush_close_unref(buses[w]); } @@ -143,7 +141,7 @@ int get_state_one_unit(sd_bus *bus, const char *unit, UnitActiveState *ret_activ state = unit_active_state_from_string(buf); if (state < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid unit state '%s' for: %s", buf, unit); + return log_error_errno(state, "Invalid unit state '%s' for: %s", buf, unit); *ret_active_state = state; return 0; @@ -237,7 +235,7 @@ int get_unit_list( int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret, bool *ret_expanded) { _cleanup_strv_free_ char **mangled = NULL, **globs = NULL; char **name; - int r, i; + int r; assert(bus); assert(ret); @@ -272,7 +270,7 @@ int expand_unit_names(sd_bus *bus, char **names, const char* suffix, char ***ret n = strv_length(mangled); allocated = n + 1; - for (i = 0; i < r; i++) { + for (int i = 0; i < r; i++) { if (!GREEDY_REALLOC(mangled, allocated, n+2)) return log_oom(); @@ -439,12 +437,15 @@ int unit_find_paths( /** * Finds where the unit is defined on disk. Returns 0 if the unit is not found. Returns 1 if it is * found, and sets: + * * - the path to the unit in *ret_frament_path, if it exists on disk, + * * - and a strv of existing drop-ins in *ret_dropin_paths, if the arg is not NULL and any dropins * were found. * * Returns -ERFKILL if the unit is masked, and -EKEYREJECTED if the unit file could not be loaded for - * some reason (the latter only applies if we are going through the service manager). + * some reason (the latter only applies if we are going through the service manager). As special + * exception it won't log for these two error cases. */ assert(unit_name); @@ -474,13 +475,13 @@ int unit_find_paths( return log_error_errno(r, "Failed to get LoadState: %s", bus_error_message(&error, r)); if (streq(load_state, "masked")) - return -ERFKILL; + return -ERFKILL; /* special case: no logging */ if (streq(load_state, "not-found")) { r = 0; - goto not_found; + goto finish; } if (!STR_IN_SET(load_state, "loaded", "bad-setting")) - return -EKEYREJECTED; + return -EKEYREJECTED; /* special case: no logging */ r = sd_bus_get_property_string( bus, @@ -517,7 +518,7 @@ int unit_find_paths( r = unit_file_find_fragment(*cached_id_map, *cached_name_map, unit_name, &_path, &names); if (r < 0) - return r; + return log_error_errno(r, "Failed to find fragment for '%s': %m", unit_name); if (_path) { path = strdup(_path); @@ -534,6 +535,7 @@ int unit_find_paths( } } + finish: if (isempty(path)) { *ret_fragment_path = NULL; r = 0; @@ -550,7 +552,6 @@ int unit_find_paths( *ret_dropin_paths = NULL; } - not_found: if (r == 0 && !arg_force) log_error("No files found for %s.", unit_name); diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c index d002d933a..bcc5f896b 100644 --- a/src/systemctl/systemctl.c +++ b/src/systemctl/systemctl.c @@ -11,8 +11,10 @@ #include "main-func.h" #include "output-mode.h" #include "pager.h" +#include "parse-argument.h" #include "path-util.h" #include "pretty-print.h" +#include "process-util.h" #include "rlimit-util.h" #include "sigbus.h" #include "signal-util.h" @@ -38,6 +40,7 @@ #include "systemctl-list-units.h" #include "systemctl-log-setting.h" #include "systemctl-logind.h" +#include "systemctl-mount.h" #include "systemctl-preset-all.h" #include "systemctl-reset-failed.h" #include "systemctl-service-watchdogs.h" @@ -66,7 +69,7 @@ const char *arg_job_mode = "replace"; UnitFileScope arg_scope = UNIT_FILE_SYSTEM; bool arg_wait = false; bool arg_no_block = false; -bool arg_no_legend = false; +int arg_legend = -1; /* -1: true, unless --quiet is passed, 1: true */ PagerFlags arg_pager_flags = 0; bool arg_no_wtmp = false; bool arg_no_sync = false; @@ -74,7 +77,7 @@ bool arg_no_wall = false; bool arg_no_reload = false; bool arg_value = false; bool arg_show_types = false; -bool arg_ignore_inhibitors = false; +int arg_check_inhibitors = -1; bool arg_dry_run = false; bool arg_quiet = false; bool arg_full = false; @@ -105,6 +108,9 @@ bool arg_jobs_before = false; bool arg_jobs_after = false; char **arg_clean_what = NULL; TimestampStyle arg_timestamp_style = TIMESTAMP_PRETTY; +bool arg_read_only = false; +bool arg_mkdir = false; +bool arg_marked = false; STATIC_DESTRUCTOR_REGISTER(arg_wall, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_root, freep); @@ -157,6 +163,10 @@ static int systemctl_help(void) { " freeze PATTERN... Freeze execution of unit processes\n" " thaw PATTERN... Resume execution of a frozen unit\n" " set-property UNIT PROPERTY=VALUE... Sets one or more properties of a unit\n" + " bind UNIT PATH [PATH] Bind-mount a path from the host into a\n" + " unit's namespace\n" + " mount-image UNIT PATH [PATH [OPTS]] Mount an image from the host into a\n" + " unit's namespace\n" " service-log-level SERVICE [LEVEL] Get/set logging threshold for service\n" " service-log-target SERVICE [TARGET] Get/set logging target for service\n" " reset-failed [PATTERN...] Reset failed state for all, one, or more\n" @@ -193,7 +203,7 @@ static int systemctl_help(void) { " show-environment Dump environment\n" " set-environment VARIABLE=VALUE... Set one or more environment variables\n" " unset-environment VARIABLE... Unset one or more environment variables\n" - " import-environment [VARIABLE...] Import all or some environment variables\n" + " import-environment VARIABLE... Import all or some environment variables\n" "\n%3$sManager State Commands:%4$s\n" " daemon-reload Reload systemd manager configuration\n" " daemon-reexec Reexecute systemd manager\n" @@ -241,7 +251,10 @@ static int systemctl_help(void) { " -T --show-transaction When enqueuing a unit job, show full transaction\n" " --show-types When showing sockets, explicitly show their type\n" " --value When showing properties, only print the value\n" - " -i --ignore-inhibitors When shutting down or sleeping, ignore inhibitors\n" + " --check-inhibitors=MODE\n" + " Specify if checking inhibitors before shutting down,\n" + " sleeping or hibernating\n" + " -i Shortcut for --check-inhibitors=no\n" " --kill-who=WHO Whom to send signal to\n" " -s --signal=SIGNAL Which signal to send\n" " --what=RESOURCES Which types of resources to remove\n" @@ -256,7 +269,7 @@ static int systemctl_help(void) { " --no-block Do not wait until operation finished\n" " --no-wall Don't send wall message before halt/power-off/reboot\n" " --no-reload Don't reload daemon after en-/dis-abling unit files\n" - " --no-legend Do not print a legend (column headers and hints)\n" + " --legend=BOOL Enable/disable the legend (column headers and hints)\n" " --no-pager Do not pipe output into a pager\n" " --no-ask-password Do not ask for system passwords\n" " --global Enable/disable/mask unit files globally\n" @@ -283,98 +296,104 @@ static int systemctl_help(void) { " 'us': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU TZ\n" " 'utc': 'Day YYYY-MM-DD HH:MM:SS UTC\n" " 'us+utc': 'Day YYYY-MM-DD HH:MM:SS.UUUUUU UTC\n" - "\nSee the %2$s for details.\n" - , program_invocation_short_name - , link - , ansi_underline(), ansi_normal() - , ansi_highlight(), ansi_normal() - ); + " --read-only Create read-only bind mount\n" + " --mkdir Create directory before mounting, if missing\n" + " --marked Restart/reload previously marked units\n" + "\nSee the %2$s for details.\n", + program_invocation_short_name, + link, + ansi_underline(), + ansi_normal(), + ansi_highlight(), + ansi_normal()); return 0; } static void help_types(void) { - if (!arg_no_legend) + if (arg_legend != 0) puts("Available unit types:"); DUMP_STRING_TABLE(unit_type, UnitType, _UNIT_TYPE_MAX); } static void help_states(void) { - if (!arg_no_legend) + if (arg_legend != 0) puts("Available unit load states:"); DUMP_STRING_TABLE(unit_load_state, UnitLoadState, _UNIT_LOAD_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable unit active states:"); DUMP_STRING_TABLE(unit_active_state, UnitActiveState, _UNIT_ACTIVE_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable unit file states:"); DUMP_STRING_TABLE(unit_file_state, UnitFileState, _UNIT_FILE_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable automount unit substates:"); DUMP_STRING_TABLE(automount_state, AutomountState, _AUTOMOUNT_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable device unit substates:"); DUMP_STRING_TABLE(device_state, DeviceState, _DEVICE_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable mount unit substates:"); DUMP_STRING_TABLE(mount_state, MountState, _MOUNT_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable path unit substates:"); DUMP_STRING_TABLE(path_state, PathState, _PATH_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable scope unit substates:"); DUMP_STRING_TABLE(scope_state, ScopeState, _SCOPE_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable service unit substates:"); DUMP_STRING_TABLE(service_state, ServiceState, _SERVICE_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable slice unit substates:"); DUMP_STRING_TABLE(slice_state, SliceState, _SLICE_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable socket unit substates:"); DUMP_STRING_TABLE(socket_state, SocketState, _SOCKET_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable swap unit substates:"); DUMP_STRING_TABLE(swap_state, SwapState, _SWAP_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable target unit substates:"); DUMP_STRING_TABLE(target_state, TargetState, _TARGET_STATE_MAX); - if (!arg_no_legend) + if (arg_legend != 0) puts("\nAvailable timer unit substates:"); DUMP_STRING_TABLE(timer_state, TimerState, _TIMER_STATE_MAX); } static int systemctl_parse_argv(int argc, char *argv[]) { enum { - ARG_FAIL = 0x100, + ARG_FAIL = 0x100, /* compatibility only */ ARG_REVERSE, ARG_AFTER, ARG_BEFORE, + ARG_CHECK_INHIBITORS, ARG_DRY_RUN, ARG_SHOW_TYPES, - ARG_IRREVERSIBLE, - ARG_IGNORE_DEPENDENCIES, + ARG_IRREVERSIBLE, /* compatibility only */ + ARG_IGNORE_DEPENDENCIES, /* compatibility only */ ARG_VALUE, ARG_VERSION, ARG_USER, ARG_SYSTEM, ARG_GLOBAL, ARG_NO_BLOCK, - ARG_NO_LEGEND, + ARG_LEGEND, + ARG_NO_LEGEND, /* compatibility only */ ARG_NO_PAGER, ARG_NO_WALL, ARG_ROOT, @@ -397,6 +416,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { ARG_WHAT, ARG_REBOOT_ARG, ARG_TIMESTAMP_STYLE, + ARG_READ_ONLY, + ARG_MKDIR, + ARG_MARKED, }; static const struct option options[] = { @@ -409,20 +431,22 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "after", no_argument, NULL, ARG_AFTER }, { "before", no_argument, NULL, ARG_BEFORE }, { "show-types", no_argument, NULL, ARG_SHOW_TYPES }, - { "failed", no_argument, NULL, ARG_FAILED }, /* compatibility only */ + { "failed", no_argument, NULL, ARG_FAILED }, { "full", no_argument, NULL, 'l' }, { "job-mode", required_argument, NULL, ARG_JOB_MODE }, { "fail", no_argument, NULL, ARG_FAIL }, /* compatibility only */ { "irreversible", no_argument, NULL, ARG_IRREVERSIBLE }, /* compatibility only */ { "ignore-dependencies", no_argument, NULL, ARG_IGNORE_DEPENDENCIES }, /* compatibility only */ - { "ignore-inhibitors", no_argument, NULL, 'i' }, + { "ignore-inhibitors", no_argument, NULL, 'i' }, /* compatibility only */ + { "check-inhibitors", required_argument, NULL, ARG_CHECK_INHIBITORS }, { "value", no_argument, NULL, ARG_VALUE }, { "user", no_argument, NULL, ARG_USER }, { "system", no_argument, NULL, ARG_SYSTEM }, { "global", no_argument, NULL, ARG_GLOBAL }, { "wait", no_argument, NULL, ARG_WAIT }, { "no-block", no_argument, NULL, ARG_NO_BLOCK }, - { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, + { "legend", required_argument, NULL, ARG_LEGEND }, + { "no-legend", no_argument, NULL, ARG_NO_LEGEND }, /* compatibility only */ { "no-pager", no_argument, NULL, ARG_NO_PAGER }, { "no-wall", no_argument, NULL, ARG_NO_WALL }, { "dry-run", no_argument, NULL, ARG_DRY_RUN }, @@ -452,6 +476,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { { "what", required_argument, NULL, ARG_WHAT }, { "reboot-argument", required_argument, NULL, ARG_REBOOT_ARG }, { "timestamp", required_argument, NULL, ARG_TIMESTAMP_STYLE }, + { "read-only", no_argument, NULL, ARG_READ_ONLY }, + { "mkdir", no_argument, NULL, ARG_MKDIR }, + { "marked", no_argument, NULL, ARG_MARKED }, {} }; @@ -473,14 +500,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) { case ARG_VERSION: return version(); - case 't': { - const char *p; - + case 't': if (isempty(optarg)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--type= requires arguments."); - for (p = optarg;;) { + for (const char *p = optarg;;) { _cleanup_free_ char *type = NULL; r = extract_first_word(&p, &type, ",", 0); @@ -514,7 +539,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } break; - } case 'P': arg_value = true; @@ -527,10 +551,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_properties = new0(char*, 1); if (!arg_properties) return log_oom(); - } else { - const char *p; - - for (p = optarg;;) { + } else + for (const char *p = optarg;;) { _cleanup_free_ char *prop = NULL; r = extract_first_word(&p, &prop, ",", 0); @@ -542,7 +564,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { if (strv_consume(&arg_properties, TAKE_PTR(prop)) < 0) return log_oom(); } - } /* If the user asked for a particular property, show it, even if it is empty. */ arg_all = true; @@ -612,7 +633,14 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_NO_LEGEND: - arg_no_legend = true; + arg_legend = false; + break; + + case ARG_LEGEND: + r = parse_boolean_argument("--legend", optarg, NULL); + if (r < 0) + return r; + arg_legend = r; break; case ARG_NO_PAGER: @@ -624,7 +652,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, false, &arg_root); + r = parse_path_argument(optarg, false, &arg_root); if (r < 0) return r; break; @@ -645,6 +673,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) { case 'q': arg_quiet = true; + + if (arg_legend < 0) + arg_legend = false; + break; case 'f': @@ -660,16 +692,9 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; case 's': - if (streq(optarg, "help")) { - DUMP_STRING_TABLE(signal, int, _NSIG); - return 0; - } - - arg_signal = signal_from_string(optarg); - if (arg_signal < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Failed to parse signal string %s.", - optarg); + r = parse_signal_argument(optarg, &arg_signal); + if (r <= 0) + return r; break; case ARG_NO_ASK_PASSWORD: @@ -710,13 +735,24 @@ static int systemctl_parse_argv(int argc, char *argv[]) { optarg); if (OUTPUT_MODE_IS_JSON(arg_output)) { - arg_no_legend = true; + arg_legend = false; arg_plain = true; } break; case 'i': - arg_ignore_inhibitors = true; + arg_check_inhibitors = 0; + break; + + case ARG_CHECK_INHIBITORS: + if (streq(optarg, "auto")) + arg_check_inhibitors = -1; + else { + r = parse_boolean(optarg); + if (r < 0) + return log_error_errno(r, "Failed to parse --check-inhibitors= argument: %s", optarg); + arg_check_inhibitors = r; + } break; case ARG_PLAIN: @@ -748,14 +784,12 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_boot_loader_entry = empty_to_null(optarg); break; - case ARG_STATE: { - const char *p; - + case ARG_STATE: if (isempty(optarg)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--state= requires arguments."); - for (p = optarg;;) { + for (const char *p = optarg;;) { _cleanup_free_ char *s = NULL; r = extract_first_word(&p, &s, ",", 0); @@ -773,7 +807,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return log_oom(); } break; - } case 'r': if (geteuid() != 0) @@ -813,13 +846,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) { arg_with_dependencies = true; break; - case ARG_WHAT: { - const char *p; - + case ARG_WHAT: if (isempty(optarg)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--what= requires arguments."); - for (p = optarg;;) { + for (const char *p = optarg;;) { _cleanup_free_ char *k = NULL; r = extract_first_word(&p, &k, ",", 0); @@ -843,7 +874,6 @@ static int systemctl_parse_argv(int argc, char *argv[]) { } break; - } case ARG_REBOOT_ARG: arg_reboot_argument = optarg; @@ -862,6 +892,18 @@ static int systemctl_parse_argv(int argc, char *argv[]) { break; + case ARG_READ_ONLY: + arg_read_only = true; + break; + + case ARG_MKDIR: + arg_mkdir = true; + break; + + case ARG_MARKED: + arg_marked = true; + break; + case '.': /* Output an error mimicking getopt, and print a hint afterwards */ log_error("%s: invalid option -- '.'", program_invocation_name); @@ -877,7 +919,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) { assert_not_reached("Unhandled option"); } - if (arg_transport != BUS_TRANSPORT_LOCAL && arg_scope != UNIT_FILE_SYSTEM) + if (arg_transport == BUS_TRANSPORT_REMOTE && arg_scope != UNIT_FILE_SYSTEM) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot access user instance remotely."); @@ -885,73 +927,88 @@ static int systemctl_parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--wait may not be combined with --no-block."); + bool do_reload_or_restart = streq_ptr(argv[optind], "reload-or-restart"); + if (arg_marked) { + if (!do_reload_or_restart) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--marked may only be used with 'reload-or-restart'."); + if (optind + 1 < argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "No additional arguments allowed with 'reload-or-restart --marked'."); + if (arg_wait) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--marked --wait is not supported."); + if (arg_show_transaction) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "--marked --show-transaction is not supported."); + + } else if (do_reload_or_restart) { + if (optind + 1 >= argc) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "List of units to restart/reload is required."); + } + return 1; } -static int parse_argv(int argc, char *argv[]) { +int systemctl_dispatch_parse_argv(int argc, char *argv[]) { assert(argc >= 0); assert(argv); - if (program_invocation_short_name) { + if (invoked_as(argv, "halt")) { + arg_action = ACTION_HALT; + return halt_parse_argv(argc, argv); - if (strstr(program_invocation_short_name, "halt")) { - arg_action = ACTION_HALT; - return halt_parse_argv(argc, argv); + } else if (invoked_as(argv, "poweroff")) { + arg_action = ACTION_POWEROFF; + return halt_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "poweroff")) { - arg_action = ACTION_POWEROFF; - return halt_parse_argv(argc, argv); + } else if (invoked_as(argv, "reboot")) { + if (kexec_loaded()) + arg_action = ACTION_KEXEC; + else + arg_action = ACTION_REBOOT; + return halt_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "reboot")) { - if (kexec_loaded()) - arg_action = ACTION_KEXEC; - else - arg_action = ACTION_REBOOT; - return halt_parse_argv(argc, argv); + } else if (invoked_as(argv, "shutdown")) { + arg_action = ACTION_POWEROFF; + return shutdown_parse_argv(argc, argv); - } else if (strstr(program_invocation_short_name, "shutdown")) { - arg_action = ACTION_POWEROFF; - return shutdown_parse_argv(argc, argv); + } else if (invoked_as(argv, "init")) { - } else if (strstr(program_invocation_short_name, "init")) { + /* Matches invocations as "init" as well as "telinit", which are synonymous when run + * as PID != 1 on SysV. + * + * On SysV "telinit" was the official command to communicate with PID 1, but "init" would + * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still, + * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence, + * for us if you invoke "init" you get "systemd", but it will execve() "systemctl" + * immediately with argv[] unmodified if PID is != 1. If you invoke "telinit" you directly + * get "systemctl". In both cases we shall do the same thing, which is why we do + * invoked_as(argv, "init") here, as a quick way to match both. + * + * Also see redirect_telinit() in src/core/main.c. */ - /* Matches invocations as "init" as well as "telinit", which are synonymous when run - * as PID != 1 on SysV. - * - * On SysV "telinit" was the official command to communicate with PID 1, but "init" would - * redirect itself to "telinit" if called with PID != 1. We follow the same logic here still, - * though we add one level of indirection, as we implement "telinit" in "systemctl". Hence, for - * us if you invoke "init" you get "systemd", but it will execve() "systemctl" immediately with - * argv[] unmodified if PID is != 1. If you invoke "telinit" you directly get "systemctl". In - * both cases we shall do the same thing, which is why we do strstr(p_i_s_n, "init") here, as a - * quick way to match both. - * - * Also see redirect_telinit() in src/core/main.c. */ - - if (sd_booted() > 0) { - arg_action = _ACTION_INVALID; - return telinit_parse_argv(argc, argv); - } else { - /* Hmm, so some other init system is running, we need to forward this request to - * it. For now we simply guess that it is Upstart. */ - - (void) rlimit_nofile_safe(); - execv(TELINIT, argv); - - return log_error_errno(SYNTHETIC_ERRNO(EIO), - "Couldn't find an alternative telinit implementation to spawn."); - } - - } else if (strstr(program_invocation_short_name, "runlevel")) { - arg_action = ACTION_RUNLEVEL; - return runlevel_parse_argv(argc, argv); + if (sd_booted() > 0) { + arg_action = _ACTION_INVALID; + return telinit_parse_argv(argc, argv); + } else { + /* Hmm, so some other init system is running, we need to forward this request to it. + */ + arg_action = ACTION_TELINIT; + return 1; } + + } else if (invoked_as(argv, "runlevel")) { + arg_action = ACTION_RUNLEVEL; + return runlevel_parse_argv(argc, argv); } arg_action = ACTION_SYSTEMCTL; return systemctl_parse_argv(argc, argv); } +#ifndef FUZZ_SYSTEMCTL_PARSE_ARGV static int systemctl_main(int argc, char *argv[]) { static const Verb verbs[] = { { "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_ONLINE_ONLY, list_units }, @@ -968,7 +1025,7 @@ static int systemctl_main(int argc, char *argv[]) { { "reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, - { "reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, + { "reload-or-restart", VERB_ANY, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "reload-or-try-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with old systemctl <= 228 */ { "try-reload-or-restart", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, { "force-reload", 2, VERB_ANY, VERB_ONLINE_ONLY, start_unit }, /* For compatibility with SysV */ @@ -1029,6 +1086,8 @@ static int systemctl_main(int argc, char *argv[]) { { "add-wants", 3, VERB_ANY, 0, add_dependency }, { "add-requires", 3, VERB_ANY, 0, add_dependency }, { "edit", 2, VERB_ANY, VERB_ONLINE_ONLY, edit }, + { "bind", 3, 4, VERB_ONLINE_ONLY, mount_bind }, + { "mount-image", 4, 5, VERB_ONLINE_ONLY, mount_image }, {} }; @@ -1045,7 +1104,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_parse_environment_cli(); + log_parse_environment(); log_open(); /* The journal merging logic potentially needs a lot of fds. */ @@ -1053,7 +1112,7 @@ static int run(int argc, char *argv[]) { sigbus_install(); - r = parse_argv(argc, argv); + r = systemctl_dispatch_parse_argv(argc, argv); if (r <= 0) goto finish; @@ -1103,6 +1162,10 @@ static int run(int argc, char *argv[]) { r = runlevel_main(); break; + case ACTION_TELINIT: + r = exec_telinit(argv); + break; + case ACTION_EXIT: case ACTION_SUSPEND: case ACTION_HIBERNATE: @@ -1110,8 +1173,8 @@ static int run(int argc, char *argv[]) { case ACTION_SUSPEND_THEN_HIBERNATE: case ACTION_EMERGENCY: case ACTION_DEFAULT: - /* systemctl verbs with no equivalent in the legacy commands. These cannot appear in - * arg_action. Fall through. */ + /* systemctl verbs with no equivalent in the legacy commands. These cannot appear in + * arg_action. Fall through. */ case _ACTION_INVALID: default: @@ -1126,3 +1189,4 @@ finish: } DEFINE_MAIN_FUNCTION_WITH_POSITIVE_FAILURE(run); +#endif diff --git a/src/systemctl/systemctl.h b/src/systemctl/systemctl.h index f8cefc9b0..3a3ff9ac1 100644 --- a/src/systemctl/systemctl.h +++ b/src/systemctl/systemctl.h @@ -29,9 +29,10 @@ enum action { ACTION_RELOAD, ACTION_REEXEC, ACTION_RUNLEVEL, + ACTION_TELINIT, ACTION_CANCEL_SHUTDOWN, _ACTION_MAX, - _ACTION_INVALID = -1 + _ACTION_INVALID = -EINVAL, }; enum dependency { @@ -51,7 +52,7 @@ extern const char *arg_job_mode; extern UnitFileScope arg_scope; extern bool arg_wait; extern bool arg_no_block; -extern bool arg_no_legend; +extern int arg_legend; extern PagerFlags arg_pager_flags; extern bool arg_no_wtmp; extern bool arg_no_sync; @@ -59,7 +60,7 @@ extern bool arg_no_wall; extern bool arg_no_reload; extern bool arg_value; extern bool arg_show_types; -extern bool arg_ignore_inhibitors; +extern int arg_check_inhibitors; extern bool arg_dry_run; extern bool arg_quiet; extern bool arg_full; @@ -90,3 +91,8 @@ extern bool arg_jobs_before; extern bool arg_jobs_after; extern char **arg_clean_what; extern TimestampStyle arg_timestamp_style; +extern bool arg_read_only; +extern bool arg_mkdir; +extern bool arg_marked; + +int systemctl_dispatch_parse_argv(int argc, char *argv[]); diff --git a/src/systemctl/systemd-sysv-install.SKELETON b/src/systemctl/systemd-sysv-install.SKELETON index 8c16cf999..a2a0059fe 100755 --- a/src/systemctl/systemd-sysv-install.SKELETON +++ b/src/systemctl/systemd-sysv-install.SKELETON @@ -1,4 +1,6 @@ #!/bin/sh +# SPDX-License-Identifier: CC0-1.0 +# # This script is called by "systemctl enable/disable" when the given unit is a # SysV init.d script. It needs to call the distribution's mechanism for # enabling/disabling those, such as chkconfig, update-rc.d, or similar. This diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index e3de2ae56..e12142964 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -99,4 +99,10 @@ typedef void (*_sd_destroy_t)(void *userdata); } \ struct _sd_useless_struct_to_allow_trailing_semicolon_ +/* The following macro should be used in all public enums, to force 64bit wideness on them, so that we can + * freely extend them later on, without breaking compatibility. */ +#define _SD_ENUM_FORCE_S64(id) \ + _SD_##id##_INT64_MIN = INT64_MIN, \ + _SD_##id##_INT64_MAX = INT64_MAX + #endif diff --git a/src/systemd/meson.build b/src/systemd/meson.build index 3d328e5fd..e01281f45 100644 --- a/src/systemd/meson.build +++ b/src/systemd/meson.build @@ -42,7 +42,6 @@ install_headers( '_sd-common.h', subdir : 'systemd') - ############################################################ opts = [['c'], diff --git a/src/systemd/sd-bus.h b/src/systemd/sd-bus.h index 87fbcf366..a07a76170 100644 --- a/src/systemd/sd-bus.h +++ b/src/systemd/sd-bus.h @@ -135,6 +135,7 @@ int sd_bus_open(sd_bus **ret); int sd_bus_open_with_description(sd_bus **ret, const char *description); int sd_bus_open_user(sd_bus **ret); int sd_bus_open_user_with_description(sd_bus **ret, const char *description); +int sd_bus_open_user_machine(sd_bus **ret, const char *machine); int sd_bus_open_system(sd_bus **ret); int sd_bus_open_system_with_description(sd_bus **ret, const char *description); int sd_bus_open_system_remote(sd_bus **ret, const char *host); @@ -353,6 +354,7 @@ int sd_bus_get_name_machine_id(sd_bus *bus, const char *name, sd_id128_t *machin /* Convenience calls */ +int sd_bus_message_send(sd_bus_message *m); int sd_bus_call_methodv(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, sd_bus_message **reply, const char *types, va_list ap); int sd_bus_call_method(sd_bus *bus, const char *destination, const char *path, const char *interface, const char *member, sd_bus_error *ret_error, sd_bus_message **reply, const char *types, ...); int sd_bus_call_method_asyncv(sd_bus *bus, sd_bus_slot **slot, const char *destination, const char *path, const char *interface, const char *member, sd_bus_message_handler_t callback, void *userdata, const char *types, va_list ap); diff --git a/src/systemd/sd-device.h b/src/systemd/sd-device.h index 78fe58416..310fcaa27 100644 --- a/src/systemd/sd-device.h +++ b/src/systemd/sd-device.h @@ -17,7 +17,9 @@ along with systemd; If not, see . ***/ +#include #include +#include #include #include @@ -31,6 +33,20 @@ typedef struct sd_device sd_device; typedef struct sd_device_enumerator sd_device_enumerator; typedef struct sd_device_monitor sd_device_monitor; +typedef enum sd_device_action_t { + SD_DEVICE_ADD, + SD_DEVICE_REMOVE, + SD_DEVICE_CHANGE, + SD_DEVICE_MOVE, + SD_DEVICE_ONLINE, + SD_DEVICE_OFFLINE, + SD_DEVICE_BIND, + SD_DEVICE_UNBIND, + _SD_DEVICE_ACTION_MAX, + _SD_DEVICE_ACTION_INVALID = -EINVAL, + _SD_ENUM_FORCE_S64(DEVICE_ACTION), +} sd_device_action_t; + /* callback */ typedef int (*sd_device_monitor_handler_t)(sd_device_monitor *m, sd_device *device, void *userdata); @@ -44,6 +60,7 @@ int sd_device_new_from_syspath(sd_device **ret, const char *syspath); int sd_device_new_from_devnum(sd_device **ret, char type, dev_t devnum); int sd_device_new_from_subsystem_sysname(sd_device **ret, const char *subsystem, const char *sysname); int sd_device_new_from_device_id(sd_device **ret, const char *id); +int sd_device_new_from_stat_rdev(sd_device **ret, const struct stat *st); int sd_device_get_parent(sd_device *child, sd_device **ret); int sd_device_get_parent_with_subsystem_devtype(sd_device *child, const char *subsystem, const char *devtype, sd_device **ret); @@ -58,6 +75,8 @@ int sd_device_get_devpath(sd_device *device, const char **ret); int sd_device_get_devname(sd_device *device, const char **ret); int sd_device_get_sysname(sd_device *device, const char **ret); int sd_device_get_sysnum(sd_device *device, const char **ret); +int sd_device_get_action(sd_device *device, sd_device_action_t *ret); +int sd_device_get_seqnum(sd_device *device, uint64_t *ret); int sd_device_get_is_initialized(sd_device *device); int sd_device_get_usec_since_initialized(sd_device *device, uint64_t *usec); @@ -80,6 +99,7 @@ int sd_device_get_sysattr_value(sd_device *device, const char *sysattr, const ch int sd_device_set_sysattr_value(sd_device *device, const char *sysattr, const char *value); int sd_device_set_sysattr_valuef(sd_device *device, const char *sysattr, const char *format, ...) _sd_printf_(3, 4); +int sd_device_trigger(sd_device *device, sd_device_action_t action); /* device enumerator */ diff --git a/src/systemd/sd-dhcp-client.h b/src/systemd/sd-dhcp-client.h index d4ee16e22..822286919 100644 --- a/src/systemd/sd-dhcp-client.h +++ b/src/systemd/sd-dhcp-client.h @@ -40,6 +40,8 @@ enum { SD_DHCP_CLIENT_EVENT_EXPIRED = 3, SD_DHCP_CLIENT_EVENT_RENEW = 4, SD_DHCP_CLIENT_EVENT_SELECTING = 5, + SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts. + * The client may want to start acquiring link-local addresses. */ }; enum { diff --git a/src/systemd/sd-dhcp-lease.h b/src/systemd/sd-dhcp-lease.h index c255a1f91..5abf9a406 100644 --- a/src/systemd/sd-dhcp-lease.h +++ b/src/systemd/sd-dhcp-lease.h @@ -18,6 +18,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -33,7 +34,7 @@ typedef struct sd_dhcp_route sd_dhcp_route; sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); -typedef enum sd_dhcp_lease_server_type { +typedef enum sd_dhcp_lease_server_type_t { SD_DHCP_LEASE_DNS, SD_DHCP_LEASE_NTP, SD_DHCP_LEASE_SIP, @@ -41,8 +42,9 @@ typedef enum sd_dhcp_lease_server_type { SD_DHCP_LEASE_SMTP, SD_DHCP_LEASE_LPR, _SD_DHCP_LEASE_SERVER_TYPE_MAX, - _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -1, -} sd_dhcp_lease_server_type; + _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL, + _SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE), +} sd_dhcp_lease_server_type_t; int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); @@ -53,7 +55,7 @@ int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type what, const struct in_addr **addr); +int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr); int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr); diff --git a/src/systemd/sd-dhcp-server.h b/src/systemd/sd-dhcp-server.h index f42c3dbb8..aa49a7434 100644 --- a/src/systemd/sd-dhcp-server.h +++ b/src/systemd/sd-dhcp-server.h @@ -60,7 +60,7 @@ int sd_dhcp_server_set_emit_router(sd_dhcp_server *server, int enabled); int sd_dhcp_server_set_servers( sd_dhcp_server *server, - sd_dhcp_lease_server_type what, + sd_dhcp_lease_server_type_t what, const struct in_addr addresses[], size_t n_addresses); diff --git a/src/systemd/sd-event.h b/src/systemd/sd-event.h index 937c9bd46..2ae2a0da4 100644 --- a/src/systemd/sd-event.h +++ b/src/systemd/sd-event.h @@ -162,6 +162,9 @@ int sd_event_source_get_floating(sd_event_source *s); int sd_event_source_set_floating(sd_event_source *s, int b); int sd_event_source_get_exit_on_failure(sd_event_source *s); int sd_event_source_set_exit_on_failure(sd_event_source *s, int b); +int sd_event_source_set_ratelimit(sd_event_source *s, uint64_t interval_usec, unsigned burst); +int sd_event_source_get_ratelimit(sd_event_source *s, uint64_t *ret_interval_usec, unsigned *ret_burst); +int sd_event_source_is_ratelimited(sd_event_source *s); /* Define helpers so that __attribute__((cleanup(sd_event_unrefp))) and similar may be used. */ _SD_DEFINE_POINTER_CLEANUP_FUNC(sd_event, sd_event_unref); diff --git a/src/systemd/sd-ipv4acd.h b/src/systemd/sd-ipv4acd.h index d900018f4..2809d8748 100644 --- a/src/systemd/sd-ipv4acd.h +++ b/src/systemd/sd-ipv4acd.h @@ -43,6 +43,8 @@ int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address); int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata); int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); +int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd); +const char *sd_ipv4acd_get_ifname(sd_ipv4acd *acd); int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); int sd_ipv4acd_is_running(sd_ipv4acd *acd); int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); diff --git a/src/systemd/sd-ipv4ll.h b/src/systemd/sd-ipv4ll.h index a0682232e..aa4d174e4 100644 --- a/src/systemd/sd-ipv4ll.h +++ b/src/systemd/sd-ipv4ll.h @@ -43,6 +43,8 @@ int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); +int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll); +const char *sd_ipv4ll_get_ifname(sd_ipv4ll *ll); int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); int sd_ipv4ll_is_running(sd_ipv4ll *ll); diff --git a/src/systemd/sd-lldp.h b/src/systemd/sd-lldp.h index f551f6b4f..e48e29fbc 100644 --- a/src/systemd/sd-lldp.h +++ b/src/systemd/sd-lldp.h @@ -17,6 +17,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -80,7 +81,7 @@ enum { SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, }; -#define SD_LLDP_SYSTEM_CAPABILITIES_ALL ((uint16_t) -1) +#define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX #define SD_LLDP_SYSTEM_CAPABILITIES_ALL_ROUTERS \ ((uint16_t) \ @@ -121,16 +122,17 @@ enum { typedef struct sd_lldp sd_lldp; typedef struct sd_lldp_neighbor sd_lldp_neighbor; -typedef enum sd_lldp_event { +typedef enum sd_lldp_event_t { SD_LLDP_EVENT_ADDED, SD_LLDP_EVENT_REMOVED, SD_LLDP_EVENT_UPDATED, SD_LLDP_EVENT_REFRESHED, _SD_LLDP_EVENT_MAX, - _SD_LLDP_EVENT_INVALID = -1, -} sd_lldp_event; + _SD_LLDP_EVENT_INVALID = -EINVAL, + _SD_ENUM_FORCE_S64(LLDP_EVENT), +} sd_lldp_event_t; -typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event event, sd_lldp_neighbor *n, void *userdata); +typedef void (*sd_lldp_callback_t)(sd_lldp *lldp, sd_lldp_event_t event, sd_lldp_neighbor *n, void *userdata); int sd_lldp_new(sd_lldp **ret); sd_lldp* sd_lldp_ref(sd_lldp *lldp); diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index c0e37899a..49b127c01 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -19,6 +19,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -54,14 +55,15 @@ enum { typedef struct sd_ndisc sd_ndisc; typedef struct sd_ndisc_router sd_ndisc_router; -typedef enum sd_ndisc_event { +typedef enum sd_ndisc_event_t { SD_NDISC_EVENT_TIMEOUT, SD_NDISC_EVENT_ROUTER, _SD_NDISC_EVENT_MAX, - _SD_NDISC_EVENT_INVALID = -1, -} sd_ndisc_event; + _SD_NDISC_EVENT_INVALID = -EINVAL, + _SD_ENUM_FORCE_S64(NDISC_EVENT), +} sd_ndisc_event_t; -typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event event, sd_ndisc_router *rt, void *userdata); +typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata); int sd_ndisc_new(sd_ndisc **ret); sd_ndisc *sd_ndisc_ref(sd_ndisc *nd); diff --git a/src/systemd/sd-netlink.h b/src/systemd/sd-netlink.h index bf6d1e47f..bc572f9b8 100644 --- a/src/systemd/sd-netlink.h +++ b/src/systemd/sd-netlink.h @@ -17,6 +17,7 @@ along with systemd; If not, see . ***/ +#include #include #include #include @@ -34,7 +35,7 @@ typedef struct sd_genl_socket sd_genl_socket; typedef struct sd_netlink_message sd_netlink_message; typedef struct sd_netlink_slot sd_netlink_slot; -typedef enum sd_gen_family { +typedef enum sd_genl_family_t { SD_GENL_ERROR, SD_GENL_DONE, SD_GENL_ID_CTRL, @@ -43,7 +44,11 @@ typedef enum sd_gen_family { SD_GENL_L2TP, SD_GENL_MACSEC, SD_GENL_NL80211, -} sd_genl_family; + SD_GENL_BATADV, + _SD_GENL_FAMILY_MAX, + _SD_GENL_FAMILY_INVALID = -EINVAL, + _SD_ENUM_FORCE_S64(GENL_FAMILY) +} sd_genl_family_t; /* callback */ @@ -60,11 +65,13 @@ sd_netlink *sd_netlink_ref(sd_netlink *nl); sd_netlink *sd_netlink_unref(sd_netlink *nl); int sd_netlink_send(sd_netlink *nl, sd_netlink_message *message, uint32_t *serial); +int sd_netlink_sendv(sd_netlink *nl, sd_netlink_message **messages, size_t msgcnt, uint32_t **ret_serial); int sd_netlink_call_async(sd_netlink *nl, sd_netlink_slot **ret_slot, sd_netlink_message *message, sd_netlink_message_handler_t callback, sd_netlink_destroy_t destoy_callback, void *userdata, uint64_t usec, const char *description); int sd_netlink_call(sd_netlink *nl, sd_netlink_message *message, uint64_t timeout, sd_netlink_message **reply); +int sd_netlink_read(sd_netlink *nl, uint32_t serial, uint64_t timeout, sd_netlink_message **reply); int sd_netlink_get_events(const sd_netlink *nl); int sd_netlink_get_timeout(const sd_netlink *nl, uint64_t *timeout); @@ -114,6 +121,7 @@ int sd_netlink_message_read_ether_addr(sd_netlink_message *m, unsigned short typ int sd_netlink_message_read_cache_info(sd_netlink_message *m, unsigned short type, struct ifa_cacheinfo *info); int sd_netlink_message_read_in_addr(sd_netlink_message *m, unsigned short type, struct in_addr *data); int sd_netlink_message_read_in6_addr(sd_netlink_message *m, unsigned short type, struct in6_addr *data); +int sd_netlink_message_has_flag(sd_netlink_message *m, unsigned short type); int sd_netlink_message_enter_container(sd_netlink_message *m, unsigned short type); int sd_netlink_message_enter_array(sd_netlink_message *m, unsigned short type); int sd_netlink_message_exit_container(sd_netlink_message *m); @@ -136,15 +144,10 @@ int sd_netlink_message_set_flags(sd_netlink_message *m, uint16_t flags); int sd_netlink_message_is_broadcast(const sd_netlink_message *m); /* rtnl */ - -int sd_rtnl_message_new_link(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index); -int sd_rtnl_message_new_addr_update(sd_netlink *nl, sd_netlink_message **ret, int index, int family); -int sd_rtnl_message_new_addr(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int family); -int sd_rtnl_message_new_route(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, int rtm_family, unsigned char rtm_protocol); -int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int nda_family); - int sd_rtnl_message_get_family(const sd_netlink_message *m, int *family); +int sd_rtnl_message_new_addr(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int family); +int sd_rtnl_message_new_addr_update(sd_netlink *nl, sd_netlink_message **ret, int index, int family); int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope); int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags); @@ -154,6 +157,7 @@ int sd_rtnl_message_addr_get_scope(const sd_netlink_message *m, unsigned char *s int sd_rtnl_message_addr_get_flags(const sd_netlink_message *m, unsigned char *flags); int sd_rtnl_message_addr_get_ifindex(const sd_netlink_message *m, int *ifindex); +int sd_rtnl_message_new_link(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index); int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change); int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type); int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family); @@ -161,6 +165,7 @@ int sd_rtnl_message_link_get_ifindex(const sd_netlink_message *m, int *ifindex); int sd_rtnl_message_link_get_flags(const sd_netlink_message *m, unsigned *flags); int sd_rtnl_message_link_get_type(const sd_netlink_message *m, unsigned short *type); +int sd_rtnl_message_new_route(sd_netlink *nl, sd_netlink_message **ret, uint16_t nlmsg_type, int rtm_family, unsigned char rtm_protocol); int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen); int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope); @@ -169,7 +174,6 @@ int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table); int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type); int sd_rtnl_message_route_get_flags(const sd_netlink_message *m, unsigned *flags); int sd_rtnl_message_route_get_family(const sd_netlink_message *m, int *family); -int sd_rtnl_message_route_set_family(sd_netlink_message *m, int family); int sd_rtnl_message_route_get_protocol(const sd_netlink_message *m, unsigned char *protocol); int sd_rtnl_message_route_get_scope(const sd_netlink_message *m, unsigned char *scope); int sd_rtnl_message_route_get_tos(const sd_netlink_message *m, unsigned char *tos); @@ -179,15 +183,15 @@ int sd_rtnl_message_route_get_src_prefixlen(const sd_netlink_message *m, unsigne int sd_rtnl_message_route_get_type(const sd_netlink_message *m, unsigned char *type); int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nhmsg_type, int nh_family, unsigned char nh_protocol); - int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags); -int sd_rtnl_message_nexthop_set_family(sd_netlink_message *m, uint8_t family); int sd_rtnl_message_nexthop_get_family(const sd_netlink_message *m, uint8_t *family); +int sd_rtnl_message_nexthop_get_protocol(const sd_netlink_message *m, uint8_t *protocol); +int sd_rtnl_message_new_neigh(sd_netlink *nl, sd_netlink_message **ret, uint16_t msg_type, int index, int nda_family); int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags); int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state); int sd_rtnl_message_neigh_get_family(const sd_netlink_message *m, int *family); -int sd_rtnl_message_neigh_get_ifindex(const sd_netlink_message *m, int *family); +int sd_rtnl_message_neigh_get_ifindex(const sd_netlink_message *m, int *index); int sd_rtnl_message_neigh_get_state(const sd_netlink_message *m, uint16_t *state); int sd_rtnl_message_neigh_get_flags(const sd_netlink_message *m, uint8_t *flags); @@ -196,18 +200,18 @@ int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char int sd_rtnl_message_addrlabel_get_prefixlen(const sd_netlink_message *m, unsigned char *prefixlen); int sd_rtnl_message_new_routing_policy_rule(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int ifal_family); -int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, unsigned char tos); -int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, unsigned char *tos); -int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, unsigned char table); -int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, unsigned char *table); -int sd_rtnl_message_routing_policy_rule_set_rtm_src_prefixlen(sd_netlink_message *m, unsigned char len); -int sd_rtnl_message_routing_policy_rule_get_rtm_src_prefixlen(const sd_netlink_message *m, unsigned char *len); -int sd_rtnl_message_routing_policy_rule_set_rtm_dst_prefixlen(sd_netlink_message *m, unsigned char len); -int sd_rtnl_message_routing_policy_rule_get_rtm_dst_prefixlen(const sd_netlink_message *m, unsigned char *len); -int sd_rtnl_message_routing_policy_rule_set_rtm_type(sd_netlink_message *m, unsigned char type); -int sd_rtnl_message_routing_policy_rule_get_rtm_type(const sd_netlink_message *m, unsigned char *type); -int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, unsigned flags); -int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, unsigned *flags); +int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t tos); +int sd_rtnl_message_routing_policy_rule_get_tos(const sd_netlink_message *m, uint8_t *tos); +int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t table); +int sd_rtnl_message_routing_policy_rule_get_table(const sd_netlink_message *m, uint8_t *table); +int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message *m, uint8_t len); +int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(const sd_netlink_message *m, uint8_t *len); +int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message *m, uint8_t len); +int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(const sd_netlink_message *m, uint8_t *len); +int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint8_t type); +int sd_rtnl_message_routing_policy_rule_get_fib_type(const sd_netlink_message *m, uint8_t *type); +int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_t flags); +int sd_rtnl_message_routing_policy_rule_get_flags(const sd_netlink_message *m, uint32_t *flags); int sd_rtnl_message_new_qdisc(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int tcm_family, int tcm_ifindex); int sd_rtnl_message_set_qdisc_parent(sd_netlink_message *m, uint32_t parent); @@ -219,10 +223,36 @@ int sd_rtnl_message_set_tclass_handle(sd_netlink_message *m, uint32_t handle); int sd_rtnl_message_new_mdb(sd_netlink *rtnl, sd_netlink_message **ret, uint16_t nlmsg_type, int mdb_ifindex); +/* nfnl */ +int sd_nfnl_socket_open(sd_netlink **nl); +int sd_nfnl_message_batch_begin(sd_netlink *nfnl, sd_netlink_message **ret); +int sd_nfnl_message_batch_end(sd_netlink *nfnl, sd_netlink_message **ret); +int sd_nfnl_nft_message_del_table(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table); +int sd_nfnl_nft_message_new_table(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, uint16_t nl_flags); +int sd_nfnl_nft_message_new_basechain(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *chain, + const char *type, uint8_t hook, int prio); +int sd_nfnl_nft_message_new_rule(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *chain); +int sd_nfnl_nft_message_new_set(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *set_name, + uint32_t setid, uint32_t klen); +int sd_nfnl_nft_message_new_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *set_name); +int sd_nfnl_nft_message_del_setelems_begin(sd_netlink *nfnl, sd_netlink_message **ret, + int family, const char *table, const char *set_name); +int sd_nfnl_nft_message_add_setelem(sd_netlink_message *m, + uint32_t num, + const void *key, uint32_t klen, + const void *data, uint32_t dlen); +int sd_nfnl_nft_message_add_setelem_end(sd_netlink_message *m); + /* genl */ int sd_genl_socket_open(sd_netlink **nl); -int sd_genl_message_new(sd_netlink *nl, sd_genl_family family, uint8_t cmd, sd_netlink_message **m); -int sd_genl_message_get_family(const sd_netlink *nl, const sd_netlink_message *m, sd_genl_family *family); +int sd_genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint8_t cmd, sd_netlink_message **m); +int sd_genl_message_get_family(const sd_netlink *nl, const sd_netlink_message *m, sd_genl_family_t *family); /* slot */ sd_netlink_slot *sd_netlink_slot_ref(sd_netlink_slot *nl); diff --git a/src/systemd/sd-network.h b/src/systemd/sd-network.h index 7e0625141..884dba81b 100644 --- a/src/systemd/sd-network.h +++ b/src/systemd/sd-network.h @@ -103,6 +103,11 @@ int sd_network_link_get_address_state(int ifindex, char **state); */ int sd_network_link_get_required_for_online(int ifindex); +/* Get activation policy for ifindex. + * Possible values are as specified for ActivationPolicy= + */ +int sd_network_link_get_activation_policy(int ifindex, char **policy); + /* Get path to .network file applied to link */ int sd_network_link_get_network_file(int ifindex, char **filename); diff --git a/src/systemd/sd-resolve.h b/src/systemd/sd-resolve.h index ee58d1813..530bfd516 100644 --- a/src/systemd/sd-resolve.h +++ b/src/systemd/sd-resolve.h @@ -68,7 +68,7 @@ int sd_resolve_get_fd(sd_resolve *resolve); * POLLOUT, ...) to check for. */ int sd_resolve_get_events(sd_resolve *resolve); -/* Return the poll() timeout to pass. Returns (uint64_t) -1 as +/* Return the poll() timeout to pass. Returns UINT64_MAX as * timeout if no timeout is needed. */ int sd_resolve_get_timeout(sd_resolve *resolve, uint64_t *timeout_usec); diff --git a/src/sysusers/sysusers.c b/src/sysusers/sysusers.c index 71bfb3b8c..b098eb27c 100644 --- a/src/sysusers/sysusers.c +++ b/src/sysusers/sysusers.c @@ -17,6 +17,7 @@ #include "mount-util.h" #include "nscd-flush.h" #include "pager.h" +#include "parse-argument.h" #include "path-util.h" #include "pretty-print.h" #include "selinux-util.h" @@ -255,7 +256,7 @@ static int make_backup(const char *target, const char *x) { if (r < 0) return r; - r = copy_bytes(src, fileno(dst), (uint64_t) -1, COPY_REFLINK); + r = copy_bytes(src, fileno(dst), UINT64_MAX, COPY_REFLINK); if (r < 0) return r; @@ -392,7 +393,7 @@ static int write_temporary_passwd(const char *passwd_path, FILE **tmpfile, char original = fopen(passwd_path, "re"); if (original) { - r = sync_rights(fileno(original), fileno(passwd)); + r = copy_rights(fileno(original), fileno(passwd)); if (r < 0) return r; @@ -493,7 +494,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char original = fopen(shadow_path, "re"); if (original) { - r = sync_rights(fileno(original), fileno(shadow)); + r = copy_rights(fileno(original), fileno(shadow)); if (r < 0) return r; @@ -538,7 +539,7 @@ static int write_temporary_shadow(const char *shadow_path, FILE **tmpfile, char .sp_warn = -1, .sp_inact = -1, .sp_expire = -1, - .sp_flag = (unsigned long) -1, /* this appears to be what everybody does ... */ + .sp_flag = ULONG_MAX, /* this appears to be what everybody does ... */ }; r = putspent_sane(&n, shadow); @@ -589,7 +590,7 @@ static int write_temporary_group(const char *group_path, FILE **tmpfile, char ** original = fopen(group_path, "re"); if (original) { - r = sync_rights(fileno(original), fileno(group)); + r = copy_rights(fileno(original), fileno(group)); if (r < 0) return r; @@ -687,7 +688,7 @@ static int write_temporary_gshadow(const char * gshadow_path, FILE **tmpfile, ch if (original) { struct sgrp *sg; - r = sync_rights(fileno(original), fileno(gshadow)); + r = copy_rights(fileno(original), fileno(gshadow)); if (r < 0) return r; @@ -1050,13 +1051,15 @@ static int add_user(Item *i) { i->uid = search_uid; } - r = ordered_hashmap_ensure_allocated(&todo_uids, NULL); - if (r < 0) + r = ordered_hashmap_ensure_put(&todo_uids, NULL, UID_TO_PTR(i->uid), i); + if (r == -EEXIST) + return log_error_errno(r, "Requested user %s with uid " UID_FMT " and gid" GID_FMT " to be created is duplicated " + "or conflicts with another user.", i->name, i->uid, i->gid); + if (r == -ENOMEM) return log_oom(); - - r = ordered_hashmap_put(todo_uids, UID_TO_PTR(i->uid), i); if (r < 0) - return log_oom(); + return log_error_errno(r, "Failed to store user %s with uid " UID_FMT " and gid " GID_FMT " to be created: %m", + i->name, i->uid, i->gid); i->todo_user = true; log_info("Creating user %s (%s) with uid " UID_FMT " and gid " GID_FMT ".", i->name, strna(i->description), i->uid, i->gid); @@ -1219,13 +1222,13 @@ static int add_group(Item *i) { i->gid = search_uid; } - r = ordered_hashmap_ensure_allocated(&todo_gids, NULL); - if (r < 0) + r = ordered_hashmap_ensure_put(&todo_gids, NULL, GID_TO_PTR(i->gid), i); + if (r == -EEXIST) + return log_error_errno(r, "Requested group %s with gid "GID_FMT " to be created is duplicated or conflicts with another user.", i->name, i->gid); + if (r == -ENOMEM) return log_oom(); - - r = ordered_hashmap_put(todo_gids, GID_TO_PTR(i->gid), i); if (r < 0) - return log_oom(); + return log_error_errno(r, "Failed to store group %s with gid " GID_FMT " to be created: %m", i->name, i->gid); i->todo_group = true; log_info("Creating group %s with gid " GID_FMT ".", i->name, i->gid); @@ -1305,10 +1308,6 @@ static int add_implicit(void) { if (!ordered_hashmap_get(users, *m)) { _cleanup_(item_freep) Item *j = NULL; - r = ordered_hashmap_ensure_allocated(&users, &item_hash_ops); - if (r < 0) - return log_oom(); - j = new0(Item, 1); if (!j) return log_oom(); @@ -1318,22 +1317,20 @@ static int add_implicit(void) { if (!j->name) return log_oom(); - r = ordered_hashmap_put(users, j->name, j); - if (r < 0) + r = ordered_hashmap_ensure_put(&users, &item_hash_ops, j->name, j); + if (r == -ENOMEM) return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to add implicit user '%s': %m", j->name); log_debug("Adding implicit user '%s' due to m line", j->name); - j = NULL; + TAKE_PTR(j); } if (!(ordered_hashmap_get(users, g) || ordered_hashmap_get(groups, g))) { _cleanup_(item_freep) Item *j = NULL; - r = ordered_hashmap_ensure_allocated(&groups, &item_hash_ops); - if (r < 0) - return log_oom(); - j = new0(Item, 1); if (!j) return log_oom(); @@ -1343,12 +1340,14 @@ static int add_implicit(void) { if (!j->name) return log_oom(); - r = ordered_hashmap_put(groups, j->name, j); - if (r < 0) + r = ordered_hashmap_ensure_put(&groups, &item_hash_ops, j->name, j); + if (r == -ENOMEM) return log_oom(); + if (r < 0) + return log_error_errno(r, "Failed to add implicit group '%s': %m", j->name); log_debug("Adding implicit group '%s' due to m line", j->name); - j = NULL; + TAKE_PTR(j); } } @@ -1764,10 +1763,9 @@ static int help(void) { " --replace=PATH Treat arguments as replacement for PATH\n" " --inline Treat arguments as configuration lines\n" " --no-pager Do not pipe output into a pager\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -1816,7 +1814,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root); + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root); if (r < 0) return r; break; @@ -1826,7 +1824,7 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "This systemd-sysusers version is compiled without support for --image=."); #else - r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image); + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image); if (r < 0) return r; break; @@ -1931,7 +1929,7 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - log_setup_service(); + log_setup(); if (arg_cat_config) return cat_config(); diff --git a/src/sysv-generator/sysv-generator.c b/src/sysv-generator/sysv-generator.c index 008a8250b..8c7aef23c 100644 --- a/src/sysv-generator/sysv-generator.c +++ b/src/sysv-generator/sysv-generator.c @@ -59,9 +59,9 @@ typedef struct SysvStub { bool loaded; } SysvStub; -static void free_sysvstub(SysvStub *s) { +static SysvStub* free_sysvstub(SysvStub *s) { if (!s) - return; + return NULL; free(s->name); free(s->path); @@ -71,9 +71,8 @@ static void free_sysvstub(SysvStub *s) { strv_free(s->after); strv_free(s->wants); strv_free(s->wanted_by); - free(s); + return mfree(s); } - DEFINE_TRIVIAL_CLEANUP_FUNC(SysvStub*, free_sysvstub); static void free_sysvstub_hashmapp(Hashmap **h) { diff --git a/src/test/generate-sym-test.py b/src/test/generate-sym-test.py index fdb9e3ecb..955d5e969 100755 --- a/src/test/generate-sym-test.py +++ b/src/test/generate-sym-test.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +# SPDX-License-Identifier: LGPL-2.1-or-later + import sys, re print('#include ') @@ -23,8 +25,7 @@ for line in open(sys.argv[1]): print('''}; int main(void) { - unsigned i; - for (i = 0; i < sizeof(symbols)/sizeof(void*); i++) + for (size_t i = 0; i < sizeof(symbols)/sizeof(void*); i++) printf("%p\\n", symbols[i]); return 0; }''') diff --git a/src/test/meson.build b/src/test/meson.build index 623429494..ff40a8d10 100644 --- a/src/test/meson.build +++ b/src/test/meson.build @@ -41,35 +41,33 @@ test_dlopen_c = files('test-dlopen.c') ############################################################ -test_systemd_tmpfiles_py = find_program('test-systemd-tmpfiles.py') - -############################################################ - tests += [ - [['src/test/test-device-nodes.c'], - [], - []], + [['src/test/test-device-nodes.c']], [['src/test/test-engine.c'], [libcore, - libudev, libshared], [threads, librt, libseccomp, libselinux, libmount, - libblkid]], + libblkid], + core_includes], [['src/test/test-emergency-action.c'], [libcore, libshared], - []], + [], + core_includes], [['src/test/test-chown-rec.c'], [libcore, libshared], - []], + [], + core_includes], + + [['src/test/test-dlopen-so.c']], [['src/test/test-job-type.c'], [libcore, @@ -79,7 +77,8 @@ tests += [ libseccomp, libselinux, libmount, - libblkid]], + libblkid], + core_includes], [['src/test/test-ns.c'], [libcore, @@ -90,30 +89,9 @@ tests += [ libselinux, libmount, libblkid], - '', 'manual'], - - [['src/test/test-nscd-flush.c'], - [libcore, - libshared], - [threads, - librt, - libseccomp, - libselinux, - libmount, - libblkid], - '', 'manual'], + core_includes, '', 'manual'], [['src/test/test-loopback.c'], - [libcore, - libshared], - [threads, - librt, - libseccomp, - libselinux, - libmount, - libblkid]], - - [['src/test/test-hostname.c'], [libcore, libshared], [threads, @@ -122,22 +100,14 @@ tests += [ libselinux, libmount, libblkid], - '', 'unsafe'], + core_includes], - [['src/test/test-dns-domain.c'], - [libcore, - libshared, - libsystemd_network], - []], + [['src/test/test-dns-domain.c']], [['src/test/test-boot-timestamps.c'], - [], - [], - 'ENABLE_EFI'], + [], [], [], 'ENABLE_EFI'], - [['src/test/test-unit-file.c'], - [], - []], + [['src/test/test-unit-file.c']], [['src/test/test-unit-name.c'], [libcore, @@ -147,7 +117,8 @@ tests += [ libseccomp, libselinux, libmount, - libblkid]], + libblkid], + core_includes], [['src/test/test-load-fragment.c'], [libcore, @@ -157,301 +128,176 @@ tests += [ libseccomp, libselinux, libmount, - libblkid]], + libblkid], + core_includes], - [['src/test/test-serialize.c'], - [], - []], + [['src/test/test-serialize.c']], - [['src/test/test-utf8.c'], - [], - []], + [['src/test/test-utf8.c']], - [['src/test/test-dev-setup.c'], - [], - []], + [['src/test/test-dev-setup.c']], [['src/test/test-capability.c'], [], [libcap]], [['src/test/test-async.c'], - [], - [], - '', 'timeout=120'], + [], [], [], '', 'timeout=120'], - [['src/test/test-locale-util.c'], - [], - []], + [['src/test/test-locale-util.c']], - [['src/test/test-copy.c'], - [], - []], + [['src/test/test-copy.c']], - [['src/test/test-static-destruct.c'], - [], - []], + [['src/test/test-static-destruct.c']], - [['src/test/test-sigbus.c'], - [], - []], + [['src/test/test-sigbus.c']], - [['src/test/test-condition.c'], - [], - []], + [['src/test/test-condition.c']], - [['src/test/test-fdset.c'], - [], - []], + [['src/test/test-fdset.c']], - [['src/test/test-fstab-util.c'], - [], - []], + [['src/test/test-fstab-util.c']], - [['src/test/test-random-util.c'], - [], - []], + [['src/test/test-random-util.c']], - [['src/test/test-format-table.c'], - [], - []], + [['src/test/test-format-table.c']], - [['src/test/test-format-util.c'], - [], - []], + [['src/test/test-format-util.c']], - [['src/test/test-ratelimit.c'], - [], - []], + [['src/test/test-ratelimit.c']], - [['src/test/test-util.c'], - [], - []], + [['src/test/test-util.c']], - [['src/test/test-json.c'], - [], - []], + [['src/test/test-json.c']], + + [['src/test/test-modhex.c']], [['src/test/test-libmount.c'], [], [threads, libmount]], - [['src/test/test-mount-util.c'], - [], - []], + [['src/test/test-mount-util.c']], - [['src/test/test-mountpoint-util.c'], - [], - []], + [['src/test/test-mountpoint-util.c']], - [['src/test/test-exec-util.c'], - [], - []], + [['src/test/test-exec-util.c']], - [['src/test/test-hexdecoct.c'], - [], - []], + [['src/test/test-hexdecoct.c']], - [['src/test/test-alloc-util.c'], - [], - []], + [['src/test/test-alloc-util.c']], - [['src/test/test-xattr-util.c'], - [], - []], + [['src/test/test-xattr-util.c']], - [['src/test/test-io-util.c'], - [], - []], + [['src/test/test-io-util.c']], - [['src/test/test-glob-util.c'], - [], - []], + [['src/test/test-glob-util.c']], - [['src/test/test-fs-util.c'], - [], - []], + [['src/test/test-fs-util.c']], - [['src/test/test-umask-util.c'], - [], - []], + [['src/test/test-umask-util.c']], - [['src/test/test-proc-cmdline.c'], - [], - []], + [['src/test/test-proc-cmdline.c']], - [['src/test/test-fd-util.c'], - [], - []], + [['src/test/test-fd-util.c']], - [['src/test/test-web-util.c'], - [], - []], + [['src/test/test-web-util.c']], - [['src/test/test-cpu-set-util.c'], - [], - []], + [['src/test/test-cpu-set-util.c']], - [['src/test/test-stat-util.c'], - [], - []], + [['src/test/test-stat-util.c']], - [['src/test/test-os-util.c'], - [], - []], + [['src/test/test-os-util.c']], [['src/test/test-libcrypt-util.c'], - [], - [], - '', 'timeout=120'], + [], [], [], '', 'timeout=120'], - [['src/test/test-offline-passwd.c', - 'src/shared/offline-passwd.c', - 'src/shared/offline-passwd.h'], - [], - []], + [['src/test/test-escape.c']], - [['src/test/test-escape.c'], - [], - []], + [['src/test/test-exit-status.c']], - [['src/test/test-exit-status.c'], - [], - []], + [['src/test/test-specifier.c']], - [['src/test/test-specifier.c'], - [], - []], + [['src/test/test-string-util.c']], - [['src/test/test-string-util.c'], - [], - []], + [['src/test/test-extract-word.c']], - [['src/test/test-extract-word.c'], - [], - []], + [['src/test/test-parse-argument.c']], - [['src/test/test-parse-util.c'], - [], - [libseccomp]], + [['src/test/test-parse-util.c']], - [['src/test/test-sysctl-util.c'], - [], - []], + [['src/test/test-sysctl-util.c']], - [['src/test/test-user-record.c'], - [], - []], + [['src/test/test-user-record.c']], - [['src/test/test-user-util.c'], - [], - []], + [['src/test/test-user-util.c']], - [['src/test/test-hostname-util.c'], - [], - []], + [['src/test/test-hostname-setup.c']], - [['src/test/test-process-util.c'], - [], - []], + [['src/test/test-hostname-util.c']], - [['src/test/test-terminal-util.c'], - [], - []], + [['src/test/test-process-util.c']], - [['src/test/test-path-lookup.c'], - [], - []], + [['src/test/test-terminal-util.c']], - [['src/test/test-pretty-print.c'], - [], - []], + [['src/test/test-path-lookup.c']], - [['src/test/test-uid-range.c'], - [], - []], + [['src/test/test-pretty-print.c']], + + [['src/test/test-uid-range.c']], [['src/test/test-cap-list.c', generated_gperf_headers], [], [libcap]], - [['src/test/test-socket-util.c'], - [], - []], + [['src/test/test-socket-util.c']], - [['src/test/test-socket-netlink.c'], - [], - []], + [['src/test/test-socket-netlink.c']], - [['src/test/test-in-addr-util.c'], - [], - []], + [['src/test/test-in-addr-util.c']], - [['src/test/test-barrier.c'], - [], - []], + [['src/test/test-barrier.c']], - [['src/test/test-tmpfiles.c'], - [], - []], + [['src/test/test-tmpfiles.c']], [['src/test/test-namespace.c'], [libcore, libshared], [threads, - libblkid]], + libblkid], + core_includes], - [['src/test/test-verbs.c'], - [], - []], + [['src/test/test-verbs.c']], - [['src/test/test-install-root.c'], - [], - []], + [['src/test/test-install-root.c']], [['src/test/test-acl-util.c'], - [], - [], - 'HAVE_ACL'], + [], [], [], 'HAVE_ACL'], [['src/test/test-seccomp.c'], [], [libseccomp], - 'HAVE_SECCOMP'], + [], 'HAVE_SECCOMP'], - [['src/test/test-rlimit-util.c'], - [], - []], + [['src/test/test-rlimit-util.c']], [['src/test/test-ask-password-api.c'], - [], - [], - '', 'manual'], + [], [], [], '', 'manual'], - [['src/test/test-signal-util.c'], - [], - []], + [['src/test/test-signal-util.c']], [['src/test/test-loop-block.c'], [libcore, libshared], [threads, libblkid], - '', - '', - [], - includes, - false], + core_includes, '', '', [], false], - [['src/test/test-selinux.c'], - [], - []], + [['src/test/test-selinux.c']], [['src/test/test-sizeof.c'], - [libbasic], - []], + [libbasic]], [['src/test/test-bpf-devices.c'], [libcore, @@ -461,7 +307,8 @@ tests += [ librt, libseccomp, libselinux, - libblkid]], + libblkid], + core_includes], [['src/test/test-bpf-firewall.c'], [libcore, @@ -471,7 +318,8 @@ tests += [ librt, libseccomp, libselinux, - libblkid]], + libblkid], + core_includes], [['src/test/test-watch-pid.c'], [libcore, @@ -481,56 +329,37 @@ tests += [ librt, libseccomp, libselinux, - libblkid]], + libblkid], + core_includes], [['src/test/test-hashmap.c', 'src/test/test-hashmap-plain.c', test_hashmap_ordered_c], - [], - [], - '', 'timeout=90'], + [], [], [], '', 'timeout=90'], [['src/test/test-set.c'], - [libbasic], - []], + [libbasic]], - [['src/test/test-ordered-set.c'], - [], - []], + [['src/test/test-ordered-set.c']], [['src/test/test-set-disable-mempool.c'], [], [threads]], - [['src/test/test-bitmap.c'], - [], - []], + [['src/test/test-bitmap.c']], - [['src/test/test-xml.c'], - [], - []], + [['src/test/test-xml.c']], - [['src/test/test-list.c'], - [], - []], + [['src/test/test-list.c']], - [['src/test/test-procfs-util.c'], - [], - []], + [['src/test/test-procfs-util.c']], - [['src/test/test-unaligned.c'], - [], - []], + [['src/test/test-unaligned.c']], - [['src/test/test-tables.c', - 'src/shared/test-tables.h', - 'src/journal/journald-server.c', - 'src/journal/journald-server.h'], + [['src/test/test-tables.c'], [libcore, libjournal_core, - libudev_core, - libudev_static, - libsystemd_network, + libudevd_core, libshared], [threads, libseccomp, @@ -538,98 +367,64 @@ tests += [ libxz, liblz4, libblkid], - '', '', [], libudev_core_includes], + [core_includes, journal_includes, udev_includes]], - [['src/test/test-prioq.c'], - [], - []], + [['src/test/test-prioq.c']], - [['src/test/test-fileio.c'], - [], - []], + [['src/test/test-fileio.c']], - [['src/test/test-time-util.c'], - [], - []], + [['src/test/test-time-util.c']], - [['src/test/test-clock.c'], - [], - []], + [['src/test/test-clock.c']], - [['src/test/test-architecture.c'], - [], - []], + [['src/test/test-tmpfile-util.c']], - [['src/test/test-log.c'], - [], - []], + [['src/test/test-architecture.c']], + + [['src/test/test-log.c']], [['src/test/test-ipcrm.c'], - [], - [], - '', 'unsafe'], + [], [], [], '', 'unsafe'], [['src/test/test-btrfs.c'], - [], - [], - '', 'manual'], + [], [], [], '', 'manual'], - - [['src/test/test-firewall-util.c'], - [libshared], - [], - 'HAVE_LIBIPTC'], + [['src/test/test-firewall-util.c']], [['src/test/test-netlink-manual.c'], [], [libkmod], - 'HAVE_KMOD', 'manual'], + [], 'HAVE_KMOD', 'manual'], - [['src/test/test-ellipsize.c'], - [], - []], + [['src/test/test-ellipsize.c']], - [['src/test/test-date.c'], - [], - []], + [['src/test/test-date.c']], - [['src/test/test-sleep.c'], - [], - []], + [['src/test/test-sleep.c']], - [['src/test/test-replace-var.c'], - [], - []], + [['src/test/test-replace-var.c']], - [['src/test/test-calendarspec.c'], - [], - []], + [['src/test/test-calendarspec.c']], - [['src/test/test-strip-tab-ansi.c'], - [], - []], + [['src/test/test-strip-tab-ansi.c']], - [['src/test/test-coredump-util.c'], - [], - []], + [['src/test/test-coredump-util.c']], - [['src/test/test-daemon.c'], - [], - []], + [['src/test/test-daemon.c']], - [['src/test/test-cgroup.c'], - [], - []], + [['src/test/test-cgroup.c']], [['src/test/test-cgroup-cpu.c'], [libcore, libshared], - []], + [], + core_includes], [['src/test/test-cgroup-unit-default.c'], [libcore, libshared], - []], + [], + core_includes], [['src/test/test-cgroup-mask.c'], [libcore, @@ -639,48 +434,31 @@ tests += [ libseccomp, libselinux, libmount, - libblkid]], + libblkid], + core_includes], [['src/test/test-varlink.c'], [], [threads]], - [['src/test/test-cgroup-util.c'], - [], - []], + [['src/test/test-cgroup-util.c']], - [['src/test/test-cgroup-setup.c'], - [], - []], + [['src/test/test-cgroup-setup.c']], - [['src/test/test-env-file.c'], - [], - []], + [['src/test/test-env-file.c']], - [['src/test/test-env-util.c'], - [], - []], + [['src/test/test-env-util.c']], - [['src/test/test-strbuf.c'], - [], - []], + [['src/test/test-strbuf.c']], - [['src/test/test-strv.c'], - [], - []], + [['src/test/test-strv.c']], - [['src/test/test-path-util.c'], - [], - []], + [['src/test/test-path-util.c']], - [['src/test/test-rm-rf.c'], - [], - []], + [['src/test/test-rm-rf.c']], [['src/test/test-chase-symlinks.c'], - [], - [], - '', 'manual'], + [], [], [], '', 'manual'], [['src/test/test-path.c'], [libcore, @@ -691,7 +469,7 @@ tests += [ libselinux, libmount, libblkid], - '', 'timeout=120'], + core_includes, '', 'timeout=120'], [['src/test/test-execute.c'], [libcore, @@ -702,25 +480,19 @@ tests += [ libselinux, libmount, libblkid], - '', 'timeout=360'], + core_includes, '', 'timeout=360'], - [['src/test/test-siphash24.c'], - [], - []], + [['src/test/test-siphash24.c']], - [['src/test/test-strxcpyx.c'], - [], - []], + [['src/test/test-strxcpyx.c']], [['src/test/test-install.c'], [libcore, libshared], [], - '', 'manual'], + core_includes, '', 'manual'], - [['src/test/test-watchdog.c'], - [], - []], + [['src/test/test-watchdog.c']], [['src/test/test-sched-prio.c'], [libcore, @@ -730,43 +502,26 @@ tests += [ libseccomp, libselinux, libmount, - libblkid]], + libblkid], + core_includes], - [['src/test/test-conf-files.c'], - [], - []], + [['src/test/test-conf-files.c']], - [['src/test/test-conf-parser.c'], - [], - []], + [['src/test/test-conf-parser.c']], [['src/test/test-af-list.c', - generated_gperf_headers], - [], - []], + generated_gperf_headers]], [['src/test/test-arphrd-list.c', - generated_gperf_headers], - [], - []], + generated_gperf_headers]], [['src/test/test-ip-protocol-list.c', - shared_generated_gperf_headers], - [], - []], + shared_generated_gperf_headers]], - [['src/test/test-journal-importer.c'], - [], - []], - - [['src/test/test-libudev.c'], - [libshared], - []], + [['src/test/test-journal-importer.c']], [['src/test/test-udev.c'], - [libudev_core, - libudev_static, - libsystemd_network, + [libudevd_core, libshared], [threads, librt, @@ -774,60 +529,40 @@ tests += [ libkmod, libacl, libselinux], - '', 'manual', '-DLOG_REALM=LOG_REALM_UDEV'], + udev_includes, '', 'manual'], - [['src/test/test-udev-util.c'], - [], - []], + [['src/test/test-udev-util.c']], - [['src/test/test-id128.c'], - [], - []], + [['src/test/test-id128.c']], - [['src/test/test-hash.c'], - [], - []], + [['src/test/test-hash.c']], [['src/test/test-gcrypt-util.c'], - [], - [], - 'HAVE_GCRYPT'], + [], [], [], 'HAVE_GCRYPT'], [['src/test/test-nss.c'], [], [libdl], - 'ENABLE_NSS', 'manual'], + [], 'ENABLE_NSS', 'manual'], - [['src/test/test-umount.c', - 'src/shutdown/umount.c', - 'src/shutdown/umount.h'], - [libcore_shared, - libshared], - [libmount]], + [['src/test/test-bus-util.c']], - [['src/test/test-bus-util.c'], - [], - []], + [['src/test/test-percent-util.c']], - [['src/test/test-sd-hwdb.c'], - [], - []], + [['src/test/test-sd-hwdb.c']], - [['src/test/test-sd-path.c'], - [], - []], + [['src/test/test-sd-path.c']], - [['src/test/test-local-addresses.c'], - [], - []], + [['src/test/test-local-addresses.c']], - [['src/test/test-psi-util.c'], - [], - []], + [['src/test/test-psi-util.c']], [['src/test/test-qrcode-util.c'], - [libshared], + [], [libdl]], + + [['src/test/test-nscd-flush.c'], + [], [], [], 'ENABLE_NSCD', 'manual'], ] ############################################################ @@ -835,360 +570,15 @@ tests += [ # define some tests here, because the link_with deps were not defined earlier tests += [ - [['src/journal/test-journal.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-send.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-syslog.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4, - libselinux]], - - [['src/journal/test-journal-match.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-enum.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4], - '', 'timeout=360'], - - [['src/journal/test-journal-stream.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-flush.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-init.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-config.c'], - [libjournal_core, - libshared], - [libxz, - liblz4, - libselinux]], - - [['src/journal/test-journal-verify.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-journal-interleaving.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-mmap-cache.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-catalog.c'], - [libjournal_core, - libshared], - [threads, - libxz, - liblz4]], - - [['src/journal/test-compress.c'], - [libjournal_core, - libshared], - [liblz4, - libzstd, - libxz]], - - [['src/journal/test-compress-benchmark.c'], - [libjournal_core, - libshared], - [liblz4, - libzstd, - libxz], - '', 'timeout=90'], - - [['src/journal/test-audit-type.c'], - [libjournal_core, - libshared], - [liblz4, - libxz]], -] - -############################################################ - -tests += [ - [['src/libsystemd/sd-bus/test-bus-address.c'], - [], - [threads]], - - [['src/libsystemd/sd-bus/test-bus-marshal.c'], - [], - [threads, - libglib, - libgobject, - libgio, - libdbus]], - - [['src/libsystemd/sd-bus/test-bus-signature.c'], - [], - [threads]], - - [['src/libsystemd/sd-bus/test-bus-queue-ref-cycle.c'], - [], - [threads]], - - [['src/libsystemd/sd-bus/test-bus-watch-bind.c'], - [], - [threads], '', 'timeout=120'], - - [['src/libsystemd/sd-bus/test-bus-chat.c'], - [], - [threads]], - - [['src/libsystemd/sd-bus/test-bus-cleanup.c'], - [], - [threads, - libseccomp]], - [['src/libsystemd/sd-bus/test-bus-error.c'], [libshared_static, - libsystemd_static], - []], - - [['src/libsystemd/sd-bus/test-bus-track.c'], - [], - [libseccomp]], - - [['src/libsystemd/sd-bus/test-bus-server.c'], - [], - [threads]], - - [['src/libsystemd/sd-bus/test-bus-objects.c'], - [], - [threads]], - - [['src/libsystemd/sd-bus/test-bus-vtable.c', - 'src/libsystemd/sd-bus/test-vtable-data.h'], - [], - []], - - [['src/libsystemd/sd-bus/test-bus-gvariant.c'], - [], - [libglib, - libgobject, - libgio]], - - [['src/libsystemd/sd-bus/test-bus-creds.c'], - [], - []], - - [['src/libsystemd/sd-bus/test-bus-match.c'], - [], - []], - - [['src/libsystemd/sd-bus/test-bus-benchmark.c'], - [], - [threads], - '', 'manual'], - - [['src/libsystemd/sd-bus/test-bus-introspect.c', - 'src/libsystemd/sd-bus/test-vtable-data.h'], - [], - []], - - [['src/libsystemd/sd-event/test-event.c'], - [], - []], - - [['src/libsystemd/sd-netlink/test-netlink.c'], - [], - []], - - [['src/libsystemd/sd-resolve/test-resolve.c'], - [], - [threads], - '', 'timeout=120'], - - [['src/libsystemd/sd-login/test-login.c'], - [], - []], - - [['src/libsystemd/sd-device/test-sd-device.c'], - [], - []], + libsystemd_static]], [['src/libsystemd/sd-device/test-sd-device-thread.c'], - [libbasic, - libshared_static, - libsystemd], + [libsystemd], [threads]], - [['src/libsystemd/sd-device/test-udev-device-thread.c'], - [libbasic, - libshared_static, - libudev], - [threads]], - - [['src/libsystemd/sd-device/test-sd-device-monitor.c'], - [], - []], - -] - -if cxx_cmd != '' - tests += [ - [['src/libsystemd/sd-bus/test-bus-vtable-cc.cc'], - [], - []] - ] -endif - -############################################################ - -tests += [ - [['src/libsystemd-network/test-dhcp-option.c', - 'src/libsystemd-network/dhcp-protocol.h', - 'src/libsystemd-network/dhcp-internal.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-sd-dhcp-lease.c', - 'src/libsystemd-network/dhcp-lease-internal.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-dhcp-client.c', - 'src/libsystemd-network/dhcp-protocol.h', - 'src/libsystemd-network/dhcp-internal.h', - 'src/systemd/sd-dhcp-client.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-dhcp-server.c'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-ipv4ll.c', - 'src/libsystemd-network/arp-util.h', - 'src/systemd/sd-ipv4ll.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-ipv4ll-manual.c', - 'src/systemd/sd-ipv4ll.h'], - [libshared, - libsystemd_network], - [], - '', 'manual'], - - [['src/libsystemd-network/test-acd.c', - 'src/systemd/sd-ipv4acd.h'], - [libshared, - libsystemd_network], - [], - '', 'manual'], - - [['src/libsystemd-network/test-ndisc-rs.c', - 'src/libsystemd-network/dhcp-identifier.h', - 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/icmp6-util.h', - 'src/systemd/sd-dhcp6-client.h', - 'src/systemd/sd-ndisc.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-ndisc-ra.c', - 'src/libsystemd-network/icmp6-util.h', - 'src/systemd/sd-ndisc.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-dhcp6-client.c', - 'src/libsystemd-network/dhcp-identifier.h', - 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/dhcp6-internal.h', - 'src/systemd/sd-dhcp6-client.h'], - [libshared, - libsystemd_network], - []], - - [['src/libsystemd-network/test-lldp.c'], - [libshared, - libsystemd_network], - []], -] - -############################################################ - -tests += [ - [['src/login/test-login-shared.c'], - [], - []], - - [['src/analyze/test-verify.c', 'src/analyze/analyze-verify.c', 'src/analyze/analyze-verify.h'], - [libcore, libshared], - []], - - [['src/login/test-inhibit.c'], - [], - [], - '', 'manual'], - - [['src/login/test-login-tables.c'], - [liblogind_core, - libshared], + [['src/libudev/test-udev-device-thread.c'], + [libudev], [threads]], ] - -############################################################ - -tests += [ - [['src/test/test-xdg-autostart.c', - 'src/xdg-autostart-generator/xdg-autostart-service.c', - 'src/xdg-autostart-generator/xdg-autostart-service.h',], - [], - []], -] diff --git a/src/test/test-bitmap.c b/src/test/test-bitmap.c index 9c5d551d2..42922a350 100644 --- a/src/test/test-bitmap.c +++ b/src/test/test-bitmap.c @@ -4,7 +4,7 @@ int main(int argc, const char *argv[]) { _cleanup_bitmap_free_ Bitmap *b = NULL, *b2 = NULL; - unsigned n = (unsigned) -1, i = 0; + unsigned n = UINT_MAX, i = 0; b = bitmap_new(); assert_se(b); @@ -59,10 +59,10 @@ int main(int argc, const char *argv[]) { else if (i == 1) i = 256; else if (i == 256) - i = (unsigned) -1; + i = UINT_MAX; } - assert_se(i == (unsigned) -1); + assert_se(i == UINT_MAX); i = 0; @@ -73,10 +73,10 @@ int main(int argc, const char *argv[]) { else if (i == 1) i = 256; else if (i == 256) - i = (unsigned) -1; + i = UINT_MAX; } - assert_se(i == (unsigned) -1); + assert_se(i == UINT_MAX); b2 = bitmap_copy(b); assert_se(b2); @@ -92,7 +92,7 @@ int main(int argc, const char *argv[]) { bitmap_free(b2); b2 = NULL; - assert_se(bitmap_set(b, (unsigned) -1) == -ERANGE); + assert_se(bitmap_set(b, UINT_MAX) == -ERANGE); bitmap_free(b); b = NULL; diff --git a/src/test/test-bpf-firewall.c b/src/test/test-bpf-firewall.c index b6fd22904..b29c0d784 100644 --- a/src/test/test-bpf-firewall.c +++ b/src/test/test-bpf-firewall.c @@ -12,7 +12,7 @@ #include "rm-rf.h" #include "service.h" #include "tests.h" -#include "unit.h" +#include "unit-serialize.h" #include "virt.h" int main(int argc, char *argv[]) { diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index e0b7f2280..4f1d0f64d 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -2,11 +2,11 @@ #include "alloc-util.h" #include "calendarspec.h" +#include "env-util.h" #include "errno-util.h" #include "string-util.h" -#include "util.h" -static void test_one(const char *input, const char *output) { +static void _test_one(int line, const char *input, const char *output) { CalendarSpec *c; _cleanup_free_ char *p = NULL, *q = NULL; usec_t u; @@ -16,13 +16,13 @@ static void test_one(const char *input, const char *output) { assert_se(calendar_spec_from_string(input, &c) >= 0); assert_se(calendar_spec_to_string(c, &p) >= 0); - printf("\"%s\" → \"%s\"\n", input, p); + log_info("line %d: \"%s\" → \"%s\"", line, input, p); assert_se(streq(p, output)); u = now(CLOCK_REALTIME); r = calendar_spec_next_usec(c, u, &u); - printf("Next: %s\n", r < 0 ? strerror_safe(r) : format_timestamp(buf, sizeof(buf), u)); + log_info("Next: %s", r < 0 ? strerror_safe(r) : format_timestamp(buf, sizeof buf, u)); calendar_spec_free(c); assert_se(calendar_spec_from_string(p, &c) >= 0); @@ -31,8 +31,9 @@ static void test_one(const char *input, const char *output) { assert_se(streq(q, p)); } +#define test_one(input, output) _test_one(__LINE__, input, output) -static void test_next(const char *input, const char *new_tz, usec_t after, usec_t expect) { +static void _test_next(int line, const char *input, const char *new_tz, usec_t after, usec_t expect) { CalendarSpec *c; usec_t u; char *old_tz; @@ -43,35 +44,30 @@ static void test_next(const char *input, const char *new_tz, usec_t after, usec_ if (old_tz) old_tz = strdupa(old_tz); - if (new_tz) { - char *colon_tz; + if (!isempty(new_tz)) + new_tz = strjoina(":", new_tz); - colon_tz = strjoina(":", new_tz); - assert_se(setenv("TZ", colon_tz, 1) >= 0); - } else - assert_se(unsetenv("TZ") >= 0); + assert_se(set_unset_env("TZ", new_tz, true) == 0); tzset(); assert_se(calendar_spec_from_string(input, &c) >= 0); - printf("\"%s\"\n", input); + log_info("line %d: \"%s\" new_tz=%s", line, input, strnull(new_tz)); u = after; r = calendar_spec_next_usec(c, after, &u); - printf("At: %s\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US)); - if (expect != (usec_t)-1) + log_info("At: %s", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US)); + if (expect != USEC_INFINITY) assert_se(r >= 0 && u == expect); else assert(r == -ENOENT); calendar_spec_free(c); - if (old_tz) - assert_se(setenv("TZ", old_tz, 1) >= 0); - else - assert_se(unsetenv("TZ") >= 0); + assert_se(set_unset_env("TZ", old_tz, true) == 0); tzset(); } +#define test_next(input, new_tz, after, expect) _test_next(__LINE__, input,new_tz,after,expect) static void test_timestamp(void) { char buf[FORMAT_TIMESTAMP_MAX]; @@ -83,12 +79,12 @@ static void test_timestamp(void) { x = now(CLOCK_REALTIME); - assert_se(format_timestamp_style(buf, sizeof(buf), x, TIMESTAMP_US)); - printf("%s\n", buf); + assert_se(format_timestamp_style(buf, sizeof buf, x, TIMESTAMP_US)); + log_info("%s", buf); assert_se(calendar_spec_from_string(buf, &c) >= 0); assert_se(calendar_spec_to_string(c, &t) >= 0); calendar_spec_free(c); - printf("%s\n", t); + log_info("%s", t); assert_se(parse_timestamp(t, &y) >= 0); assert_se(y == x); @@ -104,11 +100,11 @@ static void test_hourly_bug_4031(void) { n = now(CLOCK_REALTIME); assert_se((r = calendar_spec_next_usec(c, n, &u)) >= 0); - printf("Now: %s (%"PRIu64")\n", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n); - printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u); + log_info("Now: %s (%"PRIu64")", format_timestamp_style(buf, sizeof buf, n, TIMESTAMP_US), n); + log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : format_timestamp_style(buf, sizeof buf, u, TIMESTAMP_US), u); assert_se((r = calendar_spec_next_usec(c, u, &w)) >= 0); - printf("Next hourly: %s (%"PRIu64")\n", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w); + log_info("Next hourly: %s (%"PRIu64")", r < 0 ? strerror_safe(r) : format_timestamp_style(zaf, sizeof zaf, w, TIMESTAMP_US), w); assert_se(n < u); assert_se(u <= n + USEC_PER_HOUR); @@ -209,15 +205,18 @@ int main(int argc, char* argv[]) { test_next("2017-08-06 9..17/2:00 UTC", "", 1502029800000000, 1502031600000000); test_next("2016-12-* 3..21/6:00 UTC", "", 1482613200000001, 1482634800000000); test_next("2017-09-24 03:30:00 Pacific/Auckland", "", 12345, 1506177000000000); - // Due to daylight saving time - 2017-09-24 02:30:00 does not exist + /* Due to daylight saving time - 2017-09-24 02:30:00 does not exist */ test_next("2017-09-24 02:30:00 Pacific/Auckland", "", 12345, -1); test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 12345, 1491053400000000); - // Confirm that even though it's a time change here (backward) 02:30 happens only once + /* Confirm that even though it's a time change here (backward) 02:30 happens only once */ test_next("2017-04-02 02:30:00 Pacific/Auckland", "", 1491053400000000, -1); test_next("2017-04-02 03:30:00 Pacific/Auckland", "", 12345, 1491060600000000); - // Confirm that timezones in the Spec work regardless of current timezone + /* Confirm that timezones in the Spec work regardless of current timezone */ test_next("2017-09-09 20:42:00 Pacific/Auckland", "", 12345, 1504946520000000); test_next("2017-09-09 20:42:00 Pacific/Auckland", "EET", 12345, 1504946520000000); + /* Check that we don't start looping if mktime() moves us backwards */ + test_next("Sun *-*-* 01:00:00 Europe/Dublin", "", 1616412478000000, 1617494400000000); + test_next("Sun *-*-* 01:00:00 Europe/Dublin", "IST", 1616412478000000, 1617494400000000); assert_se(calendar_spec_from_string("test", &c) < 0); assert_se(calendar_spec_from_string(" utc", &c) < 0); diff --git a/src/test/test-cgroup-setup.c b/src/test/test-cgroup-setup.c index 72726ca59..4978a92e4 100644 --- a/src/test/test-cgroup-setup.c +++ b/src/test/test-cgroup-setup.c @@ -18,7 +18,7 @@ static void test_is_wanted_print(bool header) { assert_se(proc_cmdline(&cmdline) >= 0); log_info("cmdline: %s", cmdline); if (header) { - log_info(_CGROUP_HIERARCHY_); + log_info("default-hierarchy=" DEFAULT_HIERARCHY_NAME); (void) system("findmnt -n /sys/fs/cgroup"); } diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 41b1df117..f95832acf 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -338,7 +338,7 @@ static void test_cg_tests(void) { r = cg_unified(); if (r == -ENOMEDIUM) { - log_notice_errno(r, "Skipping cg hierarchy tests: %m"); + log_tests_skipped("cgroup not mounted"); return; } assert_se(r >= 0); diff --git a/src/test/test-cgroup.c b/src/test/test-cgroup.c index 722e11a0c..3025a9a98 100644 --- a/src/test/test-cgroup.c +++ b/src/test/test-cgroup.c @@ -47,10 +47,11 @@ static void test_cg_create(void) { int r; r = cg_unified_cached(false); - if (r < 0) { - log_info_errno(r, "Skipping %s: %m", __func__); + if (r == -ENOMEDIUM) { + log_tests_skipped("cgroup not mounted"); return; } + assert_se(r >= 0); _cleanup_free_ char *here = NULL; assert_se(cg_pid_get_path_shifted(0, NULL, &here) >= 0); diff --git a/src/test/test-chase-symlinks.c b/src/test/test-chase-symlinks.c index d9b9b62dc..892f8a073 100644 --- a/src/test/test-chase-symlinks.c +++ b/src/test/test-chase-symlinks.c @@ -84,7 +84,7 @@ static int parse_argv(int argc, char *argv[]) { static int run(int argc, char **argv) { int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/test/test-condition.c b/src/test/test-condition.c index 15099d8df..db15fe313 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -124,18 +124,40 @@ static void test_condition_test_path(void) { condition_free(condition); } +static void test_condition_test_control_group_hierarchy(void) { + Condition *condition; + int r; + + r = cg_unified(); + if (r == -ENOMEDIUM) { + log_tests_skipped("cgroup not mounted"); + return; + } + assert_se(r >= 0); + + condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "v1", false, false); + assert_se(condition); + assert_se(condition_test(condition, environ) == (r < CGROUP_UNIFIED_ALL)); + condition_free(condition); + + condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "v2", false, false); + assert_se(condition); + assert_se(condition_test(condition, environ) == (r >= CGROUP_UNIFIED_ALL)); + condition_free(condition); +} + static void test_condition_test_control_group_controller(void) { Condition *condition; CGroupMask system_mask; - CGroupController controller; _cleanup_free_ char *controller_name = NULL; int r; r = cg_unified(); - if (r < 0) { - log_notice_errno(r, "Skipping ConditionControlGroupController tests: %m"); + if (r == -ENOMEDIUM) { + log_tests_skipped("cgroup not mounted"); return; } + assert_se(r >= 0); /* Invalid controllers are ignored */ condition = condition_new(CONDITION_CONTROL_GROUP_CONTROLLER, "thisisnotarealcontroller", false, false); @@ -151,7 +173,7 @@ static void test_condition_test_control_group_controller(void) { assert_se(cg_mask_supported(&system_mask) >= 0); /* Individual valid controllers one by one */ - for (controller = 0; controller < _CGROUP_CONTROLLER_MAX; controller++) { + for (CGroupController controller = 0; controller < _CGROUP_CONTROLLER_MAX; controller++) { const char *local_controller_name = cgroup_controller_to_string(controller); log_info("chosen controller is '%s'", local_controller_name); if (system_mask & CGROUP_CONTROLLER_TO_MASK(controller)) { @@ -439,6 +461,27 @@ static void test_condition_test_kernel_version(void) { condition_free(condition); } +#if defined(__i386__) || defined(__x86_64__) +static void test_condition_test_cpufeature(void) { + Condition *condition; + + condition = condition_new(CONDITION_CPU_FEATURE, "fpu", false, false); + assert_se(condition); + assert_se(condition_test(condition, environ) > 0); + condition_free(condition); + + condition = condition_new(CONDITION_CPU_FEATURE, "somecpufeaturethatreallydoesntmakesense", false, false); + assert_se(condition); + assert_se(condition_test(condition, environ) == 0); + condition_free(condition); + + condition = condition_new(CONDITION_CPU_FEATURE, "a", false, false); + assert_se(condition); + assert_se(condition_test(condition, environ) == 0); + condition_free(condition); +} +#endif + static void test_condition_test_security(void) { Condition *condition; @@ -860,10 +903,14 @@ int main(int argc, char *argv[]) { test_condition_test_virtualization(); test_condition_test_user(); test_condition_test_group(); + test_condition_test_control_group_hierarchy(); test_condition_test_control_group_controller(); test_condition_test_cpus(); test_condition_test_memory(); test_condition_test_environment(); +#if defined(__i386__) || defined(__x86_64__) + test_condition_test_cpufeature(); +#endif return 0; } diff --git a/src/test/test-conf-parser.c b/src/test/test-conf-parser.c index 04b610c6f..5da864347 100644 --- a/src/test/test-conf-parser.c +++ b/src/test/test-conf-parser.c @@ -349,27 +349,27 @@ static void test_config_parse(unsigned i, const char *s) { switch (i) { case 0 ... 4: - assert_se(r == 0); + assert_se(r == 1); assert_se(streq(setting1, "1")); break; case 5 ... 10: - assert_se(r == 0); + assert_se(r == 1); assert_se(streq(setting1, "1 2 3")); break; case 11: - assert_se(r == 0); + assert_se(r == 1); assert_se(streq(setting1, "1\\\\ \\\\2")); break; case 12: - assert_se(r == 0); + assert_se(r == 1); assert_se(streq(setting1, x1000("ABCD"))); break; case 13 ... 14: - assert_se(r == 0); + assert_se(r == 1); assert_se(streq(setting1, x1000("ABCD") " foobar")); break; @@ -379,7 +379,7 @@ static void test_config_parse(unsigned i, const char *s) { break; case 17: - assert_se(r == 0); + assert_se(r == 1); assert_se(streq(setting1, "2")); break; } diff --git a/src/test/test-copy.c b/src/test/test-copy.c index ffa929788..7b8f8fa1b 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -207,7 +207,7 @@ static void test_copy_bytes(void) { assert_se(pipe2(pipefd, O_CLOEXEC) == 0); - r = copy_bytes(infd, pipefd[1], (uint64_t) -1, 0); + r = copy_bytes(infd, pipefd[1], UINT64_MAX, 0); assert_se(r == 0); r = read(pipefd[0], buf, sizeof(buf)); @@ -249,7 +249,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint assert_se(fd3 >= 0); r = copy_bytes(fd, fd2, max_bytes, try_reflink ? COPY_REFLINK : 0); - if (max_bytes == (uint64_t) -1) + if (max_bytes == UINT64_MAX) assert_se(r == 0); else assert_se(IN_SET(r, 0, 1)); @@ -258,14 +258,14 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint assert_se(fstat(fd2, &buf2) == 0); assert_se((uint64_t) buf2.st_size == MIN((uint64_t) buf.st_size, max_bytes)); - if (max_bytes < (uint64_t) -1) + if (max_bytes < UINT64_MAX) /* Make sure the file is now higher than max_bytes */ assert_se(ftruncate(fd2, max_bytes + 1) == 0); assert_se(lseek(fd2, 0, SEEK_SET) == 0); r = copy_bytes(fd2, fd3, max_bytes, try_reflink ? COPY_REFLINK : 0); - if (max_bytes == (uint64_t) -1) + if (max_bytes == UINT64_MAX) assert_se(r == 0); else /* We cannot distinguish between the input being exactly max_bytes @@ -277,7 +277,7 @@ static void test_copy_bytes_regular_file(const char *src, bool try_reflink, uint assert_se(fstat(fd3, &buf3) == 0); - if (max_bytes == (uint64_t) -1) + if (max_bytes == UINT64_MAX) assert_se(buf3.st_size == buf2.st_size); else assert_se((uint64_t) buf3.st_size == max_bytes); @@ -304,6 +304,22 @@ static void test_copy_atomic(void) { assert_se(copy_file_atomic("/etc/fstab", q, 0644, 0, 0, COPY_REPLACE) >= 0); } +static void test_copy_proc(void) { + _cleanup_(rm_rf_physical_and_freep) char *p = NULL; + _cleanup_free_ char *f = NULL, *a = NULL, *b = NULL; + + /* Check if copying data from /proc/ works correctly, i.e. let's see if https://lwn.net/Articles/846403/ is a problem for us */ + + assert_se(mkdtemp_malloc(NULL, &p) >= 0); + assert_se(f = path_join(p, "version")); + assert_se(copy_file("/proc/version", f, 0, MODE_INVALID, 0, 0, 0) >= 0); + + assert_se(read_one_line_file("/proc/version", &a) >= 0); + assert_se(read_one_line_file(f, &b) >= 0); + assert_se(streq(a, b)); + assert_se(!isempty(a)); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -311,13 +327,14 @@ int main(int argc, char *argv[]) { test_copy_file_fd(); test_copy_tree(); test_copy_bytes(); - test_copy_bytes_regular_file(argv[0], false, (uint64_t) -1); - test_copy_bytes_regular_file(argv[0], true, (uint64_t) -1); + test_copy_bytes_regular_file(argv[0], false, UINT64_MAX); + test_copy_bytes_regular_file(argv[0], true, UINT64_MAX); test_copy_bytes_regular_file(argv[0], false, 1000); /* smaller than copy buffer size */ test_copy_bytes_regular_file(argv[0], true, 1000); test_copy_bytes_regular_file(argv[0], false, 32000); /* larger than copy buffer size */ test_copy_bytes_regular_file(argv[0], true, 32000); test_copy_atomic(); + test_copy_proc(); return 0; } diff --git a/src/test/test-device-nodes.c b/src/test/test-device-nodes.c index 9efb3fe3b..c914d7832 100644 --- a/src/test/test-device-nodes.c +++ b/src/test/test-device-nodes.c @@ -31,6 +31,7 @@ static void test_encode_devnode_name(void) { assert_se(expect_encoded_as("s/ash/ng", "s\\x2fash\\x2fng")); assert_se(expect_encoded_as("/", "\\x2f")); assert_se(expect_encoded_as("!", "\\x21")); + assert_se(expect_encoded_as("QEMU ", "QEMU\\x20\\x20\\x20\\x20")); } int main(int argc, char *argv[]) { diff --git a/src/test/test-dlopen-so.c b/src/test/test-dlopen-so.c new file mode 100644 index 000000000..8e1ce6a0d --- /dev/null +++ b/src/test/test-dlopen-so.c @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include + +#include "cryptsetup-util.h" +#include "idn-util.h" +#include "libfido2-util.h" +#include "macro.h" +#include "main-func.h" +#include "pwquality-util.h" +#include "qrcode-util.h" +#include "tests.h" +#include "tpm2-util.h" + +static int run(int argc, char **argv) { + test_setup_logging(LOG_DEBUG); + + /* Try to load each of our weak library dependencies once. This is supposed to help finding cases + * where .so versions change and distributions update, but systemd doesn't have the new so names + * around yet. */ + +#if HAVE_LIBIDN2 || HAVE_LIBIDN + assert_se(dlopen_idn() >= 0); +#endif + +#if HAVE_LIBCRYPTSETUP + assert_se(dlopen_cryptsetup() >= 0); +#endif + +#if HAVE_PWQUALITY + assert_se(dlopen_pwquality() >= 0); +#endif + +#if HAVE_QRENCODE + assert_se(dlopen_qrencode() >= 0); +#endif + +#if HAVE_TPM2 + assert_se(dlopen_tpm2() >= 0); +#endif + +#if HAVE_LIBFIDO2 + assert_se(dlopen_libfido2() >= 0); +#endif + + return 0; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/test/test-env-util.c b/src/test/test-env-util.c index f77b1cdbc..1e2e93659 100644 --- a/src/test/test-env-util.c +++ b/src/test/test-env-util.c @@ -4,9 +4,12 @@ #include "fd-util.h" #include "fileio.h" #include "fs-util.h" +#include "parse-util.h" +#include "process-util.h" #include "serialize.h" #include "string-util.h" #include "strv.h" +#include "tests.h" #include "util.h" static void test_strv_env_delete(void) { @@ -41,6 +44,17 @@ static void test_strv_env_get(void) { assert_se(streq(strv_env_get(l, "FOUR"), "4")); } +static void test_strv_env_pairs_get(void) { + log_info("/* %s */", __func__); + + char **l = STRV_MAKE("ONE_OR_TWO", "1", "THREE", "3", "ONE_OR_TWO", "2", "FOUR", "4", "FIVE", "5", "SIX", "FIVE", "SEVEN", "7"); + + assert_se(streq(strv_env_pairs_get(l, "ONE_OR_TWO"), "2")); + assert_se(streq(strv_env_pairs_get(l, "THREE"), "3")); + assert_se(streq(strv_env_pairs_get(l, "FOUR"), "4")); + assert_se(streq(strv_env_pairs_get(l, "FIVE"), "5")); +} + static void test_strv_env_unset(void) { log_info("/* %s */", __func__); @@ -56,24 +70,6 @@ static void test_strv_env_unset(void) { assert_se(strv_length(l) == 2); } -static void test_strv_env_set(void) { - log_info("/* %s */", __func__); - - _cleanup_strv_free_ char **l = NULL, **r = NULL; - - l = strv_new("PIEP", "SCHLUMPF=SMURFF", "NANANANA=YES"); - assert_se(l); - - r = strv_env_set(l, "WALDO=WALDO"); - assert_se(r); - - assert_se(streq(r[0], "PIEP")); - assert_se(streq(r[1], "SCHLUMPF=SMURFF")); - assert_se(streq(r[2], "NANANANA=YES")); - assert_se(streq(r[3], "WALDO=WALDO")); - assert_se(strv_length(r) == 4); -} - static void test_strv_env_merge(void) { log_info("/* %s */", __func__); @@ -104,6 +100,37 @@ static void test_strv_env_merge(void) { assert_se(strv_length(r) == 5); } +static void test_strv_env_replace_strdup(void) { + log_info("/* %s */", __func__); + + _cleanup_strv_free_ char **a = NULL; + + assert_se(strv_env_replace_strdup(&a, "a=a") == 1); + assert_se(strv_env_replace_strdup(&a, "b=b") == 1); + assert_se(strv_env_replace_strdup(&a, "a=A") == 0); + + assert_se(strv_length(a) == 2); + strv_sort(a); + assert_se(streq(a[0], "a=A")); + assert_se(streq(a[1], "b=b")); +} + +static void test_strv_env_assign(void) { + log_info("/* %s */", __func__); + + _cleanup_strv_free_ char **a = NULL; + + assert_se(strv_env_assign(&a, "a", "a") == 1); + assert_se(strv_env_assign(&a, "b", "b") == 1); + assert_se(strv_env_assign(&a, "a", "A") == 0); + assert_se(strv_env_assign(&a, "b", NULL) == 0); + + assert_se(strv_env_assign(&a, "a=", "B") == -EINVAL); + + assert_se(strv_length(a) == 1); + assert_se(streq(a[0], "a=A")); +} + static void test_env_strv_get_n(void) { log_info("/* %s */", __func__); @@ -334,12 +361,64 @@ static void test_env_assignment_is_valid(void) { assert_se(!env_assignment_is_valid("głąb=printf \"\x1b]0;\x07\"")); } +static void test_putenv_dup(void) { + log_info("/* %s */", __func__); + + assert_se(putenv_dup("A=a1", true) == 0); + assert_se(streq(getenv("A"), "a1")); + assert_se(putenv_dup("A=a1", true) == 0); + assert_se(streq(getenv("A"), "a1")); + assert_se(putenv_dup("A=a2", false) == 0); + assert_se(streq(getenv("A"), "a1")); + assert_se(putenv_dup("A=a2", true) == 0); + assert_se(streq(getenv("A"), "a2")); +} + +static void test_setenv_systemd_exec_pid(void) { + _cleanup_free_ char *saved = NULL; + const char *e; + pid_t p; + + log_info("/* %s */", __func__); + + e = getenv("SYSTEMD_EXEC_PID"); + if (e) + assert_se(saved = strdup(e)); + + assert_se(unsetenv("SYSTEMD_EXEC_PID") >= 0); + assert_se(setenv_systemd_exec_pid(true) == 0); + assert_se(!getenv("SYSTEMD_EXEC_PID")); + + assert_se(setenv("SYSTEMD_EXEC_PID", "*", 1) >= 0); + assert_se(setenv_systemd_exec_pid(true) == 0); + assert_se(e = getenv("SYSTEMD_EXEC_PID")); + assert_se(streq(e, "*")); + + assert_se(setenv("SYSTEMD_EXEC_PID", "123abc", 1) >= 0); + assert_se(setenv_systemd_exec_pid(true) == 1); + assert_se(e = getenv("SYSTEMD_EXEC_PID")); + assert_se(parse_pid(e, &p) >= 0); + assert_se(p == getpid_cached()); + + assert_se(unsetenv("SYSTEMD_EXEC_PID") >= 0); + assert_se(setenv_systemd_exec_pid(false) == 1); + assert_se(e = getenv("SYSTEMD_EXEC_PID")); + assert_se(parse_pid(e, &p) >= 0); + assert_se(p == getpid_cached()); + + assert_se(set_unset_env("SYSTEMD_EXEC_PID", saved, 1) >= 0); +} + int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + test_strv_env_delete(); test_strv_env_get(); + test_strv_env_pairs_get(); test_strv_env_unset(); - test_strv_env_set(); test_strv_env_merge(); + test_strv_env_replace_strdup(); + test_strv_env_assign(); test_env_strv_get_n(); test_replace_env(false); test_replace_env(true); @@ -350,6 +429,8 @@ int main(int argc, char *argv[]) { test_env_name_is_valid(); test_env_value_is_valid(); test_env_assignment_is_valid(); + test_putenv_dup(); + test_setenv_systemd_exec_pid(); return 0; } diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 3b6a4be26..239fcea5e 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -408,6 +408,11 @@ static void test_exec_inaccessiblepaths(Manager *m) { test(m, "exec-inaccessiblepaths-mount-propagation.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); } +static void test_exec_noexecpaths(Manager *m) { + + test(m, "exec-noexecpaths-simple.service", can_unshare ? 0 : EXIT_FAILURE, CLD_EXITED); +} + static void test_exec_temporaryfilesystem(Manager *m) { test(m, "exec-temporaryfilesystem-options.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); @@ -439,6 +444,7 @@ static void test_exec_systemcallfilter(Manager *m) { test(m, "exec-systemcallfilter-with-errno-name.service", errno_from_name("EILSEQ"), CLD_EXITED); test(m, "exec-systemcallfilter-with-errno-number.service", 255, CLD_EXITED); test(m, "exec-systemcallfilter-with-errno-multi.service", errno_from_name("EILSEQ"), CLD_EXITED); + test(m, "exec-systemcallfilter-with-errno-in-allow-list.service", errno_from_name("EILSEQ"), CLD_EXITED); test(m, "exec-systemcallfilter-override-error-action.service", SIGSYS, CLD_KILLED); test(m, "exec-systemcallfilter-override-error-action2.service", errno_from_name("EILSEQ"), CLD_EXITED); #endif @@ -574,6 +580,11 @@ static void test_exec_dynamicuser(Manager *m) { return; } + if (strstr_ptr(ci_environment(), "github-actions")) { + log_notice("%s: skipping test on GH Actions because of systemd/systemd#10337", __func__); + return; + } + test(m, "exec-dynamicuser-fixeduser.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); if (check_user_has_group_with_same_name("adm")) test(m, "exec-dynamicuser-fixeduser-adm.service", can_unshare ? 0 : EXIT_NAMESPACE, CLD_EXITED); @@ -806,6 +817,10 @@ static void test_exec_standardoutput_append(Manager *m) { test(m, "exec-standardoutput-append.service", 0, CLD_EXITED); } +static void test_exec_standardoutput_truncate(Manager *m) { + test(m, "exec-standardoutput-truncate.service", 0, CLD_EXITED); +} + static void test_exec_condition(Manager *m) { test_service(m, "exec-condition-failed.service", SERVICE_FAILURE_EXIT_CODE); test_service(m, "exec-condition-skip.service", SERVICE_SKIP_CONDITION); @@ -856,6 +871,7 @@ int main(int argc, char *argv[]) { entry(test_exec_ignoresigpipe), entry(test_exec_inaccessiblepaths), entry(test_exec_ioschedulingclass), + entry(test_exec_noexecpaths), entry(test_exec_oomscoreadjust), entry(test_exec_passenvironment), entry(test_exec_personality), @@ -871,6 +887,7 @@ int main(int argc, char *argv[]) { entry(test_exec_standardinput), entry(test_exec_standardoutput), entry(test_exec_standardoutput_append), + entry(test_exec_standardoutput_truncate), entry(test_exec_supplementarygroups), entry(test_exec_systemcallerrornumber), entry(test_exec_systemcallfilter), @@ -892,8 +909,8 @@ int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); #if HAS_FEATURE_ADDRESS_SANITIZER - if (strstr_ptr(ci_environment(), "travis")) { - log_notice("Running on TravisCI under ASan, skipping, see https://github.com/systemd/systemd/issues/10696"); + if (strstr_ptr(ci_environment(), "travis") || strstr_ptr(ci_environment(), "github-actions")) { + log_notice("Running on Travis CI/GH Actions under ASan, skipping, see https://github.com/systemd/systemd/issues/10696"); return EXIT_TEST_SKIP; } #endif diff --git a/src/test/test-extract-word.c b/src/test/test-extract-word.c index 56b516fe4..f1085266d 100644 --- a/src/test/test-extract-word.c +++ b/src/test/test-extract-word.c @@ -172,19 +172,19 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo\\")); free(t); assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo\\")); free(t); assert_se(isempty(p)); p = original = "fooo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo\\")); free(t); assert_se(isempty(p)); @@ -230,17 +230,17 @@ static void test_extract_first_word(void) { assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX) == -EINVAL); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX) == -EINVAL); assert_se(p == original + 5); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo\\")); free(t); assert_se(isempty(p)); p = original = "\"foo\\"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "foo\\")); free(t); assert_se(isempty(p)); @@ -252,13 +252,13 @@ static void test_extract_first_word(void) { assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE_RELAX|EXTRACT_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_UNESCAPE_RELAX|EXTRACT_RELAX) > 0); assert_se(streq(t, "fooo bar")); free(t); assert_se(p == original + 10); @@ -268,7 +268,7 @@ static void test_extract_first_word(void) { assert_se(p == original + 5); p = original = "fooo\\ bar quux"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(streq(t, "fooo\\ bar")); free(t); assert_se(p == original + 10); @@ -278,13 +278,13 @@ static void test_extract_first_word(void) { assert_se(p == original + 1); p = original = "\\w+@\\K[\\d.]+"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(streq(t, "\\w+@\\K[\\d.]+")); free(t); assert_se(isempty(p)); p = original = "\\w+\\b"; - assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_CUNESCAPE_RELAX) > 0); + assert_se(extract_first_word(&p, &t, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_RELAX) > 0); assert_se(streq(t, "\\w+\b")); free(t); assert_se(isempty(p)); @@ -344,6 +344,39 @@ static void test_extract_first_word(void) { free(t); assert_se(p == NULL); + p = "\\:"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, ":")); + free(t); + assert_se(p == NULL); + + p = "a\\:b"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "a:b")); + free(t); + assert_se(p == NULL); + + p = "a\\ b:c"; + assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "a b")); + free(t); + assert_se(extract_first_word(&p, &t, WHITESPACE ":", EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "c")); + free(t); + assert_se(p == NULL); + + p = "a\\ b:c\\x"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL); + + p = "a\\\\ b:c\\\\x"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "a\\ b")); + free(t); + assert_se(extract_first_word(&p, &t, ":", EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "c\\x")); + free(t); + assert_se(p == NULL); + p = "\\:"; assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1); assert_se(streq(t, ":")); @@ -365,6 +398,18 @@ static void test_extract_first_word(void) { free(t); assert_se(p == NULL); + p = "a\\ b:c\\x"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == -EINVAL); + + p = "a\\\\ b:c\\\\x"; + assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "a\\ b")); + free(t); + assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS) == 1); + assert_se(streq(t, "c\\x")); + free(t); + assert_se(p == NULL); + p = "\\:"; assert_se(extract_first_word(&p, &t, ":", EXTRACT_CUNESCAPE) == -EINVAL); diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 431aea07e..c5c8116e9 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -9,6 +9,7 @@ #include "ctype.h" #include "env-file.h" #include "env-util.h" +#include "errno-util.h" #include "fd-util.h" #include "fileio.h" #include "fs-util.h" @@ -703,28 +704,28 @@ static const char buffer[] = static void test_read_line_one_file(FILE *f) { _cleanup_free_ char *line = NULL; - assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data")); + assert_se(read_line(f, SIZE_MAX, &line) == 15 && streq(line, "Some test data")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) > 0 && streq(line, "루Non-ascii chars: ąę„”")); + assert_se(read_line(f, SIZE_MAX, &line) > 0 && streq(line, "루Non-ascii chars: ąę„”")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) == 13 && streq(line, "terminators")); + assert_se(read_line(f, SIZE_MAX, &line) == 13 && streq(line, "terminators")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "and even more")); + assert_se(read_line(f, SIZE_MAX, &line) == 15 && streq(line, "and even more")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) == 25 && streq(line, "now the same with a NUL")); + assert_se(read_line(f, SIZE_MAX, &line) == 25 && streq(line, "now the same with a NUL")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) == 10 && streq(line, "and more")); + assert_se(read_line(f, SIZE_MAX, &line) == 10 && streq(line, "and more")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) == 16 && streq(line, "and even more")); + assert_se(read_line(f, SIZE_MAX, &line) == 16 && streq(line, "and even more")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, &line) == 20 && streq(line, "and yet even more")); + assert_se(read_line(f, SIZE_MAX, &line) == 20 && streq(line, "and yet even more")); line = mfree(line); assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte")); @@ -736,7 +737,7 @@ static void test_read_line_one_file(FILE *f) { assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line")); line = mfree(line); - assert_se(read_line(f, (size_t) -1, NULL) == 16); + assert_se(read_line(f, SIZE_MAX, NULL) == 16); assert_se(read_line(f, 16, &line) == -ENOBUFS); line = mfree(line); @@ -819,11 +820,11 @@ static void test_read_line4(void) { assert_se(f = fmemopen_unlocked((void*) eof_endings[i].string, eof_endings[i].length, "r")); - r = read_line(f, (size_t) -1, &s); + r = read_line(f, SIZE_MAX, &s); assert_se((size_t) r == eof_endings[i].length); assert_se(streq_ptr(s, "foo")); - assert_se(read_line(f, (size_t) -1, NULL) == 0); /* Ensure we hit EOF */ + assert_se(read_line(f, SIZE_MAX, NULL) == 0); /* Ensure we hit EOF */ } } @@ -911,8 +912,8 @@ static void test_read_full_file_socket(void) { _exit(EXIT_SUCCESS); } - assert_se(read_full_file_full(AT_FDCWD, j, 0, NULL, &data, &size) == -ENXIO); - assert_se(read_full_file_full(AT_FDCWD, j, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0); + assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, 0, NULL, &data, &size) == -ENXIO); + assert_se(read_full_file_full(AT_FDCWD, j, UINT64_MAX, SIZE_MAX, READ_FULL_FILE_CONNECT_SOCKET, clientname, &data, &size) >= 0); assert_se(size == strlen(TEST_STR)); assert_se(streq(data, TEST_STR)); @@ -920,6 +921,68 @@ static void test_read_full_file_socket(void) { #undef TEST_STR } +static void test_read_full_file_offset_size(void) { + _cleanup_fclose_ FILE *f = NULL; + _cleanup_(unlink_and_freep) char *fn = NULL; + _cleanup_free_ char *rbuf = NULL; + size_t rbuf_size; + uint8_t buf[4711]; + + random_bytes(buf, sizeof(buf)); + + assert_se(tempfn_random_child(NULL, NULL, &fn) >= 0); + assert_se(f = fopen(fn, "we")); + assert_se(fwrite(buf, 1, sizeof(buf), f) == sizeof(buf)); + assert_se(fflush_and_check(f) >= 0); + + assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0); + assert_se(rbuf_size == sizeof(buf)); + assert_se(memcmp(buf, rbuf, rbuf_size) == 0); + rbuf = mfree(rbuf); + + assert_se(read_full_file_full(AT_FDCWD, fn, UINT64_MAX, 128, 0, NULL, &rbuf, &rbuf_size) >= 0); + assert_se(rbuf_size == 128); + assert_se(memcmp(buf, rbuf, rbuf_size) == 0); + rbuf = mfree(rbuf); + + assert_se(read_full_file_full(AT_FDCWD, fn, 1234, SIZE_MAX, 0, NULL, &rbuf, &rbuf_size) >= 0); + assert_se(rbuf_size == sizeof(buf) - 1234); + assert_se(memcmp(buf + 1234, rbuf, rbuf_size) == 0); + rbuf = mfree(rbuf); + + assert_se(read_full_file_full(AT_FDCWD, fn, 2345, 777, 0, NULL, &rbuf, &rbuf_size) >= 0); + assert_se(rbuf_size == 777); + assert_se(memcmp(buf + 2345, rbuf, rbuf_size) == 0); + rbuf = mfree(rbuf); + + assert_se(read_full_file_full(AT_FDCWD, fn, 4700, 20, 0, NULL, &rbuf, &rbuf_size) >= 0); + assert_se(rbuf_size == 11); + assert_se(memcmp(buf + 4700, rbuf, rbuf_size) == 0); + rbuf = mfree(rbuf); + + assert_se(read_full_file_full(AT_FDCWD, fn, 10000, 99, 0, NULL, &rbuf, &rbuf_size) >= 0); + assert_se(rbuf_size == 0); + rbuf = mfree(rbuf); +} + +static void test_read_full_virtual_file(void) { + const char *filename; + int r; + + FOREACH_STRING(filename, + "/proc/1/cmdline", + "/etc/nsswitch.conf", + "/sys/kernel/uevent_seqnum") { + + _cleanup_free_ char *buf = NULL; + size_t size = 0; + + r = read_full_virtual_file(filename, &buf, &size); + log_info_errno(r, "read_full_virtual_file(\"%s\"): %m (%zu bytes)", filename, size); + assert_se(r == 0 || ERRNO_IS_PRIVILEGE(r) || r == -ENOENT); + } +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -946,6 +1009,8 @@ int main(int argc, char *argv[]) { test_read_line4(); test_read_nul_string(); test_read_full_file_socket(); + test_read_full_file_offset_size(); + test_read_full_virtual_file(); return 0; } diff --git a/src/test/test-firewall-util.c b/src/test/test-firewall-util.c index 64616e439..dfde01a67 100644 --- a/src/test/test-firewall-util.c +++ b/src/test/test-firewall-util.c @@ -1,42 +1,116 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + #include "firewall-util.h" +#include "firewall-util-private.h" #include "log.h" +#include "random-util.h" +#include "socket-util.h" #include "tests.h" -#define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))} +static void test_v6(FirewallContext *ctx) { + union in_addr_union u1, u2, u3; + uint8_t prefixlen; + int r; + + assert_se(ctx); + + log_info("/* %s(backend=%s) */", __func__, firewall_backend_to_string(ctx->backend)); + + if (!socket_ipv6_is_supported()) + return log_info("IPv6 is not supported by kernel, skipping tests."); + + assert_se(in_addr_from_string(AF_INET6, "dead::beef", &u1) >= 0); + assert_se(in_addr_from_string(AF_INET6, "1c3::c01d", &u2) >= 0); + + prefixlen = random_u64_range(128 + 1 - 8) + 8; + pseudo_random_bytes(&u3, sizeof(u3)); + + assert_se(fw_add_masquerade(&ctx, true, AF_INET6, &u1, 128) >= 0); + assert_se(fw_add_masquerade(&ctx, false, AF_INET6, &u1, 128) >= 0); + assert_se(fw_add_masquerade(&ctx, true, AF_INET6, &u1, 64) >= 0); + assert_se(fw_add_masquerade(&ctx, false, AF_INET6, &u1, 64) >= 0); + assert_se(fw_add_masquerade(&ctx, true, AF_INET6, &u3, prefixlen) >= 0); + assert_se(fw_add_masquerade(&ctx, false, AF_INET6, &u3, prefixlen) >= 0); + + r = fw_add_local_dnat(&ctx, true, AF_INET6, IPPROTO_TCP, 4711, &u1, 815, NULL); + if (r == -EOPNOTSUPP) { + log_info("IPv6 DNAT seems not supported, skipping the following tests."); + return; + } + assert_se(r >= 0); + + assert_se(fw_add_local_dnat(&ctx, true, AF_INET6, IPPROTO_TCP, 4711, &u2, 815, &u1) >= 0); + assert_se(fw_add_local_dnat(&ctx, false, AF_INET6, IPPROTO_TCP, 4711, &u2, 815, NULL) >= 0); + +} + +static union in_addr_union *parse_addr(const char *str, union in_addr_union *u) { + assert(str); + assert(u); + assert_se(in_addr_from_string(AF_INET, str, u) >= 0); + return u; +} + +static bool test_v4(FirewallContext *ctx) { + union in_addr_union u, v; + int r; + + assert_se(ctx); + + log_info("/* %s(backend=%s) */", __func__, firewall_backend_to_string(ctx->backend)); + + assert_se(fw_add_masquerade(&ctx, true, AF_INET, NULL, 0) == -EINVAL); + assert_se(fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.1.2.0", &u), 0) == -EINVAL); + + r = fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.1.2.3", &u), 32); + if (r < 0) { + bool ignore = IN_SET(r, -EPERM, -EOPNOTSUPP, -ENOPROTOOPT); + + log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r, + "Failed to add IPv4 masquerade%s: %m", + ignore ? ", skipping following tests" : ""); + + if (ignore) + return false; + } + assert(r >= 0); + + assert_se(fw_add_masquerade(&ctx, true, AF_INET, parse_addr("10.0.2.0", &u), 28) >= 0); + assert_se(fw_add_masquerade(&ctx, false, AF_INET, parse_addr("10.0.2.0", &u), 28) >= 0); + assert_se(fw_add_masquerade(&ctx, false, AF_INET, parse_addr("10.1.2.3", &u), 32) >= 0); + assert_se(fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.4", &u), 815, NULL) >= 0); + assert_se(fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.4", &u), 815, NULL) >= 0); + assert_se(fw_add_local_dnat(&ctx, true, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.5", &u), 815, parse_addr("1.2.3.4", &v)) >= 0); + assert_se(fw_add_local_dnat(&ctx, false, AF_INET, IPPROTO_TCP, 4711, parse_addr("1.2.3.5", &u), 815, NULL) >= 0); + + return true; +} int main(int argc, char *argv[]) { - int r; + _cleanup_(fw_ctx_freep) FirewallContext *ctx = NULL; + test_setup_logging(LOG_DEBUG); - r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); + if (getuid() != 0) + return log_tests_skipped("not root"); - r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); + assert_se(fw_ctx_new(&ctx) >= 0); + assert_se(ctx); - r = fw_add_masquerade(false, AF_INET, 0, NULL, 0, "foobar", NULL, 0); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); + if (ctx->backend == FW_BACKEND_NONE) + return EXIT_TEST_SKIP; - r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); + if (test_v4(ctx) && ctx->backend == FW_BACKEND_NFTABLES) + test_v6(ctx); - r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); - - r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, &MAKE_IN_ADDR_UNION(1, 2, 3, 4)); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); - - r = fw_add_local_dnat(false, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, NULL); - if (r < 0) - log_error_errno(r, "Failed to modify firewall: %m"); +#if HAVE_LIBIPTC + if (ctx->backend != FW_BACKEND_IPTABLES) { + ctx->backend = FW_BACKEND_IPTABLES; + test_v4(ctx); + } +#endif return 0; } diff --git a/src/test/test-format-table.c b/src/test/test-format-table.c index 24ee1df95..44d92a719 100644 --- a/src/test/test-format-table.c +++ b/src/test/test-format-table.c @@ -29,7 +29,7 @@ static void test_issue_9549(void) { printf("%s\n", formatted); assert_se(streq(formatted, - "NAME TYPE RO USAGE CREATED MODIFIED \n" + "NAME TYPE RO USAGE CREATED MODIFIED\n" "foooo raw no 673.6M Wed 2018-07-11 00:10:33 J… Wed 2018-07-11 00:16:00 JST\n" )); } @@ -72,17 +72,17 @@ static void test_multiline(void) { "FOO BAR\n" "three two\n" "different lines\n" - "lines \n")); + "lines \n")); formatted = mfree(formatted); - table_set_cell_height_max(table, (size_t) -1); + table_set_cell_height_max(table, SIZE_MAX); assert_se(table_format(table, &formatted) >= 0); fputs(formatted, stdout); assert_se(streq(formatted, "FOO BAR\n" "three two\n" "different lines\n" - "lines \n")); + "lines \n")); formatted = mfree(formatted); assert_se(table_add_many(table, @@ -123,7 +123,7 @@ static void test_multiline(void) { "FOO BAR\n" "three two\n" "different lines\n" - "lines \n" + "lines \n" "short a\n" " pair\n" "short2 a\n" @@ -131,14 +131,14 @@ static void test_multiline(void) { " line…\n")); formatted = mfree(formatted); - table_set_cell_height_max(table, (size_t) -1); + table_set_cell_height_max(table, SIZE_MAX); assert_se(table_format(table, &formatted) >= 0); fputs(formatted, stdout); assert_se(streq(formatted, "FOO BAR\n" "three two\n" "different lines\n" - "lines \n" + "lines \n" "short a\n" " pair\n" "short2 a\n" @@ -186,17 +186,17 @@ static void test_strv(void) { "FOO BAR\n" "three two\n" "different lines\n" - "lines \n")); + "lines \n")); formatted = mfree(formatted); - table_set_cell_height_max(table, (size_t) -1); + table_set_cell_height_max(table, SIZE_MAX); assert_se(table_format(table, &formatted) >= 0); fputs(formatted, stdout); assert_se(streq(formatted, "FOO BAR\n" "three two\n" "different lines\n" - "lines \n")); + "lines \n")); formatted = mfree(formatted); assert_se(table_add_many(table, @@ -237,7 +237,7 @@ static void test_strv(void) { "FOO BAR\n" "three two\n" "different lines\n" - "lines \n" + "lines \n" "short a\n" " pair\n" "short2 a\n" @@ -245,14 +245,14 @@ static void test_strv(void) { " line…\n")); formatted = mfree(formatted); - table_set_cell_height_max(table, (size_t) -1); + table_set_cell_height_max(table, SIZE_MAX); assert_se(table_format(table, &formatted) >= 0); fputs(formatted, stdout); assert_se(streq(formatted, "FOO BAR\n" "three two\n" "different lines\n" - "lines \n" + "lines \n" "short a\n" " pair\n" "short2 a\n" @@ -300,7 +300,7 @@ static void test_strv_wrapped(void) { "three different lines two lines\n")); formatted = mfree(formatted); - table_set_cell_height_max(table, (size_t) -1); + table_set_cell_height_max(table, SIZE_MAX); assert_se(table_format(table, &formatted) >= 0); fputs(formatted, stdout); assert_se(streq(formatted, @@ -333,7 +333,7 @@ static void test_strv_wrapped(void) { assert_se(streq(formatted, "FOO BAR\n" "three different two lines\n" - "lines \n" + "lines \n" "short a pair\n" "short2 a eight line ćęłł\n" " ___5___ ___6___…\n")); @@ -345,20 +345,20 @@ static void test_strv_wrapped(void) { assert_se(streq(formatted, "FOO BAR\n" "three different two lines\n" - "lines \n" + "lines \n" "short a pair\n" "short2 a eight line ćęłł\n" " ___5___ ___6___\n" " ___7___ ___8___\n")); formatted = mfree(formatted); - table_set_cell_height_max(table, (size_t) -1); + table_set_cell_height_max(table, SIZE_MAX); assert_se(table_format(table, &formatted) >= 0); fputs(formatted, stdout); assert_se(streq(formatted, "FOO BAR\n" "three different two lines\n" - "lines \n" + "lines \n" "short a pair\n" "short2 a eight line ćęłł\n" " ___5___ ___6___\n" @@ -443,8 +443,8 @@ int main(int argc, char *argv[]) { formatted = mfree(formatted); - table_set_width(t, (size_t) -1); - assert_se(table_set_sort(t, (size_t) 0, (size_t) 2, (size_t) -1) >= 0); + table_set_width(t, SIZE_MAX); + assert_se(table_set_sort(t, (size_t) 0, (size_t) 2, SIZE_MAX) >= 0); assert_se(table_format(t, &formatted) >= 0); printf("%s\n", formatted); @@ -485,7 +485,7 @@ int main(int argc, char *argv[]) { formatted = mfree(formatted); - assert_se(table_set_display(t, (size_t) 2, (size_t) 0, (size_t) 2, (size_t) 0, (size_t) 0, (size_t) -1) >= 0); + assert_se(table_set_display(t, (size_t) 2, (size_t) 0, (size_t) 2, (size_t) 0, (size_t) 0, SIZE_MAX) >= 0); assert_se(table_format(t, &formatted) >= 0); printf("%s\n", formatted); @@ -493,17 +493,17 @@ int main(int argc, char *argv[]) { if (isatty(STDOUT_FILENO)) assert_se(streq(formatted, " no a long f… no a long f… a long fi…\n" - " no fäää no fäää fäää \n" - " yes fäää yes fäää fäää \n" - " yes xxx yes xxx xxx \n" - "5min 5min \n")); + " no fäää no fäää fäää\n" + " yes fäää yes fäää fäää\n" + " yes xxx yes xxx xxx\n" + "5min 5min \n")); else assert_se(streq(formatted, " no a long field no a long field a long field\n" - " no fäää no fäää fäää \n" - " yes fäää yes fäää fäää \n" - " yes xxx yes xxx xxx \n" - "5min 5min \n")); + " no fäää no fäää fäää\n" + " yes fäää yes fäää fäää\n" + " yes xxx yes xxx xxx\n" + "5min 5min \n")); test_issue_9549(); test_multiline(); diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c index d1f925252..c42c48722 100644 --- a/src/test/test-fs-util.c +++ b/src/test/test-fs-util.c @@ -3,12 +3,15 @@ #include #include "alloc-util.h" +#include "copy.h" #include "fd-util.h" +#include "fileio.h" #include "fs-util.h" #include "id128-util.h" #include "macro.h" #include "mkdir.h" #include "path-util.h" +#include "random-util.h" #include "rm-rf.h" #include "stdio-util.h" #include "string-util.h" @@ -834,6 +837,66 @@ static void test_path_is_encrypted(void) { test_path_is_encrypted_one("/dev", booted > 0 ? false : -1); } +static void create_binary_file(const char *p, const void *data, size_t l) { + _cleanup_close_ int fd = -1; + + fd = open(p, O_CREAT|O_WRONLY|O_EXCL|O_CLOEXEC, 0600); + assert_se(fd >= 0); + assert_se(write(fd, data, l) == (ssize_t) l); +} + +static void test_conservative_rename(void) { + _cleanup_(unlink_and_freep) char *p = NULL; + _cleanup_free_ char *q = NULL; + size_t l = 16*1024 + random_u64() % (32 * 1024); /* some randomly sized buffer 16k…48k */ + uint8_t buffer[l+1]; + + random_bytes(buffer, l); + + assert_se(tempfn_random_child(NULL, NULL, &p) >= 0); + create_binary_file(p, buffer, l); + + assert_se(tempfn_random_child(NULL, NULL, &q) >= 0); + + /* Check that the hardlinked "copy" is detected */ + assert_se(link(p, q) >= 0); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) == 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); + + /* Check that a manual copy is detected */ + assert_se(copy_file(p, q, 0, MODE_INVALID, 0, 0, COPY_REFLINK) >= 0); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) == 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); + + /* Check that a manual new writeout is also detected */ + create_binary_file(q, buffer, l); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) == 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); + + /* Check that a minimally changed version is detected */ + buffer[47] = ~buffer[47]; + create_binary_file(q, buffer, l); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) > 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); + + /* Check that this really is new updated version */ + create_binary_file(q, buffer, l); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) == 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); + + /* Make sure we detect extended files */ + buffer[l++] = 47; + create_binary_file(q, buffer, l); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) > 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); + + /* Make sure we detect truncated files */ + l--; + create_binary_file(q, buffer, l); + assert_se(conservative_renameat(AT_FDCWD, q, AT_FDCWD, p) > 0); + assert_se(access(q, F_OK) < 0 && errno == ENOENT); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_INFO); @@ -852,6 +915,7 @@ int main(int argc, char *argv[]) { test_rename_noreplace(); test_chmod_and_chown(); test_path_is_encrypted(); + test_conservative_rename(); return 0; } diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c index 222ffbb2a..d2f201852 100644 --- a/src/test/test-fstab-util.c +++ b/src/test/test-fstab-util.c @@ -6,94 +6,125 @@ #include "fstab-util.h" #include "log.h" #include "string-util.h" +#include "strv.h" /* -int fstab_filter_options(const char *opts, const char *names, - const char **namefound, char **value, char **filtered); +int fstab_filter_options( + const char *opts, + const char *names, + const char **ret_namefound, + const char **ret_value, + const char **ret_values, + char **ret_filtered); */ static void do_fstab_filter_options(const char *opts, const char *remove, int r_expected, + int r_values_expected, const char *name_expected, const char *value_expected, + const char *values_expected, const char *filtered_expected) { int r; const char *name; - _cleanup_free_ char *value = NULL, *filtered = NULL; + _cleanup_free_ char *value = NULL, *filtered = NULL, *joined = NULL; + _cleanup_strv_free_ char **values = NULL; - r = fstab_filter_options(opts, remove, &name, &value, &filtered); - log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"", - opts, r, name, value, filtered, + /* test mode which returns the last value */ + + r = fstab_filter_options(opts, remove, &name, &value, NULL, &filtered); + log_info("1: \"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"", + opts, r, strnull(name), value, filtered, r_expected, name_expected, value_expected, filtered_expected ?: opts); assert_se(r == r_expected); assert_se(streq_ptr(name, name_expected)); assert_se(streq_ptr(value, value_expected)); assert_se(streq_ptr(filtered, filtered_expected ?: opts)); + /* test mode which returns all the values */ + + r = fstab_filter_options(opts, remove, &name, NULL, &values, NULL); + assert_se(joined = strv_join(values, ":")); + log_info("2: \"%s\" → %d, \"%s\", \"%s\", expected %d, \"%s\", \"%s\"", + opts, r, strnull(name), joined, + r_values_expected, name_expected, values_expected); + assert_se(r == r_values_expected); + assert_se(streq_ptr(name, r_values_expected > 0 ? name_expected : NULL)); + assert_se(streq_ptr(joined, values_expected)); + /* also test the malloc-less mode */ - r = fstab_filter_options(opts, remove, &name, NULL, NULL); - log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"\n-", - opts, r, name, + r = fstab_filter_options(opts, remove, &name, NULL, NULL, NULL); + log_info("3: \"%s\" → %d, \"%s\", expected %d, \"%s\"\n-", + opts, r, strnull(name), r_expected, name_expected); assert_se(r == r_expected); assert_se(streq_ptr(name, name_expected)); } static void test_fstab_filter_options(void) { - do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, "opt", "0", ""); - do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, "opt", "0", ""); - do_fstab_filter_options("opt", "opt\0x-opt\0", 1, "opt", NULL, ""); - do_fstab_filter_options("opt", "x-opt\0opt\0", 1, "opt", NULL, ""); - do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, "x-opt", NULL, ""); + do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", ""); + do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, 1, "opt", "0", "0", ""); + do_fstab_filter_options("opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", ""); + do_fstab_filter_options("opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", ""); + do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, 0, "x-opt", NULL, "", ""); - do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, "opt", "0", "other"); - do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, "opt", "0", "other"); - do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, "opt", NULL, "other"); - do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other"); - do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other"); + do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "other"); + do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other"); + do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other"); + do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other"); + do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "other"); - do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, "opt", "0,1", "other"); - do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, "opt", "0", "other,x-opt\\,foobar"); - do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, "opt", NULL, "other,x-opt\\,part"); - do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, "opt", NULL, "other,part\\,x-opt"); - do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, "opt", NULL, "other\\,\\,\\,opt,x-part"); + do_fstab_filter_options("opt=0\\,1,other", "opt\0x-opt\0", 1, 1, "opt", "0,1", "0,1", "other"); + do_fstab_filter_options("opt=0,other,x-opt\\,foobar", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "other,x-opt\\,foobar"); + do_fstab_filter_options("opt,other,x-opt\\,part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other,x-opt\\,part"); + do_fstab_filter_options("opt,other,part\\,x-opt", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "other,part\\,x-opt"); + do_fstab_filter_options("opt,other\\,\\,\\,opt,x-part", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "other\\,\\,\\,opt,x-part"); - do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL); - do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL); - do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); + do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); + do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); - do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first"); - do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first=1"); - do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, "opt", "", "first"); - do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, "opt", NULL, "first=1"); - do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, "x-opt", NULL, "first=1"); + do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first"); + do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first=1"); + do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, 1, "opt", "", "", "first"); + do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, 0, "opt", NULL, "", "first=1"); + do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, 0, "x-opt", NULL, "", "first=1"); - do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, "opt", "0", "first,last=1"); - do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, "opt", "0", "first=1,last=2"); - do_fstab_filter_options("first,opt,last", "opt\0", 1, "opt", NULL, "first,last"); - do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, "opt", NULL, "first=1,last"); - do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, "opt", NULL, "first=,last"); + do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, 1, "opt", "0", "0", "first,last=1"); + do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, 1, "opt", "0", "0", "first=1,last=2"); + do_fstab_filter_options("first,opt,last", "opt\0", 1, 0, "opt", NULL, "", "first,last"); + do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, 0, "opt", NULL, "", "first=1,last"); + do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, 0, "opt", NULL, "", "first=,last"); /* check repeated options */ - do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, "noopt", "1", "first,last=1"); - do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, "opt", "1", "first=1,last=2"); - do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", ""); - do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", ""); + do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, 1, "noopt", "1", "0:1", "first,last=1"); + do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, 1, "opt", "1", "0:1", "first=1,last=2"); + do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", ""); + do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, 1, "x-opt", "1", "0:1", ""); + do_fstab_filter_options("opt=0,opt=1,opt=,opt=,opt=2", "opt\0noopt\0", 1, 1, "opt", "2", "0:1:::2", ""); /* check that semicolons are not misinterpreted */ - do_fstab_filter_options("opt=0;", "opt\0", 1, "opt", "0;", ""); - do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL); - do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options("opt=0;", "opt\0", 1, 1, "opt", "0;", "0;", ""); + do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL); + do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); /* check that spaces are not misinterpreted */ - do_fstab_filter_options("opt=0 ", "opt\0", 1, "opt", "0 ", ""); - do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL); - do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options("opt=0 ", "opt\0", 1, 1, "opt", "0 ", "0 ", ""); + do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, 0, NULL, NULL, "", NULL); + do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, 0, NULL, NULL, "", NULL); - /* check function will NULL args */ - do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, ""); - do_fstab_filter_options("", "opt\0", 0, NULL, NULL, ""); + /* check function with NULL args */ + do_fstab_filter_options(NULL, "opt\0", 0, 0, NULL, NULL, "", ""); + do_fstab_filter_options("", "opt\0", 0, 0, NULL, NULL, "", ""); + + /* unnecessary comma separators */ + do_fstab_filter_options("opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", ""); + do_fstab_filter_options(",,,opt=x,,,,", "opt\0", 1, 1, "opt", "x", "x", ""); + + /* escaped characters */ + do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt1\0", 1, 1, "opt1", "\\", "\\", "opt2=\\xff"); + do_fstab_filter_options("opt1=\\\\,opt2=\\xff", "opt2\0", 1, 1, "opt2", "\\xff", "\\xff", "opt1=\\"); } static void test_fstab_find_pri(void) { diff --git a/src/test/test-hashmap-ordered.awk b/src/test/test-hashmap-ordered.awk index 10f4386fa..88ffc2562 100644 --- a/src/test/test-hashmap-ordered.awk +++ b/src/test/test-hashmap-ordered.awk @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later BEGIN { print "/* GENERATED FILE */"; print "#define ORDERED" diff --git a/src/test/test-hexdecoct.c b/src/test/test-hexdecoct.c index f0f967976..c9d318b8d 100644 --- a/src/test/test-hexdecoct.c +++ b/src/test/test-hexdecoct.c @@ -80,7 +80,7 @@ static void test_unhexmem_one(const char *s, size_t l, int retval) { if (retval == 0) { char *answer; - if (l == (size_t) -1) + if (l == SIZE_MAX) l = strlen(s); assert_se(hex = hexmem(mem, len)); @@ -96,15 +96,15 @@ static void test_unhexmem(void) { test_unhexmem_one(NULL, 0, 0); test_unhexmem_one("", 0, 0); - test_unhexmem_one("", (size_t) -1, 0); - test_unhexmem_one(" \n \t\r \t\t \n\n\n", (size_t) -1, 0); + test_unhexmem_one("", SIZE_MAX, 0); + test_unhexmem_one(" \n \t\r \t\t \n\n\n", SIZE_MAX, 0); test_unhexmem_one(hex_invalid, strlen(hex_invalid), -EINVAL); test_unhexmem_one(hex_invalid, (size_t) - 1, -EINVAL); test_unhexmem_one(hex, strlen(hex) - 1, -EPIPE); test_unhexmem_one(hex, strlen(hex), 0); - test_unhexmem_one(hex, (size_t) -1, 0); + test_unhexmem_one(hex, SIZE_MAX, 0); test_unhexmem_one(hex_space, strlen(hex_space), 0); - test_unhexmem_one(hex_space, (size_t) -1, 0); + test_unhexmem_one(hex_space, SIZE_MAX, 0); } /* https://tools.ietf.org/html/rfc4648#section-10 */ @@ -186,7 +186,7 @@ static void test_unbase32hexmem_one(const char *hex, bool padding, int retval, c _cleanup_free_ void *mem = NULL; size_t len; - assert_se(unbase32hexmem(hex, (size_t) -1, padding, &mem, &len) == retval); + assert_se(unbase32hexmem(hex, SIZE_MAX, padding, &mem, &len) == retval); if (retval == 0) { char *str; @@ -279,7 +279,7 @@ static void test_unbase64mem_one(const char *input, const char *output, int ret) _cleanup_free_ void *buffer = NULL; size_t size = 0; - assert_se(unbase64mem(input, (size_t) -1, &buffer, &size) == ret); + assert_se(unbase64mem(input, SIZE_MAX, &buffer, &size) == ret); if (ret >= 0) { assert_se(size == strlen(output)); diff --git a/src/test/test-hostname-setup.c b/src/test/test-hostname-setup.c new file mode 100644 index 000000000..55996500f --- /dev/null +++ b/src/test/test-hostname-setup.c @@ -0,0 +1,72 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#include "alloc-util.h" +#include "fileio.h" +#include "hostname-setup.h" +#include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" + +static void test_read_etc_hostname(void) { + char path[] = "/tmp/hostname.XXXXXX"; + char *hostname; + int fd; + + fd = mkostemp_safe(path); + assert(fd > 0); + close(fd); + + /* simple hostname */ + assert_se(write_string_file(path, "foo", WRITE_STRING_FILE_CREATE) == 0); + assert_se(read_etc_hostname(path, &hostname) == 0); + assert_se(streq(hostname, "foo")); + hostname = mfree(hostname); + + /* with comment */ + assert_se(write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE) == 0); + assert_se(read_etc_hostname(path, &hostname) == 0); + assert_se(hostname); + assert_se(streq(hostname, "foo")); + hostname = mfree(hostname); + + /* with comment and extra whitespace */ + assert_se(write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE) == 0); + assert_se(read_etc_hostname(path, &hostname) == 0); + assert_se(hostname); + assert_se(streq(hostname, "foo")); + hostname = mfree(hostname); + + /* cleans up name */ + assert_se(write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE) == 0); + assert_se(read_etc_hostname(path, &hostname) == 0); + assert_se(hostname); + assert_se(streq(hostname, "foobar.com")); + hostname = mfree(hostname); + + /* no value set */ + hostname = (char*) 0x1234; + assert_se(write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE) == 0); + assert_se(read_etc_hostname(path, &hostname) == -ENOENT); + assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ + + /* nonexisting file */ + assert_se(read_etc_hostname("/non/existing", &hostname) == -ENOENT); + assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ + + unlink(path); +} + +static void test_hostname_setup(void) { + hostname_setup(false); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + test_read_etc_hostname(); + test_hostname_setup(); + + return 0; +} diff --git a/src/test/test-hostname-util.c b/src/test/test-hostname-util.c index 73839b311..6d62958d6 100644 --- a/src/test/test-hostname-util.c +++ b/src/test/test-hostname-util.c @@ -6,49 +6,53 @@ #include "fileio.h" #include "hostname-util.h" #include "string-util.h" +#include "tests.h" #include "tmpfile-util.h" -#include "util.h" static void test_hostname_is_valid(void) { - assert_se(hostname_is_valid("foobar", false)); - assert_se(hostname_is_valid("foobar.com", false)); - assert_se(!hostname_is_valid("foobar.com.", false)); - assert_se(hostname_is_valid("fooBAR", false)); - assert_se(hostname_is_valid("fooBAR.com", false)); - assert_se(!hostname_is_valid("fooBAR.", false)); - assert_se(!hostname_is_valid("fooBAR.com.", false)); - assert_se(!hostname_is_valid("fööbar", false)); - assert_se(!hostname_is_valid("", false)); - assert_se(!hostname_is_valid(".", false)); - assert_se(!hostname_is_valid("..", false)); - assert_se(!hostname_is_valid("foobar.", false)); - assert_se(!hostname_is_valid(".foobar", false)); - assert_se(!hostname_is_valid("foo..bar", false)); - assert_se(!hostname_is_valid("foo.bar..", false)); - assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", false)); - assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", false)); + log_info("/* %s */", __func__); - assert_se(hostname_is_valid("foobar", true)); - assert_se(hostname_is_valid("foobar.com", true)); - assert_se(hostname_is_valid("foobar.com.", true)); - assert_se(hostname_is_valid("fooBAR", true)); - assert_se(hostname_is_valid("fooBAR.com", true)); - assert_se(!hostname_is_valid("fooBAR.", true)); - assert_se(hostname_is_valid("fooBAR.com.", true)); - assert_se(!hostname_is_valid("fööbar", true)); - assert_se(!hostname_is_valid("", true)); - assert_se(!hostname_is_valid(".", true)); - assert_se(!hostname_is_valid("..", true)); - assert_se(!hostname_is_valid("foobar.", true)); - assert_se(!hostname_is_valid(".foobar", true)); - assert_se(!hostname_is_valid("foo..bar", true)); - assert_se(!hostname_is_valid("foo.bar..", true)); - assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", true)); + assert_se(hostname_is_valid("foobar", 0)); + assert_se(hostname_is_valid("foobar.com", 0)); + assert_se(!hostname_is_valid("foobar.com.", 0)); + assert_se(hostname_is_valid("fooBAR", 0)); + assert_se(hostname_is_valid("fooBAR.com", 0)); + assert_se(!hostname_is_valid("fooBAR.", 0)); + assert_se(!hostname_is_valid("fooBAR.com.", 0)); + assert_se(!hostname_is_valid("fööbar", 0)); + assert_se(!hostname_is_valid("", 0)); + assert_se(!hostname_is_valid(".", 0)); + assert_se(!hostname_is_valid("..", 0)); + assert_se(!hostname_is_valid("foobar.", 0)); + assert_se(!hostname_is_valid(".foobar", 0)); + assert_se(!hostname_is_valid("foo..bar", 0)); + assert_se(!hostname_is_valid("foo.bar..", 0)); + assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 0)); + assert_se(!hostname_is_valid("au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", 0)); + + assert_se(hostname_is_valid("foobar", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(hostname_is_valid("foobar.com", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(hostname_is_valid("foobar.com.", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(hostname_is_valid("fooBAR", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(hostname_is_valid("fooBAR.com", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("fooBAR.", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(hostname_is_valid("fooBAR.com.", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("fööbar", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid(".", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("..", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("foobar.", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid(".foobar", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("foo..bar", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("foo.bar..", VALID_HOSTNAME_TRAILING_DOT)); + assert_se(!hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", VALID_HOSTNAME_TRAILING_DOT)); } static void test_hostname_cleanup(void) { char *s; + log_info("/* %s */", __func__); + s = strdupa("foobar"); assert_se(streq(hostname_cleanup(s), "foobar")); s = strdupa("foobar.com"); @@ -91,58 +95,11 @@ static void test_hostname_cleanup(void) { assert_se(streq(hostname_cleanup(s), "xxxx.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")); } -static void test_read_etc_hostname(void) { - char path[] = "/tmp/hostname.XXXXXX"; - char *hostname; - int fd; - - fd = mkostemp_safe(path); - assert(fd > 0); - close(fd); - - /* simple hostname */ - assert_se(write_string_file(path, "foo", WRITE_STRING_FILE_CREATE) == 0); - assert_se(read_etc_hostname(path, &hostname) == 0); - assert_se(streq(hostname, "foo")); - hostname = mfree(hostname); - - /* with comment */ - assert_se(write_string_file(path, "# comment\nfoo", WRITE_STRING_FILE_CREATE) == 0); - assert_se(read_etc_hostname(path, &hostname) == 0); - assert_se(hostname); - assert_se(streq(hostname, "foo")); - hostname = mfree(hostname); - - /* with comment and extra whitespace */ - assert_se(write_string_file(path, "# comment\n\n foo ", WRITE_STRING_FILE_CREATE) == 0); - assert_se(read_etc_hostname(path, &hostname) == 0); - assert_se(hostname); - assert_se(streq(hostname, "foo")); - hostname = mfree(hostname); - - /* cleans up name */ - assert_se(write_string_file(path, "!foo/bar.com", WRITE_STRING_FILE_CREATE) == 0); - assert_se(read_etc_hostname(path, &hostname) == 0); - assert_se(hostname); - assert_se(streq(hostname, "foobar.com")); - hostname = mfree(hostname); - - /* no value set */ - hostname = (char*) 0x1234; - assert_se(write_string_file(path, "# nothing here\n", WRITE_STRING_FILE_CREATE) == 0); - assert_se(read_etc_hostname(path, &hostname) == -ENOENT); - assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ - - /* nonexisting file */ - assert_se(read_etc_hostname("/non/existing", &hostname) == -ENOENT); - assert_se(hostname == (char*) 0x1234); /* does not touch argument on error */ - - unlink(path); -} - static void test_hostname_malloc(void) { _cleanup_free_ char *h = NULL, *l = NULL; + log_info("/* %s */", __func__); + assert_se(h = gethostname_malloc()); log_info("hostname_malloc: \"%s\"", h); @@ -150,23 +107,27 @@ static void test_hostname_malloc(void) { log_info("hostname_short_malloc: \"%s\"", l); } -static void test_fallback_hostname(void) { - if (!hostname_is_valid(FALLBACK_HOSTNAME, false)) { +static void test_default_hostname(void) { + log_info("/* %s */", __func__); + + if (!hostname_is_valid(FALLBACK_HOSTNAME, 0)) { log_error("Configured fallback hostname \"%s\" is not valid.", FALLBACK_HOSTNAME); exit(EXIT_FAILURE); } + + _cleanup_free_ char *n = get_default_hostname(); + assert_se(n); + log_info("get_default_hostname: \"%s\"", n); + assert_se(hostname_is_valid(n, 0)); } int main(int argc, char *argv[]) { - log_parse_environment(); - log_open(); + test_setup_logging(LOG_DEBUG); test_hostname_is_valid(); test_hostname_cleanup(); - test_read_etc_hostname(); test_hostname_malloc(); - - test_fallback_hostname(); + test_default_hostname(); return 0; } diff --git a/src/test/test-hostname.c b/src/test/test-hostname.c deleted file mode 100644 index 1a925f253..000000000 --- a/src/test/test-hostname.c +++ /dev/null @@ -1,14 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "hostname-setup.h" -#include "util.h" - -int main(int argc, char* argv[]) { - int r; - - r = hostname_setup(); - if (r < 0) - log_error_errno(r, "hostname: %m"); - - return 0; -} diff --git a/src/test/test-in-addr-util.c b/src/test/test-in-addr-util.c index 2b6364566..509ea7e31 100644 --- a/src/test/test-in-addr-util.c +++ b/src/test/test-in-addr-util.c @@ -238,10 +238,12 @@ static void test_in_addr_prefix_intersect(void) { static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigned pl, const char *after) { union in_addr_union ubefore, uafter, t; + log_info("/* %s(%s, prefixlen=%u) */", __func__, before, pl); + assert_se(in_addr_from_string(f, before, &ubefore) >= 0); t = ubefore; - assert_se((in_addr_prefix_next(f, &t, pl) > 0) == !!after); + assert_se((in_addr_prefix_next(f, &t, pl) >= 0) == !!after); if (after) { assert_se(in_addr_from_string(f, after, &uafter) >= 0); @@ -250,13 +252,12 @@ static void test_in_addr_prefix_next_one(unsigned f, const char *before, unsigne } static void test_in_addr_prefix_next(void) { - log_info("/* %s */", __func__); - test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 24, "192.168.1.0"); test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 16, "192.169.0.0"); test_in_addr_prefix_next_one(AF_INET, "192.168.0.0", 20, "192.168.16.0"); test_in_addr_prefix_next_one(AF_INET, "0.0.0.0", 32, "0.0.0.1"); + test_in_addr_prefix_next_one(AF_INET, "255.255.255.254", 32, "255.255.255.255"); test_in_addr_prefix_next_one(AF_INET, "255.255.255.255", 32, NULL); test_in_addr_prefix_next_one(AF_INET, "255.255.255.0", 24, NULL); @@ -275,10 +276,12 @@ static void test_in_addr_prefix_next(void) { static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned pl, uint64_t nth, const char *after) { union in_addr_union ubefore, uafter, t; + log_info("/* %s(%s, prefixlen=%u, nth=%"PRIu64") */", __func__, before, pl, nth); + assert_se(in_addr_from_string(f, before, &ubefore) >= 0); t = ubefore; - assert_se((in_addr_prefix_nth(f, &t, pl, nth) > 0) == !!after); + assert_se((in_addr_prefix_nth(f, &t, pl, nth) >= 0) == !!after); if (after) { assert_se(in_addr_from_string(f, after, &uafter) >= 0); @@ -287,10 +290,9 @@ static void test_in_addr_prefix_nth_one(unsigned f, const char *before, unsigned } static void test_in_addr_prefix_nth(void) { - log_info("/* %s */", __func__); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 0, "192.168.0.0"); - test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 1, "192.168.1.0"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.0.123", 24, 0, "192.168.0.0"); + test_in_addr_prefix_nth_one(AF_INET, "192.168.0.123", 24, 1, "192.168.1.0"); test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 24, 4, "192.168.4.0"); test_in_addr_prefix_nth_one(AF_INET, "192.168.0.0", 25, 1, "192.168.0.128"); test_in_addr_prefix_nth_one(AF_INET, "192.168.255.0", 25, 1, "192.168.255.128"); @@ -309,6 +311,48 @@ static void test_in_addr_prefix_nth(void) { test_in_addr_prefix_nth_one(AF_INET6, "0000::", 8, 256, NULL); test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 128, 1, NULL); test_in_addr_prefix_nth_one(AF_INET6, "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 0, 1, NULL); + test_in_addr_prefix_nth_one(AF_INET6, "1234:5678:90ab:cdef:1234:5678:90ab:cdef", 12, 1, "1240::"); +} + +static void test_in_addr_prefix_range_one( + int family, + const char *in, + unsigned prefixlen, + const char *expected_start, + const char *expected_end) { + + union in_addr_union a, s, e; + + log_info("/* %s(%s, prefixlen=%u) */", __func__, in, prefixlen); + + assert_se(in_addr_from_string(family, in, &a) >= 0); + assert_se((in_addr_prefix_range(family, &a, prefixlen, &s, &e) >= 0) == !!expected_start); + + if (expected_start) { + union in_addr_union es; + + assert_se(in_addr_from_string(family, expected_start, &es) >= 0); + assert_se(in_addr_equal(family, &s, &es) > 0); + } + if (expected_end) { + union in_addr_union ee; + + assert_se(in_addr_from_string(family, expected_end, &ee) >= 0); + assert_se(in_addr_equal(family, &e, &ee) > 0); + } +} + +static void test_in_addr_prefix_range(void) { + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 24, "192.168.123.0", "192.168.124.0"); + test_in_addr_prefix_range_one(AF_INET, "192.168.123.123", 16, "192.168.0.0", "192.169.0.0"); + + test_in_addr_prefix_range_one(AF_INET6, "dead:beef::", 64, "dead:beef::", "dead:beef:0:1::"); + test_in_addr_prefix_range_one(AF_INET6, "dead:0:0:beef::", 64, "dead:0:0:beef::", "dead:0:0:bef0::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 48, "2001::", "2001:0:1::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 56, "2001::", "2001:0:0:0100::"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 65, "2001::", "2001::8000:0:0:0"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 66, "2001::", "2001::4000:0:0:0"); + test_in_addr_prefix_range_one(AF_INET6, "2001::", 127, "2001::", "2001::2"); } static void test_in_addr_to_string_one(int f, const char *addr) { @@ -339,6 +383,7 @@ int main(int argc, char *argv[]) { test_in_addr_prefix_intersect(); test_in_addr_prefix_next(); test_in_addr_prefix_nth(); + test_in_addr_prefix_range(); test_in_addr_to_string(); return 0; diff --git a/src/test/test-install-root.c b/src/test/test-install-root.c index aedec54a7..bea196c0c 100644 --- a/src/test/test-install-root.c +++ b/src/test/test-install-root.c @@ -55,7 +55,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_mask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/dev/null")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/a.service"); assert_se(streq(changes[0].path, p)); @@ -75,7 +75,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_unmask(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -83,7 +83,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); @@ -103,7 +103,7 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("a.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -123,7 +123,7 @@ static void test_basic_mask_and_enable(const char *root) { /* Let's enable this indirectly via a symlink */ assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("d.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/a.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); @@ -139,10 +139,10 @@ static void test_basic_mask_and_enable(const char *root) { assert_se(unit_file_reenable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("b.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/a.service"); assert_se(streq(changes[0].path, p)); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/a.service")); assert_se(streq(changes[1].path, p)); unit_file_changes_free(changes, n_changes); @@ -224,7 +224,7 @@ static void test_linked_units(const char *root) { /* First, let's link the unit into the search path */ assert_se(unit_file_link(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("/opt/linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/opt/linked.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); assert_se(streq(changes[0].path, p)); @@ -236,7 +236,7 @@ static void test_linked_units(const char *root) { /* Let's unlink it from the search path again */ assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -250,7 +250,7 @@ static void test_linked_units(const char *root) { p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); for (i = 0 ; i < n_changes; i++) { - assert_se(changes[i].type == UNIT_FILE_SYMLINK); + assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[i].source, "/opt/linked.service")); if (p && streq(changes[i].path, p)) @@ -272,7 +272,7 @@ static void test_linked_units(const char *root) { p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked.service"); for (i = 0; i < n_changes; i++) { - assert_se(changes[i].type == UNIT_FILE_UNLINK); + assert_se(changes[i].type_or_errno == UNIT_FILE_UNLINK); if (p && streq(changes[i].path, p)) p = NULL; @@ -292,7 +292,7 @@ static void test_linked_units(const char *root) { p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/linked2.service"); q = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/linked2.service"); for (i = 0 ; i < n_changes; i++) { - assert_se(changes[i].type == UNIT_FILE_SYMLINK); + assert_se(changes[i].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[i].source, "/opt/linked2.service")); if (p && streq(changes[i].path, p)) @@ -308,7 +308,7 @@ static void test_linked_units(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("linked3.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(startswith(changes[0].path, root)); assert_se(endswith(changes[0].path, "linked3.service")); assert_se(streq(changes[0].source, "/opt/linked3.service")); @@ -332,7 +332,7 @@ static void test_default(const char *root) { assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "idontexist.target", &changes, &n_changes) == -ENOENT); assert_se(n_changes == 1); - assert_se(changes[0].type == -ENOENT); + assert_se(changes[0].type_or_errno == -ENOENT); assert_se(streq_ptr(changes[0].path, "idontexist.target")); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -341,7 +341,7 @@ static void test_default(const char *root) { assert_se(unit_file_set_default(UNIT_FILE_SYSTEM, 0, root, "test-default.target", &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/test-default-real.target")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR "/" SPECIAL_DEFAULT_TARGET); assert_se(streq(changes[0].path, p)); @@ -371,7 +371,7 @@ static void test_add_dependency(const char *root) { assert_se(unit_file_add_dependency(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("add-dependency-test-service.service"), "add-dependency-test-target.target", UNIT_WANTS, &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/real-add-dependency-test-service.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/real-add-dependency-test-target.target.wants/real-add-dependency-test-service.service"); assert_se(streq(changes[0].path, p)); @@ -412,7 +412,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@def.service"); assert_se(streq(changes[0].path, p)); @@ -428,7 +428,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -443,7 +443,7 @@ static void test_template_enable(const char *root) { log_info("== %s with template@foo.service enabled ==", __func__); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@foo.service"); assert_se(streq(changes[0].path, p)); @@ -459,7 +459,7 @@ static void test_template_enable(const char *root) { assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template@foo.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -476,7 +476,7 @@ static void test_template_enable(const char *root) { log_info("== %s with template-symlink@quux.service enabled ==", __func__); assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("template-symlink@quux.service"), &changes, &n_changes) >= 0); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/template@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/template@quux.service"); assert_se(streq(changes[0].path, p)); @@ -522,7 +522,7 @@ static void test_indirect(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/indirectb.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service"); assert_se(streq(changes[0].path, p)); @@ -535,7 +535,7 @@ static void test_indirect(const char *root) { assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("indirectc.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/indirectb.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -574,7 +574,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/preset-yes.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service"); assert_se(streq(changes[0].path, p)); @@ -586,7 +586,7 @@ static void test_preset_and_list(const char *root) { assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("preset-yes.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/preset-yes.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -611,11 +611,11 @@ static void test_preset_and_list(const char *root) { for (i = 0; i < n_changes; i++) { - if (changes[i].type == UNIT_FILE_SYMLINK) { + if (changes[i].type_or_errno == UNIT_FILE_SYMLINK) { assert_se(streq(changes[i].source, "/usr/lib/systemd/system/preset-yes.service")); assert_se(streq(changes[i].path, p)); } else - assert_se(changes[i].type == UNIT_FILE_UNLINK); + assert_se(changes[i].type_or_errno == UNIT_FILE_UNLINK); } unit_file_changes_free(changes, n_changes); @@ -678,7 +678,7 @@ static void test_revert(const char *root) { /* Revert the override file */ assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -690,11 +690,11 @@ static void test_revert(const char *root) { /* Revert the dropin file */ assert_se(unit_file_revert(UNIT_FILE_SYSTEM, root, STRV_MAKE("xx.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[0].path, p)); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/xx.service.d"); - assert_se(changes[1].type == UNIT_FILE_UNLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_UNLINK); assert_se(streq(changes[1].path, p)); unit_file_changes_free(changes, n_changes); changes = NULL; n_changes = 0; @@ -730,7 +730,7 @@ static void test_preset_order(const char *root) { assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("prefix-1.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/prefix-1.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/prefix-1.service"); assert_se(streq(changes[0].path, p)); @@ -842,8 +842,8 @@ static void test_with_dropin(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1.service")); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1.service"); @@ -856,8 +856,8 @@ static void test_with_dropin(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2.service"), &changes, &n_changes) == 1); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-2.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service")); assert_se(streq(changes[1].source, SYSTEM_CONFIG_UNIT_DIR"/with-dropin-2.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2.service"); @@ -870,8 +870,8 @@ static void test_with_dropin(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3.service"), &changes, &n_changes) == 1); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3.service")); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-3.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3.service"); @@ -884,8 +884,8 @@ static void test_with_dropin(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-4a.service"), &changes, &n_changes) == 2); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "with-dropin-3.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-4a.service")); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-4b.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-4a.service"); @@ -954,8 +954,8 @@ static void test_with_dropin_template(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-1@instance-1.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-1@.service")); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-1@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-1@instance-1.service"); @@ -967,8 +967,8 @@ static void test_with_dropin_template(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-1.service"), &changes, &n_changes) == 1); assert_se(n_changes == 2); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); - assert_se(changes[1].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); + assert_se(changes[1].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service")); assert_se(streq(changes[1].source, "/usr/lib/systemd/system/with-dropin-2@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-1.service"); @@ -980,7 +980,7 @@ static void test_with_dropin_template(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-2@instance-2.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-2@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-2@instance-2.service"); assert_se(streq(changes[0].path, p)); @@ -989,7 +989,7 @@ static void test_with_dropin_template(const char *root) { assert_se(unit_file_enable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("with-dropin-3@.service"), &changes, &n_changes) == 1); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); assert_se(streq(changes[0].source, "/usr/lib/systemd/system/with-dropin-3@.service")); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/with-dropin-3@instance-2.service"); assert_se(streq(changes[0].path, p)); @@ -1030,7 +1030,7 @@ static void test_preset_multiple_instances(const char *root) { assert_se(unit_file_preset(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), UNIT_FILE_PRESET_FULL, &changes, &n_changes) >= 0); assert_se(unit_file_get_state(UNIT_FILE_SYSTEM, root, "foo@bar0.service", &state) >= 0 && state == UNIT_FILE_ENABLED); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_SYMLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_SYMLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/foo@bar0.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -1038,7 +1038,7 @@ static void test_preset_multiple_instances(const char *root) { assert_se(unit_file_disable(UNIT_FILE_SYSTEM, 0, root, STRV_MAKE("foo@bar0.service"), &changes, &n_changes) >= 0); assert_se(n_changes == 1); - assert_se(changes[0].type == UNIT_FILE_UNLINK); + assert_se(changes[0].type_or_errno == UNIT_FILE_UNLINK); p = strjoina(root, SYSTEM_CONFIG_UNIT_DIR"/multi-user.target.wants/foo@bar0.service"); assert_se(streq(changes[0].path, p)); unit_file_changes_free(changes, n_changes); @@ -1079,7 +1079,7 @@ static void verify_one( alias2 ? "]" : ""); assert(r == expected); - /* This is is test for "instance propagation". This propagation matters mostly for WantedBy= and + /* This is test for "instance propagation". This propagation matters mostly for WantedBy= and * RequiredBy= settings, and less so for Alias=. The only case where it should happen is when we have * an Alias=alias@.service an instantiated template template@instance. In that case the instance name * should be propagated into the alias as alias@instance. */ diff --git a/src/test/test-install.c b/src/test/test-install.c index 7cd91efcb..7a0beb2d2 100644 --- a/src/test/test-install.c +++ b/src/test/test-install.c @@ -12,9 +12,9 @@ static void dump_changes(UnitFileChange *c, unsigned n) { assert_se(n == 0 || c); for (i = 0; i < n; i++) { - if (c[i].type == UNIT_FILE_UNLINK) + if (c[i].type_or_errno == UNIT_FILE_UNLINK) printf("rm '%s'\n", c[i].path); - else if (c[i].type == UNIT_FILE_SYMLINK) + else if (c[i].type_or_errno == UNIT_FILE_SYMLINK) printf("ln -s '%s' '%s'\n", c[i].source, c[i].path); } } diff --git a/src/test/test-locale-util.c b/src/test/test-locale-util.c index 62f82200a..972423e2f 100644 --- a/src/test/test-locale-util.c +++ b/src/test/test-locale-util.c @@ -101,6 +101,9 @@ static void dump_special_glyphs(void) { dump_glyph(SPECIAL_GLYPH_TREE_SPACE); dump_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET); dump_glyph(SPECIAL_GLYPH_BLACK_CIRCLE); + dump_glyph(SPECIAL_GLYPH_WHITE_CIRCLE); + dump_glyph(SPECIAL_GLYPH_MULTIPLICATION_SIGN); + dump_glyph(SPECIAL_GLYPH_CIRCLE_ARROW); dump_glyph(SPECIAL_GLYPH_BULLET); dump_glyph(SPECIAL_GLYPH_ARROW); dump_glyph(SPECIAL_GLYPH_ELLIPSIS); diff --git a/src/test/test-log.c b/src/test/test-log.c index a2a53730e..861309eb3 100644 --- a/src/test/test-log.c +++ b/src/test/test-log.c @@ -9,15 +9,6 @@ #include "string-util.h" #include "util.h" -assert_cc(LOG_REALM_REMOVE_LEVEL(LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, LOG_FTP | LOG_DEBUG)) - == LOG_REALM_SYSTEMD); -assert_cc(LOG_REALM_REMOVE_LEVEL(LOG_REALM_PLUS_LEVEL(LOG_REALM_UDEV, LOG_LOCAL7 | LOG_DEBUG)) - == LOG_REALM_UDEV); -assert_cc((LOG_REALM_PLUS_LEVEL(LOG_REALM_SYSTEMD, LOG_LOCAL3 | LOG_DEBUG) & LOG_FACMASK) - == LOG_LOCAL3); -assert_cc((LOG_REALM_PLUS_LEVEL(LOG_REALM_UDEV, LOG_USER | LOG_INFO) & LOG_PRIMASK) - == LOG_INFO); - assert_cc(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(EINVAL))); assert_cc(!IS_SYNTHETIC_ERRNO(EINVAL)); assert_cc(IS_SYNTHETIC_ERRNO(SYNTHETIC_ERRNO(0))); diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c index 298ded94d..93f2da70e 100644 --- a/src/test/test-loop-block.c +++ b/src/test/test-loop-block.c @@ -132,9 +132,9 @@ int main(int argc, char *argv[]) { return EXIT_TEST_SKIP; } - if (strstr_ptr(ci_environment(), "autopkgtest")) { + if (strstr_ptr(ci_environment(), "autopkgtest") || strstr_ptr(ci_environment(), "github-actions")) { // FIXME: we should reenable this one day - log_tests_skipped("Skipping test on Ubuntu autopkgtest CI, test too slow and installed udev too flakey."); + log_tests_skipped("Skipping test on Ubuntu autopkgtest CI/GH Actions, test too slow and installed udev too flakey."); return EXIT_TEST_SKIP; } diff --git a/src/home/test-modhex.c b/src/test/test-modhex.c similarity index 99% rename from src/home/test-modhex.c rename to src/test/test-modhex.c index 1bd9061a7..836460cec 100644 --- a/src/home/test-modhex.c +++ b/src/test/test-modhex.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "modhex.h" +#include "recovery-key.h" #include "alloc-util.h" #include "string-util.h" diff --git a/src/test/test-mountpoint-util.c b/src/test/test-mountpoint-util.c index 47fde5cb2..128daa6de 100644 --- a/src/test/test-mountpoint-util.c +++ b/src/test/test-mountpoint-util.c @@ -8,13 +8,16 @@ #include "def.h" #include "fd-util.h" #include "fileio.h" +#include "fs-util.h" #include "hashmap.h" #include "log.h" +#include "mkdir.h" #include "mountpoint-util.h" #include "path-util.h" #include "rm-rf.h" #include "string-util.h" #include "tests.h" +#include "tmpfile-util.h" static void test_mount_propagation_flags(const char *name, int ret, unsigned long expected) { long unsigned flags; @@ -280,13 +283,59 @@ static void test_fd_is_mount_point(void) { assert_se(fd_is_mount_point(fd, "proc", 0) > 0); assert_se(fd_is_mount_point(fd, "proc/", 0) > 0); - /* /root's entire raison d'etre is to be on the root file system (i.e. not in /home/ which might be - * split off), so that the user can always log in, so it cannot be a mount point unless the system is - * borked. Let's allow for it to be missing though. */ + /* /root's entire reason for being is to be on the root file system (i.e. not in /home/ which + * might be split off), so that the user can always log in, so it cannot be a mount point unless + * the system is borked. Let's allow for it to be missing though. */ assert_se(IN_SET(fd_is_mount_point(fd, "root", 0), -ENOENT, 0)); assert_se(IN_SET(fd_is_mount_point(fd, "root/", 0), -ENOENT, 0)); } +static void test_make_mount_point_inode(void) { + _cleanup_(rm_rf_physical_and_freep) char *d = NULL; + const char *src_file, *src_dir, *dst_file, *dst_dir; + struct stat st; + + log_info("/* %s */", __func__); + + assert_se(mkdtemp_malloc(NULL, &d) >= 0); + + src_file = strjoina(d, "/src/file"); + src_dir = strjoina(d, "/src/dir"); + dst_file = strjoina(d, "/dst/file"); + dst_dir = strjoina(d, "/dst/dir"); + + assert_se(mkdir_p(src_dir, 0755) >= 0); + assert_se(mkdir_parents(dst_file, 0755) >= 0); + assert_se(touch(src_file) >= 0); + + assert_se(make_mount_point_inode_from_path(src_file, dst_file, 0755) >= 0); + assert_se(make_mount_point_inode_from_path(src_dir, dst_dir, 0755) >= 0); + + assert_se(stat(dst_dir, &st) == 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se(stat(dst_file, &st) == 0); + assert_se(S_ISREG(st.st_mode)); + assert_se(!(S_IXUSR & st.st_mode)); + assert_se(!(S_IXGRP & st.st_mode)); + assert_se(!(S_IXOTH & st.st_mode)); + + assert_se(unlink(dst_file) == 0); + assert_se(rmdir(dst_dir) == 0); + + assert_se(stat(src_file, &st) == 0); + assert_se(make_mount_point_inode_from_stat(&st, dst_file, 0755) >= 0); + assert_se(stat(src_dir, &st) == 0); + assert_se(make_mount_point_inode_from_stat(&st, dst_dir, 0755) >= 0); + + assert_se(stat(dst_dir, &st) == 0); + assert_se(S_ISDIR(st.st_mode)); + assert_se(stat(dst_file, &st) == 0); + assert_se(S_ISREG(st.st_mode)); + assert_se(!(S_IXUSR & st.st_mode)); + assert_se(!(S_IXGRP & st.st_mode)); + assert_se(!(S_IXOTH & st.st_mode)); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -311,6 +360,7 @@ int main(int argc, char *argv[]) { test_mnt_id(); test_path_is_mount_point(); test_fd_is_mount_point(); + test_make_mount_point_inode(); return 0; } diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index e234f54de..bf4b87e8a 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -63,7 +63,7 @@ static void test_tmpdir(const char *id, const char *A, const char *B) { } } -static void test_netns(void) { +static void test_shareable_ns(unsigned long nsflag) { _cleanup_close_pair_ int s[2] = { -1, -1 }; pid_t pid1, pid2, pid3; int r, n = 0; @@ -80,7 +80,7 @@ static void test_netns(void) { assert_se(pid1 >= 0); if (pid1 == 0) { - r = setup_netns(s); + r = setup_shareable_ns(s, nsflag); assert_se(r >= 0); _exit(r); } @@ -89,7 +89,7 @@ static void test_netns(void) { assert_se(pid2 >= 0); if (pid2 == 0) { - r = setup_netns(s); + r = setup_shareable_ns(s, nsflag); assert_se(r >= 0); exit(r); } @@ -98,7 +98,7 @@ static void test_netns(void) { assert_se(pid3 >= 0); if (pid3 == 0) { - r = setup_netns(s); + r = setup_shareable_ns(s, nsflag); assert_se(r >= 0); exit(r); } @@ -121,6 +121,14 @@ static void test_netns(void) { assert_se(n == 1); } +static void test_netns(void) { + test_shareable_ns(CLONE_NEWNET); +} + +static void test_ipcns(void) { + test_shareable_ns(CLONE_NEWIPC); +} + static void test_protect_kernel_logs(void) { int r; pid_t pid; @@ -157,6 +165,8 @@ static void test_protect_kernel_logs(void) { NULL, NULL, NULL, + NULL, + NULL, NULL, 0, NULL, 0, NULL, 0, @@ -172,6 +182,11 @@ static void test_protect_kernel_logs(void) { 0, NULL, NULL, + NULL, + 0, + NULL, + NULL, + NULL, 0, NULL); assert_se(r == 0); @@ -217,6 +232,7 @@ int main(int argc, char *argv[]) { test_tmpdir("sys-devices-pci0000:00-0000:00:1a.0-usb3-3\\x2d1-3\\x2d1:1.0-bluetooth-hci0.device", z, zz); test_netns(); + test_ipcns(); test_protect_kernel_logs(); return EXIT_SUCCESS; diff --git a/src/test/test-ns.c b/src/test/test-ns.c index 6ec1cff28..761ee5da8 100644 --- a/src/test/test-ns.c +++ b/src/test/test-ns.c @@ -26,6 +26,19 @@ int main(int argc, char *argv[]) { NULL }; + const char * const exec[] = { + "/lib", + "/usr", + "-/lib64", + "-/usr/lib64", + NULL + }; + + const char * const no_exec[] = { + "/var", + NULL + }; + const char *inaccessible[] = { "/home/lennart/projects", NULL @@ -70,6 +83,8 @@ int main(int argc, char *argv[]) { (char **) writable, (char **) readonly, (char **) inaccessible, + (char **) exec, + (char **) no_exec, NULL, &(BindMount) { .source = (char*) "/usr/bin", .destination = (char*) "/etc/systemd", .read_only = true }, 1, &(TemporaryFileSystem) { .path = (char*) "/var", .options = (char*) "ro" }, 1, @@ -87,6 +102,11 @@ int main(int argc, char *argv[]) { 0, NULL, NULL, + NULL, + 0, + NULL, + NULL, + NULL, 0, NULL); if (r < 0) { diff --git a/src/test/test-parse-argument.c b/src/test/test-parse-argument.c new file mode 100644 index 000000000..4081a9f25 --- /dev/null +++ b/src/test/test-parse-argument.c @@ -0,0 +1,63 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "parse-argument.h" +#include "stdio-util.h" +#include "tests.h" + +static void test_parse_json_argument(void) { + log_info("/* %s */", __func__); + + JsonFormatFlags flags = JSON_FORMAT_PRETTY; + + assert_se(parse_json_argument("help", &flags) == 0); + assert_se(flags == JSON_FORMAT_PRETTY); + + assert_se(parse_json_argument("off", &flags) == 1); + assert_se(flags == JSON_FORMAT_OFF); +} + +static void test_parse_path_argument(void) { + log_info("/* %s */", __func__); + + _cleanup_free_ char *path = NULL; + + assert_se(parse_path_argument("help", false, &path) == 0); + assert_se(streq(basename(path), "help")); + + assert_se(parse_path_argument("/", false, &path) == 0); + assert_se(streq(path, "/")); + + assert_se(parse_path_argument("/", true, &path) == 0); + assert_se(path == NULL); +} + +static void test_parse_signal_argument(void) { + log_info("/* %s */", __func__); + + int signal = -1; + + assert_se(parse_signal_argument("help", &signal) == 0); + assert_se(signal == -1); + + assert_se(parse_signal_argument("list", &signal) == 0); + assert_se(signal == -1); + + assert_se(parse_signal_argument("SIGABRT", &signal) == 1); + assert_se(signal == SIGABRT); + + assert_se(parse_signal_argument("ABRT", &signal) == 1); + assert_se(signal == SIGABRT); + + char buf[DECIMAL_STR_MAX(int)]; + xsprintf(buf, "%d", SIGABRT); + assert_se(parse_signal_argument(buf, &signal) == 1); + assert_se(signal == SIGABRT); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_INFO); + + test_parse_json_argument(); + test_parse_path_argument(); + test_parse_signal_argument(); +} diff --git a/src/test/test-parse-util.c b/src/test/test-parse-util.c index 1c969091e..b1b23e2fb 100644 --- a/src/test/test-parse-util.c +++ b/src/test/test-parse-util.c @@ -11,9 +11,6 @@ #include "log.h" #include "parse-util.h" #include "string-util.h" -#if HAVE_SECCOMP -#include "seccomp-util.h" -#endif static void test_parse_boolean(void) { assert_se(parse_boolean("1") == 1); @@ -718,78 +715,6 @@ static void test_safe_atod(void) { assert_se(r == -EINVAL); } -static void test_parse_percent(void) { - assert_se(parse_percent("") == -EINVAL); - assert_se(parse_percent("foo") == -EINVAL); - assert_se(parse_percent("0") == -EINVAL); - assert_se(parse_percent("50") == -EINVAL); - assert_se(parse_percent("100") == -EINVAL); - assert_se(parse_percent("-1") == -EINVAL); - assert_se(parse_percent("0%") == 0); - assert_se(parse_percent("55%") == 55); - assert_se(parse_percent("100%") == 100); - assert_se(parse_percent("-7%") == -ERANGE); - assert_se(parse_percent("107%") == -ERANGE); - assert_se(parse_percent("%") == -EINVAL); - assert_se(parse_percent("%%") == -EINVAL); - assert_se(parse_percent("%1") == -EINVAL); - assert_se(parse_percent("1%%") == -EINVAL); - assert_se(parse_percent("3.2%") == -EINVAL); -} - -static void test_parse_percent_unbounded(void) { - assert_se(parse_percent_unbounded("101%") == 101); - assert_se(parse_percent_unbounded("400%") == 400); -} - -static void test_parse_permille(void) { - assert_se(parse_permille("") == -EINVAL); - assert_se(parse_permille("foo") == -EINVAL); - assert_se(parse_permille("0") == -EINVAL); - assert_se(parse_permille("50") == -EINVAL); - assert_se(parse_permille("100") == -EINVAL); - assert_se(parse_permille("-1") == -EINVAL); - - assert_se(parse_permille("0‰") == 0); - assert_se(parse_permille("555‰") == 555); - assert_se(parse_permille("1000‰") == 1000); - assert_se(parse_permille("-7‰") == -ERANGE); - assert_se(parse_permille("1007‰") == -ERANGE); - assert_se(parse_permille("‰") == -EINVAL); - assert_se(parse_permille("‰‰") == -EINVAL); - assert_se(parse_permille("‰1") == -EINVAL); - assert_se(parse_permille("1‰‰") == -EINVAL); - assert_se(parse_permille("3.2‰") == -EINVAL); - - assert_se(parse_permille("0%") == 0); - assert_se(parse_permille("55%") == 550); - assert_se(parse_permille("55.5%") == 555); - assert_se(parse_permille("100%") == 1000); - assert_se(parse_permille("-7%") == -ERANGE); - assert_se(parse_permille("107%") == -ERANGE); - assert_se(parse_permille("%") == -EINVAL); - assert_se(parse_permille("%%") == -EINVAL); - assert_se(parse_permille("%1") == -EINVAL); - assert_se(parse_permille("1%%") == -EINVAL); - assert_se(parse_permille("3.21%") == -EINVAL); -} - -static void test_parse_permille_unbounded(void) { - assert_se(parse_permille_unbounded("1001‰") == 1001); - assert_se(parse_permille_unbounded("4000‰") == 4000); - assert_se(parse_permille_unbounded("2147483647‰") == 2147483647); - assert_se(parse_permille_unbounded("2147483648‰") == -ERANGE); - assert_se(parse_permille_unbounded("4294967295‰") == -ERANGE); - assert_se(parse_permille_unbounded("4294967296‰") == -ERANGE); - - assert_se(parse_permille_unbounded("101%") == 1010); - assert_se(parse_permille_unbounded("400%") == 4000); - assert_se(parse_permille_unbounded("214748364.7%") == 2147483647); - assert_se(parse_permille_unbounded("214748364.8%") == -ERANGE); - assert_se(parse_permille_unbounded("429496729.5%") == -ERANGE); - assert_se(parse_permille_unbounded("429496729.6%") == -ERANGE); -} - static void test_parse_nice(void) { int n; @@ -855,60 +780,6 @@ static void test_parse_errno(void) { assert_se(parse_errno("EINVALaaa") == -EINVAL); } -static void test_parse_syscall_and_errno(void) { -#if HAVE_SECCOMP - _cleanup_free_ char *n = NULL; - int e; - - assert_se(parse_syscall_and_errno("uname:EILSEQ", &n, &e) >= 0); - assert_se(streq(n, "uname")); - assert_se(e == errno_from_name("EILSEQ") && e >= 0); - n = mfree(n); - - assert_se(parse_syscall_and_errno("uname:EINVAL", &n, &e) >= 0); - assert_se(streq(n, "uname")); - assert_se(e == errno_from_name("EINVAL") && e >= 0); - n = mfree(n); - - assert_se(parse_syscall_and_errno("@sync:4095", &n, &e) >= 0); - assert_se(streq(n, "@sync")); - assert_se(e == 4095); - n = mfree(n); - - /* If errno is omitted, then e is set to -1 */ - assert_se(parse_syscall_and_errno("mount", &n, &e) >= 0); - assert_se(streq(n, "mount")); - assert_se(e == -1); - n = mfree(n); - - /* parse_syscall_and_errno() does not check the syscall name is valid or not. */ - assert_se(parse_syscall_and_errno("hoge:255", &n, &e) >= 0); - assert_se(streq(n, "hoge")); - assert_se(e == 255); - n = mfree(n); - - assert_se(parse_syscall_and_errno("hoge:kill", &n, &e) >= 0); - assert_se(streq(n, "hoge")); - assert_se(e == SECCOMP_ERROR_NUMBER_KILL); - n = mfree(n); - - /* The function checks the syscall name is empty or not. */ - assert_se(parse_syscall_and_errno("", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno(":255", &n, &e) == -EINVAL); - - /* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095, or "kill" */ - assert_se(parse_syscall_and_errno("hoge:4096", &n, &e) == -ERANGE); - assert_se(parse_syscall_and_errno("hoge:-3", &n, &e) == -ERANGE); - assert_se(parse_syscall_and_errno("hoge:12.3", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno("hoge:123junk", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno("hoge:junk123", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno("hoge:255:EILSEQ", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno("hoge:-EINVAL", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno("hoge:EINVALaaa", &n, &e) == -EINVAL); - assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL); -#endif -} - static void test_parse_mtu(void) { uint32_t mtu = 0; @@ -983,14 +854,9 @@ int main(int argc, char *argv[]) { test_safe_atoi64(); test_safe_atoux64(); test_safe_atod(); - test_parse_percent(); - test_parse_percent_unbounded(); - test_parse_permille(); - test_parse_permille_unbounded(); test_parse_nice(); test_parse_dev(); test_parse_errno(); - test_parse_syscall_and_errno(); test_parse_mtu(); test_parse_loadavg_fixed_point(); diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index cb91a1a97..b49b0ae90 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -4,9 +4,11 @@ #include #include "alloc-util.h" +#include "exec-util.h" #include "fd-util.h" #include "macro.h" #include "path-util.h" +#include "process-util.h" #include "rm-rf.h" #include "stat-util.h" #include "string-util.h" @@ -162,12 +164,12 @@ static void test_find_executable_full(void) { log_info("/* %s */", __func__); - assert_se(find_executable_full("sh", true, &p) == 0); + assert_se(find_executable_full("sh", true, &p, NULL) == 0); puts(p); assert_se(streq(basename(p), "sh")); free(p); - assert_se(find_executable_full("sh", false, &p) == 0); + assert_se(find_executable_full("sh", false, &p, NULL) == 0); puts(p); assert_se(streq(basename(p), "sh")); free(p); @@ -179,12 +181,12 @@ static void test_find_executable_full(void) { assert_se(unsetenv("PATH") == 0); - assert_se(find_executable_full("sh", true, &p) == 0); + assert_se(find_executable_full("sh", true, &p, NULL) == 0); puts(p); assert_se(streq(basename(p), "sh")); free(p); - assert_se(find_executable_full("sh", false, &p) == 0); + assert_se(find_executable_full("sh", false, &p, NULL) == 0); puts(p); assert_se(streq(basename(p), "sh")); free(p); @@ -229,6 +231,43 @@ static void test_find_executable(const char *self) { assert_se(find_executable("/proc/filesystems", &p) == -EACCES); } +static void test_find_executable_exec_one(const char *path) { + _cleanup_free_ char *t = NULL; + _cleanup_close_ int fd = -1; + pid_t pid; + int r; + + r = find_executable_full(path, false, &t, &fd); + + log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd); + + assert_se(fd > STDERR_FILENO); + assert_se(path_is_absolute(t)); + if (path_is_absolute(path)) + assert_se(streq(t, path)); + + pid = fork(); + assert_se(pid >= 0); + if (pid == 0) { + r = fexecve_or_execve(fd, t, STRV_MAKE(t, "--version"), STRV_MAKE(NULL)); + log_error_errno(r, "[f]execve: %m"); + _exit(EXIT_FAILURE); + } + + assert_se(wait_for_terminate_and_check(t, pid, WAIT_LOG) == 0); +} + +static void test_find_executable_exec(void) { + log_info("/* %s */", __func__); + + test_find_executable_exec_one("touch"); + test_find_executable_exec_one("/bin/touch"); + + _cleanup_free_ char *script = NULL; + assert_se(get_testdata_dir("test-path-util/script.sh", &script) >= 0); + test_find_executable_exec_one(script); +} + static void test_prefixes(void) { static const char* const values[] = { "/a/b/c/d", @@ -442,6 +481,9 @@ static void test_path_startswith(void) { assert_se(!path_startswith("/foo/bar/barfoo/", "")); assert_se(!path_startswith("/foo/bar/barfoo/", "/bar/foo")); assert_se(!path_startswith("/foo/bar/barfoo/", "/f/b/b/")); + assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo")); + assert_se(!path_startswith("/foo/bar/barfoo/", "/foo/bar/bar")); + assert_se(!path_startswith("/foo/bar/barfoo/", "/fo")); } static void test_prefix_root_one(const char *r, const char *p, const char *expected) { @@ -528,7 +570,10 @@ static void test_path_extract_filename_one(const char *input, const char *output int r; r = path_extract_filename(input, &k); - log_info("%s → %s/%s [expected: %s/%s]", strnull(input), strnull(k), strerror_safe(r), strnull(output), strerror_safe(ret)); + log_info_errno(r, "%s → %s/%m [expected: %s/%s]", + strnull(input), + strnull(k), /* strerror(r) is printed via %m, to avoid that the two strerror()'s overwrite each other's buffers */ + strnull(output), ret < 0 ? strerror_safe(ret) : "-"); assert_se(streq_ptr(k, output)); assert_se(r == ret); } @@ -538,22 +583,22 @@ static void test_path_extract_filename(void) { test_path_extract_filename_one(NULL, NULL, -EINVAL); test_path_extract_filename_one("a/b/c", "c", 0); - test_path_extract_filename_one("a/b/c/", "c", 0); - test_path_extract_filename_one("/", NULL, -EINVAL); - test_path_extract_filename_one("//", NULL, -EINVAL); - test_path_extract_filename_one("///", NULL, -EINVAL); + test_path_extract_filename_one("a/b/c/", "c", O_DIRECTORY); + test_path_extract_filename_one("/", NULL, -EADDRNOTAVAIL); + test_path_extract_filename_one("//", NULL, -EADDRNOTAVAIL); + test_path_extract_filename_one("///", NULL, -EADDRNOTAVAIL); test_path_extract_filename_one(".", NULL, -EINVAL); test_path_extract_filename_one("./.", NULL, -EINVAL); test_path_extract_filename_one("././", NULL, -EINVAL); test_path_extract_filename_one("././/", NULL, -EINVAL); test_path_extract_filename_one("/foo/a", "a", 0); - test_path_extract_filename_one("/foo/a/", "a", 0); + test_path_extract_filename_one("/foo/a/", "a", O_DIRECTORY); test_path_extract_filename_one("", NULL, -EINVAL); test_path_extract_filename_one("a", "a", 0); - test_path_extract_filename_one("a/", "a", 0); + test_path_extract_filename_one("a/", "a", O_DIRECTORY); test_path_extract_filename_one("/a", "a", 0); - test_path_extract_filename_one("/a/", "a", 0); - test_path_extract_filename_one("/////////////a/////////////", "a", 0); + test_path_extract_filename_one("/a/", "a", O_DIRECTORY); + test_path_extract_filename_one("/////////////a/////////////", "a", O_DIRECTORY); test_path_extract_filename_one("xx/.", NULL, -EINVAL); test_path_extract_filename_one("xx/..", NULL, -EINVAL); test_path_extract_filename_one("..", NULL, -EINVAL); @@ -564,9 +609,66 @@ static void test_path_extract_filename(void) { test_path_extract_filename_one("./", NULL, -EINVAL); } +static void test_path_extract_directory_one(const char *input, const char *output, int ret) { + _cleanup_free_ char *k = NULL; + int r; + + r = path_extract_directory(input, &k); + log_info_errno(r, "%s → %s/%m [expected: %s/%s]", + strnull(input), + strnull(k), /* we output strerror_safe(r) via %m here, since otherwise the error buffer might be overwritten twice */ + strnull(output), strerror_safe(ret)); + assert_se(streq_ptr(k, output)); + assert_se(r == ret); + + /* Extra safety check: let's make sure that if we split out the filename too (and it works) the + * joined parts are identical to the original again */ + if (r >= 0) { + _cleanup_free_ char *f = NULL; + + r = path_extract_filename(input, &f); + if (r >= 0) { + _cleanup_free_ char *j = NULL; + + assert_se(j = path_join(k, f)); + assert_se(path_equal(input, j)); + } + } +} + +static void test_path_extract_directory(void) { + log_info("/* %s */", __func__); + + test_path_extract_directory_one(NULL, NULL, -EINVAL); + test_path_extract_directory_one("a/b/c", "a/b", 0); + test_path_extract_directory_one("a/b/c/", "a/b", 0); + test_path_extract_directory_one("/", NULL, -EADDRNOTAVAIL); + test_path_extract_directory_one("//", NULL, -EADDRNOTAVAIL); + test_path_extract_directory_one("///", NULL, -EADDRNOTAVAIL); + test_path_extract_directory_one(".", NULL, -EDESTADDRREQ); + test_path_extract_directory_one("./.", ".", 0); + test_path_extract_directory_one("././", ".", 0); + test_path_extract_directory_one("././/", ".", 0); + test_path_extract_directory_one("/foo/a", "/foo", 0); + test_path_extract_directory_one("/foo/a/", "/foo", 0); + test_path_extract_directory_one("", NULL, -EINVAL); + test_path_extract_directory_one("a", NULL, -EDESTADDRREQ); + test_path_extract_directory_one("a/", NULL, -EDESTADDRREQ); + test_path_extract_directory_one("/a", "/", 0); + test_path_extract_directory_one("/a/", "/", 0); + test_path_extract_directory_one("/////////////a/////////////", "/", 0); + test_path_extract_directory_one("xx/.", "xx", 0); + test_path_extract_directory_one("xx/..", "xx", 0); + test_path_extract_directory_one("..", NULL, -EDESTADDRREQ); + test_path_extract_directory_one("/..", "/", 0); + test_path_extract_directory_one("../", NULL, -EDESTADDRREQ); + test_path_extract_directory_one(".", NULL, -EDESTADDRREQ); + test_path_extract_directory_one("/.", "/", 0); + test_path_extract_directory_one("./", NULL, -EDESTADDRREQ); +} + static void test_filename_is_valid(void) { - char foo[FILENAME_MAX+2]; - int i; + char foo[NAME_MAX+2]; log_info("/* %s */", __func__); @@ -579,9 +681,8 @@ static void test_filename_is_valid(void) { assert_se(!filename_is_valid("bar/foo/")); assert_se(!filename_is_valid("bar//")); - for (i=0; i= 0); assert_se(prctl(PR_SET_NAME, "testa") >= 0); @@ -598,8 +603,8 @@ static void test_ioprio_class_from_to_string(void) { test_ioprio_class_from_to_string_one("1", 1); test_ioprio_class_from_to_string_one("7", 7); test_ioprio_class_from_to_string_one("8", 8); - test_ioprio_class_from_to_string_one("9", -1); - test_ioprio_class_from_to_string_one("-1", -1); + test_ioprio_class_from_to_string_one("9", -EINVAL); + test_ioprio_class_from_to_string_one("-1", -EINVAL); } static void test_setpriority_closest(void) { diff --git a/src/test/test-random-util.c b/src/test/test-random-util.c index 02a73ecdb..44103efa6 100644 --- a/src/test/test-random-util.c +++ b/src/test/test-random-util.c @@ -1,17 +1,20 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include + #include "hexdecoct.h" -#include "random-util.h" #include "log.h" +#include "memory-util.h" +#include "random-util.h" +#include "terminal-util.h" #include "tests.h" static void test_genuine_random_bytes(RandomFlags flags) { uint8_t buf[16] = {}; - unsigned i; log_info("/* %s */", __func__); - for (i = 1; i < sizeof buf; i++) { + for (size_t i = 1; i < sizeof buf; i++) { assert_se(genuine_random_bytes(buf, i, flags) == 0); if (i + 1 < sizeof buf) assert_se(buf[i] == 0); @@ -22,11 +25,10 @@ static void test_genuine_random_bytes(RandomFlags flags) { static void test_pseudo_random_bytes(void) { uint8_t buf[16] = {}; - unsigned i; log_info("/* %s */", __func__); - for (i = 1; i < sizeof buf; i++) { + for (size_t i = 1; i < sizeof buf; i++) { pseudo_random_bytes(buf, i); if (i + 1 < sizeof buf) assert_se(buf[i] == 0); @@ -36,9 +38,11 @@ static void test_pseudo_random_bytes(void) { } static void test_rdrand(void) { - int r, i; + int r; - for (i = 0; i < 10; i++) { + log_info("/* %s */", __func__); + + for (unsigned i = 0; i < 10; i++) { unsigned long x = 0; r = rdrand(&x); @@ -51,6 +55,50 @@ static void test_rdrand(void) { } } +#define TOTAL 100000 + +static void test_random_u64_range_one(unsigned mod) { + log_info("/* %s(%u) */", __func__, mod); + + unsigned max = 0, count[mod]; + zero(count); + + for (unsigned i = 0; i < TOTAL; i++) { + uint64_t x; + + x = random_u64_range(mod); + + log_trace("%05u: %"PRIu64, i, x); + count[x]++; + max = MAX(max, count[x]); + } + + /* Print histogram: vertical axis — value, horizontal axis — count. + * + * The expected value is always TOTAL/mod, because the distribution should be flat. The expected + * variance is TOTAL×p×(1-p), where p==1/mod, and standard deviation the root of the variance. + * Assert that the deviation from the expected value is less than 6 standard deviations. + */ + unsigned scale = 2 * max / (columns() < 20 ? 80 : columns() - 20); + double exp = (double) TOTAL / mod; + + for (size_t i = 0; i < mod; i++) { + double dev = (count[i] - exp) / sqrt(exp * (mod > 1 ? mod - 1 : 1) / mod); + log_debug("%02zu: %5u (%+.3f)%*s", + i, count[i], dev, + count[i] / scale, "x"); + + assert_se(fabs(dev) < 6); /* 6 sigma is excessive, but this check should be enough to + * identify catastrophic failure while minimizing false + * positives. */ + } +} + +static void test_random_u64_range(void) { + for (unsigned mod = 1; mod < 29; mod++) + test_random_u64_range_one(mod); +} + int main(int argc, char **argv) { test_setup_logging(LOG_DEBUG); @@ -61,8 +109,8 @@ int main(int argc, char **argv) { test_genuine_random_bytes(RANDOM_ALLOW_INSECURE); test_pseudo_random_bytes(); - test_rdrand(); + test_random_u64_range(); return 0; } diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c index 057ae6b2b..2ebe81df4 100644 --- a/src/test/test-rlimit-util.c +++ b/src/test/test-rlimit-util.c @@ -53,16 +53,16 @@ int main(int argc, char *argv[]) { assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0); assert_se(rlimit_from_string("NOFILE") == RLIMIT_NOFILE); - assert_se(rlimit_from_string("LimitNOFILE") == -1); - assert_se(rlimit_from_string("RLIMIT_NOFILE") == -1); - assert_se(rlimit_from_string("xxxNOFILE") == -1); - assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1); + assert_se(rlimit_from_string("LimitNOFILE") == -EINVAL); + assert_se(rlimit_from_string("RLIMIT_NOFILE") == -EINVAL); + assert_se(rlimit_from_string("xxxNOFILE") == -EINVAL); + assert_se(rlimit_from_string("DefaultLimitNOFILE") == -EINVAL); assert_se(rlimit_from_string_harder("NOFILE") == RLIMIT_NOFILE); assert_se(rlimit_from_string_harder("LimitNOFILE") == RLIMIT_NOFILE); assert_se(rlimit_from_string_harder("RLIMIT_NOFILE") == RLIMIT_NOFILE); - assert_se(rlimit_from_string_harder("xxxNOFILE") == -1); - assert_se(rlimit_from_string_harder("DefaultLimitNOFILE") == -1); + assert_se(rlimit_from_string_harder("xxxNOFILE") == -EINVAL); + assert_se(rlimit_from_string_harder("DefaultLimitNOFILE") == -EINVAL); for (i = 0; i < _RLIMIT_MAX; i++) { _cleanup_free_ char *prefixed = NULL; diff --git a/src/test/test-seccomp.c b/src/test/test-seccomp.c index 10393b6a7..b1f917eb5 100644 --- a/src/test/test-seccomp.c +++ b/src/test/test-seccomp.c @@ -41,6 +41,64 @@ # define SECCOMP_RESTRICT_ADDRESS_FAMILIES_BROKEN 0 #endif +static void test_parse_syscall_and_errno(void) { + _cleanup_free_ char *n = NULL; + int e; + + assert_se(parse_syscall_and_errno("uname:EILSEQ", &n, &e) >= 0); + assert_se(streq(n, "uname")); + assert_se(e == errno_from_name("EILSEQ") && e >= 0); + n = mfree(n); + + assert_se(parse_syscall_and_errno("uname:EINVAL", &n, &e) >= 0); + assert_se(streq(n, "uname")); + assert_se(e == errno_from_name("EINVAL") && e >= 0); + n = mfree(n); + + assert_se(parse_syscall_and_errno("@sync:4095", &n, &e) >= 0); + assert_se(streq(n, "@sync")); + assert_se(e == 4095); + n = mfree(n); + + /* If errno is omitted, then e is set to -1 */ + assert_se(parse_syscall_and_errno("mount", &n, &e) >= 0); + assert_se(streq(n, "mount")); + assert_se(e == -1); + n = mfree(n); + + /* parse_syscall_and_errno() does not check the syscall name is valid or not. */ + assert_se(parse_syscall_and_errno("hoge:255", &n, &e) >= 0); + assert_se(streq(n, "hoge")); + assert_se(e == 255); + n = mfree(n); + + /* 0 is also a valid errno. */ + assert_se(parse_syscall_and_errno("hoge:0", &n, &e) >= 0); + assert_se(streq(n, "hoge")); + assert_se(e == 0); + n = mfree(n); + + assert_se(parse_syscall_and_errno("hoge:kill", &n, &e) >= 0); + assert_se(streq(n, "hoge")); + assert_se(e == SECCOMP_ERROR_NUMBER_KILL); + n = mfree(n); + + /* The function checks the syscall name is empty or not. */ + assert_se(parse_syscall_and_errno("", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno(":255", &n, &e) == -EINVAL); + + /* errno must be a valid errno name or number between 0 and ERRNO_MAX == 4095, or "kill" */ + assert_se(parse_syscall_and_errno("hoge:4096", &n, &e) == -ERANGE); + assert_se(parse_syscall_and_errno("hoge:-3", &n, &e) == -ERANGE); + assert_se(parse_syscall_and_errno("hoge:12.3", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno("hoge:123junk", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno("hoge:junk123", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno("hoge:255:EILSEQ", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno("hoge:-EINVAL", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno("hoge:EINVALaaa", &n, &e) == -EINVAL); + assert_se(parse_syscall_and_errno("hoge:", &n, &e) == -EINVAL); +} + static void test_seccomp_arch_to_string(void) { uint32_t a, b; const char *name; @@ -1075,6 +1133,7 @@ static void test_restrict_suid_sgid(void) { int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); + test_parse_syscall_and_errno(); test_seccomp_arch_to_string(); test_architecture_table(); test_syscall_filter_set_find(); diff --git a/src/test/test-set.c b/src/test/test-set.c index b4d07b207..f89c968f2 100644 --- a/src/test/test-set.c +++ b/src/test/test-set.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ +#include "random-util.h" #include "set.h" #include "strv.h" @@ -227,6 +228,77 @@ static void test_set_strjoin(void) { assert_se(STR_IN_SET(joined, "xxxaaaxxxbbbxxx", "xxxbbbxxxaaaxxx")); } +static void test_set_equal(void) { + _cleanup_set_free_ Set *a = NULL, *b = NULL; + void *p; + int r; + + assert_se(a = set_new(NULL)); + assert_se(b = set_new(NULL)); + + assert_se(set_equal(a, a)); + assert_se(set_equal(b, b)); + assert_se(set_equal(a, b)); + assert_se(set_equal(b, a)); + assert_se(set_equal(NULL, a)); + assert_se(set_equal(NULL, b)); + assert_se(set_equal(a, NULL)); + assert_se(set_equal(b, NULL)); + assert_se(set_equal(NULL, NULL)); + + for (unsigned i = 0; i < 333; i++) { + p = INT32_TO_PTR(1 + (random_u32() & 0xFFFU)); + + r = set_put(a, p); + assert_se(r >= 0 || r == -EEXIST); + } + + assert_se(set_put(a, INT32_TO_PTR(0x1000U)) >= 0); + + assert_se(set_size(a) >= 2); + assert_se(set_size(a) <= 334); + + assert_se(!set_equal(a, b)); + assert_se(!set_equal(b, a)); + assert_se(!set_equal(a, NULL)); + + SET_FOREACH(p, a) + assert_se(set_put(b, p) >= 0); + + assert_se(set_equal(a, b)); + assert_se(set_equal(b, a)); + + assert_se(set_remove(a, INT32_TO_PTR(0x1000U)) == INT32_TO_PTR(0x1000U)); + + assert_se(!set_equal(a, b)); + assert_se(!set_equal(b, a)); + + assert_se(set_remove(b, INT32_TO_PTR(0x1000U)) == INT32_TO_PTR(0x1000U)); + + assert_se(set_equal(a, b)); + assert_se(set_equal(b, a)); + + assert_se(set_put(b, INT32_TO_PTR(0x1001U)) >= 0); + + assert_se(!set_equal(a, b)); + assert_se(!set_equal(b, a)); + + assert_se(set_put(a, INT32_TO_PTR(0x1001U)) >= 0); + + assert_se(set_equal(a, b)); + assert_se(set_equal(b, a)); + + set_clear(a); + + assert_se(!set_equal(a, b)); + assert_se(!set_equal(b, a)); + + set_clear(b); + + assert_se(set_equal(a, b)); + assert_se(set_equal(b, a)); +} + int main(int argc, const char *argv[]) { test_set_steal_first(); test_set_free_with_destructor(); @@ -238,6 +310,7 @@ int main(int argc, const char *argv[]) { test_set_ensure_put(); test_set_ensure_consume(); test_set_strjoin(); + test_set_equal(); return 0; } diff --git a/src/test/test-signal-util.c b/src/test/test-signal-util.c index e5096a8c0..76ab9b8ad 100644 --- a/src/test/test-signal-util.c +++ b/src/test/test-signal-util.c @@ -105,39 +105,32 @@ static void test_signal_from_string(void) { } static void test_block_signals(void) { - sigset_t ss; - - assert_se(sigprocmask(0, NULL, &ss) >= 0); - - assert_se(sigismember(&ss, SIGUSR1) == 0); - assert_se(sigismember(&ss, SIGALRM) == 0); - assert_se(sigismember(&ss, SIGVTALRM) == 0); + assert_se(signal_is_blocked(SIGUSR1) == 0); + assert_se(signal_is_blocked(SIGALRM) == 0); + assert_se(signal_is_blocked(SIGVTALRM) == 0); { BLOCK_SIGNALS(SIGUSR1, SIGVTALRM); - assert_se(sigprocmask(0, NULL, &ss) >= 0); - assert_se(sigismember(&ss, SIGUSR1) == 1); - assert_se(sigismember(&ss, SIGALRM) == 0); - assert_se(sigismember(&ss, SIGVTALRM) == 1); - + assert_se(signal_is_blocked(SIGUSR1) > 0); + assert_se(signal_is_blocked(SIGALRM) == 0); + assert_se(signal_is_blocked(SIGVTALRM) > 0); } - assert_se(sigprocmask(0, NULL, &ss) >= 0); - assert_se(sigismember(&ss, SIGUSR1) == 0); - assert_se(sigismember(&ss, SIGALRM) == 0); - assert_se(sigismember(&ss, SIGVTALRM) == 0); + assert_se(signal_is_blocked(SIGUSR1) == 0); + assert_se(signal_is_blocked(SIGALRM) == 0); + assert_se(signal_is_blocked(SIGVTALRM) == 0); } static void test_ignore_signals(void) { - assert_se(ignore_signals(SIGINT, -1) >= 0); + assert_se(ignore_signals(SIGINT) >= 0); assert_se(kill(getpid_cached(), SIGINT) >= 0); - assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); + assert_se(ignore_signals(SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE) >= 0); assert_se(kill(getpid_cached(), SIGUSR1) >= 0); assert_se(kill(getpid_cached(), SIGUSR2) >= 0); assert_se(kill(getpid_cached(), SIGTERM) >= 0); assert_se(kill(getpid_cached(), SIGPIPE) >= 0); - assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE, -1) >= 0); + assert_se(default_signals(SIGINT, SIGUSR1, SIGUSR2, SIGTERM, SIGPIPE) >= 0); } int main(int argc, char *argv[]) { diff --git a/src/test/test-socket-netlink.c b/src/test/test-socket-netlink.c index 704cc01e6..da484a400 100644 --- a/src/test/test-socket-netlink.c +++ b/src/test/test-socket-netlink.c @@ -47,7 +47,8 @@ static void test_socket_address_parse(void) { const int default_family = socket_ipv6_is_supported() ? AF_INET6 : AF_INET; - test_socket_address_parse_one("65535", 0, default_family, "[::]:65535"); + test_socket_address_parse_one("65535", 0, default_family, + default_family == AF_INET6 ? "[::]:65535": "0.0.0.0:65535"); /* The checks below will pass even if ipv6 is disabled in * kernel. The underlying glibc's inet_pton() is just a string @@ -65,14 +66,15 @@ static void test_socket_address_parse(void) { test_socket_address_parse_one("[::1]%lo%lo:1234", -EINVAL, 0, NULL); test_socket_address_parse_one("[::1]% lo:1234", -EINVAL, 0, NULL); - test_socket_address_parse_one("8888", 0, default_family, "[::]:8888"); + test_socket_address_parse_one("8888", 0, default_family, + default_family == AF_INET6 ? "[::]:8888": "0.0.0.0:8888"); test_socket_address_parse_one("[2001:0db8:0000:85a3:0000:0000:ac1f:8001]:8888", 0, AF_INET6, "[2001:db8:0:85a3::ac1f:8001]:8888"); test_socket_address_parse_one("[::1]:8888", 0, AF_INET6, NULL); test_socket_address_parse_one("[::1]:1234%lo", 0, AF_INET6, NULL); test_socket_address_parse_one("[::1]:0%lo", -EINVAL, 0, NULL); test_socket_address_parse_one("[::1]%lo", -EINVAL, 0, NULL); - test_socket_address_parse_one("[::1]:1234%lo%lo", -ENODEV, 0, NULL); + test_socket_address_parse_one("[::1]:1234%lo%lo", -EINVAL, 0, NULL); test_socket_address_parse_one("[::1]:1234%xxxxasdf", -ENODEV, 0, NULL); test_socket_address_parse_one("192.168.1.254:8888", 0, AF_INET, NULL); test_socket_address_parse_one("/foo/bar", 0, AF_UNIX, NULL); diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c index 4ff7d714f..584253c2f 100644 --- a/src/test/test-socket-util.c +++ b/src/test/test-socket-util.c @@ -504,6 +504,11 @@ static void test_flush_accept(void) { assert_se(flush_accept(listen_seqpacket) >= 0); } +static void test_ipv6_enabled(void) { + log_info("IPv6 supported: %s", yes_no(socket_ipv6_is_supported())); + log_info("IPv6 enabled: %s", yes_no(socket_ipv6_is_enabled())); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -519,6 +524,7 @@ int main(int argc, char *argv[]) { test_send_nodata_nofd(); test_send_emptydata(); test_flush_accept(); + test_ipv6_enabled(); return 0; } diff --git a/src/test/test-stat-util.c b/src/test/test-stat-util.c index 9aca09c4d..4dd18be65 100644 --- a/src/test/test-stat-util.c +++ b/src/test/test-stat-util.c @@ -2,6 +2,7 @@ #include #include +#include #include #include "alloc-util.h" @@ -67,18 +68,22 @@ static void test_path_is_temporary_fs(void) { assert_se(path_is_temporary_fs("/i-dont-exist") == -ENOENT); } -static void test_fd_is_network_ns(void) { +static void test_fd_is_ns(void) { _cleanup_close_ int fd = -1; - assert_se(fd_is_network_ns(STDIN_FILENO) == 0); - assert_se(fd_is_network_ns(STDERR_FILENO) == 0); - assert_se(fd_is_network_ns(STDOUT_FILENO) == 0); + assert_se(fd_is_ns(STDIN_FILENO, CLONE_NEWNET) == 0); + assert_se(fd_is_ns(STDERR_FILENO, CLONE_NEWNET) == 0); + assert_se(fd_is_ns(STDOUT_FILENO, CLONE_NEWNET) == 0); assert_se((fd = open("/proc/self/ns/mnt", O_CLOEXEC|O_RDONLY)) >= 0); - assert_se(IN_SET(fd_is_network_ns(fd), 0, -EUCLEAN)); + assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 0, -EUCLEAN)); + fd = safe_close(fd); + + assert_se((fd = open("/proc/self/ns/ipc", O_CLOEXEC|O_RDONLY)) >= 0); + assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWIPC), 1, -EUCLEAN)); fd = safe_close(fd); assert_se((fd = open("/proc/self/ns/net", O_CLOEXEC|O_RDONLY)) >= 0); - assert_se(IN_SET(fd_is_network_ns(fd), 1, -EUCLEAN)); + assert_se(IN_SET(fd_is_ns(fd, CLONE_NEWNET), 1, -EUCLEAN)); } static void test_device_major_minor_valid(void) { @@ -159,7 +164,7 @@ int main(int argc, char *argv[]) { test_is_symlink(); test_path_is_fs_type(); test_path_is_temporary_fs(); - test_fd_is_network_ns(); + test_fd_is_ns(); test_device_major_minor_valid(); test_device_path_make_canonical(); diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 867be19c8..0cdef3fb7 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -12,7 +12,7 @@ static ssize_t add_string(struct strbuf *sb, const char *s) { } static void test_strbuf(void) { - _cleanup_(strbuf_cleanupp) struct strbuf *sb; + _cleanup_(strbuf_freep) struct strbuf *sb; _cleanup_strv_free_ char **l; ssize_t a, b, c, d, e, f, g, h; diff --git a/src/test/test-string-util.c b/src/test/test-string-util.c index b74eb180f..15ea24ae4 100644 --- a/src/test/test-string-util.c +++ b/src/test/test-string-util.c @@ -244,9 +244,9 @@ static void test_strextend(void) { assert_se(strextend(&str, NULL)); assert_se(streq_ptr(str, "")); - assert_se(strextend(&str, "", "0", "", "", "123", NULL)); + assert_se(strextend(&str, "", "0", "", "", "123")); assert_se(streq_ptr(str, "0123")); - assert_se(strextend(&str, "456", "78", "9", NULL)); + assert_se(strextend(&str, "456", "78", "9")); assert_se(streq_ptr(str, "0123456789")); } @@ -265,13 +265,13 @@ static void test_strextend_with_separator(void) { assert_se(streq_ptr(str, "")); str = mfree(str); - assert_se(strextend_with_separator(&str, "xyz", "a", "bb", "ccc", NULL)); + assert_se(strextend_with_separator(&str, "xyz", "a", "bb", "ccc")); assert_se(streq_ptr(str, "axyzbbxyzccc")); str = mfree(str); - assert_se(strextend_with_separator(&str, ",", "start", "", "1", "234", NULL)); + assert_se(strextend_with_separator(&str, ",", "start", "", "1", "234")); assert_se(streq_ptr(str, "start,,1,234")); - assert_se(strextend_with_separator(&str, ";", "more", "5", "678", NULL)); + assert_se(strextend_with_separator(&str, ";", "more", "5", "678")); assert_se(streq_ptr(str, "start,,1,234;more;5;678")); } @@ -345,6 +345,12 @@ static void test_strjoina(void) { actual = strjoina("foo", NULL, "bar"); assert_se(streq(actual, "foo")); + + actual = strjoina("/sys/fs/cgroup/", "dn", "/a/b/c", "/cgroup.procs"); + assert_se(streq(actual, "/sys/fs/cgroup/dn/a/b/c/cgroup.procs")); + + actual = strjoina("/sys/fs/cgroup/", "dn", NULL, NULL); + assert_se(streq(actual, "/sys/fs/cgroup/dn")); } static void test_strjoin(void) { @@ -886,6 +892,84 @@ static void test_string_contains_word(void) { assert_se(!string_contains_word("a:b:cc", ":#", ":cc")); } +static void test_strverscmp_improved_one(const char *newer, const char *older) { + log_info("/* %s(%s, %s) */", __func__, strnull(newer), strnull(older)); + + assert_se(strverscmp_improved(newer, newer) == 0); + assert_se(strverscmp_improved(newer, older) > 0); + assert_se(strverscmp_improved(older, newer) < 0); + assert_se(strverscmp_improved(older, older) == 0); +} + +static void test_strverscmp_improved(void) { + static const char * const versions[] = { + "", + "~1", + "ab", + "abb", + "abc", + "0001", + "002", + "12", + "122", + "122.9", + "123~rc1", + "123", + "123-a", + "123-a.1", + "123-a1", + "123-a1.1", + "123-3", + "123-3.1", + "123^patch1", + "123^1", + "123.a-1", + "123.1-1", + "123a-1", + "124", + NULL, + }; + const char * const *p, * const *q; + + STRV_FOREACH(p, versions) + STRV_FOREACH(q, p + 1) + test_strverscmp_improved_one(*q, *p); + + test_strverscmp_improved_one("123.45-67.89", "123.45-67.88"); + test_strverscmp_improved_one("123.45-67.89a", "123.45-67.89"); + test_strverscmp_improved_one("123.45-67.89", "123.45-67.ab"); + test_strverscmp_improved_one("123.45-67.89", "123.45-67.9"); + test_strverscmp_improved_one("123.45-67.89", "123.45-67"); + test_strverscmp_improved_one("123.45-67.89", "123.45-66.89"); + test_strverscmp_improved_one("123.45-67.89", "123.45-9.99"); + test_strverscmp_improved_one("123.45-67.89", "123.42-99.99"); + test_strverscmp_improved_one("123.45-67.89", "123-99.99"); + + /* '~' : pre-releases */ + test_strverscmp_improved_one("123.45-67.89", "123~rc1-99.99"); + test_strverscmp_improved_one("123-45.67.89", "123~rc1-99.99"); + test_strverscmp_improved_one("123~rc2-67.89", "123~rc1-99.99"); + test_strverscmp_improved_one("123^aa2-67.89", "123~rc1-99.99"); + test_strverscmp_improved_one("123aa2-67.89", "123~rc1-99.99"); + + /* '-' : separator between version and release. */ + test_strverscmp_improved_one("123.45-67.89", "123-99.99"); + test_strverscmp_improved_one("123^aa2-67.89", "123-99.99"); + test_strverscmp_improved_one("123aa2-67.89", "123-99.99"); + + /* '^' : patch releases */ + test_strverscmp_improved_one("123.45-67.89", "123^45-67.89"); + test_strverscmp_improved_one("123^aa2-67.89", "123^aa1-99.99"); + test_strverscmp_improved_one("123aa2-67.89", "123^aa2-67.89"); + + /* '.' : point release */ + test_strverscmp_improved_one("123aa2-67.89", "123.aa2-67.89"); + test_strverscmp_improved_one("123.ab2-67.89", "123.aa2-67.89"); + + /* invalid characters */ + assert_se(strverscmp_improved("123_aa2-67.89", "123aa+2-67.89") == 0); +} + int main(int argc, char *argv[]) { test_setup_logging(LOG_DEBUG); @@ -923,6 +1007,7 @@ int main(int argc, char *argv[]) { test_string_extract_line(); test_string_contains_word_strv(); test_string_contains_word(); + test_strverscmp_improved(); return 0; } diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 6b5005f9f..039bb2c78 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -118,6 +118,20 @@ static const char* const input_table_one_empty[] = { NULL, }; +static const char* const input_table_unescape[] = { + "ID_VENDOR=QEMU", + "ID_VENDOR_ENC=QEMUx20x20x20x20", + "ID_MODEL_ENC=QEMUx20HARDDISKx20x20x20", + NULL, +}; + +static const char* const input_table_retain_escape[] = { + "ID_VENDOR=QEMU", + "ID_VENDOR_ENC=QEMU\\x20\\x20\\x20\\x20", + "ID_MODEL_ENC=QEMU\\x20HARDDISK\\x20\\x20\\x20", + NULL, +}; + static void test_strv_find(void) { log_info("/* %s */", __func__); @@ -319,12 +333,12 @@ static void test_strv_split(void) { l = strv_free_erase(l); assert_se(strv_split_full(&l, " 'one' \" two\t three \"' four five", NULL, - EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 2); + EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 2); assert_se(strv_equal(l, (char**) input_table_quoted_joined)); l = strv_free_erase(l); - assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_CUNESCAPE_RELAX) == 1); + assert_se(strv_split_full(&l, "\\", NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX | EXTRACT_UNESCAPE_RELAX) == 1); assert_se(strv_equal(l, STRV_MAKE("\\"))); } @@ -453,6 +467,25 @@ static void test_strv_split_newlines(void) { assert_se(streq(*s, input_table_multiple[i++])); } +static void test_strv_split_newlines_full(void) { + const char str[] = + "ID_VENDOR=QEMU\n" + "ID_VENDOR_ENC=QEMU\\x20\\x20\\x20\\x20\n" + "ID_MODEL_ENC=QEMU\\x20HARDDISK\\x20\\x20\\x20\n" + "\n\n\n"; + _cleanup_strv_free_ char **l = NULL; + + log_info("/* %s */", __func__); + + assert_se(strv_split_newlines_full(&l, str, 0) == 3); + assert_se(strv_equal(l, (char**) input_table_unescape)); + + l = strv_free(l); + + assert_se(strv_split_newlines_full(&l, str, EXTRACT_RETAIN_ESCAPE) == 3); + assert_se(strv_equal(l, (char**) input_table_retain_escape)); +} + static void test_strv_split_nulstr(void) { _cleanup_strv_free_ char **l = NULL; const char nulstr[] = "str0\0str1\0str2\0str3\0"; @@ -1031,6 +1064,7 @@ int main(int argc, char *argv[]) { test_strv_split_full(); test_strv_split_colon_pairs(); test_strv_split_newlines(); + test_strv_split_newlines_full(); test_strv_split_nulstr(); test_strv_parse_nulstr(); test_strv_overlap(); diff --git a/src/test/test-tables.c b/src/test/test-tables.c index e25cf9e5d..3e5df0459 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -8,6 +8,7 @@ #include "condition.h" #include "device-private.h" #include "device.h" +#include "discover-image.h" #include "execute.h" #include "import-util.h" #include "install.h" @@ -18,7 +19,6 @@ #include "locale-util.h" #include "log.h" #include "logs-show.h" -#include "machine-image.h" #include "mount.h" #include "path.h" #include "process-util.h" @@ -50,7 +50,7 @@ int main(int argc, char **argv) { test_table(collect_mode, COLLECT_MODE); test_table(condition_result, CONDITION_RESULT); test_table(condition_type, CONDITION_TYPE); - test_table(device_action, DEVICE_ACTION); + test_table(device_action, SD_DEVICE_ACTION); test_table(device_state, DEVICE_STATE); test_table(dns_over_tls_mode, DNS_OVER_TLS_MODE); test_table(dnssec_mode, DNSSEC_MODE); @@ -73,6 +73,7 @@ int main(int argc, char **argv) { test_table(log_target, LOG_TARGET); test_table(mac_address_policy, MAC_ADDRESS_POLICY); test_table(managed_oom_mode, MANAGED_OOM_MODE); + test_table(managed_oom_preference, MANAGED_OOM_PREFERENCE); test_table(manager_state, MANAGER_STATE); test_table(manager_timestamp, MANAGER_TIMESTAMP); test_table(mount_exec_command, MOUNT_EXEC_COMMAND); @@ -124,5 +125,7 @@ int main(int argc, char **argv) { test_table_sparse(object_compressed, OBJECT_COMPRESSED); + assert_cc(sizeof(sd_device_action_t) == sizeof(int64_t)); + return EXIT_SUCCESS; } diff --git a/src/test/test-tmpfile-util.c b/src/test/test-tmpfile-util.c new file mode 100644 index 000000000..83bac15d0 --- /dev/null +++ b/src/test/test-tmpfile-util.c @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "alloc-util.h" +#include "errno-util.h" +#include "log.h" +#include "string-util.h" +#include "tests.h" +#include "tmpfile-util.h" + +static void test_tempfn_random_one(const char *p, const char *extra, const char *expect, int ret) { + _cleanup_free_ char *s = NULL; + int r; + + r = tempfn_random(p, extra, &s); + log_info_errno(r, "%s+%s → %s vs. %s (%i/%m vs. %i/%s)", p, strna(extra), strna(s), strna(expect), r, ret, strerror_safe(ret)); + + assert(!s == !expect); + if (s) { + const char *suffix; + + assert_se(suffix = startswith(s, expect)); + assert_se(in_charset(suffix, HEXDIGITS)); + assert_se(strlen(suffix) == 16); + } + assert(ret == r); +} + +static void test_tempfn_random(void) { + test_tempfn_random_one("", NULL, NULL, -EINVAL); + test_tempfn_random_one(".", NULL, NULL, -EINVAL); + test_tempfn_random_one("..", NULL, NULL, -EINVAL); + test_tempfn_random_one("/", NULL, NULL, -EADDRNOTAVAIL); + + test_tempfn_random_one("foo", NULL, ".#foo", 0); + test_tempfn_random_one("foo", "bar", ".#barfoo", 0); + test_tempfn_random_one("/tmp/foo", NULL, "/tmp/.#foo", 0); + test_tempfn_random_one("/tmp/foo", "bar", "/tmp/.#barfoo", 0); + test_tempfn_random_one("./foo", NULL, "./.#foo", 0); + test_tempfn_random_one("./foo", "bar", "./.#barfoo", 0); + test_tempfn_random_one("../foo", NULL, "../.#foo", 0); + test_tempfn_random_one("../foo", "bar", "../.#barfoo", 0); + + test_tempfn_random_one("foo/", NULL, ".#foo", 0); + test_tempfn_random_one("foo/", "bar", ".#barfoo", 0); + test_tempfn_random_one("/tmp/foo/", NULL, "/tmp/.#foo", 0); + test_tempfn_random_one("/tmp/foo/", "bar", "/tmp/.#barfoo", 0); + test_tempfn_random_one("./foo/", NULL, "./.#foo", 0); + test_tempfn_random_one("./foo/", "bar", "./.#barfoo", 0); + test_tempfn_random_one("../foo/", NULL, "../.#foo", 0); + test_tempfn_random_one("../foo/", "bar", "../.#barfoo", 0); +} + +static void test_tempfn_xxxxxx_one(const char *p, const char *extra, const char *expect, int ret) { + _cleanup_free_ char *s = NULL; + int r; + + r = tempfn_xxxxxx(p, extra, &s); + log_info_errno(r, "%s+%s → %s vs. %s (%i/%m vs. %i/%s)", p, strna(extra), strna(s), strna(expect), r, ret, strerror_safe(ret)); + + assert(!s == !expect); + if (s) { + const char *suffix; + + assert_se(suffix = startswith(s, expect)); + assert_se(streq(suffix, "XXXXXX")); + } + assert(ret == r); +} + +static void test_tempfn_xxxxxx(void) { + test_tempfn_xxxxxx_one("", NULL, NULL, -EINVAL); + test_tempfn_xxxxxx_one(".", NULL, NULL, -EINVAL); + test_tempfn_xxxxxx_one("..", NULL, NULL, -EINVAL); + test_tempfn_xxxxxx_one("/", NULL, NULL, -EADDRNOTAVAIL); + + test_tempfn_xxxxxx_one("foo", NULL, ".#foo", 0); + test_tempfn_xxxxxx_one("foo", "bar", ".#barfoo", 0); + test_tempfn_xxxxxx_one("/tmp/foo", NULL, "/tmp/.#foo", 0); + test_tempfn_xxxxxx_one("/tmp/foo", "bar", "/tmp/.#barfoo", 0); + test_tempfn_xxxxxx_one("./foo", NULL, "./.#foo", 0); + test_tempfn_xxxxxx_one("./foo", "bar", "./.#barfoo", 0); + test_tempfn_xxxxxx_one("../foo", NULL, "../.#foo", 0); + test_tempfn_xxxxxx_one("../foo", "bar", "../.#barfoo", 0); + + test_tempfn_xxxxxx_one("foo/", NULL, ".#foo", 0); + test_tempfn_xxxxxx_one("foo/", "bar", ".#barfoo", 0); + test_tempfn_xxxxxx_one("/tmp/foo/", NULL, "/tmp/.#foo", 0); + test_tempfn_xxxxxx_one("/tmp/foo/", "bar", "/tmp/.#barfoo", 0); + test_tempfn_xxxxxx_one("./foo/", NULL, "./.#foo", 0); + test_tempfn_xxxxxx_one("./foo/", "bar", "./.#barfoo", 0); + test_tempfn_xxxxxx_one("../foo/", NULL, "../.#foo", 0); + test_tempfn_xxxxxx_one("../foo/", "bar", "../.#barfoo", 0); +} + +int main(int argc, char **argv) { + test_setup_logging(LOG_DEBUG); + + test_tempfn_random(); + test_tempfn_xxxxxx(); + + return 0; +} diff --git a/src/test/test-udev-util.c b/src/test/test-udev-util.c index b0213f8c3..f34c5c27d 100644 --- a/src/test/test-udev-util.c +++ b/src/test/test-udev-util.c @@ -181,6 +181,92 @@ static void test_parse_value_unicode(void) { ); } +static void test_udev_replace_whitespace_one_len(const char *str, size_t len, const char *expected) { + _cleanup_free_ char *result = NULL; + int r; + + result = new(char, len + 1); + assert_se(result); + r = udev_replace_whitespace(str, result, len); + assert_se((size_t) r == strlen(expected)); + assert_se(streq(result, expected)); +} + +static void test_udev_replace_whitespace_one(const char *str, const char *expected) { + test_udev_replace_whitespace_one_len(str, strlen(str), expected); +} + +static void test_udev_replace_whitespace(void) { + log_info("/* %s */", __func__); + + test_udev_replace_whitespace_one("hogehoge", "hogehoge"); + test_udev_replace_whitespace_one("hoge hoge", "hoge_hoge"); + test_udev_replace_whitespace_one(" hoge hoge ", "hoge_hoge"); + test_udev_replace_whitespace_one(" ", ""); + test_udev_replace_whitespace_one("hoge ", "hoge"); + + test_udev_replace_whitespace_one_len("hoge hoge ", 9, "hoge_hoge"); + test_udev_replace_whitespace_one_len("hoge hoge ", 8, "hoge_hog"); + test_udev_replace_whitespace_one_len("hoge hoge ", 7, "hoge_ho"); + test_udev_replace_whitespace_one_len("hoge hoge ", 6, "hoge_h"); + test_udev_replace_whitespace_one_len("hoge hoge ", 5, "hoge"); + test_udev_replace_whitespace_one_len("hoge hoge ", 4, "hoge"); + test_udev_replace_whitespace_one_len("hoge hoge ", 3, "hog"); + test_udev_replace_whitespace_one_len("hoge hoge ", 2, "ho"); + test_udev_replace_whitespace_one_len("hoge hoge ", 1, "h"); + test_udev_replace_whitespace_one_len("hoge hoge ", 0, ""); + + test_udev_replace_whitespace_one_len(" hoge hoge ", 16, "hoge_hoge"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 15, "hoge_hoge"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 14, "hoge_hog"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 13, "hoge_ho"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 12, "hoge_h"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 11, "hoge"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 10, "hoge"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 9, "hoge"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 8, "hoge"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 7, "hog"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 6, "ho"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 5, "h"); + test_udev_replace_whitespace_one_len(" hoge hoge ", 4, ""); + test_udev_replace_whitespace_one_len(" hoge hoge ", 3, ""); + test_udev_replace_whitespace_one_len(" hoge hoge ", 2, ""); + test_udev_replace_whitespace_one_len(" hoge hoge ", 1, ""); + test_udev_replace_whitespace_one_len(" hoge hoge ", 0, ""); +} + +static void test_udev_resolve_subsys_kernel_one(const char *str, bool read_value, int retval, const char *expected) { + char result[PATH_MAX] = ""; + int r; + + r = udev_resolve_subsys_kernel(str, result, sizeof(result), read_value); + log_info("\"%s\" → expect: \"%s\", %d, actual: \"%s\", %d", str, strnull(expected), retval, result, r); + assert_se(r == retval); + if (r >= 0) + assert_se(streq(result, expected)); +} + +static void test_udev_resolve_subsys_kernel(void) { + log_info("/* %s */", __func__); + + test_udev_resolve_subsys_kernel_one("hoge", false, -EINVAL, NULL); + test_udev_resolve_subsys_kernel_one("[hoge", false, -EINVAL, NULL); + test_udev_resolve_subsys_kernel_one("[hoge/foo", false, -EINVAL, NULL); + test_udev_resolve_subsys_kernel_one("[hoge/]", false, -ENODEV, NULL); + + test_udev_resolve_subsys_kernel_one("[net/lo]", false, 0, "/sys/devices/virtual/net/lo"); + test_udev_resolve_subsys_kernel_one("[net/lo]/", false, 0, "/sys/devices/virtual/net/lo"); + test_udev_resolve_subsys_kernel_one("[net/lo]hoge", false, 0, "/sys/devices/virtual/net/lo/hoge"); + test_udev_resolve_subsys_kernel_one("[net/lo]/hoge", false, 0, "/sys/devices/virtual/net/lo/hoge"); + + test_udev_resolve_subsys_kernel_one("[net/lo]", true, -EINVAL, NULL); + test_udev_resolve_subsys_kernel_one("[net/lo]/", true, -EINVAL, NULL); + test_udev_resolve_subsys_kernel_one("[net/lo]hoge", true, 0, ""); + test_udev_resolve_subsys_kernel_one("[net/lo]/hoge", true, 0, ""); + test_udev_resolve_subsys_kernel_one("[net/lo]address", true, 0, "00:00:00:00:00:00"); + test_udev_resolve_subsys_kernel_one("[net/lo]/address", true, 0, "00:00:00:00:00:00"); +} + int main(int argc, char **argv) { test_parse_value(); test_parse_value_with_backslashes(); @@ -198,5 +284,8 @@ int main(int argc, char **argv) { test_parse_value_invalid_termination(); test_parse_value_unicode(); + test_udev_replace_whitespace(); + test_udev_resolve_subsys_kernel(); + return EXIT_SUCCESS; } diff --git a/src/test/test-udev.c b/src/test/test-udev.c index 8acf86da3..488b965c8 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -102,7 +102,7 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_debug_errno(r, "Failed to open device '%s'", devpath); - assert_se(event = udev_event_new(dev, 0, NULL)); + assert_se(event = udev_event_new(dev, 0, NULL, log_get_max_level())); assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, SIGHUP, SIGCHLD, -1) >= 0); diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index c7b6d8dd5..042b94634 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -75,7 +75,7 @@ static void test_utf8_encoded_valid_unichar(void) { assert_se(utf8_encoded_valid_unichar("\302\256", 1) == -EINVAL); /* truncated */ assert_se(utf8_encoded_valid_unichar("\302\256", 2) == 2); assert_se(utf8_encoded_valid_unichar("\302\256", 3) == 2); - assert_se(utf8_encoded_valid_unichar("\302\256", (size_t) -1) == 2); + assert_se(utf8_encoded_valid_unichar("\302\256", SIZE_MAX) == 2); assert_se(utf8_encoded_valid_unichar("a", 1) == 1); assert_se(utf8_encoded_valid_unichar("a", 2) == 1); assert_se(utf8_encoded_valid_unichar("\341\204", 1) == -EINVAL); /* truncated, potentially valid */ @@ -196,7 +196,7 @@ static void test_utf8_n_codepoints(void) { assert_se(utf8_n_codepoints("串") == 1); assert_se(utf8_n_codepoints("") == 0); assert_se(utf8_n_codepoints("…👊🔪💐…") == 5); - assert_se(utf8_n_codepoints("\xF1") == (size_t) -1); + assert_se(utf8_n_codepoints("\xF1") == SIZE_MAX); } static void test_utf8_console_width(void) { @@ -207,7 +207,7 @@ static void test_utf8_console_width(void) { assert_se(utf8_console_width("串") == 2); assert_se(utf8_console_width("") == 0); assert_se(utf8_console_width("…👊🔪💐…") == 8); - assert_se(utf8_console_width("\xF1") == (size_t) -1); + assert_se(utf8_console_width("\xF1") == SIZE_MAX); } static void test_utf8_to_utf16(void) { diff --git a/src/timedate/timedatectl.c b/src/timedate/timedatectl.c index abc792a45..fb08f9ad2 100644 --- a/src/timedate/timedatectl.c +++ b/src/timedate/timedatectl.c @@ -916,12 +916,11 @@ static int help(void) { " -p --property=NAME Show only properties by this name\n" " -a --all Show all properties, including empty ones\n" " --value When showing properties, only print the value\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight() - , ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -1052,7 +1051,7 @@ static int run(int argc, char *argv[]) { int r; setlocale(LC_ALL, ""); - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/timedate/timedated.c b/src/timedate/timedated.c index 8149facb3..567244dc2 100644 --- a/src/timedate/timedated.c +++ b/src/timedate/timedated.c @@ -211,7 +211,7 @@ static int context_parse_ntp_services_from_disk(Context *c) { break; word = strstrip(line); - if (isempty(word) || startswith("#", word)) + if (isempty(word) || startswith(word, "#")) continue; r = context_add_ntp_service(c, word, *f); @@ -725,7 +725,7 @@ static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error if (r < 0) return r; - if (lrtc == c->local_rtc) + if (lrtc == c->local_rtc && !fix_system) return sd_bus_reply_method_return(m, NULL); r = bus_verify_polkit_async( @@ -742,13 +742,15 @@ static int method_set_local_rtc(sd_bus_message *m, void *userdata, sd_bus_error if (r == 0) return 1; - c->local_rtc = lrtc; + if (lrtc != c->local_rtc) { + c->local_rtc = lrtc; - /* 1. Write new configuration file */ - r = context_write_data_local_rtc(c); - if (r < 0) { - log_error_errno(r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC"); - return sd_bus_error_set_errnof(error, r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC"); + /* 1. Write new configuration file */ + r = context_write_data_local_rtc(c); + if (r < 0) { + log_error_errno(r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC"); + return sd_bus_error_set_errnof(error, r, "Failed to set RTC to %s: %m", lrtc ? "local" : "UTC"); + } } /* 2. Tell the kernel our timezone */ @@ -1109,7 +1111,7 @@ static int run(int argc, char *argv[]) { _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; int r; - log_setup_service(); + log_setup(); r = service_parse_argv("systemd-timedated.service", "Manage the system clock and timezone and NTP enablement.", diff --git a/src/timesync/80-systemd-timesync.list b/src/timesync/80-systemd-timesync.list index d5959ade8..95e15f786 100644 --- a/src/timesync/80-systemd-timesync.list +++ b/src/timesync/80-systemd-timesync.list @@ -1 +1,4 @@ +# This file is part of systemd. +# See systemd-timedated.service(8) for more information. + systemd-timesyncd.service diff --git a/src/timesync/meson.build b/src/timesync/meson.build index 571e3fc7e..30d2a0cae 100644 --- a/src/timesync/meson.build +++ b/src/timesync/meson.build @@ -1,32 +1,45 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -systemd_timesyncd_sources = files(''' - timesyncd.c - timesyncd-bus.c - timesyncd-bus.h - timesyncd-conf.c - timesyncd-conf.h - timesyncd-manager.c - timesyncd-manager.h - timesyncd-ntp-message.h - timesyncd-server.c - timesyncd-server.h -'''.split()) +sources = files( + 'timesyncd-conf.c', + 'timesyncd-conf.h', + 'timesyncd-manager.c', + 'timesyncd-manager.h', + 'timesyncd-ntp-message.h', + 'timesyncd-server.c', + 'timesyncd-server.h') -timesyncd_gperf_c = custom_target( +systemd_timesyncd_sources = files( + 'timesyncd.c', + 'timesyncd-bus.c', + 'timesyncd-bus.h') + +sources += custom_target( 'timesyncd-gperf.c', input : 'timesyncd-gperf.gperf', output : 'timesyncd-gperf.c', command : [gperf, '@INPUT@', '--output-file', '@OUTPUT@']) -systemd_timesyncd_sources += [timesyncd_gperf_c] +if get_option('link-timesyncd-shared') + timesyncd_link_with = [libshared] +else + timesyncd_link_with = [libsystemd_static, + libshared_static, + libbasic_gcrypt] +endif + +libtimesyncd_core = static_library( + 'timesyncd-core', + sources, + include_directories : includes, + link_with : [timesyncd_link_with]) if conf.get('ENABLE_TIMESYNCD') == 1 timesyncd_conf = configure_file( input : 'timesyncd.conf.in', output : 'timesyncd.conf', configuration : substs) - if install_sysconfdir + if install_sysconfdir_samples install_data(timesyncd_conf, install_dir : pkgsysconfdir) endif @@ -41,15 +54,8 @@ endif ############################################################ tests += [ - [['src/timesync/test-timesync.c', - 'src/timesync/timesyncd-manager.c', - 'src/timesync/timesyncd-manager.h', - 'src/timesync/timesyncd-conf.c', - 'src/timesync/timesyncd-conf.h', - 'src/timesync/timesyncd-server.c', - 'src/timesync/timesyncd-server.h', - timesyncd_gperf_c], - [libshared], - [libm], - 'ENABLE_TIMESYNCD'], + [['src/timesync/test-timesync.c'], + [libtimesyncd_core, + libshared], + [libm]], ] diff --git a/src/timesync/timesyncd-bus.c b/src/timesync/timesyncd-bus.c index c5ad5feb9..1a14564e0 100644 --- a/src/timesync/timesyncd-bus.c +++ b/src/timesync/timesyncd-bus.c @@ -165,7 +165,7 @@ static const sd_bus_vtable manager_vtable[] = { SD_BUS_PROPERTY("FallbackNTPServers", "as", property_get_servers, offsetof(Manager, fallback_servers), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("ServerName", "s", property_get_current_server_name, offsetof(Manager, current_server_name), 0), SD_BUS_PROPERTY("ServerAddress", "(iay)", property_get_current_server_address, offsetof(Manager, current_server_address), 0), - SD_BUS_PROPERTY("RootDistanceMaxUSec", "t", bus_property_get_usec, offsetof(Manager, max_root_distance_usec), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("RootDistanceMaxUSec", "t", bus_property_get_usec, offsetof(Manager, root_distance_max_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PollIntervalMinUSec", "t", bus_property_get_usec, offsetof(Manager, poll_interval_min_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PollIntervalMaxUSec", "t", bus_property_get_usec, offsetof(Manager, poll_interval_max_usec), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("PollIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, poll_interval_usec), 0), diff --git a/src/timesync/timesyncd-conf.c b/src/timesync/timesyncd-conf.c index 2c3114613..8f34441e1 100644 --- a/src/timesync/timesyncd-conf.c +++ b/src/timesync/timesyncd-conf.c @@ -124,5 +124,10 @@ int manager_parse_config_file(Manager *m) { m->poll_interval_max_usec = MAX(NTP_POLL_INTERVAL_MAX_USEC, m->poll_interval_min_usec * 32); } + if (m->connection_retry_usec < 1 * USEC_PER_SEC) { + log_warning("Invalid ConnectionRetrySec=. Using default value."); + m->connection_retry_usec = DEFAULT_CONNECTION_RETRY_USEC; + } + return r; } diff --git a/src/timesync/timesyncd-gperf.gperf b/src/timesync/timesyncd-gperf.gperf index b5020276a..556a2e9ba 100644 --- a/src/timesync/timesyncd-gperf.gperf +++ b/src/timesync/timesyncd-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -17,9 +18,10 @@ struct ConfigPerfItem; %struct-type %includes %% -Time.NTP, config_parse_servers, SERVER_SYSTEM, 0 -Time.Servers, config_parse_servers, SERVER_SYSTEM, 0 -Time.FallbackNTP, config_parse_servers, SERVER_FALLBACK, 0 -Time.RootDistanceMaxSec, config_parse_sec, 0, offsetof(Manager, max_root_distance_usec) -Time.PollIntervalMinSec, config_parse_sec, 0, offsetof(Manager, poll_interval_min_usec) -Time.PollIntervalMaxSec, config_parse_sec, 0, offsetof(Manager, poll_interval_max_usec) +Time.NTP, config_parse_servers, SERVER_SYSTEM, 0 +Time.Servers, config_parse_servers, SERVER_SYSTEM, 0 +Time.FallbackNTP, config_parse_servers, SERVER_FALLBACK, 0 +Time.RootDistanceMaxSec, config_parse_sec, 0, offsetof(Manager, root_distance_max_usec) +Time.PollIntervalMinSec, config_parse_sec, 0, offsetof(Manager, poll_interval_min_usec) +Time.PollIntervalMaxSec, config_parse_sec, 0, offsetof(Manager, poll_interval_max_usec) +Time.ConnectionRetrySec, config_parse_sec, 0, offsetof(Manager, connection_retry_usec) diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c index 93ba4ef87..42b6c29d3 100644 --- a/src/timesync/timesyncd-manager.c +++ b/src/timesync/timesyncd-manager.c @@ -34,7 +34,7 @@ #define ADJ_SETOFFSET 0x0100 /* add 'time' to current time */ #endif -/* expected accuracy of time synchronization; used to adjust the poll interval */ +/* Expected accuracy of time synchronization; used to adjust the poll interval */ #define NTP_ACCURACY_SEC 0.2 /* @@ -45,12 +45,11 @@ #define NTP_MAX_ADJUST 0.4 /* Default of maximum acceptable root distance in microseconds. */ -#define NTP_MAX_ROOT_DISTANCE (5 * USEC_PER_SEC) +#define NTP_ROOT_DISTANCE_MAX_USEC (5 * USEC_PER_SEC) /* Maximum number of missed replies before selecting another source. */ #define NTP_MAX_MISSED_REPLIES 2 -#define RETRY_USEC (30*USEC_PER_SEC) #define RATELIMIT_INTERVAL_USEC (10*USEC_PER_SEC) #define RATELIMIT_BURST 10 @@ -73,6 +72,13 @@ static double ts_to_d(const struct timespec *ts) { return ts->tv_sec + (1.0e-9 * ts->tv_nsec); } +static uint32_t graceful_add_offset_1900_1970(time_t t) { + /* Adds OFFSET_1900_1970 to t and returns it as 32bit value. This is handles overflows + * gracefully in a deterministic and well-defined way by cutting off the top bits. */ + uint64_t a = (uint64_t) t + OFFSET_1900_1970; + return (uint32_t) (a & UINT64_C(0xFFFFFFFF)); +} + static int manager_timeout(sd_event_source *source, usec_t usec, void *userdata) { _cleanup_free_ char *pretty = NULL; Manager *m = userdata; @@ -122,7 +128,7 @@ static int manager_send_request(Manager *m) { */ assert_se(clock_gettime(clock_boottime_or_monotonic(), &m->trans_time_mon) >= 0); assert_se(clock_gettime(CLOCK_REALTIME, &m->trans_time) >= 0); - ntpmsg.trans_time.sec = htobe32(m->trans_time.tv_sec + OFFSET_1900_1970); + ntpmsg.trans_time.sec = htobe32(graceful_add_offset_1900_1970(m->trans_time.tv_sec)); ntpmsg.trans_time.frac = htobe32(m->trans_time.tv_nsec); server_address_pretty(m->current_server_address, &pretty); @@ -477,7 +483,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re m->missed_replies = 0; /* check our "time cookie" (we just stored nanoseconds in the fraction field) */ - if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 || + if (be32toh(ntpmsg.origin_time.sec) != graceful_add_offset_1900_1970(m->trans_time.tv_sec) || be32toh(ntpmsg.origin_time.frac) != (unsigned long) m->trans_time.tv_nsec) { log_debug("Invalid reply; not our transmit time. Ignoring."); return 0; @@ -508,7 +514,7 @@ static int manager_receive_response(sd_event_source *source, int fd, uint32_t re } root_distance = ntp_ts_short_to_d(&ntpmsg.root_delay) / 2 + ntp_ts_short_to_d(&ntpmsg.root_dispersion); - if (root_distance > (double) m->max_root_distance_usec / (double) USEC_PER_SEC) { + if (root_distance > (double) m->root_distance_max_usec / (double) USEC_PER_SEC) { log_info("Server has too large root distance. Disconnecting."); return manager_connect(m); } @@ -787,7 +793,8 @@ int manager_connect(Manager *m) { if (!ratelimit_below(&m->ratelimit)) { log_debug("Delaying attempts to contact servers."); - r = sd_event_add_time_relative(m->event, &m->event_retry, clock_boottime_or_monotonic(), RETRY_USEC, 0, manager_retry_connect, m); + r = sd_event_add_time_relative(m->event, &m->event_retry, clock_boottime_or_monotonic(), m->connection_retry_usec, + 0, manager_retry_connect, m); if (r < 0) return log_error_errno(r, "Failed to create retry timer: %m"); @@ -915,9 +922,9 @@ void manager_flush_server_names(Manager *m, ServerType t) { server_name_free(m->fallback_servers); } -void manager_free(Manager *m) { +Manager* manager_free(Manager *m) { if (!m) - return; + return NULL; manager_disconnect(m); manager_flush_server_names(m, SERVER_SYSTEM); @@ -934,7 +941,7 @@ void manager_free(Manager *m) { sd_bus_flush_close_unref(m->bus); - free(m); + return mfree(m); } static int manager_network_read_link_servers(Manager *m) { @@ -1081,10 +1088,12 @@ int manager_new(Manager **ret) { if (!m) return -ENOMEM; - m->max_root_distance_usec = NTP_MAX_ROOT_DISTANCE; + m->root_distance_max_usec = NTP_ROOT_DISTANCE_MAX_USEC; m->poll_interval_min_usec = NTP_POLL_INTERVAL_MIN_USEC; m->poll_interval_max_usec = NTP_POLL_INTERVAL_MAX_USEC; + m->connection_retry_usec = DEFAULT_CONNECTION_RETRY_USEC; + m->server_socket = m->clock_watch_fd = -1; m->ratelimit = (RateLimit) { RATELIMIT_INTERVAL_USEC, RATELIMIT_BURST }; diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h index 940a88ed7..4aa7575a8 100644 --- a/src/timesync/timesyncd-manager.h +++ b/src/timesync/timesyncd-manager.h @@ -27,6 +27,8 @@ typedef struct Manager Manager; #define NTP_RETRY_INTERVAL_MIN_USEC (15 * USEC_PER_SEC) #define NTP_RETRY_INTERVAL_MAX_USEC (6 * 60 * USEC_PER_SEC) /* 6 minutes */ +#define DEFAULT_CONNECTION_RETRY_USEC (30*USEC_PER_SEC) + struct Manager { sd_bus *bus; sd_event *event; @@ -60,6 +62,7 @@ struct Manager { struct timespec trans_time_mon; struct timespec trans_time; usec_t retry_interval; + usec_t connection_retry_usec; bool pending; /* poll timer */ @@ -76,7 +79,7 @@ struct Manager { } samples[8]; unsigned samples_idx; double samples_jitter; - usec_t max_root_distance_usec; + usec_t root_distance_max_usec; /* last change */ bool jumped; @@ -100,7 +103,7 @@ struct Manager { }; int manager_new(Manager **ret); -void manager_free(Manager *m); +Manager* manager_free(Manager *m); DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); diff --git a/src/timesync/timesyncd.c b/src/timesync/timesyncd.c index 1f59bf14e..e6a2b0668 100644 --- a/src/timesync/timesyncd.c +++ b/src/timesync/timesyncd.c @@ -97,7 +97,7 @@ static int run(int argc, char *argv[]) { int r; log_set_facility(LOG_CRON); - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/timesync/timesyncd.conf.in b/src/timesync/timesyncd.conf.in index f91c034a0..8a9a14cf0 100644 --- a/src/timesync/timesyncd.conf.in +++ b/src/timesync/timesyncd.conf.in @@ -1,13 +1,14 @@ # This file is part of systemd. # -# systemd is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. +# systemd is free software; you can redistribute it and/or modify it under the +# terms of the GNU Lesser General Public License as published by the Free +# Software Foundation; either version 2.1 of the License, or (at your option) +# any later version. # -# Entries in this file show the compile time defaults. -# You can change settings by editing this file. -# Defaults can be restored by simply deleting this file. +# Entries in this file show the compile time defaults. Local configuration +# should be created by either modifying this file, or by creating "drop-ins" in +# the system.conf.d/ subdirectory. The latter is generally recommended. +# Defaults can be restored by simply deleting this file and all drop-ins. # # See timesyncd.conf(5) for details. diff --git a/src/time-wait-sync/time-wait-sync.c b/src/timesync/wait-sync.c similarity index 100% rename from src/time-wait-sync/time-wait-sync.c rename to src/timesync/wait-sync.c diff --git a/src/tmpfiles/meson.build b/src/tmpfiles/meson.build index 2d61568c6..c72b386cd 100644 --- a/src/tmpfiles/meson.build +++ b/src/tmpfiles/meson.build @@ -1,7 +1,12 @@ # SPDX-License-Identifier: LGPL-2.1-or-later -systemd_tmpfiles_sources = [ - 'src/tmpfiles/tmpfiles.c', - 'src/shared/offline-passwd.c', - 'src/shared/offline-passwd.h', +systemd_tmpfiles_sources = files( + 'tmpfiles.c', + 'offline-passwd.c', + 'offline-passwd.h') + +tests += [ + [['src/tmpfiles/test-offline-passwd.c', + 'src/tmpfiles/offline-passwd.c', + 'src/tmpfiles/offline-passwd.h']], ] diff --git a/src/shared/offline-passwd.c b/src/tmpfiles/offline-passwd.c similarity index 100% rename from src/shared/offline-passwd.c rename to src/tmpfiles/offline-passwd.c diff --git a/src/shared/offline-passwd.h b/src/tmpfiles/offline-passwd.h similarity index 100% rename from src/shared/offline-passwd.h rename to src/tmpfiles/offline-passwd.h diff --git a/src/test/test-offline-passwd.c b/src/tmpfiles/test-offline-passwd.c similarity index 100% rename from src/test/test-offline-passwd.c rename to src/tmpfiles/test-offline-passwd.c diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c index 9906c70ee..846e45655 100644 --- a/src/tmpfiles/tmpfiles.c +++ b/src/tmpfiles/tmpfiles.c @@ -27,6 +27,7 @@ #include "def.h" #include "dirent-util.h" #include "dissect-image.h" +#include "env-util.h" #include "escape.h" #include "fd-util.h" #include "fileio.h" @@ -45,6 +46,7 @@ #include "mountpoint-util.h" #include "offline-passwd.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -60,6 +62,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "terminal-util.h" #include "umask-util.h" #include "user-util.h" @@ -1308,11 +1311,15 @@ static int fd_set_attribute(Item *item, int fd, const char *path, const struct s if (procfs_fd < 0) return log_error_errno(procfs_fd, "Failed to re-open '%s': %m", path); - r = chattr_fd(procfs_fd, f, item->attribute_mask, NULL); - if (r < 0) - log_full_errno(IN_SET(r, -ENOTTY, -EOPNOTSUPP) ? LOG_DEBUG : LOG_WARNING, - r, - "Cannot set file attribute for '%s', value=0x%08x, mask=0x%08x, ignoring: %m", + unsigned previous, current; + r = chattr_full(NULL, procfs_fd, f, item->attribute_mask, &previous, ¤t, true); + if (r == -ENOANO) + log_warning("Cannot set file attributes for '%s', maybe due to incompatibility in specified attributes, " + "previous=0x%08x, current=0x%08x, expected=0x%08x, ignoring.", + path, previous, current, (previous & ~item->attribute_mask) | (f & item->attribute_mask)); + else if (r < 0) + log_full_errno(ERRNO_IS_NOT_SUPPORTED(r) ? LOG_DEBUG : LOG_WARNING, r, + "Cannot set file attributes for '%s', value=0x%08x, mask=0x%08x, ignoring: %m", path, item->attribute_value, item->attribute_mask); return 0; @@ -1583,7 +1590,7 @@ typedef enum { CREATION_EXISTING, CREATION_FORCE, _CREATION_MODE_MAX, - _CREATION_MODE_INVALID = -1 + _CREATION_MODE_INVALID = -EINVAL, } CreationMode; static const char *const creation_mode_verb_table[_CREATION_MODE_MAX] = { @@ -1609,8 +1616,13 @@ static int create_directory_or_subvolume(const char *path, mode_t mode, bool sub return pfd; if (subvol) { - if (btrfs_is_subvol(empty_to_root(arg_root)) <= 0) - + r = getenv_bool("SYSTEMD_TMPFILES_FORCE_SUBVOL"); + if (r < 0) { + if (r != -ENXIO) /* env var is unset */ + log_warning_errno(r, "Cannot parse value of $SYSTEMD_TMPFILES_FORCE_SUBVOL, ignoring."); + r = btrfs_is_subvol(empty_to_root(arg_root)) > 0; + } + if (!r) /* Don't create a subvolume unless the root directory is * one, too. We do this under the assumption that if the * root directory is just a plain directory (i.e. very @@ -2991,8 +3003,8 @@ static int help(void) { if (r < 0) return log_oom(); - printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" - "Creates, deletes and cleans up volatile and temporary files and directories.\n\n" + printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n" + "\n%sCreates, deletes and cleans up volatile and temporary files and directories.%s\n\n" " -h --help Show this help\n" " --user Execute user configuration\n" " --version Show package version\n" @@ -3008,10 +3020,11 @@ static int help(void) { " --image=PATH Operate on disk image as filesystem root\n" " --replace=PATH Treat arguments as replacement for PATH\n" " --no-pager Do not pipe output into a pager\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -3102,7 +3115,7 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_ROOT: - r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_root); + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_root); if (r < 0) return r; break; @@ -3112,7 +3125,7 @@ static int parse_argv(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "This systemd-tmpfiles version is compiled without support for --image=."); #else - r = parse_path_argument_and_warn(optarg, /* suppress_root= */ false, &arg_image); + r = parse_path_argument(optarg, /* suppress_root= */ false, &arg_image); if (r < 0) return r; #endif @@ -3357,7 +3370,17 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - log_setup_service(); + log_setup(); + + /* We require /proc/ for a lot of our operations, i.e. for adjusting access modes, for anything + * SELinux related, for recursive operation, for xattr, acl and chattr handling, for btrfs stuff and + * a lot more. It's probably the majority of invocations where /proc/ is required. Since people + * apparently invoke it without anyway and are surprised about the failures, let's catch this early + * and output a nice and friendly warning. */ + if (proc_mounted() == 0) + return log_error_errno(SYNTHETIC_ERRNO(ENOSYS), + "/proc/ is not mounted, but required for successful operation of systemd-tmpfiles. " + "Please mount /proc/. Alternatively, consider using the --root= or --image= switches."); /* Descending down file system trees might take a lot of fds */ (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE); @@ -3383,7 +3406,7 @@ static int run(int argc, char *argv[]) { if (!j) return log_oom(); - if (!strextend(&t, "\n\t", j, NULL)) + if (!strextend(&t, "\n\t", j)) return log_oom(); } diff --git a/src/tty-ask-password-agent/tty-ask-password-agent.c b/src/tty-ask-password-agent/tty-ask-password-agent.c index 1940792b9..5ee82c708 100644 --- a/src/tty-ask-password-agent/tty-ask-password-agent.c +++ b/src/tty-ask-password-agent/tty-ask-password-agent.c @@ -6,7 +6,6 @@ #include #include #include -#include #include #include #include @@ -366,7 +365,7 @@ static int process_and_watch_password_files(bool watch) { } for (;;) { - int timeout = -1; + usec_t timeout = USEC_INFINITY; r = process_password_files(); if (r < 0) { @@ -385,16 +384,11 @@ static int process_and_watch_password_files(bool watch) { if (!watch) break; - if (poll(pollfd, _FD_MAX, timeout) < 0) { - if (errno == EINTR) - continue; - - return -errno; - } - - if (pollfd[FD_SIGNAL].revents & POLLNVAL || - pollfd[FD_INOTIFY].revents & POLLNVAL) - return -EBADF; + r = ppoll_usec(pollfd, _FD_MAX, timeout); + if (r == -EINTR) + continue; + if (r < 0) + return r; if (pollfd[FD_INOTIFY].revents != 0) (void) flush_fd(notify); @@ -424,10 +418,9 @@ static int help(void) { " --wall Continuously forward password requests to wall\n" " --plymouth Ask question with Plymouth instead of on TTY\n" " --console Ask question on /dev/console instead of current TTY\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -685,7 +678,7 @@ static int ask_on_consoles(char *argv[]) { static int run(int argc, char *argv[]) { int r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/udev/.vimrc b/src/udev/.vimrc deleted file mode 100644 index 366fbdca4..000000000 --- a/src/udev/.vimrc +++ /dev/null @@ -1,4 +0,0 @@ -" 'set exrc' in ~/.vimrc will read .vimrc from the current directory -set tabstop=8 -set shiftwidth=8 -set expandtab diff --git a/src/udev/ata_id/ata_id.c b/src/udev/ata_id/ata_id.c index ce0bf5d24..0284630fa 100644 --- a/src/udev/ata_id/ata_id.c +++ b/src/udev/ata_id/ata_id.c @@ -23,8 +23,8 @@ #include #include +#include "device-nodes.h" #include "fd-util.h" -#include "libudev-util.h" #include "log.h" #include "memory-util.h" #include "udev-util.h" @@ -483,13 +483,13 @@ int main(int argc, char *argv[]) { memcpy(model, id.model, 40); model[40] = '\0'; - udev_util_encode_string(model, model_enc, sizeof(model_enc)); - util_replace_whitespace((char *) id.model, model, 40); - util_replace_chars(model, NULL); - util_replace_whitespace((char *) id.serial_no, serial, 20); - util_replace_chars(serial, NULL); - util_replace_whitespace((char *) id.fw_rev, revision, 8); - util_replace_chars(revision, NULL); + encode_devnode_name(model, model_enc, sizeof(model_enc)); + udev_replace_whitespace((char *) id.model, model, 40); + udev_replace_chars(model, NULL); + udev_replace_whitespace((char *) id.serial_no, serial, 20); + udev_replace_chars(serial, NULL); + udev_replace_whitespace((char *) id.fw_rev, revision, 8); + udev_replace_chars(revision, NULL); if (export) { /* Set this to convey the disk speaks the ATA protocol */ diff --git a/src/udev/cdrom_id/cdrom_id.c b/src/udev/cdrom_id/cdrom_id.c index 804cc7c5a..60c7b4922 100644 --- a/src/udev/cdrom_id/cdrom_id.c +++ b/src/udev/cdrom_id/cdrom_id.c @@ -3,93 +3,164 @@ * cdrom_id - optical drive and media information prober */ -#include #include #include -#include #include #include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include "log.h" +#include "fd-util.h" +#include "main-func.h" #include "memory-util.h" #include "random-util.h" +#include "sort-util.h" +#include "string-table.h" +#include "string-util.h" #include "udev-util.h" +#include "unaligned.h" -/* device info */ -static unsigned cd_cd_rom; -static unsigned cd_cd_r; -static unsigned cd_cd_rw; -static unsigned cd_dvd_rom; -static unsigned cd_dvd_r; -static unsigned cd_dvd_rw; -static unsigned cd_dvd_ram; -static unsigned cd_dvd_plus_r; -static unsigned cd_dvd_plus_rw; -static unsigned cd_dvd_plus_r_dl; -static unsigned cd_dvd_plus_rw_dl; -static unsigned cd_bd; -static unsigned cd_bd_r; -static unsigned cd_bd_re; -static unsigned cd_hddvd; -static unsigned cd_hddvd_r; -static unsigned cd_hddvd_rw; -static unsigned cd_mo; -static unsigned cd_mrw; -static unsigned cd_mrw_w; +static bool arg_eject = false; +static bool arg_lock = false; +static bool arg_unlock = false; +static const char *arg_node = NULL; -/* media info */ -static unsigned cd_media; -static unsigned cd_media_cd_rom; -static unsigned cd_media_cd_r; -static unsigned cd_media_cd_rw; -static unsigned cd_media_dvd_rom; -static unsigned cd_media_dvd_r; -static unsigned cd_media_dvd_rw; -static unsigned cd_media_dvd_rw_ro; /* restricted overwrite mode */ -static unsigned cd_media_dvd_rw_seq; /* sequential mode */ -static unsigned cd_media_dvd_ram; -static unsigned cd_media_dvd_plus_r; -static unsigned cd_media_dvd_plus_rw; -static unsigned cd_media_dvd_plus_r_dl; -static unsigned cd_media_dvd_plus_rw_dl; -static unsigned cd_media_bd; -static unsigned cd_media_bd_r; -static unsigned cd_media_bd_re; -static unsigned cd_media_hddvd; -static unsigned cd_media_hddvd_r; -static unsigned cd_media_hddvd_rw; -static unsigned cd_media_mo; -static unsigned cd_media_mrw; -static unsigned cd_media_mrw_w; +typedef enum Feature { + FEATURE_RW_NONREMOVABLE = 0x01, + FEATURE_RW_REMOVABLE = 0x02, -static const char *cd_media_state = NULL; -static unsigned cd_media_session_next; -static unsigned cd_media_session_count; -static unsigned cd_media_track_count; -static unsigned cd_media_track_count_data; -static unsigned cd_media_track_count_audio; -static unsigned long long int cd_media_session_last_offset; + FEATURE_MO_SE = 0x03, /* sector erase */ + FEATURE_MO_WO = 0x04, /* write once */ + FEATURE_MO_AS = 0x05, /* advance storage */ -#define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13])) -#define SK(errcode) (((errcode) >> 16) & 0xF) -#define ASC(errcode) (((errcode) >> 8) & 0xFF) -#define ASCQ(errcode) ((errcode) & 0xFF) + FEATURE_CD_ROM = 0x08, + FEATURE_CD_R = 0x09, + FEATURE_CD_RW = 0x0a, -static void info_scsi_cmd_err(const char *cmd, int err) { - if (err == -1) - log_debug("%s failed", cmd); - else - log_debug("%s failed with SK=%Xh/ASC=%02Xh/ACQ=%02Xh", cmd, SK(err), ASC(err), ASCQ(err)); + FEATURE_DVD_ROM = 0x10, + FEATURE_DVD_R = 0x11, + FEATURE_DVD_RAM = 0x12, + FEATURE_DVD_RW_RO = 0x13, /* restricted overwrite mode */ + FEATURE_DVD_RW_SEQ = 0x14, /* sequential mode */ + FEATURE_DVD_R_DL_SEQ = 0x15, /* sequential recording */ + FEATURE_DVD_R_DL_JR = 0x16, /* jump recording */ + FEATURE_DVD_RW_DL = 0x17, + FEATURE_DVD_R_DDR = 0x18, /* download disc recording - dvd for css managed recording */ + FEATURE_DVD_PLUS_RW = 0x1a, + FEATURE_DVD_PLUS_R = 0x1b, + + FEATURE_DDCD_ROM = 0x20, + FEATURE_DDCD_R = 0x21, + FEATURE_DDCD_RW = 0x22, + + FEATURE_DVD_PLUS_RW_DL = 0x2a, + FEATURE_DVD_PLUS_R_DL = 0x2b, + + FEATURE_BD = 0x40, + FEATURE_BD_R_SRM = 0x41, /* sequential recording mode */ + FEATURE_BD_R_RRM = 0x42, /* random recording mode */ + FEATURE_BD_RE = 0x43, + + FEATURE_HDDVD = 0x50, + FEATURE_HDDVD_R = 0x51, + FEATURE_HDDVD_RAM = 0x52, + FEATURE_HDDVD_RW = 0x53, + FEATURE_HDDVD_R_DL = 0x58, + FEATURE_HDDVD_RW_DL = 0x5a, + + FEATURE_MRW, + FEATURE_MRW_W, + + _FEATURE_MAX, + _FEATURE_INVALID = -EINVAL, +} Feature; + +typedef enum MediaState { + MEDIA_STATE_BLANK = 0, + MEDIA_STATE_APPENDABLE = 1, + MEDIA_STATE_COMPLETE = 2, + MEDIA_STATE_OTHER = 3, + _MEDIA_STATE_MAX, + _MEDIA_STATE_INVALID = -EINVAL, +} MediaState; + +typedef struct Context { + int fd; + + Feature *drive_features; + size_t n_drive_feature; + size_t n_allocated; + + Feature media_feature; + bool has_media; + + MediaState media_state; + unsigned media_session_next; + unsigned media_session_count; + unsigned media_track_count; + unsigned media_track_count_data; + unsigned media_track_count_audio; + uint64_t media_session_last_offset; +} Context; + +static void context_clear(Context *c) { + if (!c) + return; + + safe_close(c->fd); + free(c->drive_features); +} + +static void context_init(Context *c) { + assert(c); + + *c = (Context) { + .fd = -1, + .media_feature = _FEATURE_INVALID, + .media_state = _MEDIA_STATE_INVALID, + }; +} + +static bool drive_has_feature(const Context *c, Feature f) { + assert(c); + + for (size_t i = 0; i < c->n_drive_feature; i++) + if (c->drive_features[i] == f) + return true; + + return false; +} + +static int set_drive_feature(Context *c, Feature f) { + assert(c); + + if (drive_has_feature(c, f)) + return 0; + + if (!GREEDY_REALLOC(c->drive_features, c->n_allocated, c->n_drive_feature + 1)) + return -ENOMEM; + + c->drive_features[c->n_drive_feature++] = f; + return 1; +} + +#define ERRCODE(s) ((((s)[2] & 0x0F) << 16) | ((s)[12] << 8) | ((s)[13])) +#define SK(errcode) (((errcode) >> 16) & 0xF) +#define ASC(errcode) (((errcode) >> 8) & 0xFF) +#define ASCQ(errcode) ((errcode) & 0xFF) +#define CHECK_CONDITION 0x01 + +static int log_scsi_debug_errno(int error, const char *msg) { + assert(error != 0); + + /* error < 0 means errno-style error, error > 0 means SCSI error */ + + if (error < 0) + return log_debug_errno(error, "Failed to %s: %m", msg); + + return log_debug_errno(SYNTHETIC_ERRNO(EIO), + "Failed to %s with SK=%X/ASC=%02X/ACQ=%02X", + msg, SK(error), ASC(error), ASCQ(error)); } struct scsi_cmd { @@ -117,10 +188,14 @@ static void scsi_cmd_set(struct scsi_cmd *cmd, size_t i, unsigned char arg) { cmd->cgc.cmd[i] = arg; } -#define CHECK_CONDITION 0x01 - static int scsi_cmd_run(struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize) { - int ret = 0; + int r; + + assert(cmd); + assert(fd >= 0); + assert(buf || bufsize == 0); + + /* Return 0 on success. On failure, return negative errno or positive error code. */ if (bufsize > 0) { cmd->sg_io.dxferp = buf; @@ -129,381 +204,237 @@ static int scsi_cmd_run(struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t } else cmd->sg_io.dxfer_direction = SG_DXFER_NONE; - if (ioctl(fd, SG_IO, &cmd->sg_io)) - return -1; + if (ioctl(fd, SG_IO, &cmd->sg_io) < 0) + return -errno; if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) { - errno = EIO; - ret = -1; if (cmd->sg_io.masked_status & CHECK_CONDITION) { - ret = ERRCODE(cmd->_sense.u); - if (ret == 0) - ret = -1; + r = ERRCODE(cmd->_sense.u); + if (r != 0) + return r; } + return -EIO; } - return ret; + + return 0; +} + +static int scsi_cmd_run_and_log(struct scsi_cmd *cmd, int fd, unsigned char *buf, size_t bufsize, const char *msg) { + int r; + + assert(msg); + + r = scsi_cmd_run(cmd, fd, buf, bufsize); + if (r != 0) + return log_scsi_debug_errno(r, msg); + + return 0; } static int media_lock(int fd, bool lock) { - int err; - /* disable the kernel's lock logic */ - err = ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK); - if (err < 0) - log_debug("CDROM_CLEAR_OPTIONS, CDO_LOCK failed"); + if (ioctl(fd, CDROM_CLEAR_OPTIONS, CDO_LOCK) < 0) + log_debug_errno(errno, "Failed to issue ioctl(CDROM_CLEAR_OPTIONS, CDO_LOCK), ignoring: %m"); - err = ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0); - if (err < 0) - log_debug("CDROM_LOCKDOOR failed"); + if (ioctl(fd, CDROM_LOCKDOOR, lock ? 1 : 0) < 0) + return log_debug_errno(errno, "Failed to issue ioctl(CDROM_LOCKDOOR): %m"); - return err; + return 0; } static int media_eject(int fd) { struct scsi_cmd sc; - int err; scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x1b); + scsi_cmd_set(&sc, 0, GPCMD_START_STOP_UNIT); scsi_cmd_set(&sc, 4, 0x02); scsi_cmd_set(&sc, 5, 0); - err = scsi_cmd_run(&sc, fd, NULL, 0); - if (err != 0) { - info_scsi_cmd_err("START_STOP_UNIT", err); - return -1; - } - return 0; + + return scsi_cmd_run_and_log(&sc, fd, NULL, 0, "start/stop unit"); } -static int cd_capability_compat(int fd) { - int capability; +static int cd_capability_compat(Context *c) { + int capability, r; - capability = ioctl(fd, CDROM_GET_CAPABILITY, NULL); + assert(c); + + capability = ioctl(c->fd, CDROM_GET_CAPABILITY, NULL); if (capability < 0) return log_debug_errno(errno, "CDROM_GET_CAPABILITY failed"); - if (capability & CDC_CD_R) - cd_cd_r = 1; - if (capability & CDC_CD_RW) - cd_cd_rw = 1; - if (capability & CDC_DVD) - cd_dvd_rom = 1; - if (capability & CDC_DVD_R) - cd_dvd_r = 1; - if (capability & CDC_DVD_RAM) - cd_dvd_ram = 1; - if (capability & CDC_MRW) - cd_mrw = 1; - if (capability & CDC_MRW_W) - cd_mrw_w = 1; - return 0; -} - -static int cd_media_compat(int fd) { - if (ioctl(fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) - return log_debug_errno(errno, "CDROM_DRIVE_STATUS != CDS_DISC_OK"); - - cd_media = 1; - return 0; -} - -static int cd_inquiry(int fd) { - struct scsi_cmd sc; - unsigned char inq[128]; - int err; - - scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x12); - scsi_cmd_set(&sc, 4, 36); - scsi_cmd_set(&sc, 5, 0); - err = scsi_cmd_run(&sc, fd, inq, 36); - if (err != 0) { - info_scsi_cmd_err("INQUIRY", err); - return -1; + if (capability & CDC_CD_R) { + r = set_drive_feature(c, FEATURE_CD_R); + if (r < 0) + return log_oom_debug(); + } + if (capability & CDC_CD_RW) { + r = set_drive_feature(c, FEATURE_CD_RW); + if (r < 0) + return log_oom_debug(); + } + if (capability & CDC_DVD) { + r = set_drive_feature(c, FEATURE_DVD_ROM); + if (r < 0) + return log_oom_debug(); + } + if (capability & CDC_DVD_R) { + r = set_drive_feature(c, FEATURE_DVD_R); + if (r < 0) + return log_oom_debug(); + } + if (capability & CDC_DVD_RAM) { + r = set_drive_feature(c, FEATURE_DVD_RAM); + if (r < 0) + return log_oom_debug(); + } + if (capability & CDC_MRW) { + r = set_drive_feature(c, FEATURE_MRW); + if (r < 0) + return log_oom_debug(); + } + if (capability & CDC_MRW_W) { + r = set_drive_feature(c, FEATURE_MRW_W); + if (r < 0) + return log_oom_debug(); } + return 0; +} + +static int cd_media_compat(Context *c) { + assert(c); + + if (ioctl(c->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT) != CDS_DISC_OK) + return log_debug_errno(errno, "CDROM_DRIVE_STATUS != CDS_DISC_OK"); + + c->has_media = true; + return 0; +} + +static int cd_inquiry(Context *c) { + struct scsi_cmd sc; + unsigned char inq[36]; + int r; + + assert(c); + + scsi_cmd_init(&sc); + scsi_cmd_set(&sc, 0, GPCMD_INQUIRY); + scsi_cmd_set(&sc, 4, sizeof(inq)); + scsi_cmd_set(&sc, 5, 0); + r = scsi_cmd_run_and_log(&sc, c->fd, inq, sizeof(inq), "inquire"); + if (r < 0) + return r; + if ((inq[0] & 0x1F) != 5) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "not an MMC unit"); + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Not an MMC unit"); log_debug("INQUIRY: [%.8s][%.16s][%.4s]", inq + 8, inq + 16, inq + 32); return 0; } -static void feature_profile_media(int cur_profile) { - switch (cur_profile) { - case 0x03: - case 0x04: - case 0x05: - log_debug("profile 0x%02x ", cur_profile); - cd_media = 1; - cd_media_mo = 1; - break; - case 0x08: - log_debug("profile 0x%02x media_cd_rom", cur_profile); - cd_media = 1; - cd_media_cd_rom = 1; - break; - case 0x09: - log_debug("profile 0x%02x media_cd_r", cur_profile); - cd_media = 1; - cd_media_cd_r = 1; - break; - case 0x0a: - log_debug("profile 0x%02x media_cd_rw", cur_profile); - cd_media = 1; - cd_media_cd_rw = 1; - break; - case 0x10: - log_debug("profile 0x%02x media_dvd_ro", cur_profile); - cd_media = 1; - cd_media_dvd_rom = 1; - break; - case 0x11: - log_debug("profile 0x%02x media_dvd_r", cur_profile); - cd_media = 1; - cd_media_dvd_r = 1; - break; - case 0x12: - log_debug("profile 0x%02x media_dvd_ram", cur_profile); - cd_media = 1; - cd_media_dvd_ram = 1; - break; - case 0x13: - log_debug("profile 0x%02x media_dvd_rw_ro", cur_profile); - cd_media = 1; - cd_media_dvd_rw = 1; - cd_media_dvd_rw_ro = 1; - break; - case 0x14: - log_debug("profile 0x%02x media_dvd_rw_seq", cur_profile); - cd_media = 1; - cd_media_dvd_rw = 1; - cd_media_dvd_rw_seq = 1; - break; - case 0x1B: - log_debug("profile 0x%02x media_dvd_plus_r", cur_profile); - cd_media = 1; - cd_media_dvd_plus_r = 1; - break; - case 0x1A: - log_debug("profile 0x%02x media_dvd_plus_rw", cur_profile); - cd_media = 1; - cd_media_dvd_plus_rw = 1; - break; - case 0x2A: - log_debug("profile 0x%02x media_dvd_plus_rw_dl", cur_profile); - cd_media = 1; - cd_media_dvd_plus_rw_dl = 1; - break; - case 0x2B: - log_debug("profile 0x%02x media_dvd_plus_r_dl", cur_profile); - cd_media = 1; - cd_media_dvd_plus_r_dl = 1; - break; - case 0x40: - log_debug("profile 0x%02x media_bd", cur_profile); - cd_media = 1; - cd_media_bd = 1; - break; - case 0x41: - case 0x42: - log_debug("profile 0x%02x media_bd_r", cur_profile); - cd_media = 1; - cd_media_bd_r = 1; - break; - case 0x43: - log_debug("profile 0x%02x media_bd_re", cur_profile); - cd_media = 1; - cd_media_bd_re = 1; - break; - case 0x50: - log_debug("profile 0x%02x media_hddvd", cur_profile); - cd_media = 1; - cd_media_hddvd = 1; - break; - case 0x51: - log_debug("profile 0x%02x media_hddvd_r", cur_profile); - cd_media = 1; - cd_media_hddvd_r = 1; - break; - case 0x52: - log_debug("profile 0x%02x media_hddvd_rw", cur_profile); - cd_media = 1; - cd_media_hddvd_rw = 1; - break; - default: - log_debug("profile 0x%02x ", cur_profile); - break; +static int feature_profiles(Context *c, const unsigned char *profiles, size_t size) { + int r; + + assert(c); + + for (size_t i = 0; i + 4 <= size; i += 4) { + r = set_drive_feature(c, (Feature) unaligned_read_be16(&profiles[i])); + if (r < 0) + return log_oom_debug(); } + + return 1; } -static int feature_profiles(const unsigned char *profiles, size_t size) { - unsigned i; - - for (i = 0; i+4 <= size; i += 4) { - int profile; - - profile = profiles[i] << 8 | profiles[i+1]; - switch (profile) { - case 0x03: - case 0x04: - case 0x05: - log_debug("profile 0x%02x mo", profile); - cd_mo = 1; - break; - case 0x08: - log_debug("profile 0x%02x cd_rom", profile); - cd_cd_rom = 1; - break; - case 0x09: - log_debug("profile 0x%02x cd_r", profile); - cd_cd_r = 1; - break; - case 0x0A: - log_debug("profile 0x%02x cd_rw", profile); - cd_cd_rw = 1; - break; - case 0x10: - log_debug("profile 0x%02x dvd_rom", profile); - cd_dvd_rom = 1; - break; - case 0x12: - log_debug("profile 0x%02x dvd_ram", profile); - cd_dvd_ram = 1; - break; - case 0x13: - case 0x14: - log_debug("profile 0x%02x dvd_rw", profile); - cd_dvd_rw = 1; - break; - case 0x1B: - log_debug("profile 0x%02x dvd_plus_r", profile); - cd_dvd_plus_r = 1; - break; - case 0x1A: - log_debug("profile 0x%02x dvd_plus_rw", profile); - cd_dvd_plus_rw = 1; - break; - case 0x2A: - log_debug("profile 0x%02x dvd_plus_rw_dl", profile); - cd_dvd_plus_rw_dl = 1; - break; - case 0x2B: - log_debug("profile 0x%02x dvd_plus_r_dl", profile); - cd_dvd_plus_r_dl = 1; - break; - case 0x40: - cd_bd = 1; - log_debug("profile 0x%02x bd", profile); - break; - case 0x41: - case 0x42: - cd_bd_r = 1; - log_debug("profile 0x%02x bd_r", profile); - break; - case 0x43: - cd_bd_re = 1; - log_debug("profile 0x%02x bd_re", profile); - break; - case 0x50: - cd_hddvd = 1; - log_debug("profile 0x%02x hddvd", profile); - break; - case 0x51: - cd_hddvd_r = 1; - log_debug("profile 0x%02x hddvd_r", profile); - break; - case 0x52: - cd_hddvd_rw = 1; - log_debug("profile 0x%02x hddvd_rw", profile); - break; - default: - log_debug("profile 0x%02x ", profile); - break; - } - } - return 0; -} - -/* returns 0 if media was detected */ -static int cd_profiles_old_mmc(int fd) { +static int cd_profiles_old_mmc(Context *c) { + disc_information discinfo; struct scsi_cmd sc; - int err; + size_t len; + int r; - unsigned char header[32]; + assert(c); scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x51); - scsi_cmd_set(&sc, 8, sizeof(header)); + scsi_cmd_set(&sc, 0, GPCMD_READ_DISC_INFO); + scsi_cmd_set(&sc, 8, sizeof(discinfo.disc_information_length)); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, header, sizeof(header)); - if (err != 0) { - info_scsi_cmd_err("READ DISC INFORMATION", err); - if (cd_media == 1) { - log_debug("no current profile, but disc is present; assuming CD-ROM"); - cd_media_cd_rom = 1; - cd_media_track_count = 1; - cd_media_track_count_data = 1; - return 0; + r = scsi_cmd_run_and_log(&sc, c->fd, (unsigned char *)&discinfo.disc_information_length, sizeof(discinfo.disc_information_length), "read disc information"); + if (r >= 0) { + /* Not all drives have the same disc_info length, so requeue + * packet with the length the drive tells us it can supply */ + len = be16toh(discinfo.disc_information_length) + sizeof(discinfo.disc_information_length); + if (len > sizeof(discinfo)) + len = sizeof(discinfo); + + scsi_cmd_init(&sc); + scsi_cmd_set(&sc, 0, GPCMD_READ_DISC_INFO); + scsi_cmd_set(&sc, 8, len); + scsi_cmd_set(&sc, 9, 0); + r = scsi_cmd_run_and_log(&sc, c->fd, (unsigned char *)&discinfo, len, "read disc information"); + } + if (r < 0) { + if (c->has_media) { + log_debug("No current profile, but disc is present; assuming CD-ROM."); + c->media_feature = FEATURE_CD_ROM; + c->media_track_count = 1; + c->media_track_count_data = 1; + return 1; } else return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM), - "no current profile, assuming no media"); + "no current profile, assuming no media."); }; - cd_media = 1; + c->has_media = true; + + if (discinfo.erasable) + c->media_feature = FEATURE_CD_RW; + else if (discinfo.disc_status < 2 && drive_has_feature(c, FEATURE_CD_R)) + c->media_feature = FEATURE_CD_R; + else + c->media_feature = FEATURE_CD_ROM; - if (header[2] & 16) { - cd_media_cd_rw = 1; - log_debug("profile 0x0a media_cd_rw"); - } else if ((header[2] & 3) < 2 && cd_cd_r) { - cd_media_cd_r = 1; - log_debug("profile 0x09 media_cd_r"); - } else { - cd_media_cd_rom = 1; - log_debug("profile 0x08 media_cd_rom"); - } return 0; } -/* returns 0 if media was detected */ -static int cd_profiles(int fd) { +static int cd_profiles(Context *c) { struct scsi_cmd sc; unsigned char features[65530]; - unsigned cur_profile = 0; - unsigned len; - unsigned i; - int err; - int ret; + unsigned cur_profile; + size_t len; + int r; - ret = -1; + assert(c); /* First query the current profile */ scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x46); + scsi_cmd_set(&sc, 0, GPCMD_GET_CONFIGURATION); scsi_cmd_set(&sc, 8, 8); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, features, 8); - if (err != 0) { - info_scsi_cmd_err("GET CONFIGURATION", err); + r = scsi_cmd_run(&sc, c->fd, features, 8); + if (r != 0) { /* handle pre-MMC2 drives which do not support GET CONFIGURATION */ - if (SK(err) == 0x5 && IN_SET(ASC(err), 0x20, 0x24)) { - log_debug("drive is pre-MMC2 and does not support 46h get configuration command"); - log_debug("trying to work around the problem"); - ret = cd_profiles_old_mmc(fd); + if (r > 0 && SK(r) == 0x5 && IN_SET(ASC(r), 0x20, 0x24)) { + log_debug("Drive is pre-MMC2 and does not support 46h get configuration command; " + "trying to work around the problem."); + return cd_profiles_old_mmc(c); } - goto out; + + return log_scsi_debug_errno(r, "get configuration"); } - cur_profile = features[6] << 8 | features[7]; + cur_profile = unaligned_read_be16(&features[6]); if (cur_profile > 0) { log_debug("current profile 0x%02x", cur_profile); - feature_profile_media(cur_profile); - ret = 0; /* we have media */ - } else + c->media_feature = (Feature) cur_profile; + c->has_media = true; + } else { log_debug("no current profile, assuming no media"); + c->has_media = false; + } - len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; - log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len); + len = unaligned_read_be32(features); + log_debug("GET CONFIGURATION: size of features buffer %zu", len); if (len > sizeof(features)) { log_debug("cannot get features in a single query, truncating"); @@ -513,19 +444,17 @@ static int cd_profiles(int fd) { /* Now get the full feature buffer */ scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x46); - scsi_cmd_set(&sc, 7, ( len >> 8 ) & 0xff); + scsi_cmd_set(&sc, 0, GPCMD_GET_CONFIGURATION); + scsi_cmd_set(&sc, 7, (len >> 8) & 0xff); scsi_cmd_set(&sc, 8, len & 0xff); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, features, len); - if (err != 0) { - info_scsi_cmd_err("GET CONFIGURATION", err); - return -1; - } + r = scsi_cmd_run_and_log(&sc, c->fd, features, len, "get configuration"); + if (r < 0) + return r; /* parse the length once more, in case the drive decided to have other features suddenly :) */ - len = features[0] << 24 | features[1] << 16 | features[2] << 8 | features[3]; - log_debug("GET CONFIGURATION: size of features buffer 0x%04x", len); + len = unaligned_read_be32(features); + log_debug("GET CONFIGURATION: size of features buffer %zu", len); if (len > sizeof(features)) { log_debug("cannot get features in a single query, truncating"); @@ -533,293 +462,469 @@ static int cd_profiles(int fd) { } /* device features */ - for (i = 8; i+4 < len; i += (4 + features[i+3])) { + for (size_t i = 8; i + 4 < len; i += 4 + features[i + 3]) { unsigned feature; - feature = features[i] << 8 | features[i+1]; + feature = unaligned_read_be16(&features[i]); switch (feature) { case 0x00: - log_debug("GET CONFIGURATION: feature 'profiles', with %i entries", features[i+3] / 4); - feature_profiles(&features[i]+4, MIN(features[i+3], len - i - 4)); + log_debug("GET CONFIGURATION: feature 'profiles', with %u entries", features[i + 3] / 4); + feature_profiles(c, features + i + 4, MIN(features[i + 3], len - i - 4)); break; default: - log_debug("GET CONFIGURATION: feature 0x%04x , with 0x%02x bytes", feature, features[i+3]); + log_debug("GET CONFIGURATION: feature 0x%04x , with 0x%02x bytes", feature, features[i + 3]); break; } } -out: - return ret; + + return c->has_media; } -static int cd_media_info(int fd) { +static const char * const media_state_table[_MEDIA_STATE_MAX] = { + [MEDIA_STATE_BLANK] = "blank", + [MEDIA_STATE_APPENDABLE] = "appendable", + [MEDIA_STATE_COMPLETE] = "complete", + [MEDIA_STATE_OTHER] = "other", +}; + +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(media_state, MediaState); + +static int dvd_ram_media_update_state(Context *c) { struct scsi_cmd sc; - unsigned char header[32]; - static const char *const media_status[] = { - "blank", - "appendable", - "complete", - "other" - }; - int err; + unsigned char dvdstruct[8]; + unsigned char format[12]; + unsigned char len; + int r; + + assert(c); + + /* Return 1 if media state is determined. */ + + if (c->media_feature != FEATURE_DVD_RAM) + return 0; + + /* a write protected dvd-ram may report "complete" status */ + scsi_cmd_init(&sc); + scsi_cmd_set(&sc, 0, GPCMD_READ_DVD_STRUCTURE); + scsi_cmd_set(&sc, 7, 0xC0); + scsi_cmd_set(&sc, 9, sizeof(dvdstruct)); + scsi_cmd_set(&sc, 11, 0); + r = scsi_cmd_run_and_log(&sc, c->fd, dvdstruct, sizeof(dvdstruct), "read DVD structure"); + if (r < 0) + return r; + + if (dvdstruct[4] & 0x02) { + c->media_state = MEDIA_STATE_COMPLETE; + log_debug("write-protected DVD-RAM media inserted"); + return 1; + } + + /* let's make sure we don't try to read unformatted media */ + scsi_cmd_init(&sc); + scsi_cmd_set(&sc, 0, GPCMD_READ_FORMAT_CAPACITIES); + scsi_cmd_set(&sc, 8, sizeof(format)); + scsi_cmd_set(&sc, 9, 0); + r = scsi_cmd_run_and_log(&sc, c->fd, format, sizeof(format), "read DVD format capacities"); + if (r < 0) + return r; + + len = format[3]; + if (len & 7 || len < 16) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "invalid format capacities length"); + + switch(format[8] & 3) { + case 1: + /* This means that last format was interrupted or failed, blank dvd-ram discs are + * factory formatted. Take no action here as it takes quite a while to reformat a + * dvd-ram and it's not automatically started. */ + log_debug("unformatted DVD-RAM media inserted"); + return 1; + + case 2: + log_debug("formatted DVD-RAM media inserted"); + return 0; + + case 3: + c->has_media = false; + return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM), + "format capacities returned no media"); + } + + return 0; +} + +static int dvd_media_update_state(Context *c) { + struct scsi_cmd sc; + unsigned char buffer[32 * 2048]; + int r; + + r = dvd_ram_media_update_state(c); + if (r != 0) + return r; + + /* Take a closer look at formatted media (unformatted DVD+RW + * has "blank" status", DVD-RAM was examined earlier) and check + * for ISO and UDF PVDs or a fs superblock presence and do it + * in one ioctl (we need just sectors 0 and 16) */ scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x51); - scsi_cmd_set(&sc, 8, sizeof(header) & 0xff); + scsi_cmd_set(&sc, 0, GPCMD_READ_10); + scsi_cmd_set(&sc, 5, 0); + scsi_cmd_set(&sc, 8, sizeof(buffer)/2048); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, header, sizeof(header)); - if (err != 0) { - info_scsi_cmd_err("READ DISC INFORMATION", err); - return -1; - }; + r = scsi_cmd_run_and_log(&sc, c->fd, buffer, sizeof(buffer), "read first 32 blocks"); + if (r < 0) { + c->has_media = false; + return r; + } - cd_media = 1; + /* if any non-zero data is found in sector 16 (iso and udf) or + * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc + * is assumed non-blank */ + + for (size_t offset = 32768; offset < 32768 + 2048; offset++) + if (buffer[offset] != 0) { + log_debug("data in block 16, assuming complete"); + return 0; + } + + for (size_t offset = 0; offset < 2048; offset++) + if (buffer[offset] != 0) { + log_debug("data in block 0, assuming complete"); + return 0; + } + + log_debug("no data in blocks 0 or 16, assuming blank"); + c->media_state = MEDIA_STATE_BLANK; + return 0; +} + +static int cd_media_info(Context *c) { + struct scsi_cmd sc; + unsigned char header[32]; + MediaState state; + int r; + + assert(c); + + scsi_cmd_init(&sc); + scsi_cmd_set(&sc, 0, GPCMD_READ_DISC_INFO); + scsi_cmd_set(&sc, 8, sizeof(header)); + scsi_cmd_set(&sc, 9, 0); + r = scsi_cmd_run_and_log(&sc, c->fd, header, sizeof(header), "read disc information"); + if (r < 0) + return r; + + c->has_media = true; log_debug("disk type %02x", header[8]); - log_debug("hardware reported media status: %s", media_status[header[2] & 3]); + + state = (MediaState) (header[2] & 0x03); + log_debug("hardware reported media status: %s", strna(media_state_to_string(state))); /* exclude plain CDROM, some fake cdroms return 0 for "blank" media here */ - if (!cd_media_cd_rom) - cd_media_state = media_status[header[2] & 3]; + if (c->media_feature != FEATURE_CD_ROM) + c->media_state = state; /* fresh DVD-RW in restricted overwrite mode reports itself as * "appendable"; change it to "blank" to make it consistent with what - * gets reported after blanking, and what userspace expects */ - if (cd_media_dvd_rw_ro && (header[2] & 3) == 1) - cd_media_state = media_status[0]; + * gets reported after blanking, and what userspace expects. */ + if (c->media_feature == FEATURE_DVD_RW_RO && state == MEDIA_STATE_APPENDABLE) + c->media_state = MEDIA_STATE_BLANK; /* DVD+RW discs (and DVD-RW in restricted mode) once formatted are * always "complete", DVD-RAM are "other" or "complete" if the disc is * write protected; we need to check the contents if it is blank */ - if ((cd_media_dvd_rw_ro || cd_media_dvd_plus_rw || cd_media_dvd_plus_rw_dl || cd_media_dvd_ram) && (header[2] & 3) > 1) { - unsigned char buffer[32 * 2048]; - unsigned char len; - int offset; - - if (cd_media_dvd_ram) { - /* a write protected dvd-ram may report "complete" status */ - - unsigned char dvdstruct[8]; - unsigned char format[12]; - - scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0xAD); - scsi_cmd_set(&sc, 7, 0xC0); - scsi_cmd_set(&sc, 9, sizeof(dvdstruct)); - scsi_cmd_set(&sc, 11, 0); - err = scsi_cmd_run(&sc, fd, dvdstruct, sizeof(dvdstruct)); - if (err != 0) { - info_scsi_cmd_err("READ DVD STRUCTURE", err); - return -1; - } - if (dvdstruct[4] & 0x02) { - cd_media_state = media_status[2]; - log_debug("write-protected DVD-RAM media inserted"); - goto determined; - } - - /* let's make sure we don't try to read unformatted media */ - scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x23); - scsi_cmd_set(&sc, 8, sizeof(format)); - scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, format, sizeof(format)); - if (err != 0) { - info_scsi_cmd_err("READ DVD FORMAT CAPACITIES", err); - return -1; - } - - len = format[3]; - if (len & 7 || len < 16) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "invalid format capacities length"); - - switch(format[8] & 3) { - case 1: - log_debug("unformatted DVD-RAM media inserted"); - /* This means that last format was interrupted - * or failed, blank dvd-ram discs are factory - * formatted. Take no action here as it takes - * quite a while to reformat a dvd-ram and it's - * not automatically started */ - goto determined; - - case 2: - log_debug("formatted DVD-RAM media inserted"); - break; - - case 3: - cd_media = 0; //return no media - return log_debug_errno(SYNTHETIC_ERRNO(ENOMEDIUM), - "format capacities returned no media"); - } - } - - /* Take a closer look at formatted media (unformatted DVD+RW - * has "blank" status", DVD-RAM was examined earlier) and check - * for ISO and UDF PVDs or a fs superblock presence and do it - * in one ioctl (we need just sectors 0 and 16) */ - scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x28); - scsi_cmd_set(&sc, 5, 0); - scsi_cmd_set(&sc, 8, 32); - scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, buffer, sizeof(buffer)); - if (err != 0) { - cd_media = 0; - info_scsi_cmd_err("READ FIRST 32 BLOCKS", err); - return -1; - } - - /* if any non-zero data is found in sector 16 (iso and udf) or - * eventually 0 (fat32 boot sector, ext2 superblock, etc), disc - * is assumed non-blank */ - - for (offset = 32768; offset < (32768 + 2048); offset++) { - if (buffer [offset]) { - log_debug("data in block 16, assuming complete"); - goto determined; - } - } - - for (offset = 0; offset < 2048; offset++) { - if (buffer [offset]) { - log_debug("data in block 0, assuming complete"); - goto determined; - } - } - - cd_media_state = media_status[0]; - log_debug("no data in blocks 0 or 16, assuming blank"); + if (IN_SET(c->media_feature, FEATURE_DVD_RW_RO, FEATURE_DVD_PLUS_RW, FEATURE_DVD_PLUS_RW_DL, FEATURE_DVD_RAM) && + IN_SET(state, MEDIA_STATE_COMPLETE, MEDIA_STATE_OTHER)) { + r = dvd_media_update_state(c); + if (r < 0) + return r; } -determined: /* "other" is e. g. DVD-RAM, can't append sessions there; DVDs in * restricted overwrite mode can never append, only in sequential mode */ - if ((header[2] & 3) < 2 && !cd_media_dvd_rw_ro) - cd_media_session_next = header[10] << 8 | header[5]; - cd_media_session_count = header[9] << 8 | header[4]; - cd_media_track_count = header[11] << 8 | header[6]; + if (c->media_feature != FEATURE_DVD_RW_RO && IN_SET(state, MEDIA_STATE_BLANK, MEDIA_STATE_APPENDABLE)) + c->media_session_next = header[10] << 8 | header[5]; + c->media_session_count = header[9] << 8 | header[4]; + c->media_track_count = header[11] << 8 | header[6]; return 0; } -static int cd_media_toc(int fd) { +static int cd_media_toc(Context *c) { struct scsi_cmd sc; unsigned char header[12]; unsigned char toc[65536]; - unsigned len, i, num_tracks; - unsigned char *p; - int err; + unsigned num_tracks; + size_t len; + int r; + + assert(c); scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x43); + scsi_cmd_set(&sc, 0, GPCMD_READ_TOC_PMA_ATIP); scsi_cmd_set(&sc, 6, 1); - scsi_cmd_set(&sc, 8, sizeof(header) & 0xff); + scsi_cmd_set(&sc, 8, sizeof(header)); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, header, sizeof(header)); - if (err != 0) { - info_scsi_cmd_err("READ TOC", err); - return -1; - } + r = scsi_cmd_run_and_log(&sc, c->fd, header, sizeof(header), "read TOC"); + if (r < 0) + return r; + + len = unaligned_read_be16(header) + 2; + log_debug("READ TOC: len: %zu, start track: %u, end track: %u", len, header[2], header[3]); - len = (header[0] << 8 | header[1]) + 2; - log_debug("READ TOC: len: %d, start track: %d, end track: %d", len, header[2], header[3]); if (len > sizeof(toc)) return -1; - if (len < 2) - return -1; - /* 2: first track, 3: last track */ - num_tracks = header[3] - header[2] + 1; - /* empty media has no tracks */ if (len < 8) return 0; + /* 2: first track, 3: last track */ + num_tracks = header[3] - header[2] + 1; + scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x43); + scsi_cmd_set(&sc, 0, GPCMD_READ_TOC_PMA_ATIP); scsi_cmd_set(&sc, 6, header[2]); /* First Track/Session Number */ scsi_cmd_set(&sc, 7, (len >> 8) & 0xff); scsi_cmd_set(&sc, 8, len & 0xff); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, toc, len); - if (err != 0) { - info_scsi_cmd_err("READ TOC (tracks)", err); - return -1; - } + r = scsi_cmd_run_and_log(&sc, c->fd, toc, len, "read TOC (tracks)"); + if (r < 0) + return r; /* Take care to not iterate beyond the last valid track as specified in * the TOC, but also avoid going beyond the TOC length, just in case * the last track number is invalidly large */ - for (p = toc+4, i = 4; i < len-8 && num_tracks > 0; i += 8, p += 8, --num_tracks) { - unsigned block; - unsigned is_data_track; + for (size_t i = 4; i + 8 < len && num_tracks > 0; i += 8, --num_tracks) { + bool is_data_track; + uint32_t block; - is_data_track = (p[1] & 0x04) != 0; + is_data_track = (toc[i + 1] & 0x04) != 0; + block = unaligned_read_be32(&toc[i + 4]); - block = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7]; - log_debug("track=%u info=0x%x(%s) start_block=%u", - p[2], p[1] & 0x0f, is_data_track ? "data":"audio", block); + log_debug("track=%u info=0x%x(%s) start_block=%"PRIu32, + toc[i + 2], toc[i + 1] & 0x0f, is_data_track ? "data":"audio", block); if (is_data_track) - cd_media_track_count_data++; + c->media_track_count_data++; else - cd_media_track_count_audio++; + c->media_track_count_audio++; } scsi_cmd_init(&sc); - scsi_cmd_set(&sc, 0, 0x43); + scsi_cmd_set(&sc, 0, GPCMD_READ_TOC_PMA_ATIP); scsi_cmd_set(&sc, 2, 1); /* Session Info */ scsi_cmd_set(&sc, 8, sizeof(header)); scsi_cmd_set(&sc, 9, 0); - err = scsi_cmd_run(&sc, fd, header, sizeof(header)); - if (err != 0) { - info_scsi_cmd_err("READ TOC (multi session)", err); - return -1; - } - len = header[4+4] << 24 | header[4+5] << 16 | header[4+6] << 8 | header[4+7]; - log_debug("last track %u starts at block %u", header[4+2], len); - cd_media_session_last_offset = (unsigned long long int)len * 2048; + r = scsi_cmd_run_and_log(&sc, c->fd, header, sizeof(header), "read TOC (multi session)"); + if (r < 0) + return r; + + len = unaligned_read_be32(&header[8]); + log_debug("last track %u starts at block %zu", header[4+2], len); + c->media_session_last_offset = (uint64_t) len * 2048; + return 0; } -int main(int argc, char *argv[]) { +static int open_drive(Context *c) { + _cleanup_close_ int fd = -1; + + assert(c); + assert(c->fd < 0); + + for (int cnt = 0; cnt < 20; cnt++) { + if (cnt != 0) + (void) usleep(100 * USEC_PER_MSEC + random_u64() % (100 * USEC_PER_MSEC)); + + fd = open(arg_node, O_RDONLY|O_NONBLOCK|O_CLOEXEC); + if (fd >= 0 || errno != EBUSY) + break; + } + if (fd < 0) + return log_debug_errno(errno, "Unable to open '%s'", arg_node); + + log_debug("probing: '%s'", arg_node); + + c->fd = TAKE_FD(fd); + return 0; +} + +typedef struct FeatureToString { + Feature feature; + const char *str; +} FeatureToString; + +static const FeatureToString feature_to_string[] = { + { .feature = FEATURE_RW_NONREMOVABLE, .str = "RW_NONREMOVABLE", }, + { .feature = FEATURE_RW_REMOVABLE, .str = "RW_REMOVABLE", }, + + { .feature = FEATURE_MO_SE, .str = "MO_SE", }, + { .feature = FEATURE_MO_WO, .str = "MO_WO", }, + { .feature = FEATURE_MO_AS, .str = "MO_AS", }, + + { .feature = FEATURE_CD_ROM, .str = "CD", }, + { .feature = FEATURE_CD_R, .str = "CD_R", }, + { .feature = FEATURE_CD_RW, .str = "CD_RW", }, + + { .feature = FEATURE_DVD_ROM, .str = "DVD", }, + { .feature = FEATURE_DVD_R, .str = "DVD_R", }, + { .feature = FEATURE_DVD_RAM, .str = "DVD_RAM", }, + { .feature = FEATURE_DVD_RW_RO, .str = "DVD_RW_RO", }, + { .feature = FEATURE_DVD_RW_SEQ, .str = "DVD_RW_SEQ", }, + { .feature = FEATURE_DVD_R_DL_SEQ, .str = "DVD_R_DL_SEQ", }, + { .feature = FEATURE_DVD_R_DL_JR, .str = "DVD_R_DL_JR", }, + { .feature = FEATURE_DVD_RW_DL, .str = "DVD_RW_DL", }, + { .feature = FEATURE_DVD_R_DDR, .str = "DVD_R_DDR", }, + { .feature = FEATURE_DVD_PLUS_RW, .str = "DVD_PLUS_RW", }, + { .feature = FEATURE_DVD_PLUS_R, .str = "DVD_PLUS_R", }, + + { .feature = FEATURE_DDCD_ROM, .str = "DDCD", }, + { .feature = FEATURE_DDCD_R, .str = "DDCD_R", }, + { .feature = FEATURE_DDCD_RW, .str = "DDCD_RW", }, + + { .feature = FEATURE_DVD_PLUS_RW_DL, .str = "DVD_PLUS_RW_DL", }, + { .feature = FEATURE_DVD_PLUS_R_DL, .str = "DVD_PLUS_R_DL", }, + + { .feature = FEATURE_BD, .str = "BD", }, + { .feature = FEATURE_BD_R_SRM, .str = "BD_R_SRM", }, + { .feature = FEATURE_BD_R_RRM, .str = "BD_R_RRM", }, + { .feature = FEATURE_BD_RE, .str = "BD_RE", }, + + { .feature = FEATURE_HDDVD, .str = "HDDVD", }, + { .feature = FEATURE_HDDVD_R, .str = "HDDVD_R", }, + { .feature = FEATURE_HDDVD_RAM, .str = "HDDVD_RAM", }, + { .feature = FEATURE_HDDVD_RW, .str = "HDDVD_RW", }, + { .feature = FEATURE_HDDVD_R_DL, .str = "HDDVD_R_DL", }, + { .feature = FEATURE_HDDVD_RW_DL, .str = "HDDVD_RW_DL", }, + + { .feature = FEATURE_MRW, .str = "MRW", }, + { .feature = FEATURE_MRW_W, .str = "MRW_W", }, +}; + +static int feature_to_string_compare_func(const FeatureToString *a, const FeatureToString *b) { + assert(a); + assert(b); + + return CMP(a->feature, b->feature); +} + +static void print_feature(Feature feature, const char *prefix) { + FeatureToString *found, in = { + .feature = feature, + }; + + assert(prefix); + + found = typesafe_bsearch(&in, feature_to_string, ELEMENTSOF(feature_to_string), feature_to_string_compare_func); + if (!found) + return (void) log_debug("Unknown feature 0x%02x, ignoring", (unsigned) feature); + + printf("%s_%s=1\n", prefix, found->str); +} + +static void print_properties(const Context *c) { + const char *state; + + assert(c); + + printf("ID_CDROM=1\n"); + for (size_t i = 0; i < c->n_drive_feature; i++) + print_feature(c->drive_features[i], "ID_CDROM"); + + if (drive_has_feature(c, FEATURE_MO_SE) || + drive_has_feature(c, FEATURE_MO_WO) || + drive_has_feature(c, FEATURE_MO_AS)) + printf("ID_CDROM_MO=1\n"); + + if (drive_has_feature(c, FEATURE_DVD_RW_RO) || + drive_has_feature(c, FEATURE_DVD_RW_SEQ)) + printf("ID_CDROM_DVD_RW=1\n"); + + if (drive_has_feature(c, FEATURE_DVD_R_DL_SEQ) || + drive_has_feature(c, FEATURE_DVD_R_DL_JR)) + printf("ID_CDROM_DVD_R_DL=1\n"); + + if (drive_has_feature(c, FEATURE_DVD_R_DDR)) + printf("ID_CDROM_DVD_R=1\n"); + + if (drive_has_feature(c, FEATURE_BD_R_SRM) || + drive_has_feature(c, FEATURE_BD_R_RRM)) + printf("ID_CDROM_BD_R=1\n"); + + if (c->has_media) { + printf("ID_CDROM_MEDIA=1\n"); + print_feature(c->media_feature, "ID_CDROM_MEDIA"); + + if (IN_SET(c->media_feature, FEATURE_MO_SE, FEATURE_MO_WO, FEATURE_MO_AS)) + printf("ID_CDROM_MEDIA_MO=1\n"); + + if (IN_SET(c->media_feature, FEATURE_DVD_RW_RO, FEATURE_DVD_RW_SEQ)) + printf("ID_CDROM_MEDIA_DVD_RW=1\n"); + + if (IN_SET(c->media_feature, FEATURE_DVD_R_DL_SEQ, FEATURE_DVD_R_DL_JR)) + printf("ID_CDROM_MEDIA_DVD_R_DL=1\n"); + + if (c->media_feature == FEATURE_DVD_R_DDR) + printf("ID_CDROM_MEDIA_DVD_R=1\n"); + + if (IN_SET(c->media_feature, FEATURE_BD_R_SRM, FEATURE_BD_R_RRM)) + printf("ID_CDROM_MEDIA_BD_R=1\n"); + } + + state = media_state_to_string(c->media_state); + if (state) + printf("ID_CDROM_MEDIA_STATE=%s\n", state); + if (c->media_session_next > 0) + printf("ID_CDROM_MEDIA_SESSION_NEXT=%u\n", c->media_session_next); + if (c->media_session_count > 0) + printf("ID_CDROM_MEDIA_SESSION_COUNT=%u\n", c->media_session_count); + if (c->media_session_count > 1 && c->media_session_last_offset > 0) + printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%" PRIu64 "\n", c->media_session_last_offset); + if (c->media_track_count > 0) + printf("ID_CDROM_MEDIA_TRACK_COUNT=%u\n", c->media_track_count); + if (c->media_track_count_audio > 0) + printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%u\n", c->media_track_count_audio); + if (c->media_track_count_data > 0) + printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%u\n", c->media_track_count_data); +} + +static int help(void) { + printf("Usage: %s [options] \n" + " -l --lock-media lock the media (to enable eject request events)\n" + " -u --unlock-media unlock the media\n" + " -e --eject-media eject the media\n" + " -d --debug print debug messages to stderr\n" + " -h --help print this help text\n" + "\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { static const struct option options[] = { - { "lock-media", no_argument, NULL, 'l' }, + { "lock-media", no_argument, NULL, 'l' }, { "unlock-media", no_argument, NULL, 'u' }, - { "eject-media", no_argument, NULL, 'e' }, - { "debug", no_argument, NULL, 'd' }, - { "help", no_argument, NULL, 'h' }, + { "eject-media", no_argument, NULL, 'e' }, + { "debug", no_argument, NULL, 'd' }, + { "help", no_argument, NULL, 'h' }, {} }; - bool eject = false; - bool lock = false; - bool unlock = false; - const char *node = NULL; - int fd = -1; - int cnt; - int rc = 0; + int c; - log_set_target(LOG_TARGET_AUTO); - udev_parse_config(); - log_parse_environment(); - log_open(); - - for (;;) { - int option; - - option = getopt_long(argc, argv, "deluh", options, NULL); - if (option == -1) - break; - - switch (option) { + while ((c = getopt_long(argc, argv, "deluh", options, NULL)) >= 0) + switch (c) { case 'l': - lock = true; + arg_lock = true; break; case 'u': - unlock = true; + arg_unlock = true; break; case 'e': - eject = true; + arg_eject = true; break; case 'd': log_set_target(LOG_TARGET_CONSOLE); @@ -827,192 +932,83 @@ int main(int argc, char *argv[]) { log_open(); break; case 'h': - printf("Usage: %s [options] \n" - " -l,--lock-media lock the media (to enable eject request events)\n" - " -u,--unlock-media unlock the media\n" - " -e,--eject-media eject the media\n" - " -d,--debug debug to stderr\n" - " -h,--help print this help text\n\n", - program_invocation_short_name); - goto exit; + return help(); default: - rc = 1; - goto exit; + assert_not_reached("Unknown option"); } - } - node = argv[optind]; - if (!node) { - log_error("no device"); - rc = 1; - goto exit; - } + arg_node = argv[optind]; + if (!arg_node) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No device is specified."); - initialize_srand(); - for (cnt = 20; cnt > 0; cnt--) { - struct timespec duration; + return 1; +} - fd = open(node, O_RDONLY|O_NONBLOCK|O_CLOEXEC); - if (fd >= 0 || errno != EBUSY) - break; - duration.tv_sec = 0; - duration.tv_nsec = (100 * 1000 * 1000) + (rand() % 100 * 1000 * 1000); - nanosleep(&duration, NULL); - } - if (fd < 0) { - log_debug("unable to open '%s'", node); - rc = 1; - goto exit; - } - log_debug("probing: '%s'", node); +static int run(int argc, char *argv[]) { + _cleanup_(context_clear) Context c; + int r; + + log_set_target(LOG_TARGET_AUTO); + udev_parse_config(); + log_parse_environment(); + log_open(); + + context_init(&c); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + r = open_drive(&c); + if (r < 0) + return r; /* same data as original cdrom_id */ - if (cd_capability_compat(fd) < 0) { - rc = 1; - goto exit; - } + r = cd_capability_compat(&c); + if (r < 0) + return r; /* check for media - don't bail if there's no media as we still need to * to read profiles */ - cd_media_compat(fd); + (void) cd_media_compat(&c); /* check if drive talks MMC */ - if (cd_inquiry(fd) < 0) + if (cd_inquiry(&c) < 0) goto work; - /* read drive and possibly current profile */ - if (cd_profiles(fd) != 0) - goto work; + r = cd_profiles(&c); /* read drive and possibly current profile */ + if (r > 0) { + /* at this point we are guaranteed to have media in the drive - find out more about it */ - /* at this point we are guaranteed to have media in the drive - find out more about it */ + /* get session/track info */ + (void) cd_media_toc(&c); - /* get session/track info */ - cd_media_toc(fd); - - /* get writable media state */ - cd_media_info(fd); + /* get writable media state */ + (void) cd_media_info(&c); + } work: /* lock the media, so we enable eject button events */ - if (lock && cd_media) { + if (arg_lock && c.has_media) { log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (lock)"); - media_lock(fd, true); + (void) media_lock(c.fd, true); } - if (unlock && cd_media) { + if (arg_unlock && c.has_media) { log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)"); - media_lock(fd, false); + (void) media_lock(c.fd, false); } - if (eject) { + if (arg_eject) { log_debug("PREVENT_ALLOW_MEDIUM_REMOVAL (unlock)"); - media_lock(fd, false); + (void) media_lock(c.fd, false); log_debug("START_STOP_UNIT (eject)"); - media_eject(fd); + (void) media_eject(c.fd); } - printf("ID_CDROM=1\n"); - if (cd_cd_rom) - printf("ID_CDROM_CD=1\n"); - if (cd_cd_r) - printf("ID_CDROM_CD_R=1\n"); - if (cd_cd_rw) - printf("ID_CDROM_CD_RW=1\n"); - if (cd_dvd_rom) - printf("ID_CDROM_DVD=1\n"); - if (cd_dvd_r) - printf("ID_CDROM_DVD_R=1\n"); - if (cd_dvd_rw) - printf("ID_CDROM_DVD_RW=1\n"); - if (cd_dvd_ram) - printf("ID_CDROM_DVD_RAM=1\n"); - if (cd_dvd_plus_r) - printf("ID_CDROM_DVD_PLUS_R=1\n"); - if (cd_dvd_plus_rw) - printf("ID_CDROM_DVD_PLUS_RW=1\n"); - if (cd_dvd_plus_r_dl) - printf("ID_CDROM_DVD_PLUS_R_DL=1\n"); - if (cd_dvd_plus_rw_dl) - printf("ID_CDROM_DVD_PLUS_RW_DL=1\n"); - if (cd_bd) - printf("ID_CDROM_BD=1\n"); - if (cd_bd_r) - printf("ID_CDROM_BD_R=1\n"); - if (cd_bd_re) - printf("ID_CDROM_BD_RE=1\n"); - if (cd_hddvd) - printf("ID_CDROM_HDDVD=1\n"); - if (cd_hddvd_r) - printf("ID_CDROM_HDDVD_R=1\n"); - if (cd_hddvd_rw) - printf("ID_CDROM_HDDVD_RW=1\n"); - if (cd_mo) - printf("ID_CDROM_MO=1\n"); - if (cd_mrw) - printf("ID_CDROM_MRW=1\n"); - if (cd_mrw_w) - printf("ID_CDROM_MRW_W=1\n"); + print_properties(&c); - if (cd_media) - printf("ID_CDROM_MEDIA=1\n"); - if (cd_media_mo) - printf("ID_CDROM_MEDIA_MO=1\n"); - if (cd_media_mrw) - printf("ID_CDROM_MEDIA_MRW=1\n"); - if (cd_media_mrw_w) - printf("ID_CDROM_MEDIA_MRW_W=1\n"); - if (cd_media_cd_rom) - printf("ID_CDROM_MEDIA_CD=1\n"); - if (cd_media_cd_r) - printf("ID_CDROM_MEDIA_CD_R=1\n"); - if (cd_media_cd_rw) - printf("ID_CDROM_MEDIA_CD_RW=1\n"); - if (cd_media_dvd_rom) - printf("ID_CDROM_MEDIA_DVD=1\n"); - if (cd_media_dvd_r) - printf("ID_CDROM_MEDIA_DVD_R=1\n"); - if (cd_media_dvd_ram) - printf("ID_CDROM_MEDIA_DVD_RAM=1\n"); - if (cd_media_dvd_rw) - printf("ID_CDROM_MEDIA_DVD_RW=1\n"); - if (cd_media_dvd_plus_r) - printf("ID_CDROM_MEDIA_DVD_PLUS_R=1\n"); - if (cd_media_dvd_plus_rw) - printf("ID_CDROM_MEDIA_DVD_PLUS_RW=1\n"); - if (cd_media_dvd_plus_rw_dl) - printf("ID_CDROM_MEDIA_DVD_PLUS_RW_DL=1\n"); - if (cd_media_dvd_plus_r_dl) - printf("ID_CDROM_MEDIA_DVD_PLUS_R_DL=1\n"); - if (cd_media_bd) - printf("ID_CDROM_MEDIA_BD=1\n"); - if (cd_media_bd_r) - printf("ID_CDROM_MEDIA_BD_R=1\n"); - if (cd_media_bd_re) - printf("ID_CDROM_MEDIA_BD_RE=1\n"); - if (cd_media_hddvd) - printf("ID_CDROM_MEDIA_HDDVD=1\n"); - if (cd_media_hddvd_r) - printf("ID_CDROM_MEDIA_HDDVD_R=1\n"); - if (cd_media_hddvd_rw) - printf("ID_CDROM_MEDIA_HDDVD_RW=1\n"); - - if (cd_media_state) - printf("ID_CDROM_MEDIA_STATE=%s\n", cd_media_state); - if (cd_media_session_next > 0) - printf("ID_CDROM_MEDIA_SESSION_NEXT=%u\n", cd_media_session_next); - if (cd_media_session_count > 0) - printf("ID_CDROM_MEDIA_SESSION_COUNT=%u\n", cd_media_session_count); - if (cd_media_session_count > 1 && cd_media_session_last_offset > 0) - printf("ID_CDROM_MEDIA_SESSION_LAST_OFFSET=%llu\n", cd_media_session_last_offset); - if (cd_media_track_count > 0) - printf("ID_CDROM_MEDIA_TRACK_COUNT=%u\n", cd_media_track_count); - if (cd_media_track_count_audio > 0) - printf("ID_CDROM_MEDIA_TRACK_COUNT_AUDIO=%u\n", cd_media_track_count_audio); - if (cd_media_track_count_data > 0) - printf("ID_CDROM_MEDIA_TRACK_COUNT_DATA=%u\n", cd_media_track_count_data); -exit: - if (fd >= 0) - close(fd); - log_close(); - return rc; + return 0; } + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/udev/dmi_memory_id/dmi_memory_id.c b/src/udev/dmi_memory_id/dmi_memory_id.c new file mode 100644 index 000000000..c5bea8c9a --- /dev/null +++ b/src/udev/dmi_memory_id/dmi_memory_id.c @@ -0,0 +1,713 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * System Memory information + * + * Copyright (C) 2000-2002 Alan Cox + * Copyright (C) 2002-2020 Jean Delvare + * Copyright (C) 2020 Bastien Nocera + * + * Unless specified otherwise, all references are aimed at the "System + * Management BIOS Reference Specification, Version 3.2.0" document, + * available from http://www.dmtf.org/standards/smbios. + * + * Note to contributors: + * Please reference every value you add or modify, especially if the + * information does not come from the above mentioned specification. + * + * Additional references: + * - Intel AP-485 revision 36 + * "Intel Processor Identification and the CPUID Instruction" + * http://www.intel.com/support/processors/sb/cs-009861.htm + * - DMTF Common Information Model + * CIM Schema version 2.19.1 + * http://www.dmtf.org/standards/cim/ + * - IPMI 2.0 revision 1.0 + * "Intelligent Platform Management Interface Specification" + * http://developer.intel.com/design/servers/ipmi/spec.htm + * - AMD publication #25481 revision 2.28 + * "CPUID Specification" + * http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/25481.pdf + * - BIOS Integrity Services Application Programming Interface version 1.0 + * http://www.intel.com/design/archives/wfm/downloads/bisspec.htm + * - DMTF DSP0239 version 1.1.0 + * "Management Component Transport Protocol (MCTP) IDs and Codes" + * http://www.dmtf.org/standards/pmci + * - "TPM Main, Part 2 TPM Structures" + * Specification version 1.2, level 2, revision 116 + * https://trustedcomputinggroup.org/tpm-main-specification/ + * - "PC Client Platform TPM Profile (PTP) Specification" + * Family "2.0", Level 00, Revision 00.43, January 26, 2015 + * https://trustedcomputinggroup.org/pc-client-platform-tpm-profile-ptp-specification/ + * - "RedFish Host Interface Specification" (DMTF DSP0270) + * https://www.dmtf.org/sites/default/files/DSP0270_1.0.1.pdf + */ + +#include + +#include "alloc-util.h" +#include "build.h" +#include "fileio.h" +#include "main-func.h" +#include "string-util.h" +#include "udev-util.h" +#include "unaligned.h" + +#define SUPPORTED_SMBIOS_VER 0x030300 + +#define OUT_OF_SPEC_STR "" + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" + +/* + * Per SMBIOS v2.8.0 and later, all structures assume a little-endian + * ordering convention. + */ +#define WORD(x) (unaligned_read_le16(x)) +#define DWORD(x) (unaligned_read_le32(x)) +#define QWORD(x) (unaligned_read_le64(x)) + +struct dmi_header { + uint8_t type; + uint8_t length; + uint16_t handle; + const uint8_t *data; +}; + +static const char *arg_source_file = NULL; + +static bool verify_checksum(const uint8_t *buf, size_t len) { + uint8_t sum = 0; + + for (size_t a = 0; a < len; a++) + sum += buf[a]; + return sum == 0; +} + +/* + * Type-independant Stuff + */ + +static const char *dmi_string(const struct dmi_header *dm, uint8_t s) { + const char *bp = (const char *) dm->data; + + if (s == 0) + return "Not Specified"; + + bp += dm->length; + for (;s > 1 && !isempty(bp); s--) + bp += strlen(bp) + 1; + + if (isempty(bp)) + return ""; + + return bp; +} + +typedef enum { + MEMORY_SIZE_UNIT_BYTES, + MEMORY_SIZE_UNIT_KB +} MemorySizeUnit; + +static void dmi_print_memory_size( + const char *attr_prefix, const char *attr_suffix, + int slot_num, uint64_t code, MemorySizeUnit unit) { + if (unit == MEMORY_SIZE_UNIT_KB) + code <<= 10; + + if (slot_num >= 0) + printf("%s_%u_%s=%"PRIu64"\n", attr_prefix, slot_num, attr_suffix, code); + else + printf("%s_%s=%"PRIu64"\n", attr_prefix, attr_suffix, code); +} + +/* + * 7.17 Physical Memory Array (Type 16) + */ + +static void dmi_memory_array_location(uint8_t code) { + /* 7.17.1 */ + static const char *location[] = { + [0x01] = "Other", + [0x02] = "Unknown", + [0x03] = "System Board Or Motherboard", + [0x04] = "ISA Add-on Card", + [0x05] = "EISA Add-on Card", + [0x06] = "PCI Add-on Card", + [0x07] = "MCA Add-on Card", + [0x08] = "PCMCIA Add-on Card", + [0x09] = "Proprietary Add-on Card", + [0x0A] = "NuBus", + }; + static const char *location_0xA0[] = { + [0x00] = "PC-98/C20 Add-on Card", /* 0xA0 */ + [0x01] = "PC-98/C24 Add-on Card", /* 0xA1 */ + [0x02] = "PC-98/E Add-on Card", /* 0xA2 */ + [0x03] = "PC-98/Local Bus Add-on Card", /* 0xA3 */ + [0x04] = "CXL Flexbus 1.0", /* 0xA4 */ + }; + const char *str = OUT_OF_SPEC_STR; + + if (code < ELEMENTSOF(location) && location[code]) + str = location[code]; + else if (code >= 0xA0 && code < (ELEMENTSOF(location_0xA0) + 0xA0)) + str = location_0xA0[code - 0xA0]; + + printf("MEMORY_ARRAY_LOCATION=%s\n", str); +} + +static void dmi_memory_array_ec_type(uint8_t code) { + /* 7.17.3 */ + static const char *type[] = { + [0x01] = "Other", + [0x02] = "Unknown", + [0x03] = "None", + [0x04] = "Parity", + [0x05] = "Single-bit ECC", + [0x06] = "Multi-bit ECC", + [0x07] = "CRC", + }; + + if (code != 0x03) /* Do not print "None". */ + printf("MEMORY_ARRAY_EC_TYPE=%s\n", + code < ELEMENTSOF(type) && type[code] ? type[code] : OUT_OF_SPEC_STR); +} + +/* + * 7.18 Memory Device (Type 17) + */ + +static void dmi_memory_device_string( + const char *attr_suffix, unsigned slot_num, + const struct dmi_header *h, uint8_t s) { + char *str; + + str = strdupa(dmi_string(h, s)); + str = strstrip(str); + if (!isempty(str)) + printf("MEMORY_DEVICE_%u_%s=%s\n", slot_num, attr_suffix, str); +} + +static void dmi_memory_device_width( + const char *attr_suffix, + unsigned slot_num, uint16_t code) { + + /* If no memory module is present, width may be 0 */ + if (!IN_SET(code, 0, 0xFFFF)) + printf("MEMORY_DEVICE_%u_%s=%u\n", slot_num, attr_suffix, code); +} + +static void dmi_memory_device_size(unsigned slot_num, uint16_t code) { + if (code == 0) + return (void) printf("MEMORY_DEVICE_%u_PRESENT=0\n", slot_num); + if (code == 0xFFFF) + return; + + uint64_t s = code & 0x7FFF; + if (!(code & 0x8000)) + s <<= 10; + dmi_print_memory_size("MEMORY_DEVICE", "SIZE", slot_num, s, MEMORY_SIZE_UNIT_KB); +} + +static void dmi_memory_device_extended_size(unsigned slot_num, uint32_t code) { + uint64_t capacity = (uint64_t) code * 1024 * 1024; + + printf("MEMORY_DEVICE_%u_SIZE=%"PRIu64"\n", slot_num, capacity); +} + +static void dmi_memory_device_rank(unsigned slot_num, uint8_t code) { + code &= 0x0F; + if (code != 0) + printf("MEMORY_DEVICE_%u_RANK=%u\n", slot_num, code); +} + +static void dmi_memory_device_voltage_value( + const char *attr_suffix, + unsigned slot_num, uint16_t code) { + if (code == 0) + return; + if (code % 100 != 0) + printf("MEMORY_DEVICE_%u_%s=%g\n", slot_num, attr_suffix, (double)code / 1000); + else + printf("MEMORY_DEVICE_%u_%s=%.1g\n", slot_num, attr_suffix, (double)code / 1000); +} + +static void dmi_memory_device_form_factor(unsigned slot_num, uint8_t code) { + /* 7.18.1 */ + static const char *form_factor[] = { + [0x01] = "Other", + [0x02] = "Unknown", + [0x03] = "SIMM", + [0x04] = "SIP", + [0x05] = "Chip", + [0x06] = "DIP", + [0x07] = "ZIP", + [0x08] = "Proprietary Card", + [0x09] = "DIMM", + [0x0A] = "TSOP", + [0x0B] = "Row Of Chips", + [0x0C] = "RIMM", + [0x0D] = "SODIMM", + [0x0E] = "SRIMM", + [0x0F] = "FB-DIMM", + [0x10] = "Die", + }; + + printf("MEMORY_DEVICE_%u_FORM_FACTOR=%s\n", slot_num, + code < ELEMENTSOF(form_factor) && form_factor[code] ? form_factor[code] : OUT_OF_SPEC_STR); +} + +static void dmi_memory_device_set(unsigned slot_num, uint8_t code) { + if (code == 0xFF) + printf("MEMORY_DEVICE_%u_SET=%s\n", slot_num, "Unknown"); + else if (code != 0) + printf("MEMORY_DEVICE_%u_SET=%"PRIu8"\n", slot_num, code); +} + +static void dmi_memory_device_type(unsigned slot_num, uint8_t code) { + /* 7.18.2 */ + static const char *type[] = { + [0x01] = "Other", + [0x02] = "Unknown", + [0x03] = "DRAM", + [0x04] = "EDRAM", + [0x05] = "VRAM", + [0x06] = "SRAM", + [0x07] = "RAM", + [0x08] = "ROM", + [0x09] = "Flash", + [0x0A] = "EEPROM", + [0x0B] = "FEPROM", + [0x0C] = "EPROM", + [0x0D] = "CDRAM", + [0x0E] = "3DRAM", + [0x0F] = "SDRAM", + [0x10] = "SGRAM", + [0x11] = "RDRAM", + [0x12] = "DDR", + [0x13] = "DDR2", + [0x14] = "DDR2 FB-DIMM", + [0x15] = "Reserved", + [0x16] = "Reserved", + [0x17] = "Reserved", + [0x18] = "DDR3", + [0x19] = "FBD2", + [0x1A] = "DDR4", + [0x1B] = "LPDDR", + [0x1C] = "LPDDR2", + [0x1D] = "LPDDR3", + [0x1E] = "LPDDR4", + [0x1F] = "Logical non-volatile device", + [0x20] = "HBM", + [0x21] = "HBM2", + }; + + printf("MEMORY_DEVICE_%u_TYPE=%s\n", slot_num, + code < ELEMENTSOF(type) && type[code] ? type[code] : OUT_OF_SPEC_STR); +} + +static void dmi_memory_device_type_detail(unsigned slot_num, uint16_t code) { + /* 7.18.3 */ + static const char *detail[] = { + [1] = "Other", + [2] = "Unknown", + [3] = "Fast-paged", + [4] = "Static Column", + [5] = "Pseudo-static", + [6] = "RAMBus", + [7] = "Synchronous", + [8] = "CMOS", + [9] = "EDO", + [10] = "Window DRAM", + [11] = "Cache DRAM", + [12] = "Non-Volatile", + [13] = "Registered (Buffered)", + [14] = "Unbuffered (Unregistered)", + [15] = "LRDIMM", + }; + + if ((code & 0xFFFE) == 0) + printf("MEMORY_DEVICE_%u_TYPE_DETAIL=%s\n", slot_num, "None"); + else { + bool first_element = true; + + printf("MEMORY_DEVICE_%u_TYPE_DETAIL=", slot_num); + for (size_t i = 1; i < ELEMENTSOF(detail); i++) + if (code & (1 << i)) { + printf("%s%s", first_element ? "" : " ", detail[i]); + first_element = false; + } + printf("\n"); + } +} + +static void dmi_memory_device_speed( + const char *attr_suffix, + unsigned slot_num, uint16_t code) { + if (code != 0) + printf("MEMORY_DEVICE_%u_%s=%u\n", slot_num, attr_suffix, code); +} + +static void dmi_memory_device_technology(unsigned slot_num, uint8_t code) { + /* 7.18.6 */ + static const char * const technology[] = { + [0x01] = "Other", + [0x02] = "Unknown", + [0x03] = "DRAM", + [0x04] = "NVDIMM-N", + [0x05] = "NVDIMM-F", + [0x06] = "NVDIMM-P", + [0x07] = "Intel Optane DC persistent memory", + }; + + printf("MEMORY_DEVICE_%u_MEMORY_TECHNOLOGY=%s\n", slot_num, + code < ELEMENTSOF(technology) && technology[code] ? technology[code] : OUT_OF_SPEC_STR); +} + +static void dmi_memory_device_operating_mode_capability(unsigned slot_num, uint16_t code) { + /* 7.18.7 */ + static const char * const mode[] = { + [1] = "Other", + [2] = "Unknown", + [3] = "Volatile memory", + [4] = "Byte-accessible persistent memory", + [5] = "Block-accessible persistent memory", + }; + + if ((code & 0xFFFE) != 0) { + bool first_element = true; + + printf("MEMORY_DEVICE_%u_MEMORY_OPERATING_MODE_CAPABILITY=", slot_num); + for (size_t i = 1; i < ELEMENTSOF(mode); i++) + if (code & (1 << i)) { + printf("%s%s", first_element ? "" : " ", mode[i]); + first_element = false; + } + printf("\n"); + } +} + +static void dmi_memory_device_manufacturer_id( + const char *attr_suffix, + unsigned slot_num, uint16_t code) { + /* 7.18.8 */ + /* 7.18.10 */ + /* LSB is 7-bit Odd Parity number of continuation codes */ + if (code != 0) + printf("MEMORY_DEVICE_%u_%s=Bank %d, Hex 0x%02X\n", slot_num, attr_suffix, + (code & 0x7F) + 1, code >> 8); +} + +static void dmi_memory_device_product_id( + const char *attr_suffix, + unsigned slot_num, uint16_t code) { + /* 7.18.9 */ + /* 7.18.11 */ + if (code != 0) + printf("MEMORY_DEVICE_%u_%s=0x%04X\n", slot_num, attr_suffix, code); +} + +static void dmi_memory_device_size_detail( + const char *attr_suffix, + unsigned slot_num, uint64_t code) { + /* 7.18.12 */ + /* 7.18.13 */ + if (!IN_SET(code, 0x0LU, 0xFFFFFFFFFFFFFFFFLU)) + dmi_print_memory_size("MEMORY_DEVICE", attr_suffix, slot_num, code, MEMORY_SIZE_UNIT_BYTES); +} + +static void dmi_decode(const struct dmi_header *h) { + const uint8_t *data = h->data; + static unsigned next_slot_num = 0; + unsigned slot_num; + + /* + * Note: DMI types 37 and 42 are untested + */ + switch (h->type) { + case 16: /* 7.17 Physical Memory Array */ + log_debug("Physical Memory Array"); + if (h->length < 0x0F) + break; + + if (data[0x05] != 0x03) /* 7.17.2, Use == "System Memory" */ + break; + + log_debug("Use: System Memory"); + dmi_memory_array_location(data[0x04]); + dmi_memory_array_ec_type(data[0x06]); + if (DWORD(data + 0x07) != 0x80000000) + dmi_print_memory_size("MEMORY_ARRAY", "MAX_CAPACITY", -1, DWORD(data + 0x07), MEMORY_SIZE_UNIT_KB); + else if (h->length >= 0x17) + dmi_print_memory_size("MEMORY_ARRAY", "MAX_CAPACITY", -1, QWORD(data + 0x0F), MEMORY_SIZE_UNIT_BYTES); + printf("MEMORY_ARRAY_NUM_DEVICES=%u\n", WORD(data + 0x0D)); + + break; + + case 17: /* 7.18 Memory Device */ + slot_num = next_slot_num; + next_slot_num++; + + log_debug("Memory Device"); + if (h->length < 0x15) + break; + + dmi_memory_device_width("TOTAL_WIDTH", slot_num, WORD(data + 0x08)); + dmi_memory_device_width("DATA_WIDTH", slot_num, WORD(data + 0x0A)); + if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF) + dmi_memory_device_extended_size(slot_num, DWORD(data + 0x1C)); + else + dmi_memory_device_size(slot_num, WORD(data + 0x0C)); + dmi_memory_device_form_factor(slot_num, data[0x0E]); + dmi_memory_device_set(slot_num, data[0x0F]); + dmi_memory_device_string("LOCATOR", slot_num, h, data[0x10]); + dmi_memory_device_string("BANK_LOCATOR", slot_num, h, data[0x11]); + dmi_memory_device_type(slot_num, data[0x12]); + dmi_memory_device_type_detail(slot_num, WORD(data + 0x13)); + if (h->length < 0x17) + break; + + dmi_memory_device_speed("SPEED_MTS", slot_num, WORD(data + 0x15)); + if (h->length < 0x1B) + break; + + dmi_memory_device_string("MANUFACTURER", slot_num, h, data[0x17]); + dmi_memory_device_string("SERIAL_NUMBER", slot_num, h, data[0x18]); + dmi_memory_device_string("ASSET_TAG", slot_num, h, data[0x19]); + dmi_memory_device_string("PART_NUMBER", slot_num, h, data[0x1A]); + if (h->length < 0x1C) + break; + + dmi_memory_device_rank(slot_num, data[0x1B]); + if (h->length < 0x22) + break; + + dmi_memory_device_speed("CONFIGURED_SPEED_MTS", slot_num, WORD(data + 0x20)); + if (h->length < 0x28) + break; + + dmi_memory_device_voltage_value("MINIMUM_VOLTAGE", slot_num, WORD(data + 0x22)); + dmi_memory_device_voltage_value("MAXIMUM_VOLTAGE", slot_num, WORD(data + 0x24)); + dmi_memory_device_voltage_value("CONFIGURED_VOLTAGE", slot_num, WORD(data + 0x26)); + if (h->length < 0x34) + break; + + dmi_memory_device_technology(slot_num, data[0x28]); + dmi_memory_device_operating_mode_capability(slot_num, WORD(data + 0x29)); + dmi_memory_device_string("FIRMWARE_VERSION", slot_num, h, data[0x2B]); + dmi_memory_device_manufacturer_id("MODULE_MANUFACTURER_ID", slot_num, WORD(data + 0x2C)); + dmi_memory_device_product_id("MODULE_PRODUCT_ID", slot_num, WORD(data + 0x2E)); + dmi_memory_device_manufacturer_id("MEMORY_SUBSYSTEM_CONTROLLER_MANUFACTURER_ID", + slot_num, WORD(data + 0x30)); + dmi_memory_device_product_id("MEMORY_SUBSYSTEM_CONTROLLER_PRODUCT_ID", + slot_num, WORD(data + 0x32)); + if (h->length < 0x3C) + break; + + dmi_memory_device_size_detail("NON_VOLATILE_SIZE", slot_num, QWORD(data + 0x34)); + if (h->length < 0x44) + break; + + dmi_memory_device_size_detail("VOLATILE_SIZE", slot_num, QWORD(data + 0x3C)); + if (h->length < 0x4C) + break; + + dmi_memory_device_size_detail("CACHE_SIZE", slot_num, QWORD(data + 0x44)); + if (h->length < 0x54) + break; + + dmi_memory_device_size_detail("LOGICAL_SIZE", slot_num, QWORD(data + 0x4C)); + + break; + } +} + +static void dmi_table_decode(const uint8_t *buf, size_t len, uint16_t num) { + const uint8_t *data = buf; + + /* 4 is the length of an SMBIOS structure header */ + for (uint16_t i = 0; (i < num || num == 0) && data + 4 <= buf + len; i++) { + struct dmi_header h = (struct dmi_header) { + .type = data[0], + .length = data[1], + .handle = WORD(data + 2), + .data = data, + }; + bool display = !IN_SET(h.type, 126, 127); + const uint8_t *next; + + /* If a short entry is found (less than 4 bytes), not only it + * is invalid, but we cannot reliably locate the next entry. + * Better stop at this point, and let the user know his/her + * table is broken. */ + if (h.length < 4) + break; + + /* In quiet mode, stop decoding at end of table marker */ + if (h.type == 127) + break; + + /* Look for the next handle */ + next = data + h.length; + while ((size_t)(next - buf + 1) < len && (next[0] != 0 || next[1] != 0)) + next++; + next += 2; + + /* Make sure the whole structure fits in the table */ + if ((size_t)(next - buf) > len) + break; + + if (display) + dmi_decode(&h); + + data = next; + } +} + +static int dmi_table(int64_t base, uint32_t len, uint16_t num, const char *devmem, bool no_file_offset) { + _cleanup_free_ uint8_t *buf = NULL; + size_t size; + int r; + + /* + * When reading from sysfs or from a dump file, the file may be + * shorter than announced. For SMBIOS v3 this is expected, as we + * only know the maximum table size, not the actual table size. + * For older implementations (and for SMBIOS v3 too), this + * would be the result of the kernel truncating the table on + * parse error. + */ + r = read_full_file_full(AT_FDCWD, devmem, no_file_offset ? 0 : base, len, + 0, NULL, (char **) &buf, &size); + if (r < 0) + return log_error_errno(r, "Failed to read table: %m"); + + dmi_table_decode(buf, size, num); + + return 0; +} + +/* Same thing for SMBIOS3 entry points */ +static int smbios3_decode(const uint8_t *buf, const char *devmem, bool no_file_offset) { + uint64_t offset; + + /* Don't let checksum run beyond the buffer */ + if (buf[0x06] > 0x20) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Entry point length too large (%"PRIu8" bytes, expected %u).", + buf[0x06], 0x18U); + + if (!verify_checksum(buf, buf[0x06])) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to verify checksum."); + + offset = QWORD(buf + 0x10); + +#if __SIZEOF_SIZE_T__ != 8 + if (!no_file_offset && (offset >> 32) != 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "64-bit addresses not supported on 32-bit systems."); +#endif + + return dmi_table(offset, DWORD(buf + 0x0C), 0, devmem, no_file_offset); +} + +static int smbios_decode(const uint8_t *buf, const char *devmem, bool no_file_offset) { + /* Don't let checksum run beyond the buffer */ + if (buf[0x05] > 0x20) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Entry point length too large (%"PRIu8" bytes, expected %u).", + buf[0x05], 0x1FU); + + if (!verify_checksum(buf, buf[0x05]) + || memcmp(buf + 0x10, "_DMI_", 5) != 0 + || !verify_checksum(buf + 0x10, 0x0F)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to verify checksum."); + + return dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), + devmem, no_file_offset); +} + +static int legacy_decode(const uint8_t *buf, const char *devmem, bool no_file_offset) { + if (!verify_checksum(buf, 0x0F)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to verify checksum."); + + return dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), + devmem, no_file_offset); +} + +static int help(void) { + printf("Usage: %s [options]\n" + " -F,--from-dump FILE read DMI information from a binary file\n" + " -h,--help print this help text\n\n", + program_invocation_short_name); + return 0; +} + +static int parse_argv(int argc, char * const *argv) { + static const struct option options[] = { + { "from-dump", required_argument, NULL, 'F' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + {} + }; + int c; + + while ((c = getopt_long(argc, argv, "F:hV", options, NULL)) >= 0) + switch (c) { + case 'F': + arg_source_file = optarg; + break; + case 'V': + printf("%s\n", GIT_VERSION); + return 0; + case 'h': + return help(); + case '?': + return -EINVAL; + default: + assert_not_reached("Unknown option"); + } + + return 1; +} + +static int run(int argc, char* const* argv) { + _cleanup_free_ uint8_t *buf = NULL; + bool no_file_offset = false; + size_t size; + int r; + + log_set_target(LOG_TARGET_AUTO); + udev_parse_config(); + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + return r; + + /* Read from dump if so instructed */ + r = read_full_file_full(AT_FDCWD, + arg_source_file ?: SYS_ENTRY_FILE, + 0, 0x20, 0, NULL, (char **) &buf, &size); + if (r < 0) + return log_full_errno(!arg_source_file && r == -ENOENT ? LOG_DEBUG : LOG_ERR, + r, "Reading \"%s\" failed: %m", + arg_source_file ?: SYS_ENTRY_FILE); + + if (!arg_source_file) { + arg_source_file = SYS_TABLE_FILE; + no_file_offset = true; + } + + if (size >= 24 && memory_startswith(buf, size, "_SM3_")) + return smbios3_decode(buf, arg_source_file, no_file_offset); + if (size >= 31 && memory_startswith(buf, size, "_SM_")) + return smbios_decode(buf, arg_source_file, no_file_offset); + if (size >= 15 && memory_startswith(buf, size, "_DMI_")) + return legacy_decode(buf, arg_source_file, no_file_offset); + + return -EINVAL; +} + +DEFINE_MAIN_FUNCTION(run); diff --git a/src/udev/fido_id/fido_id.c b/src/udev/fido_id/fido_id.c index f14b81d30..a9f5f8f8a 100644 --- a/src/udev/fido_id/fido_id.c +++ b/src/udev/fido_id/fido_id.c @@ -14,7 +14,6 @@ #include #include -#include "device-internal.h" #include "device-private.h" #include "device-util.h" #include "fd-util.h" diff --git a/src/fuzz/fuzz-udev-rule-parse-value.c b/src/udev/fuzz-udev-rule-parse-value.c similarity index 100% rename from src/fuzz/fuzz-udev-rule-parse-value.c rename to src/udev/fuzz-udev-rule-parse-value.c diff --git a/src/fuzz/fuzz-udev-rules.c b/src/udev/fuzz-udev-rules.c similarity index 83% rename from src/fuzz/fuzz-udev-rules.c rename to src/udev/fuzz-udev-rules.c index e1140bc68..17f5ea121 100644 --- a/src/fuzz/fuzz-udev-rules.c +++ b/src/udev/fuzz-udev-rules.c @@ -15,10 +15,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { _cleanup_(unlink_tempfilep) char filename[] = "/tmp/fuzz-udev-rules.XXXXXX"; int r; - if (!getenv("SYSTEMD_LOG_LEVEL")) { - log_set_max_level_realm(LOG_REALM_UDEV, LOG_CRIT); - log_set_max_level_realm(LOG_REALM_SYSTEMD, LOG_CRIT); - } + if (!getenv("SYSTEMD_LOG_LEVEL")) + log_set_max_level(LOG_CRIT); assert_se(fmkostemp_safe(filename, "r+", &f) == 0); if (size != 0) diff --git a/src/fuzz/fuzz-udev-rules.options b/src/udev/fuzz-udev-rules.options similarity index 100% rename from src/fuzz/fuzz-udev-rules.options rename to src/udev/fuzz-udev-rules.options diff --git a/src/udev/generate-keyboard-keys-gperf.sh b/src/udev/generate-keyboard-keys-gperf.sh index c78652a8e..d417da22f 100755 --- a/src/udev/generate-keyboard-keys-gperf.sh +++ b/src/udev/generate-keyboard-keys-gperf.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu awk ' diff --git a/src/udev/generate-keyboard-keys-list.sh b/src/udev/generate-keyboard-keys-list.sh index aa00c15c1..b40368467 100755 --- a/src/udev/generate-keyboard-keys-list.sh +++ b/src/udev/generate-keyboard-keys-list.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu $1 -dM -include linux/input.h - = 0.47. + if name == 'dmi_memory_id' + dmi_memory_id_path = exe.full_path() + endif endforeach -if install_sysconfdir +if install_sysconfdir_samples install_data('udev.conf', install_dir : join_paths(sysconfdir, 'udev')) endif @@ -204,22 +172,37 @@ endif fuzzers += [ [['src/udev/net/fuzz-link-parser.c', 'src/fuzz/fuzz.h'], - [libudev_core, - libudev_static, - libsystemd_network, + [libudevd_core, + libshared], + [threads, + libacl], + udev_includes], + + [['src/udev/fuzz-udev-rules.c'], + [libudevd_core, libshared], [threads, libacl]], + [['src/udev/fuzz-udev-rule-parse-value.c']], + [['src/udev/fido_id/fuzz-fido-id-desc.c', - 'src/udev/fido_id/fido_id_desc.c'], - [], - []], - ] + 'src/udev/fido_id/fido_id_desc.c']], +] tests += [ + [['src/udev/test-udev-event.c'], + [libudevd_core, + libshared], + [threads, + libacl]], + + [['src/udev/test-udev-builtin.c'], + [libudevd_core, + libshared], + [threads, + libacl]], + [['src/udev/fido_id/test-fido-id-desc.c', - 'src/udev/fido_id/fido_id_desc.c'], - [], - []], - ] + 'src/udev/fido_id/fido_id_desc.c']], +] diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf index 20f5d7e5a..70c5525b5 100644 --- a/src/udev/net/link-config-gperf.gperf +++ b/src/udev/net/link-config-gperf.gperf @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ %{ #if __GNUC__ >= 7 _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") @@ -6,7 +7,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "conf-parser.h" #include "ethtool-util.h" #include "link-config.h" -#include "network-internal.h" +#include "net-condition.h" #include "socket-util.h" %} struct ConfigPerfItem; @@ -20,49 +21,54 @@ struct ConfigPerfItem; %struct-type %includes %% -Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_mac) -Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match_permanent_mac) -Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match_name) -Match.Path, config_parse_match_strv, 0, offsetof(link_config, match_path) -Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match_driver) -Match.Type, config_parse_match_strv, 0, offsetof(link_config, match_type) -Match.Property, config_parse_match_property, 0, offsetof(link_config, match_property) -Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions) -Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions) -Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions) -Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(link_config, conditions) -Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, conditions) -Link.Description, config_parse_string, 0, offsetof(link_config, description) -Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(link_config, mac_address_policy) -Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac) -Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy) -Link.Name, config_parse_ifname, 0, offsetof(link_config, name) -Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(link_config, alternative_names) -Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy) -Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias) -Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu) -Link.BitsPerSecond, config_parse_si_uint64, 0, offsetof(link_config, speed) -Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex) -Link.AutoNegotiation, config_parse_tristate, 0, offsetof(link_config, autonegotiation) -Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol) -Link.Port, config_parse_port, 0, offsetof(link_config, port) -Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_RX]) -Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TX]) -Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO]) -Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO]) -Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO6]) -Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0 -Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO]) -Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO]) -Link.RxChannels, config_parse_channel, 0, offsetof(link_config, channels) -Link.TxChannels, config_parse_channel, 0, offsetof(link_config, channels) -Link.OtherChannels, config_parse_channel, 0, offsetof(link_config, channels) -Link.CombinedChannels, config_parse_channel, 0, offsetof(link_config, channels) -Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise) -Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) -Link.RxMiniBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) -Link.RxJumboBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) -Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) -Link.RxFlowControl, config_parse_tristate, 0, offsetof(link_config, rx_flow_control) -Link.TxFlowControl, config_parse_tristate, 0, offsetof(link_config, tx_flow_control) -Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(link_config, autoneg_flow_control) +Match.MACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match.mac) +Match.PermanentMACAddress, config_parse_hwaddrs, 0, offsetof(link_config, match.permanent_mac) +Match.OriginalName, config_parse_match_ifnames, 0, offsetof(link_config, match.ifname) +Match.Path, config_parse_match_strv, 0, offsetof(link_config, match.path) +Match.Driver, config_parse_match_strv, 0, offsetof(link_config, match.driver) +Match.Type, config_parse_match_strv, 0, offsetof(link_config, match.iftype) +Match.Property, config_parse_match_property, 0, offsetof(link_config, match.property) +Match.Host, config_parse_net_condition, CONDITION_HOST, offsetof(link_config, conditions) +Match.Virtualization, config_parse_net_condition, CONDITION_VIRTUALIZATION, offsetof(link_config, conditions) +Match.KernelCommandLine, config_parse_net_condition, CONDITION_KERNEL_COMMAND_LINE, offsetof(link_config, conditions) +Match.KernelVersion, config_parse_net_condition, CONDITION_KERNEL_VERSION, offsetof(link_config, conditions) +Match.Architecture, config_parse_net_condition, CONDITION_ARCHITECTURE, offsetof(link_config, conditions) +Link.Description, config_parse_string, 0, offsetof(link_config, description) +Link.MACAddressPolicy, config_parse_mac_address_policy, 0, offsetof(link_config, mac_address_policy) +Link.MACAddress, config_parse_hwaddr, 0, offsetof(link_config, mac) +Link.NamePolicy, config_parse_name_policy, 0, offsetof(link_config, name_policy) +Link.Name, config_parse_ifname, 0, offsetof(link_config, name) +Link.AlternativeName, config_parse_ifnames, IFNAME_VALID_ALTERNATIVE, offsetof(link_config, alternative_names) +Link.AlternativeNamesPolicy, config_parse_alternative_names_policy, 0, offsetof(link_config, alternative_names_policy) +Link.Alias, config_parse_ifalias, 0, offsetof(link_config, alias) +Link.TransmitQueues, config_parse_rx_tx_queues, 0, offsetof(link_config, txqueues) +Link.ReceiveQueues, config_parse_rx_tx_queues, 0, offsetof(link_config, rxqueues) +Link.TransmitQueueLength, config_parse_txqueuelen, 0, offsetof(link_config, txqueuelen) +Link.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(link_config, mtu) +Link.BitsPerSecond, config_parse_si_uint64, 0, offsetof(link_config, speed) +Link.Duplex, config_parse_duplex, 0, offsetof(link_config, duplex) +Link.AutoNegotiation, config_parse_tristate, 0, offsetof(link_config, autonegotiation) +Link.WakeOnLan, config_parse_wol, 0, offsetof(link_config, wol) +Link.Port, config_parse_port, 0, offsetof(link_config, port) +Link.ReceiveChecksumOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_RX]) +Link.TransmitChecksumOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TX]) +Link.GenericSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GSO]) +Link.TCPSegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO]) +Link.TCP6SegmentationOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_TSO6]) +Link.UDPSegmentationOffload, config_parse_warn_compat, DISABLED_LEGACY, 0 +Link.GenericReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_GRO]) +Link.LargeReceiveOffload, config_parse_tristate, 0, offsetof(link_config, features[NET_DEV_FEAT_LRO]) +Link.RxChannels, config_parse_channel, 0, offsetof(link_config, channels) +Link.TxChannels, config_parse_channel, 0, offsetof(link_config, channels) +Link.OtherChannels, config_parse_channel, 0, offsetof(link_config, channels) +Link.CombinedChannels, config_parse_channel, 0, offsetof(link_config, channels) +Link.Advertise, config_parse_advertise, 0, offsetof(link_config, advertise) +Link.RxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) +Link.RxMiniBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) +Link.RxJumboBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) +Link.TxBufferSize, config_parse_nic_buffer_size, 0, offsetof(link_config, ring) +Link.RxFlowControl, config_parse_tristate, 0, offsetof(link_config, rx_flow_control) +Link.TxFlowControl, config_parse_tristate, 0, offsetof(link_config, tx_flow_control) +Link.AutoNegotiationFlowControl, config_parse_tristate, 0, offsetof(link_config, autoneg_flow_control) +Link.GenericSegmentOffloadMaxBytes, config_parse_iec_size, 0, offsetof(link_config, gso_max_size) +Link.GenericSegmentOffloadMaxSegments, config_parse_uint32, 0, offsetof(link_config, gso_max_segments) diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c index d12fd0e29..31e5d0cd6 100644 --- a/src/udev/net/link-config.c +++ b/src/udev/net/link-config.c @@ -18,9 +18,10 @@ #include "link-config.h" #include "log.h" #include "memory-util.h" +#include "net-condition.h" #include "netif-naming-scheme.h" #include "netlink-util.h" -#include "network-internal.h" +#include "network-util.h" #include "parse-util.h" #include "path-lookup.h" #include "path-util.h" @@ -30,6 +31,7 @@ #include "string-table.h" #include "string-util.h" #include "strv.h" +#include "utf8.h" struct link_config_ctx { LIST_HEAD(link_config, links); @@ -43,19 +45,13 @@ struct link_config_ctx { usec_t network_dirs_ts_usec; }; -static void link_config_free(link_config *link) { +static link_config* link_config_free(link_config *link) { if (!link) - return; + return NULL; free(link->filename); - set_free_free(link->match_mac); - set_free_free(link->match_permanent_mac); - strv_free(link->match_path); - strv_free(link->match_driver); - strv_free(link->match_type); - strv_free(link->match_name); - strv_free(link->match_property); + net_match_clear(&link->match); condition_free_list(link->conditions); free(link->description); @@ -66,7 +62,7 @@ static void link_config_free(link_config *link) { free(link->alternative_names_policy); free(link->alias); - free(link); + return mfree(link); } DEFINE_TRIVIAL_CLEANUP_FUNC(link_config*, link_config_free); @@ -81,19 +77,14 @@ static void link_configs_free(link_config_ctx *ctx) { link_config_free(link); } -void link_config_ctx_free(link_config_ctx *ctx) { +link_config_ctx* link_config_ctx_free(link_config_ctx *ctx) { if (!ctx) - return; + return NULL; safe_close(ctx->ethtool_fd); - sd_netlink_unref(ctx->rtnl); - link_configs_free(ctx); - - free(ctx); - - return; + return mfree(ctx); } int link_config_ctx_new(link_config_ctx **ret) { @@ -119,19 +110,20 @@ int link_config_ctx_new(link_config_ctx **ret) { int link_load_one(link_config_ctx *ctx, const char *filename) { _cleanup_(link_config_freep) link_config *link = NULL; - _cleanup_fclose_ FILE *file = NULL; _cleanup_free_ char *name = NULL; + const char *dropin_dirname; size_t i; int r; assert(ctx); assert(filename); - file = fopen(filename, "re"); - if (!file) - return errno == ENOENT ? 0 : -errno; - - if (null_or_empty_fd(fileno(file))) { + r = null_or_empty_path(filename); + if (r == -ENOENT) + return 0; + if (r < 0) + return r; + if (r > 0) { log_debug("Skipping empty file: %s", filename); return 0; } @@ -154,22 +146,24 @@ int link_load_one(link_config_ctx *ctx, const char *filename) { .rx_flow_control = -1, .tx_flow_control = -1, .autoneg_flow_control = -1, + .txqueuelen = UINT32_MAX, }; for (i = 0; i < ELEMENTSOF(link->features); i++) link->features[i] = -1; - r = config_parse(NULL, filename, file, - "Match\0Link\0", - config_item_perf_lookup, link_config_gperf_lookup, - CONFIG_PARSE_WARN, link, - NULL); + dropin_dirname = strjoina(basename(filename), ".d"); + r = config_parse_many( + STRV_MAKE_CONST(filename), + (const char* const*) CONF_PATHS_STRV("systemd/network"), + dropin_dirname, + "Match\0Link\0", + config_item_perf_lookup, link_config_gperf_lookup, + CONFIG_PARSE_WARN, link, NULL); if (r < 0) return r; - if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) && - strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) && - strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions) { + if (net_match_is_empty(&link->match) && !link->conditions) { log_warning("%s: No valid settings found in the [Match] section, ignoring file. " "To match all interfaces, add OriginalName=* in the [Match] section.", filename); @@ -279,11 +273,8 @@ int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) (void) link_unsigned_attribute(device, "name_assign_type", &name_assign_type); LIST_FOREACH(links, link, ctx->links) { - if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver, - link->match_type, link->match_name, link->match_property, NULL, NULL, NULL, - device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) { - - if (link->match_name && !strv_contains(link->match_name, "*") && name_assign_type == NET_NAME_ENUM) + if (net_match_config(&link->match, device, NULL, &permanent_mac, NULL, iftype, NULL, NULL, 0, NULL, NULL)) { + if (link->match.ifname && !strv_contains(link->match.ifname, "*") && name_assign_type == NET_NAME_ENUM) log_device_warning(device, "Config file %s is applied to device based on potentially unpredictable interface name.", link->filename); else @@ -435,17 +426,21 @@ static int link_config_apply_rtnl_settings(sd_netlink **rtnl, const link_config } else mac = config->mac; - r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, config->mtu); + r = rtnl_set_link_properties(rtnl, ifindex, config->alias, mac, + config->txqueues, config->rxqueues, config->txqueuelen, + config->mtu, config->gso_max_size, config->gso_max_segments); if (r < 0) - log_device_warning_errno(device, r, "Could not set Alias=, MACAddress= or MTU=, ignoring: %m"); + log_device_warning_errno(device, r, + "Could not set Alias=, MACAddress=, " + "TransmitQueues=, ReceiveQueues=, TransmitQueueLength=, MTU=, " + "GenericSegmentOffloadMaxBytes= or GenericSegmentOffloadMaxSegments=, " + "ignoring: %m"); return 0; } static int link_config_generate_new_name(const link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) { unsigned name_type = NET_NAME_UNKNOWN; - const char *new_name = NULL; - NamePolicy policy; int r; assert(ctx); @@ -463,7 +458,8 @@ static int link_config_generate_new_name(const link_config_ctx *ctx, const link_ if (ctx->enable_name_policy && config->name_policy) for (NamePolicy *p = config->name_policy; *p != _NAMEPOLICY_INVALID; p++) { - policy = *p; + const char *new_name = NULL; + NamePolicy policy = *p; switch (policy) { case NAMEPOLICY_KERNEL: @@ -499,16 +495,13 @@ static int link_config_generate_new_name(const link_config_ctx *ctx, const link_ default: assert_not_reached("invalid policy"); } - if (ifname_valid(new_name)) - break; + if (ifname_valid(new_name)) { + log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); + *ret_name = new_name; + return 0; + } } - if (new_name) { - log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name); - *ret_name = new_name; - return 0; - } - if (config->name) { log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", config->name); *ret_name = config->name; @@ -601,7 +594,7 @@ static int link_config_apply_alternative_names(sd_netlink **rtnl, const link_con int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device *device, const char **ret_name) { const char *new_name; - DeviceAction a; + sd_device_action_t a; int r; assert(ctx); @@ -609,11 +602,11 @@ int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device assert(device); assert(ret_name); - r = device_get_action(device, &a); + r = sd_device_get_action(device, &a); if (r < 0) return log_device_error_errno(device, r, "Failed to get ACTION= property: %m"); - if (!IN_SET(a, DEVICE_ACTION_ADD, DEVICE_ACTION_BIND, DEVICE_ACTION_MOVE)) { + if (!IN_SET(a, SD_DEVICE_ADD, SD_DEVICE_BIND, SD_DEVICE_MOVE)) { log_device_debug(device, "Skipping to apply .link settings on '%s' uevent.", device_action_to_string(a)); r = sd_device_get_sysname(device, ret_name); @@ -631,7 +624,7 @@ int link_config_apply(link_config_ctx *ctx, const link_config *config, sd_device if (r < 0) return r; - if (a == DEVICE_ACTION_MOVE) { + if (a == SD_DEVICE_MOVE) { log_device_debug(device, "Skipping to apply Name= and NamePolicy= on '%s' uevent.", device_action_to_string(a)); r = sd_device_get_sysname(device, &new_name); @@ -668,6 +661,113 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) { return 0; } +int config_parse_ifalias( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char **s = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + if (!isempty(rvalue)) { + *s = mfree(*s); + return 0; + } + + if (!ascii_is_valid(rvalue)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Interface alias is not ASCII clean, ignoring assignment: %s", rvalue); + return 0; + } + + if (strlen(rvalue) >= IFALIASZ) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Interface alias is too long, ignoring assignment: %s", rvalue); + return 0; + } + + return free_and_strdup_warn(s, rvalue); +} + +int config_parse_rx_tx_queues( + 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) { + + uint32_t k, *v = data; + int r; + + if (isempty(rvalue)) { + *v = 0; + return 0; + } + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue); + return 0; + } + if (k == 0 || k > 4096) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s=, ignoring assignment: %s.", lvalue, rvalue); + return 0; + } + + *v = k; + return 0; +} + +int config_parse_txqueuelen( + 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) { + + uint32_t k, *v = data; + int r; + + if (isempty(rvalue)) { + *v = UINT32_MAX; + return 0; + } + + r = safe_atou32(rvalue, &k); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse %s=, ignoring assignment: %s.", lvalue, rvalue); + return 0; + } + if (k == UINT32_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid %s=, ignoring assignment: %s.", lvalue, rvalue); + return 0; + } + + *v = k; + return 0; +} + static const char* const mac_address_policy_table[_MAC_ADDRESS_POLICY_MAX] = { [MAC_ADDRESS_POLICY_PERSISTENT] = "persistent", [MAC_ADDRESS_POLICY_RANDOM] = "random", diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h index eab1849fc..71f8983fb 100644 --- a/src/udev/net/link-config.h +++ b/src/udev/net/link-config.h @@ -7,7 +7,7 @@ #include "conf-parser.h" #include "ethtool-util.h" #include "list.h" -#include "set.h" +#include "net-condition.h" typedef struct link_config_ctx link_config_ctx; typedef struct link_config link_config; @@ -17,7 +17,7 @@ typedef enum MACAddressPolicy { MAC_ADDRESS_POLICY_RANDOM, MAC_ADDRESS_POLICY_NONE, _MAC_ADDRESS_POLICY_MAX, - _MAC_ADDRESS_POLICY_INVALID = -1 + _MAC_ADDRESS_POLICY_INVALID = -EINVAL, } MACAddressPolicy; typedef enum NamePolicy { @@ -29,19 +29,13 @@ typedef enum NamePolicy { NAMEPOLICY_PATH, NAMEPOLICY_MAC, _NAMEPOLICY_MAX, - _NAMEPOLICY_INVALID = -1 + _NAMEPOLICY_INVALID = -EINVAL, } NamePolicy; struct link_config { char *filename; - Set *match_mac; - Set *match_permanent_mac; - char **match_path; - char **match_driver; - char **match_type; - char **match_name; - char **match_property; + NetMatch match; LIST_HEAD(Condition, conditions); char *description; @@ -52,7 +46,12 @@ struct link_config { char *name; char **alternative_names; char *alias; + uint32_t txqueues; + uint32_t rxqueues; + uint32_t txqueuelen; uint32_t mtu; + uint32_t gso_max_segments; + size_t gso_max_size; uint64_t speed; Duplex duplex; int autonegotiation; @@ -70,7 +69,7 @@ struct link_config { }; int link_config_ctx_new(link_config_ctx **ret); -void link_config_ctx_free(link_config_ctx *ctx); +link_config_ctx* link_config_ctx_free(link_config_ctx *ctx); DEFINE_TRIVIAL_CLEANUP_FUNC(link_config_ctx*, link_config_ctx_free); int link_load_one(link_config_ctx *ctx, const char *filename); @@ -93,6 +92,9 @@ MACAddressPolicy mac_address_policy_from_string(const char *p) _pure_; /* gperf lookup function */ const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN_TYPE length); +CONFIG_PARSER_PROTOTYPE(config_parse_ifalias); +CONFIG_PARSER_PROTOTYPE(config_parse_rx_tx_queues); +CONFIG_PARSER_PROTOTYPE(config_parse_txqueuelen); CONFIG_PARSER_PROTOTYPE(config_parse_mac_address_policy); CONFIG_PARSER_PROTOTYPE(config_parse_name_policy); CONFIG_PARSER_PROTOTYPE(config_parse_alternative_names_policy); diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index 57202564d..0c4a17c45 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -18,8 +18,8 @@ #include "alloc-util.h" #include "build.h" +#include "device-nodes.h" #include "fd-util.h" -#include "libudev-util.h" #include "scsi_id.h" #include "string-util.h" #include "strxcpyx.h" @@ -299,9 +299,8 @@ static void help(void) { " -g --whitelisted Treat device as whitelisted\n" " -u --replace-whitespace Replace all whitespace by underscores\n" " -v --verbose Verbose logging\n" - " -x --export Print values as environment keys\n" - , program_invocation_short_name); - + " -x --export Print values as environment keys\n", + program_invocation_short_name); } static int set_options(int argc, char **argv, @@ -453,16 +452,16 @@ static int set_inq_values(struct scsi_id_device *dev_scsi, const char *path) { if (retval) return retval; - udev_util_encode_string(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str)); - udev_util_encode_string(dev_scsi->model, model_enc_str, sizeof(model_enc_str)); + encode_devnode_name(dev_scsi->vendor, vendor_enc_str, sizeof(vendor_enc_str)); + encode_devnode_name(dev_scsi->model, model_enc_str, sizeof(model_enc_str)); - util_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str)-1); - util_replace_chars(vendor_str, NULL); - util_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str)-1); - util_replace_chars(model_str, NULL); + udev_replace_whitespace(dev_scsi->vendor, vendor_str, sizeof(vendor_str)-1); + udev_replace_chars(vendor_str, NULL); + udev_replace_whitespace(dev_scsi->model, model_str, sizeof(model_str)-1); + udev_replace_chars(model_str, NULL); set_type(dev_scsi->type, type_str, sizeof(type_str)); - util_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str)-1); - util_replace_chars(revision_str, NULL); + udev_replace_whitespace(dev_scsi->revision, revision_str, sizeof(revision_str)-1); + udev_replace_chars(revision_str, NULL); return 0; } @@ -502,11 +501,11 @@ static int scsi_id(char *maj_min_dev) { printf("ID_REVISION=%s\n", revision_str); printf("ID_TYPE=%s\n", type_str); if (dev_scsi.serial[0] != '\0') { - util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)-1); - util_replace_chars(serial_str, NULL); + udev_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)-1); + udev_replace_chars(serial_str, NULL); printf("ID_SERIAL=%s\n", serial_str); - util_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)-1); - util_replace_chars(serial_str, NULL); + udev_replace_whitespace(dev_scsi.serial_short, serial_str, sizeof(serial_str)-1); + udev_replace_chars(serial_str, NULL); printf("ID_SERIAL_SHORT=%s\n", serial_str); } if (dev_scsi.wwn[0] != '\0') { @@ -532,8 +531,8 @@ static int scsi_id(char *maj_min_dev) { if (reformat_serial) { char serial_str[MAX_SERIAL_LEN]; - util_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)-1); - util_replace_chars(serial_str, NULL); + udev_replace_whitespace(dev_scsi.serial, serial_str, sizeof(serial_str)-1); + udev_replace_chars(serial_str, NULL); printf("%s\n", serial_str); goto out; } diff --git a/src/udev/test-udev-builtin.c b/src/udev/test-udev-builtin.c new file mode 100644 index 000000000..21a8ea3fa --- /dev/null +++ b/src/udev/test-udev-builtin.c @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "tests.h" +#include "udev-builtin.h" + +static void test_udev_builtin_cmd_to_ptr(void) { + log_info("/* %s */", __func__); + + /* Those could have been static asserts, but ({}) is not allowed there. */ +#if HAVE_BLKID + assert_se(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID)); + assert_se(PTR_TO_UDEV_BUILTIN_CMD(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BLKID)) == UDEV_BUILTIN_BLKID); +#endif + assert_se(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BTRFS)); + assert_se(PTR_TO_UDEV_BUILTIN_CMD(UDEV_BUILTIN_CMD_TO_PTR(UDEV_BUILTIN_BTRFS)) == UDEV_BUILTIN_BTRFS); + assert_se(PTR_TO_UDEV_BUILTIN_CMD(UDEV_BUILTIN_CMD_TO_PTR(_UDEV_BUILTIN_INVALID)) == _UDEV_BUILTIN_INVALID); + + assert_se(PTR_TO_UDEV_BUILTIN_CMD(NULL) == _UDEV_BUILTIN_INVALID); + assert_se(PTR_TO_UDEV_BUILTIN_CMD((void*) 10000) == _UDEV_BUILTIN_INVALID); +} + +int main(int argc, char *argv[]) { + test_setup_logging(LOG_DEBUG); + + test_udev_builtin_cmd_to_ptr(); +} diff --git a/src/udev/test-udev-event.c b/src/udev/test-udev-event.c new file mode 100644 index 000000000..584e5c27e --- /dev/null +++ b/src/udev/test-udev-event.c @@ -0,0 +1,108 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "path-util.h" +#include "signal-util.h" +#include "strv.h" +#include "tests.h" +#include "udev-event.h" +#include "util.h" + +#define BUF_SIZE 1024 + +static void test_event_spawn_core(bool with_pidfd, const char *cmd, char result_buf[BUF_SIZE]) { + _cleanup_(sd_device_unrefp) sd_device *dev = NULL; + _cleanup_(udev_event_freep) UdevEvent *event = NULL; + + assert_se(setenv("SYSTEMD_PIDFD", yes_no(with_pidfd), 1) >= 0); + + assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net/lo") >= 0); + assert_se(event = udev_event_new(dev, 0, NULL, LOG_DEBUG)); + assert_se(udev_event_spawn(event, 5 * USEC_PER_SEC, SIGKILL, false, cmd, result_buf, BUF_SIZE) == 0); + + assert_se(unsetenv("SYSTEMD_PIDFD") >= 0); +} + +static void test_event_spawn_cat(bool with_pidfd) { + _cleanup_strv_free_ char **lines = NULL; + _cleanup_free_ char *cmd = NULL; + char result_buf[BUF_SIZE]; + + log_debug("/* %s(%s) */", __func__, yes_no(with_pidfd)); + + assert_se(find_executable("cat", &cmd) >= 0); + assert_se(strextend_with_separator(&cmd, " ", "/sys/class/net/lo/uevent")); + + test_event_spawn_core(with_pidfd, cmd, result_buf); + + assert_se(lines = strv_split_newlines(result_buf)); + strv_print(lines); + + assert_se(strv_contains(lines, "INTERFACE=lo")); + assert_se(strv_contains(lines, "IFINDEX=1")); +} + +static void test_event_spawn_self(const char *self, const char *arg, bool with_pidfd) { + _cleanup_strv_free_ char **lines = NULL; + _cleanup_free_ char *cmd = NULL; + char result_buf[BUF_SIZE]; + + log_debug("/* %s(%s, %s) */", __func__, arg, yes_no(with_pidfd)); + + assert_se(cmd = strjoin(self, " ", arg)); + + test_event_spawn_core(with_pidfd, cmd, result_buf); + + assert_se(lines = strv_split_newlines(result_buf)); + strv_print(lines); + + assert_se(strv_contains(lines, "aaa")); + assert_se(strv_contains(lines, "bbb")); +} + +static void test1(void) { + fprintf(stdout, "aaa\nbbb"); + fprintf(stderr, "ccc\nddd"); +} + +static void test2(void) { + char buf[16384]; + + fprintf(stdout, "aaa\nbbb"); + + memset(buf, 'a', sizeof(buf) - 1); + char_array_0(buf); + fputs(buf, stderr); +} + +int main(int argc, char *argv[]) { + _cleanup_free_ char *self = NULL; + + if (argc > 1) { + if (streq(argv[1], "test1")) + test1(); + else if (streq(argv[1], "test2")) + test2(); + else + assert_not_reached("unknown command."); + + return 0; + } + + test_setup_logging(LOG_DEBUG); + + assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0); + + test_event_spawn_cat(true); + test_event_spawn_cat(false); + + assert_se(path_make_absolute_cwd(argv[0], &self) >= 0); + path_simplify(self, true); + + test_event_spawn_self(self, "test1", true); + test_event_spawn_self(self, "test1", false); + + test_event_spawn_self(self, "test2", true); + test_event_spawn_self(self, "test2", false); + + return 0; +} diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index 3f64548ad..2daafb115 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -91,6 +91,22 @@ static void print_property(sd_device *dev, bool test, const char *name, const ch } else if (streq(name, "BOOT_SYSTEM_ID")) { blkid_encode_string(value, s, sizeof(s)); udev_builtin_add_property(dev, test, "ID_FS_BOOT_SYSTEM_ID", s); + + } else if (streq(name, "VOLUME_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_VOLUME_ID", s); + + } else if (streq(name, "LOGICAL_VOLUME_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_LOGICAL_VOLUME_ID", s); + + } else if (streq(name, "VOLUME_SET_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_VOLUME_SET_ID", s); + + } else if (streq(name, "DATA_PREPARER_ID")) { + blkid_encode_string(value, s, sizeof(s)); + udev_builtin_add_property(dev, test, "ID_FS_DATA_PREPARER_ID", s); } } @@ -222,24 +238,46 @@ static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) { static const struct option options[] = { { "offset", required_argument, NULL, 'o' }, - { "noraid", no_argument, NULL, 'R' }, + { "hint", required_argument, NULL, 'H' }, + { "noraid", no_argument, NULL, 'R' }, {} }; + errno = 0; + pr = blkid_new_probe(); + if (!pr) + return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to create blkid prober: %m"); + for (;;) { int option; - option = getopt_long(argc, argv, "o:R", options, NULL); + option = getopt_long(argc, argv, "o:H:R", options, NULL); if (option == -1) break; switch (option) { + case 'H': +#if HAVE_BLKID_PROBE_SET_HINT + errno = 0; + r = blkid_probe_set_hint(pr, optarg, 0); + if (r < 0) + return log_device_error_errno(dev, errno_or_else(ENOMEM), "Failed to use '%s' probing hint: %m", optarg); + break; +#else + /* Use the hint = as probing offset for old versions */ + optarg = strchr(optarg, '='); + if (!optarg) + /* no value means 0, do nothing for old versions */ + break; + ++optarg; + _fallthrough_; +#endif case 'o': r = safe_atoi64(optarg, &offset); if (r < 0) return log_device_error_errno(dev, r, "Failed to parse '%s' as an integer: %m", optarg); if (offset < 0) - return log_device_error_errno(dev, SYNTHETIC_ERRNO(ERANGE), "Invalid offset %"PRIi64": %m", offset); + return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid offset %"PRIi64": %m", offset); break; case 'R': noraid = true; @@ -247,11 +285,6 @@ static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) { } } - errno = 0; - pr = blkid_new_probe(); - if (!pr) - return log_device_debug_errno(dev, errno > 0 ? errno : ENOMEM, "Failed to create blkid prober: %m"); - blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_LABEL | BLKID_SUBLKS_UUID | BLKID_SUBLKS_TYPE | BLKID_SUBLKS_SECTYPE | @@ -271,7 +304,7 @@ static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) { errno = 0; r = blkid_probe_set_device(pr, fd, offset, 0); if (r < 0) - return log_device_debug_errno(dev, errno > 0 ? errno : ENOMEM, "Failed to set device to blkid prober: %m"); + return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to set device to blkid prober: %m"); log_device_debug(dev, "Probe %s with %sraid and offset=%"PRIi64, devnode, noraid ? "no" : "", offset); @@ -285,7 +318,7 @@ static int builtin_blkid(sd_device *dev, int argc, char *argv[], bool test) { errno = 0; nvals = blkid_probe_numof_values(pr); if (nvals < 0) - return log_device_debug_errno(dev, errno > 0 ? errno : ENOMEM, "Failed to get number of probed values: %m"); + return log_device_debug_errno(dev, errno_or_else(ENOMEM), "Failed to get number of probed values: %m"); for (i = 0; i < nvals; i++) { if (blkid_probe_get_value(pr, i, &name, &data, NULL) < 0) diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index 9079d1b8e..436bf6bd4 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -21,8 +21,17 @@ static int builtin_btrfs(sd_device *dev, int argc, char *argv[], bool test) { return log_device_error_errno(dev, SYNTHETIC_ERRNO(EINVAL), "Invalid arguments"); fd = open("/dev/btrfs-control", O_RDWR|O_CLOEXEC); - if (fd < 0) + if (fd < 0) { + if (IN_SET(errno, ENOENT, ENXIO, ENODEV)) { + /* Driver not installed? Then we aren't ready. This is useful in initrds that lack + * btrfs.ko. After the host transition (where btrfs.ko will hopefully become + * available) the device can be retriggered and will then be considered ready. */ + udev_builtin_add_property(dev, test, "ID_BTRFS_READY", "0"); + return 0; + } + return log_device_debug_errno(dev, errno, "Failed to open /dev/btrfs-control: %m"); + } strscpy(args.name, sizeof(args.name), argv[2]); r = ioctl(fd, BTRFS_IOC_DEVICES_READY, &args); diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index d06a8c715..872833ebb 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -474,8 +474,7 @@ static int names_platform(sd_device *dev, struct netnames *names, bool test) { /* Platform devices are named after ACPI table match, and instance id * eg. "/sys/devices/platform/HISI00C2:00"); - * The Vendor (3 or 4 char), followed by hexdecimal model number : instance id. - */ + * The Vendor (3 or 4 char), followed by hexadecimal model number : instance id. */ DISABLE_WARNING_FORMAT_NONLITERAL; if (sscanf(syspath, pattern, vendor, &model, &instance, ðid) != 4) diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c index cb12b943f..87e1fb133 100644 --- a/src/udev/udev-builtin-net_setup_link.c +++ b/src/udev/udev-builtin-net_setup_link.c @@ -1,7 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "device-util.h" #include "alloc-util.h" +#include "device-util.h" +#include "errno-util.h" #include "link-config.h" #include "log.h" #include "string-util.h" @@ -20,7 +21,7 @@ static int builtin_net_setup_link(sd_device *dev, int argc, char **argv, bool te r = link_get_driver(ctx, dev, &driver); if (r < 0) - log_device_full_errno(dev, r == -EOPNOTSUPP ? LOG_DEBUG : LOG_WARNING, + log_device_full_errno(dev, ERRNO_IS_NOT_SUPPORTED(r) || r == -ENODEV ? LOG_DEBUG : LOG_WARNING, r, "Failed to query device driver: %m"); else udev_builtin_add_property(dev, test, "ID_NET_DRIVER", driver); @@ -29,13 +30,17 @@ static int builtin_net_setup_link(sd_device *dev, int argc, char **argv, bool te if (r < 0) { if (r == -ENOENT) return log_device_debug_errno(dev, r, "No matching link configuration found."); + if (r == -ENODEV) + return log_device_debug_errno(dev, r, "Link vanished while searching for configuration for it."); return log_device_error_errno(dev, r, "Failed to get link config: %m"); } r = link_config_apply(ctx, link, dev, &name); - if (r < 0) - log_device_warning_errno(dev, r, "Could not apply link config, ignoring: %m"); + if (r == -ENODEV) + log_device_debug_errno(dev, r, "Link vanished while applying configuration, ignoring."); + else if (r < 0) + log_device_warning_errno(dev, r, "Could not apply link configuration, ignoring: %m"); udev_builtin_add_property(dev, test, "ID_NET_LINK_FILE", link->filename); diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index 0da59e2c7..09cc1c3bd 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -17,11 +17,11 @@ #include "alloc-util.h" #include "dirent-util.h" #include "fd-util.h" -#include "libudev-util.h" #include "string-util.h" #include "strv.h" #include "sysexits.h" #include "udev-builtin.h" +#include "udev-util.h" _printf_(2,3) static void path_prepend(char **path, const char *fmt, ...) { @@ -680,7 +680,7 @@ static int builtin_path_id(sd_device *dev, int argc, char *argv[], bool test) { return -ENOENT; { - char tag[UTIL_NAME_SIZE]; + char tag[UDEV_NAME_SIZE]; size_t i; const char *p; diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index cfdf130f1..3fdbb88bc 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -11,8 +11,8 @@ #include "sd-login.h" #include "device-util.h" +#include "devnode-acl.h" #include "login-util.h" -#include "logind-acl.h" #include "log.h" #include "udev-builtin.h" diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c index fa554e740..7d94c6b0a 100644 --- a/src/udev/udev-builtin-usb_id.c +++ b/src/udev/udev-builtin-usb_id.c @@ -15,12 +15,13 @@ #include #include "alloc-util.h" +#include "device-nodes.h" #include "device-util.h" #include "fd-util.h" -#include "libudev-util.h" #include "string-util.h" #include "strxcpyx.h" #include "udev-builtin.h" +#include "udev-util.h" static void set_usb_iftype(char *to, int if_class_num, size_t len) { const char *type = "generic"; @@ -234,8 +235,8 @@ static int builtin_usb_id(sd_device *dev, int argc, char *argv[], bool test) { char model_str[64] = ""; char model_str_enc[256]; const char *product_id; - char serial_str[UTIL_NAME_SIZE] = ""; - char packed_if_str[UTIL_NAME_SIZE] = ""; + char serial_str[UDEV_NAME_SIZE] = ""; + char packed_if_str[UDEV_NAME_SIZE] = ""; char revision_str[64] = ""; char type_str[64] = ""; char instance_str[64] = ""; @@ -328,18 +329,18 @@ static int builtin_usb_id(sd_device *dev, int argc, char *argv[], bool test) { log_device_debug_errno(dev_scsi, r, "Failed to get SCSI vendor attribute: %m"); goto fallback; } - udev_util_encode_string(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc)); - util_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1); - util_replace_chars(vendor_str, NULL); + encode_devnode_name(scsi_vendor, vendor_str_enc, sizeof(vendor_str_enc)); + udev_replace_whitespace(scsi_vendor, vendor_str, sizeof(vendor_str)-1); + udev_replace_chars(vendor_str, NULL); r = sd_device_get_sysattr_value(dev_scsi, "model", &scsi_model); if (r < 0) { log_device_debug_errno(dev_scsi, r, "Failed to get SCSI model attribute: %m"); goto fallback; } - udev_util_encode_string(scsi_model, model_str_enc, sizeof(model_str_enc)); - util_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1); - util_replace_chars(model_str, NULL); + encode_devnode_name(scsi_model, model_str_enc, sizeof(model_str_enc)); + udev_replace_whitespace(scsi_model, model_str, sizeof(model_str)-1); + udev_replace_chars(model_str, NULL); r = sd_device_get_sysattr_value(dev_scsi, "type", &scsi_type); if (r < 0) { @@ -353,8 +354,8 @@ static int builtin_usb_id(sd_device *dev, int argc, char *argv[], bool test) { log_device_debug_errno(dev_scsi, r, "Failed to get SCSI revision attribute: %m"); goto fallback; } - util_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1); - util_replace_chars(revision_str, NULL); + udev_replace_whitespace(scsi_rev, revision_str, sizeof(revision_str)-1); + udev_replace_chars(revision_str, NULL); /* * some broken devices have the same identifiers @@ -378,9 +379,9 @@ fallback: if (sd_device_get_sysattr_value(dev_usb, "manufacturer", &usb_vendor) < 0) usb_vendor = vendor_id; - udev_util_encode_string(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc)); - util_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1); - util_replace_chars(vendor_str, NULL); + encode_devnode_name(usb_vendor, vendor_str_enc, sizeof(vendor_str_enc)); + udev_replace_whitespace(usb_vendor, vendor_str, sizeof(vendor_str)-1); + udev_replace_chars(vendor_str, NULL); } if (model_str[0] == '\0') { @@ -388,17 +389,17 @@ fallback: if (sd_device_get_sysattr_value(dev_usb, "product", &usb_model) < 0) usb_model = product_id; - udev_util_encode_string(usb_model, model_str_enc, sizeof(model_str_enc)); - util_replace_whitespace(usb_model, model_str, sizeof(model_str)-1); - util_replace_chars(model_str, NULL); + encode_devnode_name(usb_model, model_str_enc, sizeof(model_str_enc)); + udev_replace_whitespace(usb_model, model_str, sizeof(model_str)-1); + udev_replace_chars(model_str, NULL); } if (revision_str[0] == '\0') { const char *usb_rev; if (sd_device_get_sysattr_value(dev_usb, "bcdDevice", &usb_rev) >= 0) { - util_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1); - util_replace_chars(revision_str, NULL); + udev_replace_whitespace(usb_rev, revision_str, sizeof(revision_str)-1); + udev_replace_chars(revision_str, NULL); } } @@ -416,8 +417,8 @@ fallback: } if (usb_serial) { - util_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1); - util_replace_chars(serial_str, NULL); + udev_replace_whitespace(usb_serial, serial_str, sizeof(serial_str)-1); + udev_replace_chars(serial_str, NULL); } } } diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h index 14d6406d2..849e5d9e8 100644 --- a/src/udev/udev-builtin.h +++ b/src/udev/udev-builtin.h @@ -24,7 +24,7 @@ typedef enum { UDEV_BUILTIN_UACCESS, #endif _UDEV_BUILTIN_MAX, - _UDEV_BUILTIN_INVALID = -1, + _UDEV_BUILTIN_INVALID = -EINVAL, } UdevBuiltinCommand; typedef struct UdevBuiltin { @@ -37,8 +37,18 @@ typedef struct UdevBuiltin { bool run_once; } UdevBuiltin; -#define PTR_TO_UDEV_BUILTIN_CMD(p) ((UdevBuiltinCommand) ((intptr_t) (p)-1)) -#define UDEV_BUILTIN_CMD_TO_PTR(u) ((void *) ((intptr_t) (u)+1)) +#define UDEV_BUILTIN_CMD_TO_PTR(u) \ + ({ \ + UdevBuiltinCommand _u = (u); \ + _u < 0 ? NULL : (void*)(intptr_t) (_u + 1); \ + }) + +#define PTR_TO_UDEV_BUILTIN_CMD(p) \ + ({ \ + void *_p = (p); \ + _p && (intptr_t)(_p) <= _UDEV_BUILTIN_MAX ? \ + (UdevBuiltinCommand)((intptr_t)_p - 1) : _UDEV_BUILTIN_INVALID; \ + }) #if HAVE_BLKID extern const UdevBuiltin udev_builtin_blkid; diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 48355aa50..3d5635471 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -1,12 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later - * - * libudev - interface to udev device information - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include @@ -44,10 +36,10 @@ struct udev_ctrl { int sock_connect; union sockaddr_union saddr; socklen_t addrlen; - bool bound:1; - bool cleanup_socket:1; - bool connected:1; - bool maybe_disconnected:1; + bool bound; + bool cleanup_socket; + bool connected; + bool maybe_disconnected; sd_event *event; sd_event_source *event_source; sd_event_source *event_source_connect; @@ -172,9 +164,10 @@ static void udev_ctrl_disconnect_and_listen_again(struct udev_ctrl *uctrl) { udev_ctrl_disconnect(uctrl); udev_ctrl_unref(uctrl); (void) sd_event_source_set_enabled(uctrl->event_source, SD_EVENT_ON); + /* We don't return NULL here because uctrl is not freed */ } -DEFINE_TRIVIAL_CLEANUP_FUNC(struct udev_ctrl *, udev_ctrl_disconnect_and_listen_again); +DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(struct udev_ctrl*, udev_ctrl_disconnect_and_listen_again, NULL); static int udev_ctrl_connection_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) { _cleanup_(udev_ctrl_disconnect_and_listen_againp) struct udev_ctrl *uctrl = NULL; diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 5159d19a3..12597194a 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -17,7 +17,6 @@ #include "fd-util.h" #include "fs-util.h" #include "format-util.h" -#include "libudev-util.h" #include "netlink-util.h" #include "parse-util.h" #include "path-util.h" @@ -51,7 +50,7 @@ typedef struct Spawn { size_t result_len; } Spawn; -UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl) { +UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level) { UdevEvent *event; assert(dev); @@ -68,6 +67,8 @@ UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rt .uid = UID_INVALID, .gid = GID_INVALID, .mode = MODE_INVALID, + .log_level_was_debug = log_level == LOG_DEBUG, + .default_log_level = log_level, }; return event; @@ -106,7 +107,7 @@ typedef enum { FORMAT_SUBST_ROOT, FORMAT_SUBST_SYS, _FORMAT_SUBST_TYPE_MAX, - _FORMAT_SUBST_TYPE_INVALID = -1 + _FORMAT_SUBST_TYPE_INVALID = -EINVAL, } FormatSubstitutionType; struct subst_map_entry { @@ -150,7 +151,7 @@ static char format_type_to_char(FormatSubstitutionType t) { return '\0'; } -static int get_subst_type(const char **str, bool strict, FormatSubstitutionType *ret_type, char ret_attr[static UTIL_PATH_SIZE]) { +static int get_subst_type(const char **str, bool strict, FormatSubstitutionType *ret_type, char ret_attr[static UDEV_PATH_SIZE]) { const char *p = *str, *q = NULL; size_t i; @@ -196,10 +197,10 @@ static int get_subst_type(const char **str, bool strict, FormatSubstitutionType return -EINVAL; len = end - start; - if (len == 0 || len >= UTIL_PATH_SIZE) + if (len == 0 || len >= UDEV_PATH_SIZE) return -EINVAL; - strnscpy(ret_attr, UTIL_PATH_SIZE, start, len); + strnscpy(ret_attr, UDEV_PATH_SIZE, start, len); q = end + 1; } else *ret_attr = '\0'; @@ -337,14 +338,14 @@ static ssize_t udev_event_subst_format( break; } case FORMAT_SUBST_ATTR: { - char vbuf[UTIL_NAME_SIZE]; + char vbuf[UDEV_NAME_SIZE]; int count; if (isempty(attr)) return -EINVAL; /* try to read the value specified by "[dmi/id]product_name" */ - if (util_resolve_subsys_kernel(attr, vbuf, sizeof(vbuf), true) == 0) + if (udev_resolve_subsys_kernel(attr, vbuf, sizeof(vbuf), true) == 0) val = vbuf; /* try to read the attribute the device */ @@ -362,7 +363,7 @@ static ssize_t udev_event_subst_format( if (val != vbuf) strscpy(vbuf, sizeof(vbuf), val); delete_trailing_chars(vbuf, NULL); - count = util_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT); + count = udev_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT); if (count > 0) log_device_debug(dev, "%i character(s) replaced", count); l = strpcpy(&s, l, vbuf); @@ -451,7 +452,7 @@ size_t udev_event_apply_format(UdevEvent *event, while (*s) { FormatSubstitutionType type; - char attr[UTIL_PATH_SIZE]; + char attr[UDEV_PATH_SIZE]; ssize_t subst_len; r = get_subst_type(&s, false, &type, attr); @@ -476,9 +477,9 @@ size_t udev_event_apply_format(UdevEvent *event, /* FORMAT_SUBST_RESULT handles spaces itself */ if (replace_whitespace && type != FORMAT_SUBST_RESULT) - /* util_replace_whitespace can replace in-place, + /* udev_replace_whitespace can replace in-place, * and does nothing if subst_len == 0 */ - subst_len = util_replace_whitespace(dest, dest, subst_len); + subst_len = udev_replace_whitespace(dest, dest, subst_len); dest += subst_len; size -= subst_len; @@ -492,7 +493,7 @@ size_t udev_event_apply_format(UdevEvent *event, int udev_check_format(const char *value, size_t *offset, const char **hint) { FormatSubstitutionType type; const char *s = value; - char attr[UTIL_PATH_SIZE]; + char attr[UDEV_PATH_SIZE]; int r; while (*s) { @@ -572,21 +573,23 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd _cleanup_strv_free_ char **v = NULL; char **q; - v = strv_split_newlines(p); - if (!v) - return 0; + r = strv_split_newlines_full(&v, p, EXTRACT_RETAIN_ESCAPE); + if (r < 0) + log_device_debug(spawn->device, + "Failed to split output from '%s'(%s), ignoring: %m", + spawn->cmd, fd == spawn->fd_stdout ? "out" : "err"); STRV_FOREACH(q, v) log_device_debug(spawn->device, "'%s'(%s) '%s'", spawn->cmd, fd == spawn->fd_stdout ? "out" : "err", *q); } - if (l == 0) return 0; - /* Re-enable the event source if we did not encounter EOF */ reenable: + /* Re-enable the event source if we did not encounter EOF */ + r = sd_event_source_set_enabled(s, SD_EVENT_ONESHOT); if (r < 0) log_device_error_errno(spawn->device, r, @@ -660,7 +663,7 @@ static int spawn_wait(Spawn *spawn) { r = sd_event_new(&e); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to allocate sd-event object: %m"); if (spawn->timeout_usec > 0) { usec_t usec, age_usec; @@ -677,7 +680,7 @@ static int spawn_wait(Spawn *spawn) { usec + spawn->timeout_warn_usec, USEC_PER_SEC, on_spawn_timeout_warning, spawn); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to create timeout warning event source: %m"); } spawn->timeout_usec -= age_usec; @@ -685,36 +688,35 @@ static int spawn_wait(Spawn *spawn) { r = sd_event_add_time(e, NULL, CLOCK_MONOTONIC, usec + spawn->timeout_usec, USEC_PER_SEC, on_spawn_timeout, spawn); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to create timeout event source: %m"); } } if (spawn->fd_stdout >= 0) { r = sd_event_add_io(e, &stdout_source, spawn->fd_stdout, EPOLLIN, on_spawn_io, spawn); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to create stdio event source: %m"); r = sd_event_source_set_enabled(stdout_source, SD_EVENT_ONESHOT); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to enable stdio event source: %m"); } if (spawn->fd_stderr >= 0) { r = sd_event_add_io(e, &stderr_source, spawn->fd_stderr, EPOLLIN, on_spawn_io, spawn); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to create stderr event source: %m"); r = sd_event_source_set_enabled(stderr_source, SD_EVENT_ONESHOT); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to enable stderr event source: %m"); } r = sd_event_add_child(e, &sigchld_source, spawn->pid, WEXITED, on_spawn_sigchld, spawn); if (r < 0) - return r; + return log_device_debug_errno(spawn->device, r, "Failed to create sigchild event source: %m"); /* SIGCHLD should be processed after IO is complete */ r = sd_event_source_set_priority(sigchld_source, SD_EVENT_PRIORITY_NORMAL + 1); if (r < 0) - return r; - + return log_device_debug_errno(spawn->device, r, "Failed to set priority to sigchild event source: %m"); return sd_event_loop(e); } @@ -831,7 +833,7 @@ static int rename_netif(UdevEvent *event) { if (streq(event->name, oldname)) return 0; /* The interface name is already requested name. */ - if (!device_for_action(dev, DEVICE_ACTION_ADD)) + if (!device_for_action(dev, SD_DEVICE_ADD)) return 0; /* Rename the interface only when it is added. */ r = sd_device_get_ifindex(dev, &ifindex); @@ -904,7 +906,7 @@ static int update_devnode(UdevEvent *event) { /* If group is set, but mode is not set, "upgrade" mode for the group. */ event->mode = 0660; - bool apply_mac = device_for_action(dev, DEVICE_ACTION_ADD); + bool apply_mac = device_for_action(dev, SD_DEVICE_ADD); return udev_node_add(dev, apply_mac, event->mode, event->uid, event->gid, event->seclabel_list); } @@ -975,7 +977,7 @@ int udev_event_execute_rules(UdevEvent *event, Hashmap *properties_list, UdevRules *rules) { const char *subsystem; - DeviceAction action; + sd_device_action_t action; sd_device *dev; int r; @@ -988,11 +990,11 @@ int udev_event_execute_rules(UdevEvent *event, if (r < 0) return log_device_error_errno(dev, r, "Failed to get subsystem: %m"); - r = device_get_action(dev, &action); + r = sd_device_get_action(dev, &action); if (r < 0) return log_device_error_errno(dev, r, "Failed to get ACTION: %m"); - if (action == DEVICE_ACTION_REMOVE) { + if (action == SD_DEVICE_REMOVE) { event_execute_rules_on_remove(event, timeout_usec, timeout_signal, properties_list, rules); return 0; } @@ -1009,7 +1011,7 @@ int udev_event_execute_rules(UdevEvent *event, /* Disable watch during event processing. */ (void) udev_watch_end(event->dev_db_clone); - if (action == DEVICE_ACTION_MOVE) { + if (action == SD_DEVICE_MOVE) { r = udev_event_on_move(event->dev); if (r < 0) return r; @@ -1041,6 +1043,8 @@ int udev_event_execute_rules(UdevEvent *event, if (r < 0) return log_device_debug_errno(dev, r, "Failed to update database under /run/udev/data/: %m"); + device_set_is_initialized(dev); + /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database, * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure * symlinks point to devices that claim them with the highest priority. */ @@ -1048,8 +1052,6 @@ int udev_event_execute_rules(UdevEvent *event, if (r < 0) return r; - device_set_is_initialized(dev); - return 0; } diff --git a/src/udev/udev-event.h b/src/udev/udev-event.h index 864782822..ecbe957b4 100644 --- a/src/udev/udev-event.h +++ b/src/udev/udev-event.h @@ -16,6 +16,7 @@ #define READ_END 0 #define WRITE_END 1 +#define UDEV_ALLOWED_CHARS_INPUT "/ $%?," typedef struct UdevEvent { sd_device *dev; @@ -34,17 +35,19 @@ typedef struct UdevEvent { unsigned builtin_run; unsigned builtin_ret; UdevRuleEscapeType esc:8; - bool inotify_watch:1; - bool inotify_watch_final:1; - bool group_final:1; - bool owner_final:1; - bool mode_final:1; - bool name_final:1; - bool devlink_final:1; - bool run_final:1; + bool inotify_watch; + bool inotify_watch_final; + bool group_final; + bool owner_final; + bool mode_final; + bool name_final; + bool devlink_final; + bool run_final; + bool log_level_was_debug; + int default_log_level; } UdevEvent; -UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl); +UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level); UdevEvent *udev_event_free(UdevEvent *event); DEFINE_TRIVIAL_CLEANUP_FUNC(UdevEvent*, udev_event_free); diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index b8b93eeb7..96963a434 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -15,7 +15,6 @@ #include "fd-util.h" #include "format-util.h" #include "fs-util.h" -#include "libudev-util.h" #include "mkdir.h" #include "path-util.h" #include "selinux-util.h" @@ -192,6 +191,40 @@ static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, return 0; } +static size_t escape_path(const char *src, char *dest, size_t size) { + size_t i, j; + + assert(src); + assert(dest); + + for (i = 0, j = 0; src[i] != '\0'; i++) { + if (src[i] == '/') { + if (j+4 >= size) { + j = 0; + break; + } + memcpy(&dest[j], "\\x2f", 4); + j += 4; + } else if (src[i] == '\\') { + if (j+4 >= size) { + j = 0; + break; + } + memcpy(&dest[j], "\\x5c", 4); + j += 4; + } else { + if (j+1 >= size) { + j = 0; + break; + } + dest[j] = src[i]; + j++; + } + } + dest[j] = '\0'; + return j; +} + /* manage "stack of names" with possibly specified device priorities */ static int link_update(sd_device *dev, const char *slink, bool add) { _cleanup_free_ char *filename = NULL, *dirname = NULL; @@ -206,7 +239,7 @@ static int link_update(sd_device *dev, const char *slink, bool add) { if (r < 0) return log_device_debug_errno(dev, r, "Failed to get id_filename: %m"); - util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc)); + escape_path(slink + STRLEN("/dev"), name_enc, sizeof(name_enc)); dirname = path_join("/run/udev/links/", name_enc); if (!dirname) return log_oom(); diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index ef6a0c112..57ede6a19 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -6,6 +6,7 @@ #include "architecture.h" #include "conf-files.h" #include "def.h" +#include "device-private.h" #include "device-util.h" #include "dirent-util.h" #include "escape.h" @@ -14,7 +15,6 @@ #include "format-util.h" #include "fs-util.h" #include "glob-util.h" -#include "libudev-util.h" #include "list.h" #include "mkdir.h" #include "nulstr-util.h" @@ -25,6 +25,7 @@ #include "strv.h" #include "strxcpyx.h" #include "sysctl-util.h" +#include "syslog-util.h" #include "udev-builtin.h" #include "udev-event.h" #include "udev-rules.h" @@ -41,7 +42,7 @@ typedef enum { OP_ASSIGN, /* = */ OP_ASSIGN_FINAL, /* := */ _OP_TYPE_MAX, - _OP_TYPE_INVALID = -1 + _OP_TYPE_INVALID = -EINVAL, } UdevRuleOperatorType; typedef enum { @@ -52,7 +53,7 @@ typedef enum { MATCH_TYPE_GLOB_WITH_EMPTY, /* shell globs ?,*,[] with empty string, e.g., "|foo*" */ MATCH_TYPE_SUBSYSTEM, /* "subsystem", "bus", or "class" */ _MATCH_TYPE_MAX, - _MATCH_TYPE_INVALID = -1 + _MATCH_TYPE_INVALID = -EINVAL, } UdevRuleMatchType; typedef enum { @@ -60,7 +61,7 @@ typedef enum { SUBST_TYPE_FORMAT, /* % or $ */ SUBST_TYPE_SUBSYS, /* "[/]" format */ _SUBST_TYPE_MAX, - _SUBST_TYPE_INVALID = -1 + _SUBST_TYPE_INVALID = -EINVAL, } UdevRuleSubstituteType; typedef enum { @@ -75,7 +76,7 @@ typedef enum { TK_M_TAG, /* strv, sd_device_get_tag_first(), sd_device_get_tag_next() */ TK_M_SUBSYSTEM, /* string, sd_device_get_subsystem() */ TK_M_DRIVER, /* string, sd_device_get_driver() */ - TK_M_ATTR, /* string, takes filename through attribute, sd_device_get_sysattr_value(), util_resolve_subsys_kernel(), etc. */ + TK_M_ATTR, /* string, takes filename through attribute, sd_device_get_sysattr_value(), udev_resolve_subsys_kernel(), etc. */ TK_M_SYSCTL, /* string, takes kernel parameter through attribute */ /* matches parent parameters */ @@ -104,6 +105,7 @@ typedef enum { TK_A_OPTIONS_DB_PERSIST, /* no argument */ TK_A_OPTIONS_INOTIFY_WATCH, /* boolean */ TK_A_OPTIONS_DEVLINK_PRIORITY, /* int */ + TK_A_OPTIONS_LOG_LEVEL, /* string of log level or "reset" */ TK_A_OWNER, /* user name */ TK_A_GROUP, /* group name */ TK_A_MODE, /* mode string */ @@ -122,7 +124,7 @@ typedef enum { TK_A_RUN_PROGRAM, /* string */ _TK_TYPE_MAX, - _TK_TYPE_INVALID = -1, + _TK_TYPE_INVALID = -EINVAL, } UdevRuleTokenType; typedef enum { @@ -263,9 +265,9 @@ static void udev_rule_line_clear_tokens(UdevRuleLine *rule_line) { rule_line->tokens = NULL; } -static void udev_rule_line_free(UdevRuleLine *rule_line) { +static UdevRuleLine* udev_rule_line_free(UdevRuleLine *rule_line) { if (!rule_line) - return; + return NULL; udev_rule_line_clear_tokens(rule_line); @@ -277,7 +279,7 @@ static void udev_rule_line_free(UdevRuleLine *rule_line) { } free(rule_line->line); - free(rule_line); + return mfree(rule_line); } DEFINE_TRIVIAL_CLEANUP_FUNC(UdevRuleLine*, udev_rule_line_free); @@ -335,11 +337,7 @@ static int rule_resolve_user(UdevRules *rules, const char *name, uid_t *ret) { if (!n) return -ENOMEM; - r = hashmap_ensure_allocated(&rules->known_users, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(rules->known_users, n, UID_TO_PTR(uid)); + r = hashmap_ensure_put(&rules->known_users, &string_hash_ops, n, UID_TO_PTR(uid)); if (r < 0) return r; @@ -374,11 +372,7 @@ static int rule_resolve_group(UdevRules *rules, const char *name, gid_t *ret) { if (!n) return -ENOMEM; - r = hashmap_ensure_allocated(&rules->known_groups, &string_hash_ops); - if (r < 0) - return r; - - r = hashmap_put(rules->known_groups, n, GID_TO_PTR(gid)); + r = hashmap_ensure_put(&rules->known_groups, &string_hash_ops, n, GID_TO_PTR(gid)); if (r < 0) return r; @@ -834,6 +828,17 @@ static int parse_token(UdevRules *rules, const char *key, char *attr, UdevRuleOp if (r < 0) return log_token_error_errno(rules, r, "Failed to parse link priority '%s': %m", tmp); r = rule_line_add_token(rule_line, TK_A_OPTIONS_DEVLINK_PRIORITY, op, NULL, INT_TO_PTR(prio)); + } else if ((tmp = startswith(value, "log_level="))) { + int level; + + if (streq(tmp, "reset")) + level = -1; + else { + level = log_level_from_string(tmp); + if (level < 0) + return log_token_error_errno(rules, level, "Failed to parse log level '%s': %m", tmp); + } + r = rule_line_add_token(rule_line, TK_A_OPTIONS_LOG_LEVEL, op, NULL, INT_TO_PTR(level)); } else { log_token_warning(rules, "Invalid value for OPTIONS key, ignoring: '%s'", value); return 0; @@ -1211,7 +1216,7 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { size_t len; char *line; - r = read_line(f, UTIL_LINE_SIZE, &buf); + r = read_line(f, UDEV_LINE_SIZE, &buf); if (r < 0) return r; if (r == 0) @@ -1226,10 +1231,10 @@ int udev_rules_parse_file(UdevRules *rules, const char *filename) { len = strlen(line); if (continuation && !ignore_line) { - if (strlen(continuation) + len >= UTIL_LINE_SIZE) + if (strlen(continuation) + len >= UDEV_LINE_SIZE) ignore_line = true; - if (!strextend(&continuation, line, NULL)) + if (!strextend(&continuation, line)) return log_oom(); if (!ignore_line) { @@ -1364,7 +1369,7 @@ static bool token_match_string(UdevRuleToken *token, const char *str) { } static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *event) { - char nbuf[UTIL_NAME_SIZE], vbuf[UTIL_NAME_SIZE]; + char nbuf[UDEV_NAME_SIZE], vbuf[UDEV_NAME_SIZE]; const char *name, *value; assert(token); @@ -1383,7 +1388,7 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev return false; break; case SUBST_TYPE_SUBSYS: - if (util_resolve_subsys_kernel(name, vbuf, sizeof(vbuf), true) < 0) + if (udev_resolve_subsys_kernel(name, vbuf, sizeof(vbuf), true) < 0) return false; value = vbuf; break; @@ -1474,10 +1479,10 @@ static int import_parent_into_properties(sd_device *dev, const char *filter) { return 1; } -static int attr_subst_subdir(char attr[static UTIL_PATH_SIZE]) { +static int attr_subst_subdir(char attr[static UDEV_PATH_SIZE]) { _cleanup_closedir_ DIR *dir = NULL; struct dirent *dent; - char buf[UTIL_PATH_SIZE], *p; + char buf[UDEV_PATH_SIZE], *p; const char *tail; size_t len, size; @@ -1522,7 +1527,7 @@ static int udev_rule_apply_token_to_event( Hashmap *properties_list) { UdevRuleToken *token; - char buf[UTIL_PATH_SIZE]; + char buf[UDEV_PATH_SIZE]; const char *val; size_t count; bool match; @@ -1541,9 +1546,9 @@ static int udev_rule_apply_token_to_event( switch (token->type) { case TK_M_ACTION: { - DeviceAction a; + sd_device_action_t a; - r = device_get_action(dev, &a); + r = sd_device_get_action(dev, &a); if (r < 0) return log_rule_error_errno(dev, rules, r, "Failed to get uevent action type: %m"); @@ -1628,8 +1633,8 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false); if (!path_is_absolute(buf) && - util_resolve_subsys_kernel(buf, buf, sizeof(buf), false) < 0) { - char tmp[UTIL_PATH_SIZE]; + udev_resolve_subsys_kernel(buf, buf, sizeof(buf), false) < 0) { + char tmp[UDEV_PATH_SIZE]; r = sd_device_get_syspath(dev, &val); if (r < 0) @@ -1655,7 +1660,7 @@ static int udev_rule_apply_token_to_event( return token->op == (match ? OP_MATCH : OP_NOMATCH); } case TK_M_PROGRAM: { - char result[UTIL_LINE_SIZE]; + char result[UDEV_LINE_SIZE]; event->program_result = mfree(event->program_result); (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false); @@ -1671,7 +1676,7 @@ static int udev_rule_apply_token_to_event( } delete_trailing_chars(result, "\n"); - count = util_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT); + count = udev_replace_chars(result, UDEV_ALLOWED_CHARS_INPUT); if (count > 0) log_rule_debug(dev, rules, "Replaced %zu character(s) in result of \"%s\"", count, buf); @@ -1726,7 +1731,8 @@ static int udev_rule_apply_token_to_event( return token->op == OP_MATCH; } case TK_M_IMPORT_PROGRAM: { - char result[UTIL_LINE_SIZE], *line, *pos; + _cleanup_strv_free_ char **lines = NULL; + char result[UDEV_LINE_SIZE], **line; (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false); log_rule_debug(dev, rules, "Importing properties from results of '%s'", buf); @@ -1740,18 +1746,19 @@ static int udev_rule_apply_token_to_event( return token->op == OP_NOMATCH; } - for (line = result; !isempty(line); line = pos) { + r = strv_split_newlines_full(&lines, result, EXTRACT_RETAIN_ESCAPE); + if (r < 0) + log_rule_warning_errno(dev, rules, r, + "Failed to extract lines from result of command \"%s\", ignoring: %m", buf); + + STRV_FOREACH(line, lines) { char *key, *value; - pos = strchr(line, '\n'); - if (pos) - *pos++ = '\0'; - - r = get_property_from_string(line, &key, &value); + r = get_property_from_string(*line, &key, &value); if (r < 0) { log_rule_debug_errno(dev, rules, r, "Failed to parse key and value from '%s', ignoring: %m", - line); + *line); continue; } if (r == 0) @@ -1768,6 +1775,7 @@ static int udev_rule_apply_token_to_event( } case TK_M_IMPORT_BUILTIN: { UdevBuiltinCommand cmd = PTR_TO_UDEV_BUILTIN_CMD(token->data); + assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX); unsigned mask = 1U << (int) cmd; if (udev_builtin_run_once(cmd)) { @@ -1858,8 +1866,24 @@ static int udev_rule_apply_token_to_event( case TK_A_OPTIONS_DEVLINK_PRIORITY: device_set_devlink_priority(dev, PTR_TO_INT(token->data)); break; + case TK_A_OPTIONS_LOG_LEVEL: { + int level = PTR_TO_INT(token->data); + + if (level < 0) + level = event->default_log_level; + + log_set_max_level(level); + + if (level == LOG_DEBUG && !event->log_level_was_debug) { + /* The log level becomes LOG_DEBUG at first time. Let's log basic information. */ + log_device_uevent(dev, "The log level is changed to 'debug' while processing device"); + event->log_level_was_debug = true; + } + + break; + } case TK_A_OWNER: { - char owner[UTIL_NAME_SIZE]; + char owner[UDEV_NAME_SIZE]; const char *ow = owner; if (event->owner_final) @@ -1876,7 +1900,7 @@ static int udev_rule_apply_token_to_event( break; } case TK_A_GROUP: { - char group[UTIL_NAME_SIZE]; + char group[UDEV_NAME_SIZE]; const char *gr = group; if (event->group_final) @@ -1893,7 +1917,7 @@ static int udev_rule_apply_token_to_event( break; } case TK_A_MODE: { - char mode_str[UTIL_NAME_SIZE]; + char mode_str[UDEV_NAME_SIZE]; if (event->mode_final) break; @@ -1940,7 +1964,7 @@ static int udev_rule_apply_token_to_event( break; case TK_A_SECLABEL: { _cleanup_free_ char *name = NULL, *label = NULL; - char label_str[UTIL_LINE_SIZE] = {}; + char label_str[UDEV_LINE_SIZE] = {}; name = strdup(token->data); if (!name) @@ -1957,20 +1981,21 @@ static int udev_rule_apply_token_to_event( if (token->op == OP_ASSIGN) ordered_hashmap_clear_free_free(event->seclabel_list); - r = ordered_hashmap_ensure_allocated(&event->seclabel_list, NULL); - if (r < 0) + r = ordered_hashmap_ensure_put(&event->seclabel_list, NULL, name, label); + if (r == -ENOMEM) return log_oom(); + if (r < 0) + return log_rule_error_errno(dev, rules, r, "Failed to store SECLABEL{%s}='%s': %m", name, label);; - r = ordered_hashmap_put(event->seclabel_list, name, label); - if (r < 0) - return log_oom(); log_rule_debug(dev, rules, "SECLABEL{%s}='%s'", name, label); - name = label = NULL; + + TAKE_PTR(name); + TAKE_PTR(label); break; } case TK_A_ENV: { const char *name = token->data; - char value_new[UTIL_NAME_SIZE], *p = value_new; + char value_new[UDEV_NAME_SIZE], *p = value_new; size_t l = sizeof(value_new); if (isempty(token->value)) { @@ -2019,7 +2044,7 @@ static int udev_rule_apply_token_to_event( (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false); if (IN_SET(event->esc, ESCAPE_UNSET, ESCAPE_REPLACE)) { - count = util_replace_chars(buf, "/"); + count = udev_replace_chars(buf, "/"); if (count > 0) log_rule_debug(dev, rules, "Replaced %zu character(s) from result of NAME=\"%s\"", count, token->value); @@ -2032,8 +2057,9 @@ static int udev_rule_apply_token_to_event( token->value); break; } - if (free_and_strdup(&event->name, buf) < 0) - return log_oom(); + r = free_and_strdup_warn(&event->name, buf); + if (r < 0) + return r; log_rule_debug(dev, rules, "NAME '%s'", event->name); break; @@ -2053,9 +2079,9 @@ static int udev_rule_apply_token_to_event( /* allow multiple symlinks separated by spaces */ (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), event->esc != ESCAPE_NONE); if (event->esc == ESCAPE_UNSET) - count = util_replace_chars(buf, "/ "); + count = udev_replace_chars(buf, "/ "); else if (event->esc == ESCAPE_REPLACE) - count = util_replace_chars(buf, "/"); + count = udev_replace_chars(buf, "/"); else count = 0; if (count > 0) @@ -2063,7 +2089,7 @@ static int udev_rule_apply_token_to_event( p = skip_leading_chars(buf, NULL); while (!isempty(p)) { - char filename[UTIL_PATH_SIZE], *next; + char filename[UDEV_PATH_SIZE], *next; next = strchr(p, ' '); if (next) { @@ -2083,9 +2109,9 @@ static int udev_rule_apply_token_to_event( } case TK_A_ATTR: { const char *key_name = token->data; - char value[UTIL_NAME_SIZE]; + char value[UDEV_NAME_SIZE]; - if (util_resolve_subsys_kernel(key_name, buf, sizeof(buf), false) < 0 && + if (udev_resolve_subsys_kernel(key_name, buf, sizeof(buf), false) < 0 && sd_device_get_syspath(dev, &val) >= 0) strscpyl(buf, sizeof(buf), val, "/", key_name, NULL); @@ -2103,7 +2129,7 @@ static int udev_rule_apply_token_to_event( break; } case TK_A_SYSCTL: { - char value[UTIL_NAME_SIZE]; + char value[UDEV_NAME_SIZE]; (void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false); (void) udev_event_apply_format(event, token->value, value, sizeof(value), false); @@ -2126,19 +2152,17 @@ static int udev_rule_apply_token_to_event( if (IN_SET(token->op, OP_ASSIGN, OP_ASSIGN_FINAL)) ordered_hashmap_clear_free_key(event->run_list); - r = ordered_hashmap_ensure_allocated(&event->run_list, NULL); - if (r < 0) - return log_oom(); - (void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false); cmd = strdup(buf); if (!cmd) return log_oom(); - r = ordered_hashmap_put(event->run_list, cmd, token->data); - if (r < 0) + r = ordered_hashmap_ensure_put(&event->run_list, NULL, cmd, token->data); + if (r == -ENOMEM) return log_oom(); + if (r < 0) + return log_rule_error_errno(dev, rules, r, "Failed to store command '%s': %m", cmd); TAKE_PTR(cmd); @@ -2204,14 +2228,14 @@ static int udev_rule_apply_line_to_event( UdevRuleLineType mask = LINE_HAS_GOTO | LINE_UPDATE_SOMETHING; UdevRuleToken *token, *next_token; bool parents_done = false; - DeviceAction action; + sd_device_action_t action; int r; - r = device_get_action(event->dev, &action); + r = sd_device_get_action(event->dev, &action); if (r < 0) return r; - if (action != DEVICE_ACTION_REMOVE) { + if (action != SD_DEVICE_REMOVE) { if (sd_device_get_devnum(event->dev, NULL) >= 0) mask |= LINE_HAS_DEVLINK; @@ -2276,7 +2300,7 @@ int udev_rules_apply_to_event( } static int apply_static_dev_perms(const char *devnode, uid_t uid, gid_t gid, mode_t mode, char **tags) { - char device_node[UTIL_PATH_SIZE], tags_dir[UTIL_PATH_SIZE], tag_symlink[UTIL_PATH_SIZE]; + char device_node[UDEV_PATH_SIZE], tags_dir[UDEV_PATH_SIZE], tag_symlink[UDEV_PATH_SIZE]; _cleanup_free_ char *unescaped_filename = NULL; struct stat stats; char **t; diff --git a/src/udev/udev-rules.h b/src/udev/udev-rules.h index 3f40a5395..d11297da8 100644 --- a/src/udev/udev-rules.h +++ b/src/udev/udev-rules.h @@ -13,7 +13,7 @@ typedef enum { ESCAPE_NONE, /* OPTIONS="string_escape=none" */ ESCAPE_REPLACE, /* OPTIONS="string_escape=replace" */ _ESCAPE_TYPE_MAX, - _ESCAPE_TYPE_INVALID = -1 + _ESCAPE_TYPE_INVALID = -EINVAL, } UdevRuleEscapeType; int udev_rules_parse_file(UdevRules *rules, const char *filename); diff --git a/src/udev/udev.pc.in b/src/udev/udev.pc.in index 7b4f4006b..05caca0ca 100644 --- a/src/udev/udev.pc.in +++ b/src/udev/udev.pc.in @@ -1,3 +1,12 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + Name: udev Description: udev Version: @PROJECT_VERSION@ diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index ef23a6c9f..437ac9b83 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -41,8 +41,8 @@ static int help(void) { " -p --property=KEY=VALUE Set a global property for all events\n" " -m --children-max=N Maximum number of children\n" " --ping Wait for udev to respond to a ping message\n" - " -t --timeout=SECONDS Maximum time to block for a reply\n" - , program_invocation_short_name); + " -t --timeout=SECONDS Maximum time to block for a reply\n", + program_invocation_short_name); return 0; } diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 3d219222b..9414269fb 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -23,8 +23,8 @@ static int help(void) { " -r --root=PATH Alternative root path in the filesystem\n\n" "NOTE:\n" "The sub-command 'hwdb' is deprecated, and is left for backwards compatibility.\n" - "Please use systemd-hwdb instead.\n" - , program_invocation_short_name); + "Please use systemd-hwdb instead.\n", + program_invocation_short_name); return 0; } diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 5ff6256df..71cc0d2d9 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -356,8 +356,8 @@ static int help(void) { " -e --export-db Export the content of the udev database\n" " -c --cleanup-db Clean up the udev database\n" " -w --wait-for-initialization[=SECONDS]\n" - " Wait for device to be initialized\n" - , program_invocation_short_name); + " Wait for device to be initialized\n", + program_invocation_short_name); return 0; } diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index cae7f1bbb..00b03c550 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -27,7 +27,7 @@ static Set *arg_tag_filter = NULL; static Hashmap *arg_subsystem_filter = NULL; static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, void *userdata) { - DeviceAction action = _DEVICE_ACTION_INVALID; + sd_device_action_t action = _SD_DEVICE_ACTION_INVALID; const char *devpath = NULL, *subsystem = NULL; MonitorNetlinkGroup group = PTR_TO_INT(userdata); struct timespec ts; @@ -35,7 +35,7 @@ static int device_monitor_handler(sd_device_monitor *monitor, sd_device *device, assert(device); assert(IN_SET(group, MONITOR_GROUP_UDEV, MONITOR_GROUP_KERNEL)); - (void) device_get_action(device, &action); + (void) sd_device_get_action(device, &action); (void) sd_device_get_devpath(device, &devpath); (void) sd_device_get_subsystem(device, &subsystem); @@ -107,8 +107,8 @@ static int help(void) { " -k --kernel Print kernel uevents\n" " -u --udev Print udev events\n" " -s --subsystem-match=SUBSYSTEM[/DEVTYPE] Filter events by subsystem\n" - " -t --tag-match=TAG Filter events by tag\n" - , program_invocation_short_name); + " -t --tag-match=TAG Filter events by tag\n", + program_invocation_short_name); return 0; } @@ -157,15 +157,12 @@ static int parse_argv(int argc, char *argv[]) { if (!subsystem) return -ENOMEM; - r = hashmap_ensure_allocated(&arg_subsystem_filter, NULL); + r = hashmap_ensure_put(&arg_subsystem_filter, NULL, subsystem, devtype); if (r < 0) return r; - r = hashmap_put(arg_subsystem_filter, subsystem, devtype); - if (r < 0) - return r; - - subsystem = devtype = NULL; + TAKE_PTR(subsystem); + TAKE_PTR(devtype); break; } case 't': diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 2bd585355..2c61c2d8b 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -17,12 +17,13 @@ #include "sd-messages.h" #include "bus-util.h" +#include "fd-util.h" #include "io-util.h" -#include "libudev-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" #include "udev-ctrl.h" +#include "udev-util.h" #include "udevadm.h" #include "unit-def.h" #include "util.h" @@ -37,8 +38,8 @@ static int help(void) { " -h --help Show this help\n" " -V --version Show package version\n" " -t --timeout=SEC Maximum time to wait for events\n" - " -E --exit-if-exists=FILE Stop waiting if file exists\n" - , program_invocation_short_name); + " -E --exit-if-exists=FILE Stop waiting if file exists\n", + program_invocation_short_name); return 0; } @@ -158,9 +159,9 @@ static int emit_deprecation_warning(void) { } int settle_main(int argc, char *argv[], void *userdata) { - _cleanup_(udev_queue_unrefp) struct udev_queue *queue = NULL; + _cleanup_close_ int fd = -1; usec_t deadline; - int r, fd; + int r; r = parse_argv(argc, argv); if (r <= 0) @@ -190,11 +191,7 @@ int settle_main(int argc, char *argv[], void *userdata) { } } - queue = udev_queue_new(NULL); - if (!queue) - return log_error_errno(errno, "Failed to get udev queue: %m"); - - fd = udev_queue_get_fd(queue); + fd = udev_queue_init(); if (fd < 0) { log_debug_errno(fd, "Queue is empty, nothing to watch: %m"); return 0; @@ -207,7 +204,10 @@ int settle_main(int argc, char *argv[], void *userdata) { return 0; /* exit if queue is empty */ - if (udev_queue_get_queue_is_empty(queue)) + r = udev_queue_is_empty(); + if (r < 0) + return log_error_errno(r, "Failed to check queue is empty: %m"); + if (r > 0) return 0; if (now(CLOCK_MONOTONIC) >= deadline) @@ -218,7 +218,7 @@ int settle_main(int argc, char *argv[], void *userdata) { if (r < 0) return r; if (r & POLLIN) { - r = udev_queue_flush(queue); + r = flush_fd(fd); if (r < 0) return log_error_errno(r, "Failed to flush queue: %m"); } diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index 8995e5cca..008d6f291 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -19,8 +19,8 @@ static int help(void) { "Test a built-in command.\n\n" " -h --help Print this message\n" " -V --version Print version of the program\n\n" - "Commands:\n" - , program_invocation_short_name); + "Commands:\n", + program_invocation_short_name); udev_builtin_list(); diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index a029622af..7a30e2513 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -16,7 +16,6 @@ #include "device-private.h" #include "device-util.h" -#include "libudev-util.h" #include "path-util.h" #include "string-util.h" #include "strxcpyx.h" @@ -26,7 +25,7 @@ static const char *arg_action = "add"; static ResolveNameTiming arg_resolve_name_timing = RESOLVE_NAME_EARLY; -static char arg_syspath[UTIL_PATH_SIZE] = {}; +static char arg_syspath[UDEV_PATH_SIZE] = {}; static int help(void) { @@ -35,8 +34,8 @@ static int help(void) { " -h --help Show this help\n" " -V --version Show package version\n" " -a --action=ACTION|help Set action string\n" - " -N --resolve-names=early|late|never When to resolve names\n" - , program_invocation_short_name); + " -N --resolve-names=early|late|never When to resolve names\n", + program_invocation_short_name); return 0; } @@ -55,7 +54,7 @@ static int parse_argv(int argc, char *argv[]) { while ((c = getopt_long(argc, argv, "a:N:Vh", options, NULL)) >= 0) switch (c) { case 'a': { - DeviceAction a; + sd_device_action_t a; if (streq(optarg, "help")) { dump_device_action_table(); @@ -64,10 +63,9 @@ static int parse_argv(int argc, char *argv[]) { a = device_action_from_string(optarg); if (a < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Invalid action '%s'", optarg); + return log_error_errno(a, "Invalid action '%s'", optarg); - arg_action = optarg; + arg_action = device_action_to_string(a); break; } case 'N': @@ -138,7 +136,7 @@ int test_main(int argc, char *argv[], void *userdata) { /* don't read info from the db */ device_seal(dev); - event = udev_event_new(dev, 0, NULL); + event = udev_event_new(dev, 0, NULL, LOG_DEBUG); assert_se(sigfillset(&mask) >= 0); assert_se(sigprocmask(SIG_SETMASK, &mask, &sigmask_orig) >= 0); @@ -149,7 +147,7 @@ int test_main(int argc, char *argv[], void *userdata) { printf("%s=%s\n", key, value); ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list) { - char program[UTIL_PATH_SIZE]; + char program[UDEV_PATH_SIZE]; (void) udev_event_apply_format(event, cmd, program, sizeof(program), false); printf("run: '%s'\n", program); diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 5c74184c3..ade92286d 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -8,6 +8,7 @@ #include "device-enumerator-private.h" #include "device-private.h" +#include "device-util.h" #include "fd-util.h" #include "fileio.h" #include "path-util.h" @@ -22,36 +23,63 @@ static bool arg_verbose = false; static bool arg_dry_run = false; +static bool arg_quiet = false; -static int exec_list(sd_device_enumerator *e, const char *action, Set **settle_set) { +static int exec_list(sd_device_enumerator *e, sd_device_action_t action, Set **settle_set) { + const char *action_str; sd_device *d; int r, ret = 0; + action_str = device_action_to_string(action); + FOREACH_DEVICE_AND_SUBSYSTEM(e, d) { - _cleanup_free_ char *filename = NULL; const char *syspath; if (sd_device_get_syspath(d, &syspath) < 0) continue; if (arg_verbose) - printf("%s\n", syspath); + printf("%s\n", strna(syspath)); + if (arg_dry_run) continue; - filename = path_join(syspath, "uevent"); - if (!filename) - return log_oom(); - - r = write_string_file(filename, action, WRITE_STRING_FILE_DISABLE_BUFFER); + r = sd_device_trigger(d, action); if (r < 0) { - bool ignore = IN_SET(r, -ENOENT, -ENODEV); + /* ENOENT may be returned when a device does not have /uevent or is already + * removed. Hence, this is logged at debug level and ignored. + * + * ENODEV may be returned by some buggy device drivers e.g. /sys/devices/vio. + * See, + * https://github.com/systemd/systemd/issues/13652#issuecomment-535129791 and + * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1845319. + * So, this error is ignored, but logged at warning level to encourage people to + * fix the driver. + * + * EROFS is returned when /sys is read only. In that case, all subsequent + * writes will also fail, hence return immediately. + * + * EACCES or EPERM may be returned when this is invoked by non-priviledged user. + * We do NOT return immediately, but continue operation and propagate the error. + * Why? Some device can be owned by a user, e.g., network devices configured in + * a network namespace. See, https://github.com/systemd/systemd/pull/18559 and + * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=ebb4a4bf76f164457184a3f43ebc1552416bc823 + * + * All other errors are logged at error level, but let's continue the operation, + * and propagate the error. + */ - log_full_errno(ignore ? LOG_DEBUG : LOG_ERR, r, - "Failed to write '%s' to '%s'%s: %m", - action, filename, ignore ? ", ignoring" : ""); - if (IN_SET(r, -EACCES, -EROFS)) - /* Inovoked by unpriviledged user, or read only filesystem. Return earlier. */ + bool ignore = IN_SET(r, -ENOENT, -ENODEV); + int level = + arg_quiet ? LOG_DEBUG : + r == -ENOENT ? LOG_DEBUG : + r == -ENODEV ? LOG_WARNING : LOG_ERR; + + log_device_full_errno(d, level, r, + "Failed to write '%s' to '%s/uevent'%s: %m", + action_str, syspath, ignore ? ", ignoring" : ""); + + if (r == -EROFS) return r; if (ret == 0 && !ignore) ret = r; @@ -118,6 +146,7 @@ static int help(void) { " -V --version Show package version\n" " -v --verbose Print the list of devices while running\n" " -n --dry-run Do not actually trigger the events\n" + " -q --quiet Suppress error logging in triggering events\n" " -t --type= Type of events to trigger\n" " devices sysfs devices (default)\n" " subsystems sysfs subsystems and drivers\n" @@ -133,8 +162,8 @@ static int help(void) { " -b --parent-match=NAME Trigger devices with that parent device\n" " -w --settle Wait for the triggered events to complete\n" " --wait-daemon[=SECONDS] Wait for udevd daemon to be initialized\n" - " before triggering uevents\n" - , program_invocation_short_name); + " before triggering uevents\n", + program_invocation_short_name); return 0; } @@ -148,6 +177,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { static const struct option options[] = { { "verbose", no_argument, NULL, 'v' }, { "dry-run", no_argument, NULL, 'n' }, + { "quiet", no_argument, NULL, 'q' }, { "type", required_argument, NULL, 't' }, { "action", required_argument, NULL, 'c' }, { "subsystem-match", required_argument, NULL, 's' }, @@ -169,7 +199,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { TYPE_DEVICES, TYPE_SUBSYSTEMS, } device_type = TYPE_DEVICES; - const char *action = "change"; + sd_device_action_t action = SD_DEVICE_CHANGE; _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; _cleanup_(sd_device_monitor_unrefp) sd_device_monitor *m = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; @@ -191,7 +221,7 @@ int trigger_main(int argc, char *argv[], void *userdata) { if (r < 0) return r; - while ((c = getopt_long(argc, argv, "vnt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { + while ((c = getopt_long(argc, argv, "vnqt:c:s:S:a:A:p:g:y:b:wVh", options, NULL)) >= 0) { _cleanup_free_ char *buf = NULL; const char *key, *val; @@ -202,6 +232,9 @@ int trigger_main(int argc, char *argv[], void *userdata) { case 'n': arg_dry_run = true; break; + case 'q': + arg_quiet = true; + break; case 't': if (streq(optarg, "devices")) device_type = TYPE_DEVICES; @@ -210,16 +243,17 @@ int trigger_main(int argc, char *argv[], void *userdata) { else return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown type --type=%s", optarg); break; - case 'c': + case 'c': { if (streq(optarg, "help")) { dump_device_action_table(); return 0; } - if (device_action_from_string(optarg) < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown action '%s'", optarg); - action = optarg; + action = device_action_from_string(optarg); + if (action < 0) + return log_error_errno(action, "Unknown action '%s'", optarg); break; + } case 's': r = sd_device_enumerator_add_match_subsystem(e, optarg, true); if (r < 0) diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 39d0c7eb3..10191d88b 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -20,7 +20,7 @@ static int find_device_from_path(const char *path, sd_device **ret) { if (stat(path, &st) < 0) return -errno; - return device_new_from_stat_rdev(ret, &st); + return sd_device_new_from_stat_rdev(ret, &st); } return -EINVAL; diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 408e4a346..e55ae4bd5 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -8,13 +8,14 @@ #include "alloc-util.h" #include "main-func.h" #include "pretty-print.h" +#include "process-util.h" #include "selinux-util.h" #include "string-util.h" +#include "udev-util.h" #include "udevadm.h" #include "udevd.h" -#include "udev-util.h" -#include "verbs.h" #include "util.h" +#include "verbs.h" static int help(void) { static const char *const short_descriptions[][2] = { @@ -37,8 +38,8 @@ static int help(void) { printf("%s [--help] [--version] [--debug] COMMAND [COMMAND OPTIONS]\n\n" "Send control commands or test the device manager.\n\n" - "Commands:\n" - , program_invocation_short_name); + "Commands:\n", + program_invocation_short_name); for (i = 0; i < ELEMENTSOF(short_descriptions); i++) printf(" %-12s %s\n", short_descriptions[i][0], short_descriptions[i][1]); @@ -111,7 +112,7 @@ static int udevadm_main(int argc, char *argv[]) { static int run(int argc, char *argv[]) { int r; - if (strstr(program_invocation_short_name, "udevd")) + if (invoked_as(argv, "udevd")) return run_udevd(argc, argv); udev_parse_config(); @@ -122,8 +123,6 @@ static int run(int argc, char *argv[]) { if (r <= 0) return r; - log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); - r = mac_selinux_init(); if (r < 0) return r; diff --git a/src/udev/udevd.c b/src/udev/udevd.c index d24b8d439..6fffd8407 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -42,7 +42,6 @@ #include "fs-util.h" #include "hashmap.h" #include "io-util.h" -#include "libudev-device-internal.h" #include "limits-util.h" #include "list.h" #include "main-func.h" @@ -84,6 +83,7 @@ typedef struct Manager { LIST_HEAD(struct event, events); const char *cgroup; pid_t pid; /* the process that originally allocated the manager object */ + int log_level; UdevRules *rules; Hashmap *properties; @@ -100,8 +100,8 @@ typedef struct Manager { usec_t last_usec; - bool stop_exec_queue:1; - bool exit:1; + bool stop_exec_queue; + bool exit; } Manager; enum event_state { @@ -173,9 +173,9 @@ static void event_free(struct event *event) { free(event); } -static void worker_free(struct worker *worker) { +static struct worker* worker_free(struct worker *worker) { if (!worker) - return; + return NULL; assert(worker->manager); @@ -183,7 +183,7 @@ static void worker_free(struct worker *worker) { sd_device_monitor_unref(worker->monitor); event_free(worker->event); - free(worker); + return mfree(worker); } DEFINE_TRIVIAL_CLEANUP_FUNC(struct worker *, worker_free); @@ -211,11 +211,7 @@ static int worker_new(struct worker **ret, Manager *manager, sd_device_monitor * .pid = pid, }; - r = hashmap_ensure_allocated(&manager->workers, &worker_hash_op); - if (r < 0) - return r; - - r = hashmap_put(manager->workers, PID_TO_PTR(pid), worker); + r = hashmap_ensure_put(&manager->workers, &worker_hash_op, PID_TO_PTR(pid), worker); if (r < 0) return r; @@ -291,9 +287,9 @@ static void manager_clear_for_worker(Manager *manager) { manager->worker_watch[READ_END] = safe_close(manager->worker_watch[READ_END]); } -static void manager_free(Manager *manager) { +static Manager* manager_free(Manager *manager) { if (!manager) - return; + return NULL; udev_builtin_exit(); @@ -310,7 +306,7 @@ static void manager_free(Manager *manager) { safe_close(manager->fd_inotify); safe_close_pair(manager->worker_watch); - free(manager); + return mfree(manager); } DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); @@ -329,16 +325,12 @@ static int worker_lock_block_device(sd_device *dev, int *ret_fd) { assert(dev); assert(ret_fd); - /* - * Take a shared lock on the device node; this establishes - * a concept of device "ownership" to serialize device - * access. External processes holding an exclusive lock will - * cause udev to skip the event handling; in the case udev - * acquired the lock, the external process can block until - * udev has finished its event handling. - */ + /* Take a shared lock on the device node; this establishes a concept of device "ownership" to + * serialize device access. External processes holding an exclusive lock will cause udev to skip the + * event handling; in the case udev acquired the lock, the external process can block until udev has + * finished its event handling. */ - if (device_for_action(dev, DEVICE_ACTION_REMOVE)) + if (device_for_action(dev, SD_DEVICE_REMOVE)) return 0; r = sd_device_get_subsystem(dev, &val); @@ -396,7 +388,7 @@ static int worker_mark_block_device_read_only(sd_device *dev) { /* Do this only once, when the block device is new. If the device is later retriggered let's not * toggle the bit again, so that people can boot up with full read-only mode and then unset the bit * for specific devices only. */ - if (!device_for_action(dev, DEVICE_ACTION_ADD)) + if (!device_for_action(dev, SD_DEVICE_ADD)) return 0; r = sd_device_get_subsystem(dev, &val); @@ -436,25 +428,14 @@ static int worker_mark_block_device_read_only(sd_device *dev) { static int worker_process_device(Manager *manager, sd_device *dev) { _cleanup_(udev_event_freep) UdevEvent *udev_event = NULL; _cleanup_close_ int fd_lock = -1; - DeviceAction action; - uint64_t seqnum; int r; assert(manager); assert(dev); - r = device_get_seqnum(dev, &seqnum); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get SEQNUM: %m"); + log_device_uevent(dev, "Processing device"); - r = device_get_action(dev, &action); - if (r < 0) - return log_device_debug_errno(dev, r, "Failed to get ACTION: %m"); - - log_device_debug(dev, "Processing device (SEQNUM=%"PRIu64", ACTION=%s)", - seqnum, device_action_to_string(action)); - - udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl); + udev_event = udev_event_new(dev, arg_exec_delay_usec, manager->rtnl, manager->log_level); if (!udev_event) return -ENOMEM; @@ -521,9 +502,7 @@ static int worker_process_device(Manager *manager, sd_device *dev) { } else (void) udev_watch_end(dev); - log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) processed", - seqnum, device_action_to_string(action)); - + log_device_uevent(dev, "Device processed"); return 0; } @@ -553,6 +532,9 @@ static int worker_device_monitor_handler(sd_device_monitor *monitor, sd_device * if (r < 0) log_device_warning_errno(dev, r, "Failed to send signal to main daemon, ignoring: %m"); + /* Reset the log level, as it might be changed by "OPTIONS=log_level=". */ + log_set_max_level(manager->log_level); + return 1; } @@ -655,13 +637,7 @@ static void event_run(Manager *manager, struct event *event) { assert(manager); assert(event); - if (DEBUG_LOGGING) { - DeviceAction action; - - r = device_get_action(event->dev, &action); - log_device_debug(event->dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) ready for processing", - event->seqnum, r >= 0 ? device_action_to_string(action) : ""); - } + log_device_uevent(event->dev, "Device ready for processing"); HASHMAP_FOREACH(worker, manager->workers) { if (worker->state != WORKER_IDLE) @@ -704,7 +680,6 @@ static void event_run(Manager *manager, struct event *event) { static int event_queue_insert(Manager *manager, sd_device *dev) { _cleanup_(sd_device_unrefp) sd_device *clone = NULL; struct event *event; - DeviceAction action; uint64_t seqnum; int r; @@ -715,12 +690,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { assert(manager->pid == getpid_cached()); /* We only accepts devices received by device monitor. */ - r = device_get_seqnum(dev, &seqnum); - if (r < 0) - return r; - - /* Refuse devices do not have ACTION property. */ - r = device_get_action(dev, &action); + r = sd_device_get_seqnum(dev, &seqnum); if (r < 0) return r; @@ -753,8 +723,7 @@ static int event_queue_insert(Manager *manager, sd_device *dev) { LIST_APPEND(event, manager->events, event); - log_device_debug(dev, "Device (SEQNUM=%"PRIu64", ACTION=%s) is queued", - seqnum, device_action_to_string(action)); + log_device_uevent(dev, "Device is queued"); return 0; } @@ -1089,8 +1058,8 @@ static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, co switch (type) { case UDEV_CTRL_SET_LOG_LEVEL: log_debug("Received udev control message (SET_LOG_LEVEL), setting log_level=%i", value->intval); - log_set_max_level_realm(LOG_REALM_UDEV, value->intval); - log_set_max_level_realm(LOG_REALM_SYSTEMD, value->intval); + log_set_max_level(value->intval); + manager->log_level = value->intval; manager_kill_workers(manager); break; case UDEV_CTRL_STOP_EXEC_QUEUE: @@ -1186,56 +1155,54 @@ static int on_ctrl_msg(struct udev_ctrl *uctrl, enum udev_ctrl_msg_type type, co return 1; } -static int synthesize_change_one(sd_device *dev, const char *syspath) { - const char *filename; +static int synthesize_change_one(sd_device *dev, sd_device *target) { int r; - filename = strjoina(syspath, "/uevent"); - log_device_debug(dev, "device is closed, synthesising 'change' on %s", syspath); - r = write_string_file(filename, "change", WRITE_STRING_FILE_DISABLE_BUFFER); + if (DEBUG_LOGGING) { + const char *syspath = NULL; + (void) sd_device_get_syspath(target, &syspath); + log_device_debug(dev, "device is closed, synthesising 'change' on %s", strna(syspath)); + } + + r = sd_device_trigger(target, SD_DEVICE_CHANGE); if (r < 0) - return log_device_debug_errno(dev, r, "Failed to write 'change' to %s: %m", filename); + return log_device_debug_errno(target, r, "Failed to trigger 'change' uevent: %m"); + return 0; } static int synthesize_change(sd_device *dev) { - const char *subsystem, *sysname, *devname, *syspath, *devtype; + const char *subsystem, *sysname, *devtype; int r; r = sd_device_get_subsystem(dev, &subsystem); if (r < 0) return r; - r = sd_device_get_sysname(dev, &sysname); - if (r < 0) - return r; - - r = sd_device_get_devname(dev, &devname); - if (r < 0) - return r; - - r = sd_device_get_syspath(dev, &syspath); - if (r < 0) - return r; - r = sd_device_get_devtype(dev, &devtype); if (r < 0) return r; - if (streq_ptr("block", subsystem) && - streq_ptr("disk", devtype) && + r = sd_device_get_sysname(dev, &sysname); + if (r < 0) + return r; + + if (streq_ptr(subsystem, "block") && + streq_ptr(devtype, "disk") && !startswith(sysname, "dm-")) { _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; bool part_table_read = false, has_partitions = false; + const char *devname; sd_device *d; int fd; - /* - * Try to re-read the partition table. This only succeeds if - * none of the devices is busy. The kernel returns 0 if no - * partition table is found, and we will not get an event for - * the disk. - */ + r = sd_device_get_devname(dev, &devname); + if (r < 0) + return r; + + /* Try to re-read the partition table. This only succeeds if none of the devices is + * busy. The kernel returns 0 if no partition table is found, and we will not get an + * event for the disk. */ fd = open(devname, O_RDONLY|O_CLOEXEC|O_NOFOLLOW|O_NONBLOCK); if (fd >= 0) { r = flock(fd, LOCK_EX|LOCK_NB); @@ -1267,44 +1234,33 @@ static int synthesize_change(sd_device *dev) { FOREACH_DEVICE(e, d) { const char *t; - if (sd_device_get_devtype(d, &t) < 0 || - !streq("partition", t)) + if (sd_device_get_devtype(d, &t) < 0 || !streq(t, "partition")) continue; has_partitions = true; break; } - /* - * We have partitions and re-read the table, the kernel already sent - * out a "change" event for the disk, and "remove/add" for all - * partitions. - */ + /* We have partitions and re-read the table, the kernel already sent out a "change" + * event for the disk, and "remove/add" for all partitions. */ if (part_table_read && has_partitions) return 0; - /* - * We have partitions but re-reading the partition table did not - * work, synthesize "change" for the disk and all partitions. - */ - (void) synthesize_change_one(dev, syspath); + /* We have partitions but re-reading the partition table did not work, synthesize + * "change" for the disk and all partitions. */ + (void) synthesize_change_one(dev, dev); FOREACH_DEVICE(e, d) { - const char *t, *n, *s; + const char *t; - if (sd_device_get_devtype(d, &t) < 0 || - !streq("partition", t)) + if (sd_device_get_devtype(d, &t) < 0 || !streq(t, "partition")) continue; - if (sd_device_get_devname(d, &n) < 0 || - sd_device_get_syspath(d, &s) < 0) - continue; - - (void) synthesize_change_one(dev, s); + (void) synthesize_change_one(dev, d); } } else - (void) synthesize_change_one(dev, syspath); + (void) synthesize_change_one(dev, dev); return 0; } @@ -1605,10 +1561,9 @@ static int help(void) { " -t --event-timeout=SECONDS Seconds to wait before terminating an event\n" " -N --resolve-names=early|late|never\n" " When to resolve users and groups\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + link); return 0; } @@ -1735,6 +1690,8 @@ static int manager_new(Manager **ret, int fd_ctrl, int fd_uevent, const char *cg if (r < 0) return log_error_errno(r, "Failed to bind netlink socket: %m"); + manager->log_level = log_get_max_level(); + *ret = TAKE_PTR(manager); return 0; @@ -1877,8 +1834,6 @@ int run_udevd(int argc, char *argv[]) { log_set_max_level(LOG_DEBUG); } - log_set_max_level_realm(LOG_REALM_SYSTEMD, log_get_max_level()); - r = must_be_root(); if (r < 0) return r; diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c index 932446b76..26b634ef5 100644 --- a/src/udev/v4l_id/v4l_id.c +++ b/src/udev/v4l_id/v4l_id.c @@ -45,8 +45,8 @@ int main(int argc, char *argv[]) { case 'h': printf("%s [-h,--help] \n\n" "Video4Linux device identification.\n\n" - " -h Print this message\n" - , program_invocation_short_name); + " -h Print this message\n", + program_invocation_short_name); return 0; case '?': return -EINVAL; diff --git a/src/update-done/update-done.c b/src/update-done/update-done.c index 212892527..651883071 100644 --- a/src/update-done/update-done.c +++ b/src/update-done/update-done.c @@ -41,7 +41,7 @@ int main(int argc, char *argv[]) { struct stat st; int r, q = 0; - log_setup_service(); + log_setup(); if (stat("/usr", &st) < 0) { log_error_errno(errno, "Failed to stat /usr: %m"); diff --git a/src/update-utmp/update-utmp.c b/src/update-utmp/update-utmp.c index 59c49f2a8..38df4cddf 100644 --- a/src/update-utmp/update-utmp.c +++ b/src/update-utmp/update-utmp.c @@ -215,7 +215,7 @@ static int on_runlevel(Context *c) { static int run(int argc, char *argv[]) { _cleanup_(context_clear) Context c = { #if HAVE_AUDIT - .audit_fd = -1 + .audit_fd = -1, #endif }; int r; @@ -224,7 +224,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires one argument."); - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index d1b817671..6b7493fd8 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -21,7 +21,7 @@ static int run(int argc, char *argv[]) { return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires one argument."); - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/userdb/userdbctl.c b/src/userdb/userdbctl.c index a0e22dff5..e9c695714 100644 --- a/src/userdb/userdbctl.c +++ b/src/userdb/userdbctl.c @@ -10,6 +10,7 @@ #include "format-util.h" #include "main-func.h" #include "pager.h" +#include "parse-argument.h" #include "parse-util.h" #include "pretty-print.h" #include "socket-util.h" @@ -25,7 +26,7 @@ static enum { OUTPUT_TABLE, OUTPUT_FRIENDLY, OUTPUT_JSON, - _OUTPUT_INVALID = -1 + _OUTPUT_INVALID = -EINVAL, } arg_output = _OUTPUT_INVALID; static PagerFlags arg_pager_flags = 0; @@ -111,8 +112,8 @@ static int display_user(int argc, char *argv[], void *userdata) { (void) table_set_align_percent(table, table_get_cell(table, 0, 2), 100); (void) table_set_align_percent(table, table_get_cell(table, 0, 3), 100); (void) table_set_empty_string(table, "-"); - (void) table_set_sort(table, (size_t) 7, (size_t) 2, (size_t) -1); - (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 5, (size_t) 6, (size_t) -1); + (void) table_set_sort(table, (size_t) 7, (size_t) 2); + (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) 4, (size_t) 5, (size_t) 6); } if (argc > 1) { @@ -261,8 +262,8 @@ static int display_group(int argc, char *argv[], void *userdata) { (void) table_set_align_percent(table, table_get_cell(table, 0, 2), 100); (void) table_set_empty_string(table, "-"); - (void) table_set_sort(table, (size_t) 3, (size_t) 2, (size_t) -1); - (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3, (size_t) -1); + (void) table_set_sort(table, (size_t) 3, (size_t) 2); + (void) table_set_display(table, (size_t) 0, (size_t) 1, (size_t) 2, (size_t) 3); } if (argc > 1) { @@ -401,7 +402,7 @@ static int display_memberships(int argc, char *argv[], void *userdata) { if (!table) return log_oom(); - (void) table_set_sort(table, (size_t) 0, (size_t) 1, (size_t) -1); + (void) table_set_sort(table, (size_t) 0, (size_t) 1); } if (argc > 1) { @@ -490,7 +491,7 @@ static int display_services(int argc, char *argv[], void *userdata) { if (!t) return log_oom(); - (void) table_set_sort(t, (size_t) 0, (size_t) -1); + (void) table_set_sort(t, (size_t) 0); FOREACH_DIRENT(de, d, return -errno) { _cleanup_free_ char *j = NULL, *no = NULL; @@ -600,11 +601,11 @@ static int help(int argc, char *argv[], void *userdata) { " -N Do not synthesize or include glibc NSS data\n" " (Same as --synthesize=no --with-nss=no)\n" " --synthesize=BOOL Synthesize root/nobody user\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , ansi_highlight(), ansi_normal() - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + ansi_highlight(), + ansi_normal(), + link); return 0; } @@ -720,17 +721,17 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_WITH_NSS: - r = parse_boolean(optarg); + r = parse_boolean_argument("--with-nss=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --with-nss= parameter: %s", optarg); + return r; SET_FLAG(arg_userdb_flags, USERDB_AVOID_NSS, !r); break; case ARG_SYNTHESIZE: - r = parse_boolean(optarg); + r = parse_boolean_argument("--synthesize=", optarg, NULL); if (r < 0) - return log_error_errno(r, "Failed to parse --synthesize= parameter: %s", optarg); + return r; SET_FLAG(arg_userdb_flags, USERDB_DONT_SYNTHESIZE, !r); break; @@ -763,7 +764,7 @@ static int run(int argc, char *argv[]) { int r; - log_setup_cli(); + log_setup(); r = parse_argv(argc, argv); if (r <= 0) diff --git a/src/userdb/userdbd.c b/src/userdb/userdbd.c index 6f2c80784..6b28dd0a0 100644 --- a/src/userdb/userdbd.c +++ b/src/userdb/userdbd.c @@ -24,7 +24,7 @@ static int run(int argc, char *argv[]) { _cleanup_(notify_on_cleanup) const char *notify_stop = NULL; int r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/userdb/userwork.c b/src/userdb/userwork.c index d525a6e05..c62a21974 100644 --- a/src/userdb/userwork.c +++ b/src/userdb/userwork.c @@ -662,7 +662,7 @@ static int run(int argc, char *argv[]) { unsigned n_iterations = 0; int m, listen_fd, r; - log_setup_service(); + log_setup(); m = sd_listen_fds(false); if (m < 0) diff --git a/src/vconsole/vconsole-setup.c b/src/vconsole/vconsole-setup.c index b28e2853e..45915ef85 100644 --- a/src/vconsole/vconsole-setup.c +++ b/src/vconsole/vconsole-setup.c @@ -430,7 +430,7 @@ int main(int argc, char **argv) { unsigned idx = 0; int r; - log_setup_service(); + log_setup(); umask(0022); diff --git a/src/veritysetup/veritysetup-generator.c b/src/veritysetup/veritysetup-generator.c index 7c807c874..fd95e6f30 100644 --- a/src/veritysetup/veritysetup-generator.c +++ b/src/veritysetup/veritysetup-generator.c @@ -26,16 +26,21 @@ static const char *arg_dest = NULL; static bool arg_enabled = true; +static bool arg_read_veritytab = true; +static const char *arg_veritytab = NULL; static char *arg_root_hash = NULL; static char *arg_data_what = NULL; static char *arg_hash_what = NULL; +static char *arg_options = NULL; STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep); STATIC_DESTRUCTOR_REGISTER(arg_data_what, freep); STATIC_DESTRUCTOR_REGISTER(arg_hash_what, freep); +STATIC_DESTRUCTOR_REGISTER(arg_options, freep); static int create_device(void) { - _cleanup_free_ char *u = NULL, *v = NULL, *d = NULL, *e = NULL, *u_escaped = NULL, *v_escaped = NULL, *root_hash_escaped = NULL; + _cleanup_free_ char *u = NULL, *v = NULL, *d = NULL, *e = NULL, *u_escaped = NULL, *v_escaped = NULL, + *root_hash_escaped = NULL, *options_escaped = NULL; _cleanup_fclose_ FILE *f = NULL; const char *to; int r; @@ -57,7 +62,8 @@ static int create_device(void) { log_debug("Using root verity data device %s,\n" " hash device %s,\n" - " and root hash %s.", arg_data_what, arg_hash_what, arg_root_hash); + " options %s,\n" + " and root hash %s.", arg_data_what, arg_hash_what, arg_options, arg_root_hash); u = fstab_node_to_udev_node(arg_data_what); if (!u) @@ -80,6 +86,10 @@ static int create_device(void) { if (r < 0) return log_error_errno(r, "Failed to generate unit name: %m"); + options_escaped = specifier_escape(strempty(arg_options)); + if (!options_escaped) + return log_oom(); + root_hash_escaped = specifier_escape(arg_root_hash); if (!root_hash_escaped) return log_oom(); @@ -97,22 +107,22 @@ static int create_device(void) { "Conflicts=umount.target\n" "BindsTo=%s %s\n" "IgnoreOnIsolate=true\n" - "After=cryptsetup-pre.target systemd-udevd-kernel.socket %s %s\n" - "Before=cryptsetup.target umount.target\n" + "After=veritysetup-pre.target systemd-udevd-kernel.socket %s %s\n" + "Before=veritysetup.target umount.target\n" "\n[Service]\n" "Type=oneshot\n" "RemainAfterExit=yes\n" - "ExecStart=" ROOTLIBEXECDIR "/systemd-veritysetup attach root '%s' '%s' '%s'\n" + "ExecStart=" ROOTLIBEXECDIR "/systemd-veritysetup attach root '%s' '%s' '%s' '%s'\n" "ExecStop=" ROOTLIBEXECDIR "/systemd-veritysetup detach root\n", d, e, d, e, - u_escaped, v_escaped, root_hash_escaped); + u_escaped, v_escaped, root_hash_escaped, options_escaped); r = fflush_and_check(f); if (r < 0) return log_error_errno(r, "Failed to write file unit "SYSTEMD_VERITYSETUP_SERVICE": %m"); - to = strjoina(arg_dest, "/cryptsetup.target.requires/" SYSTEMD_VERITYSETUP_SERVICE); + to = strjoina(arg_dest, "/veritysetup.target.requires/" SYSTEMD_VERITYSETUP_SERVICE); (void) mkdir_parents(to, 0755); if (symlink("../" SYSTEMD_VERITYSETUP_SERVICE, to) < 0) @@ -132,6 +142,14 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat else arg_enabled = r; + } else if (streq(key, "veritytab")) { + + r = value ? parse_boolean(value) : 1; + if (r < 0) + log_warning("Failed to parse veritytab= kernel command line switch %s. Ignoring.", value); + else + arg_read_veritytab = r; + } else if (proc_cmdline_key_streq(key, "roothash")) { if (proc_cmdline_value_missing(key, value)) @@ -158,6 +176,16 @@ static int parse_proc_cmdline_item(const char *key, const char *value, void *dat r = free_and_strdup(&arg_hash_what, value); if (r < 0) return log_oom(); + + } else if (proc_cmdline_key_streq(key, "systemd.verity_root_options")) { + + if (proc_cmdline_value_missing(key, value)) + return 0; + + r = free_and_strdup(&arg_options, value); + if (r < 0) + return log_oom(); + } return 0; @@ -205,21 +233,216 @@ static int determine_devices(void) { return 1; } +static int create_disk( + const char *name, + const char *data_device, + const char *hash_device, + const char *roothash, + const char *options, + const char *source) { + + _cleanup_free_ char *n = NULL, *dd = NULL, *du = NULL, *hd = NULL, *hu = NULL, *e = NULL, + *du_escaped = NULL, *hu_escaped = NULL, *name_escaped = NULL; + _cleanup_fclose_ FILE *f = NULL; + const char *dmname; + bool noauto, nofail, netdev, attach_in_initrd; + int r; + + assert(name); + assert(data_device); + assert(hash_device); + assert(roothash); + + noauto = fstab_test_yes_no_option(options, "noauto\0" "auto\0"); + nofail = fstab_test_yes_no_option(options, "nofail\0" "fail\0"); + netdev = fstab_test_option(options, "_netdev\0"); + attach_in_initrd = fstab_test_option(options, "x-initrd.attach\0"); + + name_escaped = specifier_escape(name); + if (!name_escaped) + return log_oom(); + + e = unit_name_escape(name); + if (!e) + return log_oom(); + + du = fstab_node_to_udev_node(data_device); + if (!du) + return log_oom(); + + hu = fstab_node_to_udev_node(hash_device); + if (!hu) + return log_oom(); + + r = unit_name_build("systemd-veritysetup", e, ".service", &n); + if (r < 0) + return log_error_errno(r, "Failed to generate unit name: %m"); + + du_escaped = specifier_escape(du); + if (!du_escaped) + return log_oom(); + + hu_escaped = specifier_escape(hu); + if (!hu_escaped) + return log_oom(); + + r = unit_name_from_path(du, ".device", &dd); + if (r < 0) + return log_error_errno(r, "Failed to generate unit name: %m"); + + r = unit_name_from_path(hu, ".device", &hd); + if (r < 0) + return log_error_errno(r, "Failed to generate unit name: %m"); + + r = generator_open_unit_file(arg_dest, NULL, n, &f); + if (r < 0) + return r; + + r = generator_write_veritysetup_unit_section(f, source); + if (r < 0) + return r; + + if (netdev) + fprintf(f, "After=remote-fs-pre.target\n"); + + /* If initrd takes care of attaching the disk then it should also detach it during shutdown. */ + if (!attach_in_initrd) + fprintf(f, "Conflicts=umount.target\n"); + + if (!nofail) + fprintf(f, + "Before=%s\n", + netdev ? "remote-veritysetup.target" : "veritysetup.target"); + + if (path_startswith(du, "/dev/")) + fprintf(f, + "BindsTo=%s\n" + "After=%s\n" + "Before=umount.target\n", + dd, dd); + else + /* For loopback devices, add systemd-tmpfiles-setup-dev.service + dependency to ensure that loopback support is available in + the kernel (/dev/loop-control needs to exist) */ + fprintf(f, + "RequiresMountsFor=%s\n" + "Requires=systemd-tmpfiles-setup-dev.service\n" + "After=systemd-tmpfiles-setup-dev.service\n", + du_escaped); + + if (path_startswith(hu, "/dev/")) + fprintf(f, + "BindsTo=%s\n" + "After=%s\n" + "Before=umount.target\n", + hd, hd); + else + /* For loopback devices, add systemd-tmpfiles-setup-dev.service + dependency to ensure that loopback support is available in + the kernel (/dev/loop-control needs to exist) */ + fprintf(f, + "RequiresMountsFor=%s\n" + "Requires=systemd-tmpfiles-setup-dev.service\n" + "After=systemd-tmpfiles-setup-dev.service\n", + hu_escaped); + + r = generator_write_veritysetup_service_section(f, name, du_escaped, hu_escaped, roothash, options); + if (r < 0) + return r; + + r = fflush_and_check(f); + if (r < 0) + return log_error_errno(r, "Failed to write unit file %s: %m", n); + + if (!noauto) { + r = generator_add_symlink(arg_dest, + netdev ? "remote-veritysetup.target" : "veritysetup.target", + nofail ? "wants" : "requires", n); + if (r < 0) + return r; + } + + dmname = strjoina("dev-mapper-", e, ".device"); + return generator_add_symlink(arg_dest, dmname, "requires", n); +} + +static int add_veritytab_devices(void) { + _cleanup_fclose_ FILE *f = NULL; + unsigned veritytab_line = 0; + int r; + + if (!arg_read_veritytab) + return 0; + + r = fopen_unlocked(arg_veritytab, "re", &f); + if (r < 0) { + if (errno != ENOENT) + log_error_errno(errno, "Failed to open %s: %m", arg_veritytab); + return 0; + } + + for (;;) { + _cleanup_free_ char *line = NULL, *name = NULL, *data_device = NULL, *hash_device = NULL, + *roothash = NULL, *options = NULL; + char *l, *data_uuid, *hash_uuid; + + r = read_line(f, LONG_LINE_MAX, &line); + if (r < 0) + return log_error_errno(r, "Failed to read %s: %m", arg_veritytab); + if (r == 0) + break; + + veritytab_line++; + + l = strstrip(line); + if (IN_SET(l[0], 0, '#')) + continue; + + r = sscanf(l, "%ms %ms %ms %ms %ms", &name, &data_device, &hash_device, &roothash, &options); + if (!IN_SET(r, 4, 5)) { + log_error("Failed to parse %s:%u, ignoring.", arg_veritytab, veritytab_line); + continue; + } + + data_uuid = startswith(data_device, "UUID="); + if (!data_uuid) + data_uuid = path_startswith(data_device, "/dev/disk/by-uuid/"); + + hash_uuid = startswith(hash_device, "UUID="); + if (!hash_uuid) + hash_uuid = path_startswith(hash_device, "/dev/disk/by-uuid/"); + + r = create_disk(name, + data_device, + hash_device, + roothash, + options, + arg_veritytab); + if (r < 0) + return r; + } + + return 0; +} + static int run(const char *dest, const char *dest_early, const char *dest_late) { int r; assert_se(arg_dest = dest); + arg_veritytab = getenv("SYSTEMD_VERITYTAB") ?: "/etc/veritytab"; + r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX); if (r < 0) return log_warning_errno(r, "Failed to parse kernel command line: %m"); - /* For now we only support the root device on verity. Later on we might want to add support for /etc/veritytab - * or similar to define additional mappings */ - if (!arg_enabled) return 0; + r = add_veritytab_devices(); + if (r < 0) + return r; + r = determine_devices(); if (r < 0) return r; diff --git a/src/veritysetup/veritysetup.c b/src/veritysetup/veritysetup.c index 558e9510f..2b5406543 100644 --- a/src/veritysetup/veritysetup.c +++ b/src/veritysetup/veritysetup.c @@ -15,13 +15,10 @@ #include "string-util.h" #include "terminal-util.h" -static char *arg_root_hash = NULL; -static char *arg_data_what = NULL; -static char *arg_hash_what = NULL; +static uint32_t arg_activate_flags = CRYPT_ACTIVATE_READONLY; +static char *arg_root_hash_signature = NULL; -STATIC_DESTRUCTOR_REGISTER(arg_root_hash, freep); -STATIC_DESTRUCTOR_REGISTER(arg_data_what, freep); -STATIC_DESTRUCTOR_REGISTER(arg_hash_what, freep); +STATIC_DESTRUCTOR_REGISTER(arg_root_hash_signature, freep); static int help(void) { _cleanup_free_ char *link = NULL; @@ -31,18 +28,104 @@ static int help(void) { if (r < 0) return log_oom(); - printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH [ROOTHASHSIG]\n" + printf("%s attach VOLUME DATADEVICE HASHDEVICE ROOTHASH [OPTIONS]\n" "%s detach VOLUME\n\n" "Attaches or detaches an integrity protected block device.\n" - "\nSee the %s for details.\n" - , program_invocation_short_name - , program_invocation_short_name - , link - ); + "\nSee the %s for details.\n", + program_invocation_short_name, + program_invocation_short_name, + link); return 0; } +static int looks_like_roothashsig(const char *option) { + const char *val; + int r; + + if (path_is_absolute(option)) { + + r = free_and_strdup(&arg_root_hash_signature, option); + if (r < 0) + return log_oom(); + + return 1; + } + + val = startswith(option, "base64:"); + if (val) { + + r = free_and_strdup(&arg_root_hash_signature, val); + if (r < 0) + return log_oom(); + + return 1; + } + + return 0; +} + +static int parse_options(const char *options) { + int r; + + /* backward compatibility with the obsolete ROOTHASHSIG positional argument */ + r = looks_like_roothashsig(options); + if (r < 0) + return r; + if (r == 1) { + log_warning("Usage of ROOTHASHSIG positional argument is deprecated. " + "Please use the option root-hash-signature=%s instead.", options); + return 0; + } + + for (;;) { + _cleanup_free_ char *word = NULL; + char *val; + + r = extract_first_word(&options, &word, ",", EXTRACT_DONT_COALESCE_SEPARATORS | EXTRACT_UNESCAPE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to parse options: %m"); + if (r == 0) + break; + + if (STR_IN_SET(word, "noauto", "auto", "nofail", "fail", "_netdev")) + continue; + + if (isempty(word)) + continue; + else if (streq(word, "ignore-corruption")) + arg_activate_flags |= CRYPT_ACTIVATE_IGNORE_CORRUPTION; + else if (streq(word, "restart-on-corruption")) + arg_activate_flags |= CRYPT_ACTIVATE_RESTART_ON_CORRUPTION; + else if (streq(word, "ignore-zero-blocks")) + arg_activate_flags |= CRYPT_ACTIVATE_IGNORE_ZERO_BLOCKS; +#ifdef CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE + else if (streq(word, "check-at-most-once")) + arg_activate_flags |= CRYPT_ACTIVATE_CHECK_AT_MOST_ONCE; +#endif +#ifdef CRYPT_ACTIVATE_PANIC_ON_CORRUPTION + else if (streq(word, "panic-on-corruption")) + arg_activate_flags |= CRYPT_ACTIVATE_PANIC_ON_CORRUPTION; +#endif + else if ((val = startswith(word, "root-hash-signature="))) { + + r = looks_like_roothashsig(val); + if (r < 0) + return r; + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "root-hash-signature expects either full path to signature file or " + "base64 string encoding signature prefixed by base64:."); + + r = free_and_strdup(&arg_root_hash_signature, val); + if (r < 0) + return log_oom(); + } else + log_warning("Encountered unknown option '%s', ignoring.", word); + } + + return r; +} + static int run(int argc, char *argv[]) { _cleanup_(crypt_freep) struct crypt_device *cd = NULL; int r; @@ -53,7 +136,7 @@ static int run(int argc, char *argv[]) { if (argc < 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "This program requires at least two arguments."); - log_setup_service(); + log_setup(); umask(0022); @@ -81,6 +164,12 @@ static int run(int argc, char *argv[]) { return 0; } + if (argc > 6) { + r = parse_options(argv[6]); + if (r < 0) + return log_error_errno(r, "Failed to parse options: %m"); + } + r = crypt_load(cd, CRYPT_VERITY, NULL); if (r < 0) return log_error_errno(r, "Failed to load verity superblock: %m"); @@ -89,28 +178,32 @@ static int run(int argc, char *argv[]) { if (r < 0) return log_error_errno(r, "Failed to configure data device: %m"); - if (argc > 6) { + if (arg_root_hash_signature && *arg_root_hash_signature) { #if HAVE_CRYPT_ACTIVATE_BY_SIGNED_KEY _cleanup_free_ char *hash_sig = NULL; size_t hash_sig_size; char *value; - if ((value = startswith(argv[6], "base64:"))) { + if ((value = startswith(arg_root_hash_signature, "base64:"))) { r = unbase64mem(value, strlen(value), (void *)&hash_sig, &hash_sig_size); if (r < 0) - return log_error_errno(r, "Failed to parse root hash signature '%s': %m", argv[6]); + return log_error_errno(r, "Failed to parse root hash signature '%s': %m", arg_root_hash_signature); } else { - r = read_full_file_full(AT_FDCWD, argv[6], READ_FULL_FILE_CONNECT_SOCKET, NULL, &hash_sig, &hash_sig_size); + r = read_full_file_full( + AT_FDCWD, arg_root_hash_signature, UINT64_MAX, SIZE_MAX, + READ_FULL_FILE_CONNECT_SOCKET, + NULL, + &hash_sig, &hash_sig_size); if (r < 0) return log_error_errno(r, "Failed to read root hash signature: %m"); } - r = crypt_activate_by_signed_key(cd, argv[2], m, l, hash_sig, hash_sig_size, CRYPT_ACTIVATE_READONLY); + r = crypt_activate_by_signed_key(cd, argv[2], m, l, hash_sig, hash_sig_size, arg_activate_flags); #else return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "activation of verity device with signature %s requested, but not supported by cryptsetup due to missing crypt_activate_by_signed_key()", argv[6]); #endif } else - r = crypt_activate_by_volume_key(cd, argv[2], m, l, CRYPT_ACTIVATE_READONLY); + r = crypt_activate_by_volume_key(cd, argv[2], m, l, arg_activate_flags); if (r < 0) return log_error_errno(r, "Failed to set up verity device: %m"); diff --git a/src/version/version.h.in b/src/version/version.h.in index 7b0bf8e26..083779aab 100644 --- a/src/version/version.h.in +++ b/src/version/version.h.in @@ -1,4 +1,6 @@ -/* Detailed project version that includes git commit when not built from a release. +/* SPDX-License-Identifier: LGPL-2.1-or-later + * + * Detailed project version that includes git commit when not built from a release. * Use this in preference to PROJECT_VERSION, with the following exceptions: * - where a simplified form is expected for compatibility, for example * 'udevadm version', diff --git a/src/volatile-root/volatile-root.c b/src/volatile-root/volatile-root.c index ee3532cc0..1a6593f9c 100644 --- a/src/volatile-root/volatile-root.c +++ b/src/volatile-root/volatile-root.c @@ -119,7 +119,7 @@ static int run(int argc, char *argv[]) { dev_t devt; int r; - log_setup_service(); + log_setup(); if (argc > 3) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), @@ -132,7 +132,7 @@ static int run(int argc, char *argv[]) { /* The kernel command line always wins. However if nothing was set there, the argument passed here wins instead. */ m = volatile_mode_from_string(argv[1]); if (m < 0) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Couldn't parse volatile mode: %s", argv[1]); + return log_error_errno(m, "Couldn't parse volatile mode: %s", argv[1]); } if (argc < 3) diff --git a/src/fuzz/fuzz-xdg-desktop.c b/src/xdg-autostart-generator/fuzz-xdg-desktop.c similarity index 100% rename from src/fuzz/fuzz-xdg-desktop.c rename to src/xdg-autostart-generator/fuzz-xdg-desktop.c index 23077e48d..52ba7ff0a 100644 --- a/src/fuzz/fuzz-xdg-desktop.c +++ b/src/xdg-autostart-generator/fuzz-xdg-desktop.c @@ -3,12 +3,12 @@ #include "alloc-util.h" #include "fd-util.h" #include "fs-util.h" +#include "fuzz.h" #include "rm-rf.h" #include "string-util.h" #include "strv.h" #include "tests.h" #include "tmpfile-util.h" -#include "fuzz.h" #include "xdg-autostart-service.h" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { diff --git a/src/xdg-autostart-generator/meson.build b/src/xdg-autostart-generator/meson.build new file mode 100644 index 000000000..aa722f7f3 --- /dev/null +++ b/src/xdg-autostart-generator/meson.build @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +systemd_xdg_autostart_generator_sources = files( + 'xdg-autostart-generator.c', + 'xdg-autostart-service.c', + 'xdg-autostart-service.h') + +tests += [ + [['src/xdg-autostart-generator/test-xdg-autostart.c', + 'src/xdg-autostart-generator/xdg-autostart-service.c', + 'src/xdg-autostart-generator/xdg-autostart-service.h']], +] + +fuzzers += [ + [['src/xdg-autostart-generator/fuzz-xdg-desktop.c', + 'src/xdg-autostart-generator/xdg-autostart-service.c', + 'src/xdg-autostart-generator/xdg-autostart-service.h']], +] diff --git a/src/test/test-xdg-autostart.c b/src/xdg-autostart-generator/test-xdg-autostart.c similarity index 87% rename from src/test/test-xdg-autostart.c rename to src/xdg-autostart-generator/test-xdg-autostart.c index a437e2cfe..c7a816bc2 100644 --- a/src/test/test-xdg-autostart.c +++ b/src/xdg-autostart-generator/test-xdg-autostart.c @@ -13,7 +13,7 @@ static void test_translate_name(void) { _cleanup_free_ char *t; assert_se(t = xdg_autostart_service_translate_name("a-b.blub.desktop")); - assert_se(streq(t, "app-a\\x2db.blub-autostart.service")); + assert_se(streq(t, "app-a\\x2db.blub@autostart.service")); } static void test_xdg_format_exec_start_one(const char *exec, const char *expected) { @@ -37,17 +37,17 @@ static void test_xdg_format_exec_start(void) { } static const char* const xdg_desktop_file[] = { - "[Desktop Entry]\n" - "Exec\t =\t /bin/sleep 100\n" /* Whitespace Before/After = must be ignored */ - "OnlyShowIn = A;B;\n" - "NotShowIn=C;;D\\\\\\;;E\n", /* "C", "", "D\;", "E" */ + ("[Desktop Entry]\n" + "Exec\t =\t /bin/sleep 100\n" /* Whitespace Before/After = must be ignored */ + "OnlyShowIn = A;B;\n" + "NotShowIn=C;;D\\\\\\;;E\n"), /* "C", "", "D\;", "E" */ - "[Desktop Entry]\n" - "Exec=a\n" - "Exec=b\n", + ("[Desktop Entry]\n" + "Exec=a\n" + "Exec=b\n"), - "[Desktop Entry]\n" - "Hidden=\t true\n", + ("[Desktop Entry]\n" + "Hidden=\t true\n"), }; static void test_xdg_desktop_parse(unsigned i, const char *s) { diff --git a/src/xdg-autostart-generator/xdg-autostart-service.c b/src/xdg-autostart-generator/xdg-autostart-service.c index 671d16d2d..1528432f4 100644 --- a/src/xdg-autostart-generator/xdg-autostart-service.c +++ b/src/xdg-autostart-generator/xdg-autostart-service.c @@ -58,7 +58,7 @@ char *xdg_autostart_service_translate_name(const char *name) { if (!escaped) return NULL; - return strjoin("app-", escaped, "-autostart.service"); + return strjoin("app-", escaped, "@autostart.service"); } static int xdg_config_parse_bool( @@ -320,33 +320,34 @@ XdgAutostartService *xdg_autostart_service_parse_desktop(const char *path) { return NULL; const ConfigTableItem items[] = { - { "Desktop Entry", "Name", xdg_config_parse_string, 0, &service->description}, - { "Desktop Entry", "Exec", xdg_config_parse_string, 0, &service->exec_string}, - { "Desktop Entry", "Path", xdg_config_parse_string, 0, &service->working_directory}, - { "Desktop Entry", "TryExec", xdg_config_parse_string, 0, &service->try_exec}, - { "Desktop Entry", "Type", xdg_config_parse_string, 0, &service->type}, - { "Desktop Entry", "OnlyShowIn", xdg_config_parse_strv, 0, &service->only_show_in}, - { "Desktop Entry", "NotShowIn", xdg_config_parse_strv, 0, &service->not_show_in}, - { "Desktop Entry", "Hidden", xdg_config_parse_bool, 0, &service->hidden}, - { "Desktop Entry", "AutostartCondition", xdg_config_parse_string, 0, &service->autostart_condition}, - { "Desktop Entry", "X-KDE-autostart-condition", xdg_config_parse_string, 0, &service->kde_autostart_condition}, - { "Desktop Entry", "X-GNOME-Autostart-Phase", xdg_config_parse_string, 0, &service->gnome_autostart_phase}, - { "Desktop Entry", "X-systemd-skip", xdg_config_parse_bool, 0, &service->systemd_skip}, + { "Desktop Entry", "Name", xdg_config_parse_string, 0, &service->description }, + { "Desktop Entry", "Exec", xdg_config_parse_string, 0, &service->exec_string }, + { "Desktop Entry", "Path", xdg_config_parse_string, 0, &service->working_directory }, + { "Desktop Entry", "TryExec", xdg_config_parse_string, 0, &service->try_exec }, + { "Desktop Entry", "Type", xdg_config_parse_string, 0, &service->type }, + { "Desktop Entry", "OnlyShowIn", xdg_config_parse_strv, 0, &service->only_show_in }, + { "Desktop Entry", "NotShowIn", xdg_config_parse_strv, 0, &service->not_show_in }, + { "Desktop Entry", "Hidden", xdg_config_parse_bool, 0, &service->hidden }, + { "Desktop Entry", "AutostartCondition", xdg_config_parse_string, 0, &service->autostart_condition }, + { "Desktop Entry", "X-KDE-autostart-condition", xdg_config_parse_string, 0, &service->kde_autostart_condition }, + { "Desktop Entry", "X-GNOME-Autostart-Phase", xdg_config_parse_string, 0, &service->gnome_autostart_phase }, + { "Desktop Entry", "X-systemd-skip", xdg_config_parse_bool, 0, &service->systemd_skip }, /* Common entries that we do not use currently. */ - { "Desktop Entry", "Categories", NULL, 0, NULL}, - { "Desktop Entry", "Comment", NULL, 0, NULL}, - { "Desktop Entry", "Encoding", NULL, 0, NULL}, - { "Desktop Entry", "GenericName", NULL, 0, NULL}, - { "Desktop Entry", "Icon", NULL, 0, NULL}, - { "Desktop Entry", "Keywords", NULL, 0, NULL}, - { "Desktop Entry", "MimeType", NULL, 0, NULL}, - { "Desktop Entry", "NoDisplay", NULL, 0, NULL}, - { "Desktop Entry", "StartupNotify", NULL, 0, NULL}, - { "Desktop Entry", "StartupWMClass", NULL, 0, NULL}, - { "Desktop Entry", "Terminal", NULL, 0, NULL}, - { "Desktop Entry", "URL", NULL, 0, NULL}, - { "Desktop Entry", "Version", NULL, 0, NULL}, + { "Desktop Entry", "Categories", NULL, 0, NULL}, + { "Desktop Entry", "Comment", NULL, 0, NULL}, + { "Desktop Entry", "DBusActivatable", NULL, 0, NULL}, + { "Desktop Entry", "Encoding", NULL, 0, NULL}, + { "Desktop Entry", "GenericName", NULL, 0, NULL}, + { "Desktop Entry", "Icon", NULL, 0, NULL}, + { "Desktop Entry", "Keywords", NULL, 0, NULL}, + { "Desktop Entry", "MimeType", NULL, 0, NULL}, + { "Desktop Entry", "NoDisplay", NULL, 0, NULL}, + { "Desktop Entry", "StartupNotify", NULL, 0, NULL}, + { "Desktop Entry", "StartupWMClass", NULL, 0, NULL}, + { "Desktop Entry", "Terminal", NULL, 0, NULL}, + { "Desktop Entry", "URL", NULL, 0, NULL}, + { "Desktop Entry", "Version", NULL, 0, NULL}, {} }; @@ -375,20 +376,17 @@ int xdg_autostart_format_exec_start( int r; /* - * Unfortunately, there is a mismatch between systemd's idea of $PATH - * and XDGs. i.e. we need to ensure that we have an absolute path to - * support cases where $PATH has been modified from the default set. + * Unfortunately, there is a mismatch between systemd's idea of $PATH and XDGs. I.e. we need to + * ensure that we have an absolute path to support cases where $PATH has been modified from the + * default set. * - * Note that this is only needed for development environments though; - * so while it is important, this should have no effect in production - * environments. + * Note that this is only needed for development environments though; so while it is important, this + * should have no effect in production environments. * - * To be compliant with the XDG specification, we also need to strip - * certain parameters and such. Doing so properly makes parsing the - * command line unavoidable. + * To be compliant with the XDG specification, we also need to strip certain parameters and + * such. Doing so properly makes parsing the command line unavoidable. * - * NOTE: Technically, XDG only specifies " as quotes, while this also - * accepts '. + * NOTE: Technically, XDG only specifies " as quotes, while this also accepts '. */ r = strv_split_full(&exec_split, exec, NULL, EXTRACT_UNQUOTE | EXTRACT_RELAX); if (r < 0) @@ -424,28 +422,26 @@ int xdg_autostart_format_exec_start( } /* - * Remove any standardised XDG fields; we assume they never appear as - * part of another argument as that just does not make any sense as - * they can be empty (GLib will e.g. turn "%f" into an empty argument). - * Other implementations may handle this differently. + * Remove any standardised XDG fields; we assume they never appear as part of another + * argument as that just does not make any sense as they can be empty (GLib will e.g. turn + * "%f" into an empty argument). Other implementations may handle this differently. */ if (STR_IN_SET(c, "%f", "%F", "%u", "%U", "%d", "%D", "%n", "%N", - "%i", /* Location of icon, could be implemented. */ - "%c", /* Translated application name, could be implemented. */ - "%k", /* Location of desktop file, could be implemented. */ + "%i", /* Location of icon, could be implemented. */ + "%c", /* Translated application name, could be implemented. */ + "%k", /* Location of desktop file, could be implemented. */ "%v", "%m" )) continue; /* - * %% -> % and then % -> %% means that we correctly quote any % - * and also quote any left over (and invalid) % specifier from - * the desktop file. + * %% -> % and then % -> %% means that we correctly quote any % and also quote any left over + * (and invalid) % specifier from the desktop file. */ raw = strreplace(c, "%%", "%"); if (!raw) @@ -539,10 +535,8 @@ int xdg_autostart_service_generate_unit( return 0; } - /* - * The TryExec key cannot be checked properly from the systemd unit, - * it is trivial to check using find_executable though. - */ + /* The TryExec key cannot be checked properly from the systemd unit, it is trivial to check using + * find_executable though. */ if (service->try_exec) { r = find_executable(service->try_exec, NULL); if (r < 0) { diff --git a/sysctl.d/50-coredump.conf.in b/sysctl.d/50-coredump.conf.in index 4338756ef..2ffc1cb0f 100644 --- a/sysctl.d/50-coredump.conf.in +++ b/sysctl.d/50-coredump.conf.in @@ -15,15 +15,14 @@ # See systemd-coredump(8) and core(5). kernel.core_pattern=|@rootlibexecdir@/systemd-coredump %P %u %g %s %t %c %h -# Allow that 16 coredumps are dispatched in parallel by the kernel. We want to -# be able to collect process metadata from /proc/%P/ while processing -# coredumps, and thus need to make sure the crashed processes are not reaped -# until we finished collecting what we need. The kernel default for this sysctl -# is "0" which means the kernel doesn't wait for userspace processes to finish -# processing before reaping the crashed processes — by setting this higher the -# kernel will delay reaping until we are done, but only for the specified -# number of crashes in parallel. The value of 16 is chosen to match -# systemd-coredump.socket's MaxConnections= value. +# Allow 16 coredumps to be dispatched in parallel by the kernel. +# We collect metadata from /proc/%P/, and thus need to make sure the crashed +# processes are not reaped until we have finished collecting what we need. The +# kernel default for this sysctl is "0" which means the kernel doesn't wait for +# userspace to finish processing before reaping the crashed processes. With a +# higher setting the kernel will delay reaping until we are done, but only for +# the specified number of crashes in parallel. The value of 16 is chosen to +# match systemd-coredump.socket's MaxConnections= value. kernel.core_pipe_limit=16 # Also dump processes executing a set-user-ID/set-group-ID program that is diff --git a/sysctl.d/50-default.conf b/sysctl.d/50-default.conf index 14378b24a..f41e24bcb 100644 --- a/sysctl.d/50-default.conf +++ b/sysctl.d/50-default.conf @@ -41,11 +41,11 @@ net.ipv4.conf.*.promote_secondaries = 1 # the kernel because of this definition in linux/include/net/ping.h: # #define GID_T_MAX (((gid_t)~0U) >> 1) # That's not so bad because values between 2^31 and 2^32-1 are reserved on -# systemd-based systems anyway: https://systemd.io/UIDS-GIDS.html#summary +# systemd-based systems anyway: https://systemd.io/UIDS-GIDS#summary -net.ipv4.ping_group_range = 0 2147483647 # Fair Queue CoDel packet scheduler to fight bufferbloat -net.core.default_qdisc = fq_codel +-net.core.default_qdisc = fq_codel # Enable hard and soft link protection fs.protected_hardlinks = 1 diff --git a/sysctl.d/README b/sysctl.d/README new file mode 100644 index 000000000..ab216b108 --- /dev/null +++ b/sysctl.d/README @@ -0,0 +1,8 @@ +Files in this directory contain configuration for systemd-sysctl.service, a +service to configure sysctl kernel parameters. + +See man:sysctl.d(5) for explanation of the configuration file format, and +man:sysctl(8) and man:systemd-sysctl.service(8) for a description of when and +how this configuration is applied. + +Use 'systemd-analyze cat-config sysctl.d' to display the effective config. diff --git a/sysctl.d/meson.build b/sysctl.d/meson.build index e8d8fc8c5..7e3482af6 100644 --- a/sysctl.d/meson.build +++ b/sysctl.d/meson.build @@ -1,6 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-or-later install_data( + 'README', '50-default.conf', install_dir : sysctldir) diff --git a/sysusers.d/README b/sysusers.d/README new file mode 100644 index 000000000..df3049cc5 --- /dev/null +++ b/sysusers.d/README @@ -0,0 +1,8 @@ +Files in this directory contain configuration for systemd-sysusers, a program +to allocate system users and groups. + +See man:sysusers.d(5) for explanation of the configuration file format, and +man:systemd-sysusers(8) for a description of when and how this configuration is +applied. + +Use 'systemd-analyze cat-config sysusers.d' to display the effective config. diff --git a/sysusers.d/basic.conf.in b/sysusers.d/basic.conf.in index 8e358c02d..4be0bd869 100644 --- a/sysusers.d/basic.conf.in +++ b/sysusers.d/basic.conf.in @@ -31,6 +31,7 @@ g input - - - g kvm - - - g lp - - - g render - - - +g sgx - - - g tape - - - g video - - - diff --git a/sysusers.d/meson.build b/sysusers.d/meson.build index 93a61f0d9..ef809a4f4 100644 --- a/sysusers.d/meson.build +++ b/sysusers.d/meson.build @@ -1,5 +1,9 @@ # SPDX-License-Identifier: LGPL-2.1-or-later +if enable_sysusers + install_data('README', install_dir : sysusersdir) +endif + in_files = ['basic.conf'] foreach file : in_files diff --git a/test/README.testsuite b/test/README.testsuite index 5d9e498c5..da989c1e0 100644 --- a/test/README.testsuite +++ b/test/README.testsuite @@ -8,7 +8,7 @@ $ sudo test/run-integration-tests.sh ninja: Entering directory `/home/zbyszek/src/systemd/build' ninja: no work to do. --x-- Running TEST-01-BASIC --x-- -+ make -C TEST-01-BASIC BUILD_DIR=/home/zbyszek/src/systemd/build clean setup run ++ make -C TEST-01-BASIC clean setup run make: Entering directory '/home/zbyszek/src/systemd/test/TEST-01-BASIC' TEST-01-BASIC CLEANUP: Basic systemd setup TEST-01-BASIC SETUP: Basic systemd setup @@ -17,7 +17,7 @@ TEST-01-BASIC RUN: Basic systemd setup [OK] make: Leaving directory '/home/zbyszek/src/systemd/test/TEST-01-BASIC' --x-- Result of TEST-01-BASIC: 0 --x-- --x-- Running TEST-02-CRYPTSETUP --x-- -+ make -C TEST-02-CRYPTSETUP BUILD_DIR=/home/zbyszek/src/systemd/build clean setup run ++ make -C TEST-02-CRYPTSETUP clean setup run If one of the tests fails, then $subdir/test.log contains the log file of the test. @@ -41,15 +41,29 @@ $ sudo make -C test/TEST-01-BASIC BUILD_DIR=../../some-other-build/ ... Note that in the second case, the path is relative to the test case directory. An absolute path may also be used in both cases. +Testing installed binaries instead of built +=========================================== + +To run the extended testsuite using the systemd installed on the system instead +of the systemd from a build, use the NO_BUILD=1: + +$ sudo NO_BUILD=1 test/run-integration-tests + Configuration variables ======================= TEST_NO_QEMU=1 Don't run tests under QEMU +TEST_QEMU_ONLY=1 + Run only tests that require QEMU + TEST_NO_NSPAWN=1 Don't run tests under systemd-nspawn +TEST_PREFER_NSPAWN=1 + Run all tests that do not require qemu under systemd-nspawn + TEST_NO_KVM=1 Disable QEMU KVM auto-detection (may be necessary when you're trying to run the *vanilla* QEMU and have both qemu and qemu-kvm installed) @@ -129,3 +143,8 @@ the Github CI status. To add new dependencies or new binaries to the packages used during the tests, a merge request can be sent to: https://salsa.debian.org/systemd-team/systemd targeting the 'upstream-ci' branch. + +The cloud-side infrastructure, that is hooked into the Github interface, is +located at: + +https://git.launchpad.net/autopkgtest-cloud/ diff --git a/test/TEST-01-BASIC/Makefile b/test/TEST-01-BASIC/Makefile index 79fe9688b..9b90a1c2b 100644 --- a/test/TEST-01-BASIC/Makefile +++ b/test/TEST-01-BASIC/Makefile @@ -1,6 +1,4 @@ -BUILD_DIR=$(shell ../../tools/find-build-dir.sh) - all setup run clean clean-again: - @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@ + @TEST_BASE_DIR=../ ./test.sh --$@ .PHONY: all setup run clean clean-again diff --git a/test/TEST-01-BASIC/test.sh b/test/TEST-01-BASIC/test.sh index 58f6cd141..66c35fe2b 100755 --- a/test/TEST-01-BASIC/test.sh +++ b/test/TEST-01-BASIC/test.sh @@ -7,19 +7,11 @@ TEST_REQUIRE_INSTALL_TESTS=0 . $TEST_BASE_DIR/test-functions -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay - ( - LOG_LEVEL=5 - setup_basic_environment - - # install tests manually so the test is functional even when -Dinstall-tests=false - mkdir -p $initdir/usr/lib/systemd/tests/testdata/units/ - cp -v $(dirname $0)/../units/{testsuite-01,end}.service $initdir/usr/lib/systemd/tests/testdata/units/ - ) - setup_nspawn_root +test_append_files() { + # install tests manually so the test is functional even when -Dinstall-tests=false + local dst="$1/usr/lib/systemd/tests/testdata/units/" + mkdir -p "$dst" + cp -v $TEST_UNITS_DIR/{testsuite-01,end}.service $TEST_UNITS_DIR/testsuite.target "$dst" } do_test "$@" 01 diff --git a/test/TEST-06-SELINUX/systemd_test.fc b/test/TEST-06-SELINUX/systemd_test.fc new file mode 100644 index 000000000..249c6792c --- /dev/null +++ b/test/TEST-06-SELINUX/systemd_test.fc @@ -0,0 +1 @@ +/usr/lib/systemd/tests/testdata/testsuite-06\.units(/.*)? system_u:object_r:systemd_unit_file_t:s0 diff --git a/test/TEST-06-SELINUX/test.sh b/test/TEST-06-SELINUX/test.sh index 0acd7a10e..f05cd3559 100755 --- a/test/TEST-06-SELINUX/test.sh +++ b/test/TEST-06-SELINUX/test.sh @@ -16,34 +16,28 @@ test -f /usr/share/selinux/devel/include/system/systemd.if || exit 0 SETUP_SELINUX=yes KERNEL_APPEND="$KERNEL_APPEND selinux=1 security=selinux" -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay +test_append_files() { ( - LOG_LEVEL=5 - - setup_basic_environment - mask_supporting_services - + setup_selinux local _modules_dir=/var/lib/selinux - rm -rf $initdir/$_modules_dir - if ! cp -ar $_modules_dir $initdir/$_modules_dir; then + rm -rf $1/$_modules_dir + if ! cp -ar $_modules_dir $1/$_modules_dir; then dfatal "Failed to copy $_modules_dir" exit 1 fi local _policy_headers_dir=/usr/share/selinux/devel - rm -rf $initdir/$_policy_headers_dir + rm -rf $1/$_policy_headers_dir inst_dir /usr/share/selinux - if ! cp -ar $_policy_headers_dir $initdir/$_policy_headers_dir; then + if ! cp -ar $_policy_headers_dir $1/$_policy_headers_dir; then dfatal "Failed to copy $_policy_headers_dir" exit 1 fi - mkdir $initdir/systemd-test-module - cp systemd_test.te $initdir/systemd-test-module - cp systemd_test.if $initdir/systemd-test-module + mkdir $1/systemd-test-module + cp systemd_test.te $1/systemd-test-module + cp systemd_test.if $1/systemd-test-module + cp systemd_test.fc $1/systemd-test-module dracut_install -o sesearch dracut_install runcon dracut_install checkmodule semodule semodule_package m4 make load_policy sefcontext_compile diff --git a/test/TEST-08-ISSUE-2730/test.sh b/test/TEST-08-ISSUE-2730/test.sh index e5dedf2f0..34d68835d 100755 --- a/test/TEST-08-ISSUE-2730/test.sh +++ b/test/TEST-08-ISSUE-2730/test.sh @@ -7,16 +7,6 @@ TEST_NO_NSPAWN=1 . $TEST_BASE_DIR/test-functions QEMU_TIMEOUT=300 FSTYPE=ext4 - -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay - ( - LOG_LEVEL=5 - setup_basic_environment - ) - mask_supporting_services -} +TEST_FORCE_NEWIMAGE=1 do_test "$@" 08 diff --git a/test/TEST-13-NSPAWN-SMOKE/test.sh b/test/TEST-13-NSPAWN-SMOKE/test.sh index 236378a38..0f6bf587a 100755 --- a/test/TEST-13-NSPAWN-SMOKE/test.sh +++ b/test/TEST-13-NSPAWN-SMOKE/test.sh @@ -6,17 +6,10 @@ TEST_NO_NSPAWN=1 . $TEST_BASE_DIR/test-functions -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay +test_append_files() { ( - LOG_LEVEL=5 - setup_basic_environment - mask_supporting_services - - ../create-busybox-container $initdir/testsuite-13.nc-container - initdir="$initdir/testsuite-13.nc-container" dracut_install nc ip md5sum + ../create-busybox-container $1/testsuite-13.nc-container + initdir="$1/testsuite-13.nc-container" dracut_install nc ip md5sum ) } diff --git a/test/TEST-14-MACHINE-ID/test.sh b/test/TEST-14-MACHINE-ID/test.sh index e8dbf23c5..87abe2e43 100755 --- a/test/TEST-14-MACHINE-ID/test.sh +++ b/test/TEST-14-MACHINE-ID/test.sh @@ -6,16 +6,8 @@ TEST_NO_NSPAWN=1 . $TEST_BASE_DIR/test-functions -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay - ( - LOG_LEVEL=5 - setup_basic_environment - mask_supporting_services - printf "556f48e837bc4424a710fa2e2c9d3e3c\ne3d\n" >$initdir/etc/machine-id - ) +test_append_files() { + printf "556f48e837bc4424a710fa2e2c9d3e3c\ne3d\n" >$1/etc/machine-id } do_test "$@" 14 diff --git a/test/TEST-17-UDEV-WANTS/test.sh b/test/TEST-17-UDEV-WANTS/test.sh deleted file mode 100755 index 5b8f22cba..000000000 --- a/test/TEST-17-UDEV-WANTS/test.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -e -TEST_DESCRIPTION="UDEV SYSTEMD_WANTS property" -TEST_NO_NSPAWN=1 - -. $TEST_BASE_DIR/test-functions -QEMU_TIMEOUT=300 - -do_test "$@" 17 diff --git a/test/TEST-17-UDEV-WANTS/Makefile b/test/TEST-17-UDEV/Makefile similarity index 100% rename from test/TEST-17-UDEV-WANTS/Makefile rename to test/TEST-17-UDEV/Makefile diff --git a/test/TEST-17-UDEV/test.sh b/test/TEST-17-UDEV/test.sh new file mode 100755 index 000000000..b13ae0aa7 --- /dev/null +++ b/test/TEST-17-UDEV/test.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash +set -e +TEST_DESCRIPTION="UDEV" +IMAGE_NAME="udev" +TEST_NO_NSPAWN=1 + +. $TEST_BASE_DIR/test-functions +QEMU_TIMEOUT=500 + +test_append_files() { + ( + instmods dummy + generate_module_dependencies + ) +} + +do_test "$@" 17 diff --git a/test/TEST-22-TMPFILES/test.sh b/test/TEST-22-TMPFILES/test.sh index 317e4a88f..e4874b4d2 100755 --- a/test/TEST-22-TMPFILES/test.sh +++ b/test/TEST-22-TMPFILES/test.sh @@ -4,4 +4,15 @@ TEST_DESCRIPTION="Tmpfiles related tests" TEST_NO_QEMU=1 . $TEST_BASE_DIR/test-functions +test_append_files() { + if [[ "$IS_BUILT_WITH_ASAN" == "yes" ]]; then + if [[ -z "$initdir" ]]; then + echo >&2 "\$initdir is not defined, can't continue" + exit 1 + fi + + sed -i "s/systemd//g" "$initdir/etc/nsswitch.conf" + fi +} + do_test "$@" 22 diff --git a/test/TEST-24-CRYPTSETUP/test.sh b/test/TEST-24-CRYPTSETUP/test.sh index 2a6ad310e..d7b338c7f 100755 --- a/test/TEST-24-CRYPTSETUP/test.sh +++ b/test/TEST-24-CRYPTSETUP/test.sh @@ -3,6 +3,7 @@ set -e TEST_DESCRIPTION="cryptsetup systemd setup" IMAGE_NAME="cryptsetup" TEST_NO_NSPAWN=1 +TEST_FORCE_NEWIMAGE=1 . $TEST_BASE_DIR/test-functions diff --git a/test/TEST-29-UDEV-ID_RENAMING/Makefile b/test/TEST-29-PORTABLE/Makefile similarity index 100% rename from test/TEST-29-UDEV-ID_RENAMING/Makefile rename to test/TEST-29-PORTABLE/Makefile diff --git a/test/TEST-29-PORTABLE/test.sh b/test/TEST-29-PORTABLE/test.sh new file mode 100755 index 000000000..801e74c13 --- /dev/null +++ b/test/TEST-29-PORTABLE/test.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh +set -e +TEST_DESCRIPTION="test systemd-portabled" +IMAGE_NAME="portabled" +TEST_NO_NSPAWN=1 +TEST_INSTALL_VERITY_MINIMAL=1 + +. $TEST_BASE_DIR/test-functions + +# Need loop devices for mounting images +test_append_files() { + ( + instmods loop =block + instmods squashfs =squashfs + instmods dm_verity =md + install_dmevent + generate_module_dependencies + inst_binary losetup + inst_binary mksquashfs + inst_binary unsquashfs + install_verity_minimal + ) +} + +do_test "$@" 29 diff --git a/test/TEST-29-UDEV-ID_RENAMING/test.sh b/test/TEST-29-UDEV-ID_RENAMING/test.sh deleted file mode 100755 index ddf6db973..000000000 --- a/test/TEST-29-UDEV-ID_RENAMING/test.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env bash -set -e -TEST_DESCRIPTION="UDEV ID_RENAMING property" -IMAGE_NAME="udev-id-renaming" -TEST_NO_NSPAWN=1 - -. $TEST_BASE_DIR/test-functions -QEMU_TIMEOUT=300 - -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay - ( - LOG_LEVEL=5 - setup_basic_environment - mask_supporting_services - - instmods dummy - generate_module_dependencies - ) -} - -do_test "$@" 29 diff --git a/test/TEST-36-NUMAPOLICY/test.sh b/test/TEST-36-NUMAPOLICY/test.sh index a08ad6c14..cec8b6992 100755 --- a/test/TEST-36-NUMAPOLICY/test.sh +++ b/test/TEST-36-NUMAPOLICY/test.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -TEST_DESCRIPTION="test MUMAPolicy= and NUMAMask= options" +TEST_DESCRIPTION="test NUMAPolicy= and NUMAMask= options" TEST_NO_NSPAWN=1 . $TEST_BASE_DIR/test-functions if qemu_min_version "5.2.0"; then diff --git a/test/TEST-49-UDEV-EVENT-TIMEOUT/Makefile b/test/TEST-49-RUNTIME-BIND-PATHS/Makefile similarity index 100% rename from test/TEST-49-UDEV-EVENT-TIMEOUT/Makefile rename to test/TEST-49-RUNTIME-BIND-PATHS/Makefile diff --git a/test/TEST-49-RUNTIME-BIND-PATHS/test.sh b/test/TEST-49-RUNTIME-BIND-PATHS/test.sh new file mode 100755 index 000000000..ff24a4f25 --- /dev/null +++ b/test/TEST-49-RUNTIME-BIND-PATHS/test.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash +set -e + +TEST_DESCRIPTION="test adding new BindPaths while unit is already running" +. $TEST_BASE_DIR/test-functions + +do_test "$@" 49 diff --git a/test/TEST-49-UDEV-EVENT-TIMEOUT/test.sh b/test/TEST-49-UDEV-EVENT-TIMEOUT/test.sh deleted file mode 100755 index 249d8a22a..000000000 --- a/test/TEST-49-UDEV-EVENT-TIMEOUT/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -e - -TEST_DESCRIPTION="test udev's event-timeout and timeout-signal options" -TEST_NO_NSPAWN=1 -. $TEST_BASE_DIR/test-functions - -do_test "$@" 49 diff --git a/test/TEST-50-DISSECT/deny-list-ubuntu-ci b/test/TEST-50-DISSECT/deny-list-ubuntu-ci new file mode 100644 index 000000000..e7585d747 --- /dev/null +++ b/test/TEST-50-DISSECT/deny-list-ubuntu-ci @@ -0,0 +1,2 @@ +Skip this test due to issue #17469 +https://github.com/systemd/systemd/issues/17469 diff --git a/test/TEST-50-DISSECT/test.sh b/test/TEST-50-DISSECT/test.sh index 073ca8c31..9d42e4891 100755 --- a/test/TEST-50-DISSECT/test.sh +++ b/test/TEST-50-DISSECT/test.sh @@ -5,6 +5,7 @@ set -e TEST_DESCRIPTION="test systemd-dissect" IMAGE_NAME="dissect" TEST_NO_NSPAWN=1 +TEST_INSTALL_VERITY_MINIMAL=1 . $TEST_BASE_DIR/test-functions @@ -13,39 +14,16 @@ command -v veritysetup >/dev/null 2>&1 || exit 0 command -v sfdisk >/dev/null 2>&1 || exit 0 # Need loop devices for systemd-dissect -test_create_image() { - create_empty_image_rootdir - - # Create what will eventually be our root filesystem onto an overlay - # If some pieces are missing from the host, skip rather than fail +test_append_files() { ( - LOG_LEVEL=5 - setup_basic_environment - mask_supporting_services - instmods loop =block instmods squashfs =squashfs instmods dm_verity =md + instmods overlay =overlayfs install_dmevent generate_module_dependencies inst_binary losetup - - BASICTOOLS=( - bash - cat - mount - ) - oldinitdir=$initdir - export initdir=$TESTDIR/minimal - mkdir -p $initdir/usr/lib $initdir/etc - setup_basic_dirs - install_basic_tools - cp $os_release $initdir/usr/lib/os-release - ln -s ../usr/lib/os-release $initdir/etc/os-release - echo MARKER=1 >> $initdir/usr/lib/os-release - mksquashfs $initdir $oldinitdir/usr/share/minimal.raw - veritysetup format $oldinitdir/usr/share/minimal.raw $oldinitdir/usr/share/minimal.verity | grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal.roothash - export initdir=$oldinitdir + install_verity_minimal ) } diff --git a/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile b/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile index a06599081..71487d707 100644 --- a/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile +++ b/test/TEST-52-HONORFIRSTSHUTDOWN/Makefile @@ -1,7 +1,5 @@ -BUILD_DIR=$(shell ../../tools/find-build-dir.sh) - all setup run clean clean-again: - @basedir=../.. TEST_BASE_DIR=../ BUILD_DIR=$(BUILD_DIR) ./test.sh --$@ + @TEST_BASE_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 @@ -11,6 +9,6 @@ all setup run clean clean-again: # 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 --$@ + @TEST_BASE_DIR=../ ./fini.sh --$@ .PHONY: all setup run clean clean-again finish diff --git a/test/TEST-55-UDEV-TAGS/Makefile b/test/TEST-55-OOMD/Makefile similarity index 100% rename from test/TEST-55-UDEV-TAGS/Makefile rename to test/TEST-55-OOMD/Makefile diff --git a/test/TEST-56-OOMD/test.sh b/test/TEST-55-OOMD/test.sh similarity index 98% rename from test/TEST-56-OOMD/test.sh rename to test/TEST-55-OOMD/test.sh index 55b0d1daf..121aa8d56 100755 --- a/test/TEST-56-OOMD/test.sh +++ b/test/TEST-55-OOMD/test.sh @@ -45,4 +45,4 @@ check_result_qemu() { return $ret } -do_test "$@" 56 +do_test "$@" 55 diff --git a/test/TEST-55-UDEV-TAGS/test.sh b/test/TEST-55-UDEV-TAGS/test.sh deleted file mode 100755 index 325d70f01..000000000 --- a/test/TEST-55-UDEV-TAGS/test.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -set -e -TEST_DESCRIPTION="UDEV tags management" -TEST_NO_NSPAWN=1 - -. $TEST_BASE_DIR/test-functions - -do_test "$@" 55 diff --git a/test/TEST-56-OOMD/Makefile b/test/TEST-56-OOMD/Makefile deleted file mode 120000 index e9f93b110..000000000 --- a/test/TEST-56-OOMD/Makefile +++ /dev/null @@ -1 +0,0 @@ -../TEST-01-BASIC/Makefile \ No newline at end of file diff --git a/test/create-busybox-container b/test/create-busybox-container index 5ded42950..b2b7b2629 100755 --- a/test/create-busybox-container +++ b/test/create-busybox-container @@ -28,6 +28,9 @@ ln -s busybox "$root/bin/cat" ln -s busybox "$root/bin/tr" ln -s busybox "$root/bin/ps" ln -s busybox "$root/bin/ip" +ln -s busybox "$root/bin/seq" +ln -s busybox "$root/bin/sleep" +ln -s busybox "$root/bin/test" mkdir -p "$root/sbin" cat <<'EOF' >"$root/sbin/init" diff --git a/test/dmidecode-dumps/HP-Z600.bin b/test/dmidecode-dumps/HP-Z600.bin new file mode 100644 index 000000000..cf759042b Binary files /dev/null and b/test/dmidecode-dumps/HP-Z600.bin differ diff --git a/test/dmidecode-dumps/HP-Z600.bin.txt b/test/dmidecode-dumps/HP-Z600.bin.txt new file mode 100644 index 000000000..d17fb8307 --- /dev/null +++ b/test/dmidecode-dumps/HP-Z600.bin.txt @@ -0,0 +1,94 @@ +MEMORY_ARRAY_LOCATION=System Board Or Motherboard +MEMORY_ARRAY_EC_TYPE=Multi-bit ECC +MEMORY_ARRAY_MAX_CAPACITY=12884901888 +MEMORY_ARRAY_NUM_DEVICES=3 +MEMORY_ARRAY_LOCATION=System Board Or Motherboard +MEMORY_ARRAY_EC_TYPE=Multi-bit ECC +MEMORY_ARRAY_MAX_CAPACITY=12884901888 +MEMORY_ARRAY_NUM_DEVICES=3 +MEMORY_DEVICE_0_TOTAL_WIDTH=72 +MEMORY_DEVICE_0_DATA_WIDTH=64 +MEMORY_DEVICE_0_SIZE=8589934592 +MEMORY_DEVICE_0_FORM_FACTOR=DIMM +MEMORY_DEVICE_0_LOCATOR=CPU0 DIMM1 +MEMORY_DEVICE_0_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_0_TYPE=DDR3 +MEMORY_DEVICE_0_TYPE_DETAIL=Synchronous Unbuffered (Unregistered) +MEMORY_DEVICE_0_SPEED_MTS=1600 +MEMORY_DEVICE_0_MANUFACTURER=JEDEC ID:80 AD +MEMORY_DEVICE_0_SERIAL_NUMBER=BC8A0E80 +MEMORY_DEVICE_0_ASSET_TAG=Not Specified +MEMORY_DEVICE_0_PART_NUMBER=HMT41GU7AFR8C-PB +MEMORY_DEVICE_0_RANK=2 +MEMORY_DEVICE_1_TOTAL_WIDTH=72 +MEMORY_DEVICE_1_DATA_WIDTH=64 +MEMORY_DEVICE_1_SIZE=8589934592 +MEMORY_DEVICE_1_FORM_FACTOR=DIMM +MEMORY_DEVICE_1_LOCATOR=CPU0 DIMM2 +MEMORY_DEVICE_1_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_1_TYPE=DDR3 +MEMORY_DEVICE_1_TYPE_DETAIL=Synchronous Unbuffered (Unregistered) +MEMORY_DEVICE_1_SPEED_MTS=1600 +MEMORY_DEVICE_1_MANUFACTURER=JEDEC ID:80 AD +MEMORY_DEVICE_1_SERIAL_NUMBER=86A6934F +MEMORY_DEVICE_1_ASSET_TAG=Not Specified +MEMORY_DEVICE_1_PART_NUMBER=HMT41GU7AFR8C-PB +MEMORY_DEVICE_1_RANK=2 +MEMORY_DEVICE_2_DATA_WIDTH=64 +MEMORY_DEVICE_2_PRESENT=0 +MEMORY_DEVICE_2_FORM_FACTOR=DIMM +MEMORY_DEVICE_2_LOCATOR=CPU0 DIMM3 +MEMORY_DEVICE_2_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_2_TYPE=DDR3 +MEMORY_DEVICE_2_TYPE_DETAIL=Synchronous +MEMORY_DEVICE_2_MANUFACTURER=JEDEC ID: +MEMORY_DEVICE_2_ASSET_TAG=Not Specified +MEMORY_DEVICE_3_TOTAL_WIDTH=72 +MEMORY_DEVICE_3_DATA_WIDTH=64 +MEMORY_DEVICE_3_SIZE=8589934592 +MEMORY_DEVICE_3_FORM_FACTOR=DIMM +MEMORY_DEVICE_3_LOCATOR=CPU1 DIMM1 +MEMORY_DEVICE_3_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_3_TYPE=DDR3 +MEMORY_DEVICE_3_TYPE_DETAIL=Synchronous Unbuffered (Unregistered) +MEMORY_DEVICE_3_SPEED_MTS=1600 +MEMORY_DEVICE_3_MANUFACTURER=JEDEC ID:80 AD +MEMORY_DEVICE_3_SERIAL_NUMBER=A18A0E80 +MEMORY_DEVICE_3_ASSET_TAG=Not Specified +MEMORY_DEVICE_3_PART_NUMBER=HMT41GU7AFR8C-PB +MEMORY_DEVICE_3_RANK=2 +MEMORY_DEVICE_4_TOTAL_WIDTH=72 +MEMORY_DEVICE_4_DATA_WIDTH=64 +MEMORY_DEVICE_4_SIZE=8589934592 +MEMORY_DEVICE_4_FORM_FACTOR=DIMM +MEMORY_DEVICE_4_LOCATOR=CPU1 DIMM2 +MEMORY_DEVICE_4_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_4_TYPE=DDR3 +MEMORY_DEVICE_4_TYPE_DETAIL=Synchronous Unbuffered (Unregistered) +MEMORY_DEVICE_4_SPEED_MTS=1600 +MEMORY_DEVICE_4_MANUFACTURER=JEDEC ID:80 AD +MEMORY_DEVICE_4_SERIAL_NUMBER=7D8A0E80 +MEMORY_DEVICE_4_ASSET_TAG=Not Specified +MEMORY_DEVICE_4_PART_NUMBER=HMT41GU7AFR8C-PB +MEMORY_DEVICE_4_RANK=2 +MEMORY_DEVICE_5_DATA_WIDTH=64 +MEMORY_DEVICE_5_PRESENT=0 +MEMORY_DEVICE_5_FORM_FACTOR=DIMM +MEMORY_DEVICE_5_LOCATOR=CPU1 DIMM3 +MEMORY_DEVICE_5_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_5_TYPE=DDR3 +MEMORY_DEVICE_5_TYPE_DETAIL=Synchronous +MEMORY_DEVICE_5_MANUFACTURER=JEDEC ID: +MEMORY_DEVICE_5_ASSET_TAG=Not Specified +MEMORY_DEVICE_6_TOTAL_WIDTH=2 +MEMORY_DEVICE_6_DATA_WIDTH=2 +MEMORY_DEVICE_6_SIZE=2097152 +MEMORY_DEVICE_6_FORM_FACTOR=Chip +MEMORY_DEVICE_6_LOCATOR=SYSTEM ROM +MEMORY_DEVICE_6_BANK_LOCATOR=Not Specified +MEMORY_DEVICE_6_TYPE=Flash +MEMORY_DEVICE_6_TYPE_DETAIL=Non-Volatile +MEMORY_DEVICE_6_MANUFACTURER=Not Specified +MEMORY_DEVICE_6_SERIAL_NUMBER=Not Specified +MEMORY_DEVICE_6_ASSET_TAG=Not Specified +MEMORY_DEVICE_6_PART_NUMBER=Not Specified diff --git a/test/dmidecode-dumps/Lenovo-ThinkPad-X280.bin b/test/dmidecode-dumps/Lenovo-ThinkPad-X280.bin new file mode 100644 index 000000000..4c02fb71c Binary files /dev/null and b/test/dmidecode-dumps/Lenovo-ThinkPad-X280.bin differ diff --git a/test/dmidecode-dumps/Lenovo-ThinkPad-X280.bin.txt b/test/dmidecode-dumps/Lenovo-ThinkPad-X280.bin.txt new file mode 100644 index 000000000..26a8faf5d --- /dev/null +++ b/test/dmidecode-dumps/Lenovo-ThinkPad-X280.bin.txt @@ -0,0 +1,33 @@ +MEMORY_ARRAY_LOCATION=System Board Or Motherboard +MEMORY_ARRAY_MAX_CAPACITY=34359738368 +MEMORY_ARRAY_NUM_DEVICES=2 +MEMORY_DEVICE_0_TOTAL_WIDTH=64 +MEMORY_DEVICE_0_DATA_WIDTH=64 +MEMORY_DEVICE_0_SIZE=4294967296 +MEMORY_DEVICE_0_FORM_FACTOR=SODIMM +MEMORY_DEVICE_0_LOCATOR=ChannelA-DIMM0 +MEMORY_DEVICE_0_BANK_LOCATOR=BANK 0 +MEMORY_DEVICE_0_TYPE=DDR4 +MEMORY_DEVICE_0_TYPE_DETAIL=Synchronous Unbuffered (Unregistered) +MEMORY_DEVICE_0_SPEED_MTS=2400 +MEMORY_DEVICE_0_MANUFACTURER=0000 +MEMORY_DEVICE_0_SERIAL_NUMBER=00000000 +MEMORY_DEVICE_0_ASSET_TAG=None +MEMORY_DEVICE_0_RANK=1 +MEMORY_DEVICE_0_CONFIGURED_SPEED_MTS=2400 +MEMORY_DEVICE_0_CONFIGURED_VOLTAGE=1 +MEMORY_DEVICE_1_TOTAL_WIDTH=64 +MEMORY_DEVICE_1_DATA_WIDTH=64 +MEMORY_DEVICE_1_SIZE=4294967296 +MEMORY_DEVICE_1_FORM_FACTOR=SODIMM +MEMORY_DEVICE_1_LOCATOR=ChannelB-DIMM0 +MEMORY_DEVICE_1_BANK_LOCATOR=BANK 2 +MEMORY_DEVICE_1_TYPE=DDR4 +MEMORY_DEVICE_1_TYPE_DETAIL=Synchronous Unbuffered (Unregistered) +MEMORY_DEVICE_1_SPEED_MTS=2400 +MEMORY_DEVICE_1_MANUFACTURER=0000 +MEMORY_DEVICE_1_SERIAL_NUMBER=00000000 +MEMORY_DEVICE_1_ASSET_TAG=None +MEMORY_DEVICE_1_RANK=1 +MEMORY_DEVICE_1_CONFIGURED_SPEED_MTS=2400 +MEMORY_DEVICE_1_CONFIGURED_VOLTAGE=1 diff --git a/test/dmidecode-dumps/Lenovo-Thinkcentre-m720s.bin b/test/dmidecode-dumps/Lenovo-Thinkcentre-m720s.bin new file mode 100644 index 000000000..c07e7a29b Binary files /dev/null and b/test/dmidecode-dumps/Lenovo-Thinkcentre-m720s.bin differ diff --git a/test/dmidecode-dumps/Lenovo-Thinkcentre-m720s.bin.txt b/test/dmidecode-dumps/Lenovo-Thinkcentre-m720s.bin.txt new file mode 100644 index 000000000..c90af66a7 --- /dev/null +++ b/test/dmidecode-dumps/Lenovo-Thinkcentre-m720s.bin.txt @@ -0,0 +1,67 @@ +MEMORY_ARRAY_LOCATION=System Board Or Motherboard +MEMORY_ARRAY_MAX_CAPACITY=68719476736 +MEMORY_ARRAY_NUM_DEVICES=4 +MEMORY_DEVICE_0_TOTAL_WIDTH=64 +MEMORY_DEVICE_0_DATA_WIDTH=64 +MEMORY_DEVICE_0_SIZE=8589934592 +MEMORY_DEVICE_0_FORM_FACTOR=DIMM +MEMORY_DEVICE_0_LOCATOR=ChannelA-DIMM0 +MEMORY_DEVICE_0_BANK_LOCATOR=BANK 0 +MEMORY_DEVICE_0_TYPE=DDR4 +MEMORY_DEVICE_0_TYPE_DETAIL=Synchronous +MEMORY_DEVICE_0_SPEED_MTS=2667 +MEMORY_DEVICE_0_MANUFACTURER=Samsung +MEMORY_DEVICE_0_SERIAL_NUMBER=416433E9 +MEMORY_DEVICE_0_ASSET_TAG=9876543210 +MEMORY_DEVICE_0_PART_NUMBER=M378A1K43CB2-CTD +MEMORY_DEVICE_0_RANK=1 +MEMORY_DEVICE_0_CONFIGURED_SPEED_MTS=2400 +MEMORY_DEVICE_0_MINIMUM_VOLTAGE=1 +MEMORY_DEVICE_0_MAXIMUM_VOLTAGE=1 +MEMORY_DEVICE_0_CONFIGURED_VOLTAGE=1 +MEMORY_DEVICE_1_TOTAL_WIDTH=64 +MEMORY_DEVICE_1_DATA_WIDTH=64 +MEMORY_DEVICE_1_SIZE=8589934592 +MEMORY_DEVICE_1_FORM_FACTOR=DIMM +MEMORY_DEVICE_1_LOCATOR=ChannelA-DIMM1 +MEMORY_DEVICE_1_BANK_LOCATOR=BANK 1 +MEMORY_DEVICE_1_TYPE=DDR4 +MEMORY_DEVICE_1_TYPE_DETAIL=Synchronous +MEMORY_DEVICE_1_SPEED_MTS=2400 +MEMORY_DEVICE_1_MANUFACTURER=859B +MEMORY_DEVICE_1_SERIAL_NUMBER=A02550A6 +MEMORY_DEVICE_1_ASSET_TAG=9876543210 +MEMORY_DEVICE_1_PART_NUMBER=BLT8G4D26AFTA.16FBD +MEMORY_DEVICE_1_RANK=2 +MEMORY_DEVICE_1_CONFIGURED_SPEED_MTS=2400 +MEMORY_DEVICE_1_MINIMUM_VOLTAGE=1 +MEMORY_DEVICE_1_MAXIMUM_VOLTAGE=1 +MEMORY_DEVICE_1_CONFIGURED_VOLTAGE=1 +MEMORY_DEVICE_2_PRESENT=0 +MEMORY_DEVICE_2_FORM_FACTOR=Unknown +MEMORY_DEVICE_2_LOCATOR=ChannelB-DIMM0 +MEMORY_DEVICE_2_BANK_LOCATOR=BANK 2 +MEMORY_DEVICE_2_TYPE=Unknown +MEMORY_DEVICE_2_TYPE_DETAIL=None +MEMORY_DEVICE_2_MANUFACTURER=Not Specified +MEMORY_DEVICE_2_SERIAL_NUMBER=Not Specified +MEMORY_DEVICE_2_ASSET_TAG=Not Specified +MEMORY_DEVICE_2_PART_NUMBER=Not Specified +MEMORY_DEVICE_3_TOTAL_WIDTH=64 +MEMORY_DEVICE_3_DATA_WIDTH=64 +MEMORY_DEVICE_3_SIZE=8589934592 +MEMORY_DEVICE_3_FORM_FACTOR=DIMM +MEMORY_DEVICE_3_LOCATOR=ChannelB-DIMM1 +MEMORY_DEVICE_3_BANK_LOCATOR=BANK 3 +MEMORY_DEVICE_3_TYPE=DDR4 +MEMORY_DEVICE_3_TYPE_DETAIL=Synchronous +MEMORY_DEVICE_3_SPEED_MTS=2400 +MEMORY_DEVICE_3_MANUFACTURER=859B +MEMORY_DEVICE_3_SERIAL_NUMBER=A0254F38 +MEMORY_DEVICE_3_ASSET_TAG=9876543210 +MEMORY_DEVICE_3_PART_NUMBER=BLT8G4D26AFTA.16FBD +MEMORY_DEVICE_3_RANK=2 +MEMORY_DEVICE_3_CONFIGURED_SPEED_MTS=2400 +MEMORY_DEVICE_3_MINIMUM_VOLTAGE=1 +MEMORY_DEVICE_3_MAXIMUM_VOLTAGE=1 +MEMORY_DEVICE_3_CONFIGURED_VOLTAGE=1 diff --git a/test/fuzz/fuzz-bus-match/bugzilla1935084.input b/test/fuzz/fuzz-bus-match/bugzilla1935084.input new file mode 100644 index 000000000..1a0b3cfaa Binary files /dev/null and b/test/fuzz/fuzz-bus-match/bugzilla1935084.input differ diff --git a/test/fuzz/fuzz-bus-match/test.input b/test/fuzz/fuzz-bus-match/test.input new file mode 100644 index 000000000..92c02fc75 Binary files /dev/null and b/test/fuzz/fuzz-bus-match/test.input differ diff --git a/test/fuzz/fuzz-dns-packet/oss-fuzz-19227 b/test/fuzz/fuzz-dns-packet/oss-fuzz-19227 new file mode 100644 index 000000000..62828e744 Binary files /dev/null and b/test/fuzz/fuzz-dns-packet/oss-fuzz-19227 differ diff --git a/test/fuzz/fuzz-link-parser/directives.link b/test/fuzz/fuzz-link-parser/directives.link index 7d23a9ecf..112a81930 100644 --- a/test/fuzz/fuzz-link-parser/directives.link +++ b/test/fuzz/fuzz-link-parser/directives.link @@ -20,6 +20,9 @@ Name= AlternativeNamesPolicy= AlternativeName= Alias= +TransmitQueues= +ReceiveQueues= +TransmitQueueLength= MTUBytes= BitsPerSecond= Duplex= @@ -46,3 +49,5 @@ TxBufferSize= RxFlowControl= TxFlowControl= AutoNegotiationFlowControl= +GenericSegmentOffloadMaxBytes= +GenericSegmentOffloadMaxSegments= diff --git a/test/fuzz/fuzz-netdev-parser/28-batadv.netdev b/test/fuzz/fuzz-netdev-parser/28-batadv.netdev new file mode 100644 index 000000000..2a9d92e23 --- /dev/null +++ b/test/fuzz/fuzz-netdev-parser/28-batadv.netdev @@ -0,0 +1,16 @@ +[NetDev] +Name=bat0 +Kind=batadv +Description=Batman test + +[BatmanAdvanced] +GatewayMode=server +Aggregation=1 +BridgeLoopAvoidance=1 +DistributedArpTable=1 +Fragmentation=1 +HopPenalty=10 +OriginatorIntervalSec=1 +GatewayBandwithDown=100K +GatewayBandwithUp=12K +RoutingAlgorithm=batman-v diff --git a/test/fuzz/fuzz-netdev-parser/directives.netdev b/test/fuzz/fuzz-netdev-parser/directives.netdev index a7aa76f49..d4e559840 100644 --- a/test/fuzz/fuzz-netdev-parser/directives.netdev +++ b/test/fuzz/fuzz-netdev-parser/directives.netdev @@ -4,9 +4,13 @@ LooseBinding= ReorderHeader= Id= GVRP= +Protocol= +EgressQOSMaps= +IngressQOSMaps= [MACVLAN] Mode= SourceMACAddress= +BroadcastMulticastQueueLength= [WireGuard] ListenPort= PrivateKey= @@ -219,3 +223,14 @@ InterfaceId= [BareUDP] DestinationPort= EtherType= +[BatmanAdvanced] +GatewayMode= +Aggregation= +BridgeLoopAvoidance= +DistributedArpTable= +Fragmentation= +HopPenalty= +OriginatorIntervalSec= +GatewayBandwithDown= +GatewayBandwithUp= +RoutingAlgorithm= diff --git a/test/fuzz/fuzz-network-parser/directives.network b/test/fuzz/fuzz-network-parser/directives.network index cb0c3205a..8352ecb56 100644 --- a/test/fuzz/fuzz-network-parser/directives.network +++ b/test/fuzz/fuzz-network-parser/directives.network @@ -30,6 +30,7 @@ Host= MACAddress= PermanentMACAddress= [Link] +ActivationPolicy= RequiredForOnline= ARP= AllMulticast= @@ -38,6 +39,7 @@ MTUBytes= Multicast= MACAddress= Group= +Promiscuous= [SR-IOV] VirtualFunction= MACSpoofCheck= @@ -122,8 +124,10 @@ MUDURL= RouteMTUBytes= FallbackLeaseLifetimeSec= [DHCPv6] +UseAddress= UseNTP= UseDNS= +UseHostname= RapidCommit= ForceDHCPv6PDOtherInformation= PrefixDelegationHint= @@ -139,6 +143,7 @@ RouteMetric= SubnetId= Announce= Assign= +ManageTemporaryAddress= Token= [Route] Destination= @@ -160,6 +165,8 @@ Source= Metric= TTLPropagate= MultiPathRoute= +TCPAdvertisedMaximumSegmentSize= +NextHop= [Network] IPv6DuplicateAddressDetection= IPMasquerade= @@ -172,6 +179,7 @@ IPv6ProxyNDPAddress= IPv6AcceptRA= IPv6AcceptRouterAdvertisements= IPv4AcceptLocal= +IPv4RouteLocalnet= DNSSECNegativeTrustAnchors= MACVTAP= IPv6PrivacyExtensions= @@ -218,6 +226,7 @@ VRF= IgnoreCarrierLoss= KeepConfiguration= DHCPv6PrefixDelegation= +BatmanAdvanced= [IPv6Prefix] Prefix= OnLink= @@ -243,6 +252,7 @@ FDMode= FDNonISO= RestartSec= TripleSampling= +BusErrorReporting= Termination= ListenOnly= [Address] @@ -274,6 +284,7 @@ InvertRule= Family= SuppressPrefixLength= User= +Type= [IPv6SendRA] RouterPreference= DNSLifetimeSec= @@ -308,6 +319,12 @@ UseDNS= DHCPv6Client= UseAutonomousPrefix= UseOnLinkPrefix= +RouterAllowList= +RouterDenyList= +PrefixAllowList= +PrefixDenyList= +RouteAllowList= +RouteDenyList= DenyList= BlackList= [DHCPServer] @@ -335,6 +352,9 @@ SendVendorOption= [NextHop] Id= Gateway= +Family= +OnLink= +Blackhole= [QDisc] Parent= Handle= diff --git a/test/fuzz/fuzz-systemctl-parse-argv/help.input b/test/fuzz/fuzz-systemctl-parse-argv/help.input new file mode 100644 index 000000000..faf1a42e1 Binary files /dev/null and b/test/fuzz/fuzz-systemctl-parse-argv/help.input differ diff --git a/test/fuzz/fuzz-systemctl-parse-argv/missing-strv-free.input b/test/fuzz/fuzz-systemctl-parse-argv/missing-strv-free.input new file mode 100644 index 000000000..5600f4fd0 Binary files /dev/null and b/test/fuzz/fuzz-systemctl-parse-argv/missing-strv-free.input differ diff --git a/test/fuzz/fuzz-systemctl-parse-argv/oss-fuzz-31055 b/test/fuzz/fuzz-systemctl-parse-argv/oss-fuzz-31055 new file mode 100644 index 000000000..a8f907110 Binary files /dev/null and b/test/fuzz/fuzz-systemctl-parse-argv/oss-fuzz-31055 differ diff --git a/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules b/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules index 1d8880ef0..d4114bf29 100644 --- a/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules +++ b/test/fuzz/fuzz-udev-rules/60-persistent-storage.rules @@ -86,7 +86,7 @@ KERNEL=="vd*[0-9]", ENV{ID_PATH}=="pci-*", SYMLINK+="disk/by-path/virtio-$env{ID # probe filesystem metadata of optical drives which have a media inserted KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="?*", \ - IMPORT{builtin}="blkid --offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}" + IMPORT{builtin}="blkid --hint=session_offset=$env{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}" # single-session CDs do not have ID_CDROM_MEDIA_SESSION_LAST_OFFSET KERNEL=="sr*", ENV{DISK_EJECT_REQUEST}!="?*", ENV{ID_CDROM_MEDIA_TRACK_COUNT_DATA}=="?*", ENV{ID_CDROM_MEDIA_SESSION_LAST_OFFSET}=="", \ IMPORT{builtin}="blkid --noraid" diff --git a/test/fuzz/fuzz-udev-rules/99-systemd.rules b/test/fuzz/fuzz-udev-rules/99-systemd.rules index b6a5c5ad5..e8a0f5a73 100644 --- a/test/fuzz/fuzz-udev-rules/99-systemd.rules +++ b/test/fuzz/fuzz-udev-rules/99-systemd.rules @@ -42,8 +42,6 @@ SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTE # just an identification string for systemd, so whether the path actually is # accessible or not does not matter as long as it is unique and in the # filesystem namespace. -# -# http://cgit.freedesktop.org/systemd/systemd/tree/src/libudev/libudev-enumerate.c#n955 SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name" SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k" diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service index 30ce98687..55204463c 100644 --- a/test/fuzz/fuzz-unit-file/directives.service +++ b/test/fuzz/fuzz-unit-file/directives.service @@ -85,6 +85,7 @@ DirectoryMode= DirectoryNotEmpty= Documentation= DynamicUser= +ExecPaths= ExecReload= ExecCondition= ExecStart= @@ -110,6 +111,7 @@ IOWriteIOPSMax= IPAccounting= IPAddressAllow= IPAddressDeny= +IPCNamespacePath= IPTOS= IPTTL= IgnoreOnIsolate= @@ -137,6 +139,10 @@ MakeDirectory= Mark= MaxConnections= MaxConnectionsPerSource= +ManagedOOMSwap= +ManagedOOMMemoryPressure= +ManagedOOMMemoryPressureLimitPercent= +ManagedOOMPreference= MemoryAccounting= MemoryHigh= MemoryLimit= @@ -146,7 +152,9 @@ MemorySwapMax= MessageQueueMaxMessages= MessageQueueMessageSize= MountAPIVFS= +NetworkNamespacePath= NoDelay= +NoExecPaths= NoNewPrivileges= NonBlocking= NotifyAccess= @@ -200,6 +208,7 @@ RootImage= RootHash= RootHashSignature= RootVerity= +ExtensionImages= RuntimeMaxSec= SELinuxContextFromNet= SecureBits= @@ -326,6 +335,7 @@ systemd.unit= systemd.verity= systemd.verity_root_data= systemd.verity_root_hash= +systemd.verity_root_options= systemd.volatile= systemd.wants= systemd.watchdog_device= @@ -374,6 +384,7 @@ Bond= Bridge= Broadcast= Cache= +CacheFromLocalhost= ClientIdentifier= ConfigureWithoutCarrier= CopyDSCP= @@ -847,6 +858,7 @@ PivotRoot= Port= PowerKeyIgnoreInhibited= Private= +PrivateIPC= PrivateDevices= PrivateNetwork= PrivateTmp= diff --git a/test/fuzz/meson.build b/test/fuzz/meson.build index 7a83961d1..fc8033dbb 100644 --- a/test/fuzz/meson.build +++ b/test/fuzz/meson.build @@ -23,9 +23,10 @@ sanitizers = [['address,undefined', sanitize_address_undefined]] if git.found() out = run_command( + 'env', '-u', 'GIT_WORK_TREE', git, '--git-dir=@0@/.git'.format(project_source_root), - 'ls-files', ':/test/fuzz/*/*') + 'ls-files', ':/test/fuzz/*/*') else out = run_command( 'sh', '-c', 'ls @0@/test/fuzz/*/*'.format(project_source_root)) diff --git a/test/meson.build b/test/meson.build index cc461febf..4d7b929a8 100644 --- a/test/meson.build +++ b/test/meson.build @@ -11,6 +11,8 @@ if install_tests install_dir : testdata_dir) install_subdir('test-path', install_dir : testdata_dir) + install_subdir('test-path-util', + install_dir : testdata_dir) install_subdir('test-umount', install_dir : testdata_dir) install_subdir('test-network-generator-conversion', @@ -58,7 +60,9 @@ test_network_generator_conversion_sh = find_program('test-network-generator-conv ############################################################ -test_sysusers_dir = join_paths(meson.current_source_dir(), 'test-sysusers') +test_systemd_tmpfiles_py = find_program('test-systemd-tmpfiles.py') + +############################################################ test_sysusers_sh = configure_file( input : 'test-sysusers.sh.in', @@ -122,6 +126,8 @@ else message('Skipping udev-test because perl is not available') endif +############################################################ + if conf.get('ENABLE_HWDB') == 1 hwdb_test_sh = find_program('hwdb-test.sh') if want_tests != 'false' @@ -131,4 +137,30 @@ if conf.get('ENABLE_HWDB') == 1 endif endif +############################################################ + +if want_tests != 'false' and dmi_arches.contains(host_machine.cpu_family()) + udev_dmi_memory_id_test = find_program('udev-dmi-memory-id-test.sh') + + if git.found() + out = run_command( + 'env', '-u', 'GIT_WORK_TREE', + git, + '--git-dir=@0@/.git'.format(project_source_root), + 'ls-files', ':/test/dmidecode-dumps/*.bin') + else + out = run_command( + 'sh', '-c', 'ls @0@/test/dmidecode-dumps/*.bin'.format(project_source_root)) + endif + + foreach p : out.stdout().split() + source = join_paths(project_source_root, p) + name = 'dmidecode_' + p.split('/')[-1].split('.')[0] + + test(name, + udev_dmi_memory_id_test, + args : [dmi_memory_id_path, source, source + '.txt']) + endforeach +endif + subdir('fuzz') diff --git a/test/networkd-test.py b/test/networkd-test.py index 8496ec881..726cc2e0e 100755 --- a/test/networkd-test.py +++ b/test/networkd-test.py @@ -192,33 +192,39 @@ class BridgeTest(NetworkdTestingUtilities, unittest.TestCase): [NetDev] Name=port1 Kind=dummy -MACAddress=12:34:56:78:9a:bc''') +MACAddress=12:34:56:78:9a:bc +''') self.write_network('port2.netdev', '''\ [NetDev] Name=port2 Kind=dummy -MACAddress=12:34:56:78:9a:bd''') +MACAddress=12:34:56:78:9a:bd +''') self.write_network('mybridge.netdev', '''\ [NetDev] Name=mybridge -Kind=bridge''') +Kind=bridge +''') self.write_network('port1.network', '''\ [Match] Name=port1 [Network] -Bridge=mybridge''') +Bridge=mybridge +''') self.write_network('port2.network', '''\ [Match] Name=port2 [Network] -Bridge=mybridge''') +Bridge=mybridge +''') self.write_network('mybridge.network', '''\ [Match] Name=mybridge [Network] DNS=192.168.250.1 Address=192.168.250.33/24 -Gateway=192.168.250.1''') +Gateway=192.168.250.1 +''') subprocess.call(['systemctl', 'reset-failed', 'systemd-networkd', 'systemd-resolved']) subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) @@ -351,10 +357,11 @@ class ClientTestBase(NetworkdTestingUtilities): self.start_unit('systemd-resolved') self.write_network(self.config, '''\ [Match] -Name={} +Name={iface} [Network] -DHCP={} -{}'''.format(self.iface, dhcp_mode, extra_opts)) +DHCP={dhcp_mode} +{extra_opts} +'''.format(iface=self.iface, dhcp_mode=dhcp_mode, extra_opts=extra_opts)) if coldplug: # create interface first, then start networkd @@ -476,14 +483,16 @@ DHCP={} [NetDev] Name=dummy0 Kind=dummy -MACAddress=12:34:56:78:9a:bc''') +MACAddress=12:34:56:78:9a:bc +''') self.write_network('myvpn.network', '''\ [Match] Name=dummy0 [Network] Address=192.168.42.100/24 DNS=192.168.42.1 -Domains= ~company''') +Domains= ~company +''') try: self.do_test(coldplug=True, ipv6=False, @@ -508,13 +517,15 @@ Domains= ~company''') self.write_network('myvpn.netdev', '''[NetDev] Name=dummy0 Kind=dummy -MACAddress=12:34:56:78:9a:bc''') +MACAddress=12:34:56:78:9a:bc +''') self.write_network('myvpn.network', '''[Match] Name=dummy0 [Network] Address=192.168.42.100/24 DNS=192.168.42.1 -Domains= ~company ~.''') +Domains= ~company ~. +''') try: self.do_test(coldplug=True, ipv6=False, @@ -598,11 +609,11 @@ class DnsmasqClientTest(ClientTestBase, unittest.TestCase): def test_resolved_domain_restricted_dns(self): '''resolved: domain-restricted DNS servers''' - # FIXME: resolvectl query fails with enabled DNSSEC against our dnsmasq - conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf' + # enable DNSSEC in allow downgrade mode, and turn off stuff we don't want to test to make looking at logs easier + conf = '/run/systemd/resolved.conf.d/test-enable-dnssec.conf' os.makedirs(os.path.dirname(conf), exist_ok=True) with open(conf, 'w') as f: - f.write('[Resolve]\nDNSSEC=no\n') + f.write('[Resolve]\nDNSSEC=allow-downgrade\nLLMNR=no\nMulticastDNS=no\nDNSOverTLS=no\n') self.addCleanup(os.remove, conf) # create interface for generic connections; this will map all DNS names @@ -613,7 +624,9 @@ class DnsmasqClientTest(ClientTestBase, unittest.TestCase): Name={} [Network] DHCP=ipv4 -IPv6AcceptRA=False'''.format(self.iface)) +IPv6AcceptRA=False +DNSSECNegativeTrustAnchors=megasearch.net +'''.format(self.iface)) # create second device/dnsmasq for a .company/.lab VPN interface # static IPs for simplicity @@ -639,7 +652,9 @@ Name=testvpnclient IPv6AcceptRA=False Address=10.241.3.2/24 DNS=10.241.3.1 -Domains= ~company ~lab''') +Domains=~company ~lab +DNSSECNegativeTrustAnchors=company lab +''') self.start_unit('systemd-networkd') subprocess.check_call([NETWORKD_WAIT_ONLINE, '--interface', self.iface, @@ -677,21 +692,27 @@ Domains= ~company ~lab''') def test_resolved_etc_hosts(self): '''resolved queries to /etc/hosts''' - # FIXME: -t MX query fails with enabled DNSSEC (even when using - # the known negative trust anchor .internal instead of .example.com) - conf = '/run/systemd/resolved.conf.d/test-disable-dnssec.conf' + # enabled DNSSEC in allow-downgrade mode + conf = '/run/systemd/resolved.conf.d/test-enable-dnssec.conf' os.makedirs(os.path.dirname(conf), exist_ok=True) with open(conf, 'w') as f: - f.write('[Resolve]\nDNSSEC=no\nLLMNR=no\nMulticastDNS=no\n') + f.write('[Resolve]\nDNSSEC=allow-downgrade\nLLMNR=no\nMulticastDNS=no\nDNSOverTLS=no\n') self.addCleanup(os.remove, conf) + # Add example.com to NTA list for this test + negative = '/run/dnssec-trust-anchors.d/example.com.negative' + os.makedirs(os.path.dirname(negative), exist_ok=True) + with open(negative, 'w') as f: + f.write('example.com\n16.172.in-addr.arpa\n') + self.addCleanup(os.remove, negative) + # create /etc/hosts bind mount which resolves my.example.com for IPv4 hosts = os.path.join(self.workdir, 'hosts') with open(hosts, 'w') as f: f.write('172.16.99.99 my.example.com\n') subprocess.check_call(['mount', '--bind', hosts, '/etc/hosts']) self.addCleanup(subprocess.call, ['umount', '/etc/hosts']) - subprocess.check_call(['systemctl', 'stop', 'systemd-resolved.service']) + subprocess.check_call(['systemctl', 'restart', 'systemd-resolved.service']) # note: different IPv4 address here, so that it's easy to tell apart # what resolved the query @@ -825,35 +846,37 @@ mount -t tmpfs none /run/systemd/network mount -t tmpfs none /run/systemd/netif [ ! -e /run/dbus ] || mount -t tmpfs none /run/dbus # create router/client veth pair -cat << EOF > /run/systemd/network/test.netdev +cat </run/systemd/network/test.netdev [NetDev] -Name=%(ifr)s +Name={ifr} Kind=veth [Peer] -Name=%(ifc)s +Name={ifc} EOF -cat << EOF > /run/systemd/network/test.network +cat </run/systemd/network/test.network [Match] -Name=%(ifr)s +Name={ifr} [Network] Address=192.168.5.1/24 -%(addr6)s +{addr6} DHCPServer=yes [DHCPServer] PoolOffset=10 PoolSize=50 DNS=192.168.5.1 -%(dhopts)s +{dhopts} EOF # run networkd as in systemd-networkd.service -exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//; s/^[@+-]//; s/^!*//; p}') -''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or '', - 'dhopts': dhcpserver_opts or ''}) +exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ {{ s/^.*=//; s/^[@+-]//; s/^!*//; p}}') +'''.format(ifr=self.if_router, + ifc=self.iface, + addr6=('Address=2600::1/64' if ipv6 else ''), + dhopts=(dhcpserver_opts or ''))) os.fchmod(fd, 0o755) @@ -902,14 +925,16 @@ exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=// [NetDev] Name=dummy0 Kind=dummy -MACAddress=12:34:56:78:9a:bc''') +MACAddress=12:34:56:78:9a:bc +''') self.write_network('test.network', '''\ [Match] Name=dummy0 [Network] Address=192.168.42.100/24 DNS=192.168.42.1 -Domains= one two three four five six seven eight nine ten''') +Domains= one two three four five six seven eight nine ten +''') self.start_unit('systemd-networkd') @@ -929,16 +954,19 @@ Domains= one two three four five six seven eight nine ten''') [NetDev] Name=dummy0 Kind=dummy -MACAddress=12:34:56:78:9a:bc''') +MACAddress=12:34:56:78:9a:bc +''') self.write_network('test.network', '''\ [Match] Name=dummy0 [Network] Address=192.168.42.100/24 -DNS=192.168.42.1''') +DNS=192.168.42.1 +''') self.write_network_dropin('test.network', 'dns', '''\ [Network] -DNS=127.0.0.1''') +DNS=127.0.0.1 +''') self.start_unit('systemd-resolved') self.start_unit('systemd-networkd') diff --git a/test/run-integration-tests.sh b/test/run-integration-tests.sh index 04b8385be..036c075ee 100755 --- a/test/run-integration-tests.sh +++ b/test/run-integration-tests.sh @@ -1,16 +1,46 @@ #!/usr/bin/env bash set -e -BUILD_DIR="$($(dirname "$0")/../tools/find-build-dir.sh)" +if [ "$NO_BUILD" ]; then + BUILD_DIR="" +elif BUILD_DIR="$($(dirname "$0")/../tools/find-build-dir.sh)"; then + ninja -C "$BUILD_DIR" +else + echo "No build found, please set BUILD_DIR or NO_BUILD" >&2 + exit 1 +fi + if [ $# -gt 0 ]; then - args="$@" + args="$*" else args="setup run clean-again" fi -args_no_clean=$(sed -r 's/\bclean\b//g' <<<$args) -do_clean=$( [ "$args" = "$args_no_clean" ]; echo $? ) -ninja -C "$BUILD_DIR" +VALID_TARGETS="all setup run clean clean-again" + +is_valid_target() { + for target in $VALID_TARGETS; do + [ "$1" = "$target" ] && return 0 + done + return 1 +} + +# reject invalid make targets in $args +for arg in $args; do + if ! is_valid_target "$arg"; then + echo "Invalid target: $arg" >&2 + exit 1 + fi +done + +CLEAN=0 +CLEANAGAIN=0 + +# separate 'clean' and 'clean-again' operations +[[ "$args" =~ "clean-again" ]] && CLEANAGAIN=1 +args=${args/clean-again} +[[ "$args" =~ "clean" ]] && CLEAN=1 +args=${args/clean} declare -A results declare -A times @@ -20,48 +50,50 @@ FAILURES=0 cd "$(dirname "$0")" -# Let's always do the cleaning operation first, because it destroys the image -# cache. -if [ $do_clean = 1 ]; then - for TEST in TEST-??-* ; do - ( set -x ; make -C "$TEST" "BUILD_DIR=$BUILD_DIR" clean ) - done - - [ -n "$args_no_clean" ] || exit 0 -fi - -pass_blacklist() { - for marker in $BLACKLIST_MARKERS; do +pass_deny_list() { + for marker in $DENY_LIST_MARKERS $BLACKLIST_MARKERS; do if [ -f "$1/$marker" ]; then - echo "========== BLACKLISTED: $1 ($marker) ==========" + echo "========== DENY-LISTED: $1 ($marker) ==========" return 1 fi done return 0 } -for TEST in TEST-??-* ; do - COUNT=$(($COUNT+1)) +# Let's always do the cleaning operation first, because it destroys the image +# cache. +if [ $CLEAN = 1 ]; then + for TEST in TEST-??-* ; do + ( set -x ; make -C "$TEST" clean ) + done +fi - pass_blacklist $TEST || continue - start=$(date +%s) +# Run actual tests (if requested) +if [[ $args =~ [a-z] ]]; then + for TEST in TEST-??-* ; do + COUNT=$(($COUNT+1)) - echo -e "\n--x-- Running $TEST --x--" - set +e - ( set -x ; make -C "$TEST" "BUILD_DIR=$BUILD_DIR" $args_no_clean ) - RESULT=$? - set -e - echo "--x-- Result of $TEST: $RESULT --x--" + pass_deny_list $TEST || continue + start=$(date +%s) - results["$TEST"]="$RESULT" - times["$TEST"]=$(( $(date +%s) - $start )) + echo -e "\n--x-- Running $TEST --x--" + set +e + ( set -x ; make -C "$TEST" $args ) + RESULT=$? + set -e + echo "--x-- Result of $TEST: $RESULT --x--" - [ "$RESULT" -ne "0" ] && FAILURES=$(($FAILURES+1)) -done + results["$TEST"]="$RESULT" + times["$TEST"]=$(( $(date +%s) - $start )) -if [ $FAILURES -eq 0 -a $do_clean = 1 ]; then + [ "$RESULT" -ne "0" ] && FAILURES=$(($FAILURES+1)) + done +fi + +# Run clean-again, if requested, and if no tests failed +if [ $FAILURES -eq 0 -a $CLEANAGAIN = 1 ]; then for TEST in ${!results[@]}; do - ( set -x ; make -C "$TEST" "BUILD_DIR=$BUILD_DIR" clean-again ) + ( set -x ; make -C "$TEST" clean-again ) done fi diff --git a/test/sd-script.py b/test/sd-script.py index c695c2e2c..7662b12ab 100644 --- a/test/sd-script.py +++ b/test/sd-script.py @@ -7,7 +7,7 @@ # # Run after sys-script.py # Usage: sd-script.py -# is the number of device nodes (disks + partititions) +# is the number of device nodes (disks + partitions) # to create in addition to what sys-script.py already did. # The script can be run several times in a row if is increased, # adding yet more device entries. diff --git a/test/test-execute/exec-noexecpaths-simple.service b/test/test-execute/exec-noexecpaths-simple.service new file mode 100644 index 000000000..45152a26f --- /dev/null +++ b/test/test-execute/exec-noexecpaths-simple.service @@ -0,0 +1,10 @@ +[Unit] +Description=Test for NoExecPaths= + +[Service] +Type=oneshot +# This should work, as we explicitly disable the effect of NoExecPaths= +ExecStart=+/bin/sh -c '/bin/cat /dev/null' +# This should also work, as we do not disable the effect of NoExecPaths= but invert the exit code +ExecStart=/bin/sh -x -c '! /bin/cat /dev/null' +NoExecPaths=/bin/cat diff --git a/test/test-execute/exec-standardoutput-truncate.service b/test/test-execute/exec-standardoutput-truncate.service new file mode 100644 index 000000000..4b4bb87b7 --- /dev/null +++ b/test/test-execute/exec-standardoutput-truncate.service @@ -0,0 +1,12 @@ +[Unit] +Description=Test for StandardOutput=truncate: + +[Service] +ExecStartPre=sh -c 'printf "hello\n" > /tmp/test-exec-standardoutput-output' +ExecStartPre=sh -c 'printf "hi\n" > /tmp/test-exec-standardoutput-expected' +StandardInput=data +StandardInputText=hi +StandardOutput=truncate:/tmp/test-exec-standardoutput-output +StandardError=null +ExecStart=sh -c 'cat && cmp /tmp/test-exec-standardoutput-output /tmp/test-exec-standardoutput-expected' +Type=oneshot diff --git a/test/test-execute/exec-systemcallfilter-failing.service b/test/test-execute/exec-systemcallfilter-failing.service index 996f85921..c4b079903 100644 --- a/test/test-execute/exec-systemcallfilter-failing.service +++ b/test/test-execute/exec-systemcallfilter-failing.service @@ -2,7 +2,7 @@ Description=Test for SystemCallFilter [Service] -ExecStart=/bin/sh -c 'echo "This should not be seen"' +ExecStart=/bin/sh -c '/bin/echo "This should not be seen"' Type=oneshot LimitCORE=0 SystemCallFilter=ioperm diff --git a/test/test-execute/exec-systemcallfilter-failing2.service b/test/test-execute/exec-systemcallfilter-failing2.service index c74f42248..452aaf827 100644 --- a/test/test-execute/exec-systemcallfilter-failing2.service +++ b/test/test-execute/exec-systemcallfilter-failing2.service @@ -2,7 +2,7 @@ Description=Test for SystemCallFilter [Service] -ExecStart=/bin/sh -c 'echo "This should not be seen"' +ExecStart=/bin/sh -c '/bin/echo "This should not be seen"' Type=oneshot LimitCORE=0 -SystemCallFilter=~write open execve exit_group close mmap munmap fstat DONOTEXIST +SystemCallFilter=~write open execve fexecve execveat exit_group close mmap munmap fstat DONOTEXIST diff --git a/test/test-execute/exec-systemcallfilter-with-errno-in-allow-list.service b/test/test-execute/exec-systemcallfilter-with-errno-in-allow-list.service new file mode 100644 index 000000000..4b2636eb4 --- /dev/null +++ b/test/test-execute/exec-systemcallfilter-with-errno-in-allow-list.service @@ -0,0 +1,9 @@ +[Unit] +Description=Test for SystemCallFilter with errno name (for issue #18916) + +[Service] +ExecStart=/usr/bin/python3 -c 'import os\ntry: os.uname()\nexcept Exception as e: exit(e.errno)' +Type=oneshot +SystemCallFilter=@system-service +SystemCallFilter=~uname:EILSEQ +SystemCallErrorNumber=EACCES diff --git a/test/test-functions b/test/test-functions index 52b52bf29..6b94058fd 100644 --- a/test/test-functions +++ b/test/test-functions @@ -17,6 +17,11 @@ TIMED_OUT= # will be 1 after run_* if *_TIMEOUT is set and test timed out UNIFIED_CGROUP_HIERARCHY="${UNIFIED_CGROUP_HIERARCHY:-default}" EFI_MOUNT="${EFI_MOUNT:-$(bootctl -x 2>/dev/null || echo /boot)}" QEMU_MEM="${QEMU_MEM:-512M}" +# Note that defining a different IMAGE_NAME in a test setup script will only result +# in default.img being copied and renamed. It can then be extended by defining +# a test_append_files() function. The $1 parameter will be the root directory. +# To force creating a new image from scratch (eg: to encrypt it), also define +# TEST_FORCE_NEWIMAGE=1 in the test setup script. IMAGE_NAME=${IMAGE_NAME:-default} TEST_REQUIRE_INSTALL_TESTS="${TEST_REQUIRE_INSTALL_TESTS:-1}" TEST_PARALLELIZE="${TEST_PARALLELIZE:-0}" @@ -38,6 +43,22 @@ if ! ROOTLIBDIR=$(pkg-config --variable=systemdutildir systemd); then ROOTLIBDIR=/usr/lib/systemd fi +# The calling test.sh scripts have TEST_BASE_DIR set via their Makefile, but we don't need them to provide it +TEST_BASE_DIR=${TEST_BASE_DIR:-$(realpath $(dirname "$BASH_SOURCE"))} +TEST_UNITS_DIR="$TEST_BASE_DIR/units" +SOURCE_DIR=$(realpath "$TEST_BASE_DIR/..") +TOOLS_DIR="$SOURCE_DIR/tools" + +# note that find-build-dir.sh will return $BUILD_DIR if provided, else it will try to find it +if ! BUILD_DIR=$($TOOLS_DIR/find-build-dir.sh); then + if [ "$NO_BUILD" ]; then + BUILD_DIR=$SOURCE_DIR + else + echo "ERROR: no build found, please set BUILD_DIR or use NO_BUILD" >&2 + exit 1 + fi +fi + PATH_TO_INIT=$ROOTLIBDIR/systemd [ "$SYSTEMD_JOURNALD" ] || SYSTEMD_JOURNALD=$(which -a $BUILD_DIR/systemd-journald $ROOTLIBDIR/systemd-journald 2>/dev/null | grep '^/' -m1) [ "$SYSTEMD_JOURNAL_REMOTE" ] || SYSTEMD_JOURNAL_REMOTE=$(which -a $BUILD_DIR/systemd-journal-remote $ROOTLIBDIR/systemd-journal-remote 2>/dev/null | grep '^/' -m1) @@ -45,6 +66,17 @@ PATH_TO_INIT=$ROOTLIBDIR/systemd [ "$SYSTEMD_NSPAWN" ] || SYSTEMD_NSPAWN=$(which -a $BUILD_DIR/systemd-nspawn systemd-nspawn 2>/dev/null | grep '^/' -m1) [ "$JOURNALCTL" ] || JOURNALCTL=$(which -a $BUILD_DIR/journalctl journalctl 2>/dev/null | grep '^/' -m1) +TESTFILE=${BASH_SOURCE[1]} +if [ -z "$TESTFILE" ]; then + echo "ERROR: test-functions must be sourced from one of the TEST-*/test.sh scripts" >&2 + exit 1 +fi +TESTNAME=$(basename $(dirname $(realpath $TESTFILE))) +STATEDIR="$BUILD_DIR/test/$TESTNAME" +STATEFILE="$STATEDIR/.testdir" +IMAGESTATEDIR="$STATEDIR/.." +TESTLOG="$STATEDIR/test.log" + BASICTOOLS=( awk basename @@ -92,6 +124,7 @@ BASICTOOLS=( rmdir sed seq + setfattr setfont setsid sfdisk @@ -143,11 +176,6 @@ DEBUGTOOLS=( vi ) -STATEDIR="${BUILD_DIR:-.}/test/$(basename $(dirname $(realpath $0)))" -STATEFILE="$STATEDIR/.testdir" -IMAGESTATEDIR="$STATEDIR/.." -TESTLOG="$STATEDIR/test.log" - is_built_with_asan() { if ! type -P objdump >/dev/null; then ddebug "Failed to find objdump. Assuming systemd hasn't been built with ASAN." @@ -155,7 +183,7 @@ is_built_with_asan() { fi # Borrowed from https://github.com/google/oss-fuzz/blob/cd9acd02f9d3f6e80011cc1e9549be526ce5f270/infra/base-images/base-runner/bad_build_check#L182 - local _asan_calls=$(objdump -dC $SYSTEMD_JOURNALD | egrep "callq\s+[0-9a-f]+\s+<__asan" -c) + local _asan_calls=$(objdump -dC $SYSTEMD_JOURNALD | egrep "callq?\s+[0-9a-f]+\s+<__asan" -c) if (( $_asan_calls < 1000 )); then return 1 else @@ -170,13 +198,15 @@ if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then SKIP_INITRD="${SKIP_INITRD:-yes}" PATH_TO_INIT=$ROOTLIBDIR/systemd-under-asan QEMU_MEM="2048M" - QEMU_SMP=4 + QEMU_SMP="${QEMU_SMP:-4}" # We need to correctly distinguish between gcc's and clang's ASan DSOs. - if ldd $SYSTEMD | grep -q libasan.so; then + if ASAN_RT_NAME="$(ldd "$SYSTEMD" | awk '/libasan.so/ {x=$1; exit} END {print x; exit x==""}')"; then ASAN_COMPILER=gcc - elif ldd $SYSTEMD | grep -q libclang_rt.asan; then + ASAN_RT_PATH="$(readlink -f "$(${CC:-gcc} --print-file-name "$ASAN_RT_NAME")")" + elif ASAN_RT_NAME="$(ldd "$SYSTEMD" | awk '/libclang_rt.asan/ {x=$1; exit} END {print x; exit x==""}')"; then ASAN_COMPILER=clang + ASAN_RT_PATH="$(readlink -f "$(${CC:-clang} --print-file-name "$ASAN_RT_NAME")")" # As clang's ASan DSO is usually in a non-standard path, let's check if # the environment is set accordingly. If not, warn the user and exit. @@ -184,10 +214,8 @@ if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then # user should encounter (and fix) the same issue when running the unit # tests (meson test) if ldd "$SYSTEMD" | grep -q "libclang_rt.asan.*not found"; then - _asan_rt_name="$(ldd $SYSTEMD | awk '/libclang_rt.asan/ {print $1; exit}')" - _asan_rt_path="$(find /usr/lib* /usr/local/lib* -type f -name "$_asan_rt_name" 2>/dev/null | sed 1q)" - echo >&2 "clang's ASan DSO ($_asan_rt_name) is not present in the runtime library path" - echo >&2 "Consider setting LD_LIBRARY_PATH=${_asan_rt_path%/*}" + echo >&2 "clang's ASan DSO ($ASAN_RT_NAME) is not present in the runtime library path" + echo >&2 "Consider setting LD_LIBRARY_PATH=${ASAN_RT_PATH%/*}" exit 1 fi else @@ -195,6 +223,8 @@ if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then echo >&2 "gcc does this by default, for clang compile with -shared-libasan" exit 1 fi + + echo "Detected ASan RT '$ASAN_RT_NAME' located at '$ASAN_RT_PATH'" fi function find_qemu_bin() { @@ -235,7 +265,7 @@ function qemu_min_version() { find_qemu_bin || return 2 # get version from binary - qemu_ver=$($QEMU_BIN --version | awk '/^QEMU emulator version ([0-9]*\.[0-9]*\.[0-9]*) / {print $4}') + qemu_ver=$($QEMU_BIN --version | awk '/^QEMU emulator version ([0-9]*\.[0-9]*\.[0-9]*)/ {print $4}') # Check version string format echo "$qemu_ver" | grep -q '^[0-9]*\.[0-9]*\.[0-9]*$' || return 2 @@ -435,6 +465,108 @@ run_nspawn() { return 0 } +# Build two very minimal root images, with two units, one is the same and one is different across them +install_verity_minimal() { + if [ -e $initdir/usr/share/minimal.raw ]; then + return + fi + if ! command -v mksquashfs >/dev/null 2>&1; then + dfatal "mksquashfs not found" + exit 1 + fi + if ! command -v veritysetup >/dev/null 2>&1; then + dfatal "veritysetup not found" + exit 1 + fi + ( + BASICTOOLS=( + bash + cat + grep + mount + sleep + ) + oldinitdir=$initdir + rm -rfv $TESTDIR/minimal + export initdir=$TESTDIR/minimal + mkdir -p $initdir/usr/lib/systemd/system $initdir/usr/lib/extension-release.d $initdir/etc $initdir/var/tmp $initdir/opt + setup_basic_dirs + install_basic_tools + if [[ -v ASAN_RT_PATH ]]; then + # If we're compiled with ASan, install the ASan RT (and its dependencies) + # into the verity images to get rid of the annoying errors about + # missing $LD_PRELOAD libraries. + inst_libs "$ASAN_RT_PATH" + inst_library "$ASAN_RT_PATH" + fi + cp $os_release $initdir/usr/lib/os-release + ln -s ../usr/lib/os-release $initdir/etc/os-release + touch $initdir/etc/machine-id $initdir/etc/resolv.conf + touch $initdir/opt/some_file + echo MARKER=1 >> $initdir/usr/lib/os-release + echo -e "[Service]\nExecStartPre=cat /usr/lib/os-release\nExecStart=sleep 120" > $initdir/usr/lib/systemd/system/app0.service + cp $initdir/usr/lib/systemd/system/app0.service $initdir/usr/lib/systemd/system/app0-foo.service + + mksquashfs $initdir $oldinitdir/usr/share/minimal_0.raw + veritysetup format $oldinitdir/usr/share/minimal_0.raw $oldinitdir/usr/share/minimal_0.verity | \ + grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal_0.roothash + + sed -i "s/MARKER=1/MARKER=2/g" $initdir/usr/lib/os-release + rm $initdir/usr/lib/systemd/system/app0-foo.service + cp $initdir/usr/lib/systemd/system/app0.service $initdir/usr/lib/systemd/system/app0-bar.service + + mksquashfs $initdir $oldinitdir/usr/share/minimal_1.raw + veritysetup format $oldinitdir/usr/share/minimal_1.raw $oldinitdir/usr/share/minimal_1.verity | \ + grep '^Root hash:' | cut -f2 | tr -d '\n' > $oldinitdir/usr/share/minimal_1.roothash + + # Rolling distros like Arch do not set VERSION_ID + local version_id="" + if grep -q "^VERSION_ID=" $os_release; then + version_id="$(grep "^VERSION_ID=" $os_release)" + fi + + export initdir=$TESTDIR/app0 + mkdir -p $initdir/usr/lib/extension-release.d $initdir/usr/lib/systemd/system $initdir/opt + grep "^ID=" $os_release > $initdir/usr/lib/extension-release.d/extension-release.app0 + echo "${version_id}" >> $initdir/usr/lib/extension-release.d/extension-release.app0 + cat < $initdir/usr/lib/systemd/system/app0.service +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/opt/script0.sh +EOF + cat < $initdir/opt/script0.sh +#!/bin/bash +set -e +test -e /usr/lib/os-release +cat /usr/lib/extension-release.d/extension-release.app0 +EOF + chmod +x $initdir/opt/script0.sh + echo MARKER=1 > $initdir/usr/lib/systemd/system/some_file + mksquashfs $initdir $oldinitdir/usr/share/app0.raw + + export initdir=$TESTDIR/app1 + mkdir -p $initdir/usr/lib/extension-release.d $initdir/usr/lib/systemd/system $initdir/opt + grep "^ID=" $os_release > $initdir/usr/lib/extension-release.d/extension-release.app1 + echo "${version_id}" >> $initdir/usr/lib/extension-release.d/extension-release.app1 + cat < $initdir/usr/lib/systemd/system/app1.service +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/opt/script1.sh +EOF + cat < $initdir/opt/script1.sh +#!/bin/bash +set -e +test -e /usr/lib/os-release +cat /usr/lib/extension-release.d/extension-release.app1 +EOF + chmod +x $initdir/opt/script1.sh + echo MARKER=1 > $initdir/usr/lib/systemd/system/other_file + mksquashfs $initdir $oldinitdir/usr/share/app1.raw + ) +} + setup_basic_environment() { # create the basic filesystem layout setup_basic_dirs @@ -465,6 +597,9 @@ setup_basic_environment() { if [[ "$IS_BUILT_WITH_ASAN" = "yes" ]]; then create_asan_wrapper fi + if [ -n "$TEST_INSTALL_VERITY_MINIMAL" ]; then + install_verity_minimal + fi } setup_selinux() { @@ -528,26 +663,23 @@ create_asan_wrapper() { local _asan_rt_pattern ddebug "Create $_asan_wrapper" - case "$ASAN_COMPILER" in - gcc) - _asan_rt_pattern="*libasan*" - ;; - clang) - _asan_rt_pattern="libclang_rt.asan-*" - # Install llvm-symbolizer to generate useful reports - # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports - dracut_install "llvm-symbolizer" - ;; - *) - dfail "Unsupported compiler: $ASAN_COMPILER" - exit 1 - esac + [[ -z "$ASAN_RT_PATH" ]] && dfatal "ASAN_RT_PATH is empty, but it shouldn't be" + + # clang: install llvm-symbolizer to generate useful reports + # See: https://clang.llvm.org/docs/AddressSanitizer.html#symbolizing-the-reports + [[ "$ASAN_COMPILER" == "clang" ]] && dracut_install "llvm-symbolizer" cat >$_asan_wrapper <&2 "Couldn't find ASan RT at '$ASAN_RT_PATH', can't continue" + exit 1 +fi + DEFAULT_ASAN_OPTIONS=${ASAN_OPTIONS:-strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1} DEFAULT_UBSAN_OPTIONS=${UBSAN_OPTIONS:-print_stacktrace=1:print_summary=1:halt_on_error=1} DEFAULT_ENVIRONMENT="ASAN_OPTIONS=\$DEFAULT_ASAN_OPTIONS UBSAN_OPTIONS=\$DEFAULT_UBSAN_OPTIONS" @@ -560,15 +692,15 @@ mount -t proc proc /proc mount -t sysfs sysfs /sys mount -o remount,rw / -PATH_TO_ASAN=\$(find / -name '$_asan_rt_pattern' | sed 1q) -if [[ "\$PATH_TO_ASAN" ]]; then - # A lot of services (most notably dbus) won't start without preloading libasan - # See https://github.com/systemd/systemd/issues/5004 - DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=\$PATH_TO_ASAN" +# A lot of services (most notably dbus) won't start without preloading libasan +# See https://github.com/systemd/systemd/issues/5004 +DEFAULT_ENVIRONMENT="\$DEFAULT_ENVIRONMENT LD_PRELOAD=$ASAN_RT_PATH" + +if [[ "$ASAN_COMPILER" == "clang" ]]; then # Let's add the ASan DSO's path to the dynamic linker's cache. This is pretty # unnecessary for gcc & libasan, however, for clang this is crucial, as its # runtime ASan DSO is in a non-standard (library) path. - echo \${PATH_TO_ASAN%/*} > /etc/ld.so.conf.d/asan-path-override.conf + echo "${ASAN_RT_PATH%/*}" > /etc/ld.so.conf.d/asan-path-override.conf ldconfig fi echo DefaultEnvironment=\$DEFAULT_ENVIRONMENT >>/etc/systemd/system.conf @@ -599,6 +731,21 @@ printf "[Unit]\nConditionVirtualization=container\n\n[Service]\nTimeoutSec=240s\ mkdir -p /etc/systemd/system/systemd-journal-flush.service.d printf "[Service]\nTimeoutSec=180s\n" >/etc/systemd/system/systemd-journal-flush.service.d/timeout.conf +# D-Bus has troubles during system shutdown causing it to fail. Although it's +# harmless, it causes unnecessary noise in the logs, so let's disable LSan's +# at_exit check just for the dbus.service +mkdir -p /etc/systemd/system/dbus.service.d +printf "[Service]\nEnvironment=ASAN_OPTIONS=leak_check_at_exit=false\n" >/etc/systemd/system/dbus.service.d/disable-lsan.conf + +# Some utilities run via IMPORT/RUN/PROGRAM udev directives fail because +# they're uninstrumented (like dmsetup). Let's add a simple rule which sets +# LD_PRELOAD to the ASan RT library to fix this. +mkdir -p /etc/udev/rules.d +cat > /etc/udev/rules.d/00-set-LD_PRELOAD.rules << INNER_EOF +SUBSYSTEM=="block", ENV{LD_PRELOAD}="$ASAN_RT_PATH" +INNER_EOF +chmod 0644 /etc/udev/rules.d/00-set-LD_PRELOAD.rules + # The 'mount' utility doesn't behave well under libasan, causing unexpected # fails during boot and subsequent test results check: # bash-5.0# mount -o remount,rw -v / @@ -629,7 +776,7 @@ create_strace_wrapper() { cat >$_strace_wrapper </dev/null) || continue + ddebug "Install debian files from package $deb" + for file in $_files; do + [ -e "$file" ] || continue + [ -d "$file" ] && continue + inst $file + done + done +} + +install_distro_systemd() { + ddebug "Install distro systemd" + + if [ "$LOOKS_LIKE_DEBIAN" ]; then + install_debian_systemd + else + dfatal "NO_BUILD not supported for this distro" + exit 1 + fi +} + +install_systemd() { + if [ "$NO_BUILD" ]; then + install_distro_systemd + else + install_compiled_systemd + fi + # remove unneeded documentation rm -fr $initdir/usr/share/{man,doc} @@ -692,7 +875,31 @@ get_ldpath() { install_missing_libraries() { # install possible missing libraries for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/{,tests/{,manual/,unsafe/}}*; do - LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i):$(get_ldpath $i)/src/udev" inst_libs $i + LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i)" inst_libs $i + done + + # A number of dependencies is now optional via dlopen, so the install + # script will not pick them up, since it looks at linkage. + for lib in libcryptsetup libidn libidn2 pwquality libqrencode tss2-esys tss2-rc tss2-mu libfido2; do + ddebug "Searching for $lib via pkg-config" + if pkg-config --exists ${lib}; then + path=$(pkg-config --variable=libdir ${lib}) + if [ -z "${path}" ]; then + ddebug "$lib.pc does not contain a libdir variable, skipping" + continue + fi + + if ! [[ ${lib} =~ ^lib ]]; then + lib="lib${lib}" + fi + # Some pkg-config files are broken and give out the wrong paths + # (eg: libcryptsetup), so just ignore them + inst_libs "${path}/${lib}.so" || true + inst_library "${path}/${lib}.so" || true + else + ddebug "$lib.pc not found, skipping" + continue + fi done } @@ -851,6 +1058,9 @@ check_result_nspawn() { test -s $TESTDIR/failed && ret=$(($ret+1)) [ -n "$TIMED_OUT" ] && ret=$(($ret+1)) check_asan_reports "$1" || ret=$(($ret+1)) + if [ -d "${ARTIFACT_DIRECTORY}" ] && [ -f $1/strace.out ]; then + cp $1/strace.out "${ARTIFACT_DIRECTORY}/" + fi _umount_dir $initdir return $ret } @@ -863,6 +1073,9 @@ check_result_qemu() { [[ -f $initdir/failed ]] && cp -a $initdir/failed $TESTDIR save_journal $initdir/var/log/journal check_asan_reports "$initdir" || ret=$(($ret+1)) + if [ -d "${ARTIFACT_DIRECTORY}" ] && [ -f $initdir/strace.out ]; then + cp $initdir/strace.out "${ARTIFACT_DIRECTORY}/" + fi _umount_dir $initdir [[ -f $TESTDIR/failed ]] && cat $TESTDIR/failed echo $JOURNAL_LIST @@ -903,7 +1116,7 @@ install_execs() { # some {rc,halt}.local scripts and programs are okay to not exist, the rest should # also, plymouth is pulled in by rescue.service, but even there the exit code # is ignored; as it's not present on some distros, don't fail if it doesn't exist - dinfo "Attempting to install $i" + dinfo "Attempting to install $i (based on unit file reference)" inst $i || [ "${i%.local}" != "$i" ] || [ "${i%systemd-update-done}" != "$i" ] || [ "${i##*/}" == "plymouth" ] done ) @@ -963,6 +1176,7 @@ install_config_files() { # we want an empty environment > $initdir/etc/environment > $initdir/etc/machine-id + > $initdir/etc/resolv.conf # set the hostname echo systemd-testsuite > $initdir/etc/hostname @@ -1045,8 +1259,14 @@ EOF } install_user_dbus() { - inst $ROOTLIBDIR/user/dbus.socket - inst_symlink /usr/lib/systemd/user/sockets.target.wants/dbus.socket || inst_symlink /etc/systemd/user/sockets.target.wants/dbus.socket + local userunitdir + if ! userunitdir=$(pkg-config --variable=systemduserunitdir systemd); then + echo "WARNING! Cannot determine userunitdir from pkg-config, assuming /usr/lib/systemd/user" >&2 + local userunitdir=/usr/lib/systemd/user + fi + + inst $userunitdir/dbus.socket + inst_symlink $userunitdir/sockets.target.wants/dbus.socket || inst_symlink /etc/systemd/user/sockets.target.wants/dbus.socket # Append the After= dependency on dbus in case it isn't already set up mkdir -p "$initdir/etc/systemd/system/user@.service.d/" @@ -1056,16 +1276,16 @@ After=dbus.service EOF # Newer Fedora versions use dbus-broker by default. Let's install it if it's available. - if [ -f $ROOTLIBDIR/user/dbus-broker.service ]; then - inst $ROOTLIBDIR/user/dbus-broker.service + if [ -f $userunitdir/dbus-broker.service ]; then + inst $userunitdir/dbus-broker.service inst_symlink /etc/systemd/user/dbus.service elif [ -f $ROOTLIBDIR/system/dbus-daemon.service ]; then # Fedora rawhide replaced dbus.service with dbus-daemon.service - inst $ROOTLIBDIR/user/dbus-daemon.service + inst $userunitdir/dbus-daemon.service # Alias symlink inst_symlink /etc/systemd/user/dbus.service else - inst $ROOTLIBDIR/user/dbus.service + inst $userunitdir/dbus.service fi } @@ -1120,6 +1340,7 @@ install_zoneinfo() { inst_any /usr/share/zoneinfo/Asia/Vladivostok inst_any /usr/share/zoneinfo/Australia/Sydney inst_any /usr/share/zoneinfo/Europe/Berlin + inst_any /usr/share/zoneinfo/Europe/Dublin inst_any /usr/share/zoneinfo/Europe/Kiev inst_any /usr/share/zoneinfo/Pacific/Auckland inst_any /usr/share/zoneinfo/Pacific/Honolulu @@ -1172,7 +1393,7 @@ setup_basic_dirs() { mkdir -p $initdir/etc/systemd/system mkdir -p $initdir/var/log/journal - for d in usr/bin usr/sbin bin etc lib "$libdir" sbin tmp usr var var/log dev proc sys sysroot root run run/lock run/initramfs; do + for d in usr/bin usr/sbin bin etc lib "$libdir" sbin tmp usr var var/log var/tmp dev proc sys sysroot root run run/lock run/initramfs; do if [ -L "/$d" ]; then inst_symlink "/$d" else @@ -1556,7 +1777,7 @@ inst_binary() { # In such cases, let's check if the binary indeed exists in the image # before doing any other chcecks. If it does, immediately return with # success. - [[ $# -eq 1 && -e $initdir/$1 ]] && return 0 + [[ $# -eq 1 && -e $initdir/$1 || -e $initdir/bin/$1 || -e $initdir/sbin/$1 || -e $initdir/usr/bin/$1 || -e $initdir/usr/sbin/$1 ]] && return 0 _bin=$(find_binary "$1") || return 1 _target=${2:-$_bin} @@ -1989,6 +2210,10 @@ _test_cleanup() { set +e _umount_dir $initdir rm -vf "$IMAGE_PUBLIC" + # If multiple setups/cleans are ran in parallel, this can cause a race + if [ ${TEST_PARALLELIZE} -ne 1 ]; then + rm -vf "${IMAGESTATEDIR}/default.img" + fi rm -vfr "$TESTDIR" rm -vf "$STATEFILE" ) || : @@ -2029,24 +2254,43 @@ test_setup() { mount_initdir else if [ ! -e "$IMAGE_PUBLIC" ]; then - # Create the backing public image, but then completely unmount - # it and drop the loopback device responsible for it, since we're - # going to symlink/copy the image and mount it again from - # elsewhere. - test_create_image - test_setup_cleanup - umount_loopback - cleanup_loopdev + # default.img is the base that every test uses and optionally appends to + if [ ! -e "${IMAGESTATEDIR}/default.img" ] || [ -n "${TEST_FORCE_NEWIMAGE}" ]; then + # Create the backing public image, but then completely unmount + # it and drop the loopback device responsible for it, since we're + # going to symlink/copy the image and mount it again from + # elsewhere. + local image_old=${IMAGE_PUBLIC} + if [ -z "${TEST_FORCE_NEWIMAGE}" ]; then + IMAGE_PUBLIC="${IMAGESTATEDIR}/default.img" + fi + test_create_image + test_setup_cleanup + umount_loopback + cleanup_loopdev + IMAGE_PUBLIC="${image_old}" + fi + if [ "${IMAGE_NAME}" != "default" ] && [ -z "${TEST_FORCE_NEWIMAGE}" ]; then + cp -v "$(realpath "${IMAGESTATEDIR}/default.img")" "$IMAGE_PUBLIC" + fi + fi + + local hook_defined=1 + if declare -f -F test_append_files > /dev/null; then + hook_defined=$? fi echo "Reusing existing cached image $IMAGE_PUBLIC → $(realpath $IMAGE_PUBLIC)" - if [ ${TEST_PARALLELIZE} -ne 0 ]; then + if [ ${TEST_PARALLELIZE} -ne 0 ] || [ ${hook_defined} -eq 0 ]; then cp -v "$(realpath $IMAGE_PUBLIC)" "$IMAGE_PRIVATE" else ln -sv "$(realpath $IMAGE_PUBLIC)" "$IMAGE_PRIVATE" fi mount_initdir + if [ ${hook_defined} -eq 0 ]; then + test_append_files "$initdir" + fi fi setup_nspawn_root @@ -2088,6 +2332,20 @@ do_test() { exit 0 fi + if [ -n "$TEST_NO_QEMU" ] && [ -n "$TEST_NO_NSPAWN" ]; then + echo "TEST: $TEST_DESCRIPTION [SKIPPED]: both QEMU and nspawn disabled" >&2 + exit 0 + fi + + if [ -n "$TEST_QEMU_ONLY" ] && [ -z "$TEST_NO_NSPAWN" ]; then + echo "TEST: $TEST_DESCRIPTION [SKIPPED]: QEMU-only tests requested" >&2 + exit 0 + fi + + if [ -n "$TEST_PREFER_NSPAWN" ] && [ -z "$TEST_NO_NSPAWN" ]; then + TEST_NO_QEMU=1 + fi + # Detect lib paths [[ $libdir ]] || for libdir in /lib64 /lib; do [[ -d $libdir ]] && libdirs+=" $libdir" && break @@ -2132,11 +2390,15 @@ do_test() { --all) ret=0 echo -n "${testname}: $TEST_DESCRIPTION " - ( - test_setup - test_setup_cleanup - test_run "$2" - ) "$TESTLOG" 2>&1 || ret=$? + # Do not use a subshell, otherwise cleanup variables (LOOPDEV) will be lost + # and loop devices will leak + test_setup "$TESTLOG" 2>&1 || ret=$? + if [ $ret -eq 0 ]; then + test_setup_cleanup >"$TESTLOG" 2>&1 || ret=$? + fi + if [ $ret -eq 0 ]; then + test_run "$2" >"$TESTLOG" 2>&1 || ret=$? + fi test_cleanup if [ $ret -eq 0 ]; then rm "$TESTLOG" diff --git a/test/test-network/conf/25-activation-policy.network b/test/test-network/conf/25-activation-policy.network new file mode 100644 index 000000000..c53e0919c --- /dev/null +++ b/test/test-network/conf/25-activation-policy.network @@ -0,0 +1,6 @@ +[Match] +Name=test1 + +[Network] +Address=192.168.10.30/24 +Gateway=192.168.10.1 diff --git a/test/test-network/conf/25-activation-policy.network.d/always-down.conf b/test/test-network/conf/25-activation-policy.network.d/always-down.conf new file mode 100644 index 000000000..edfd12e06 --- /dev/null +++ b/test/test-network/conf/25-activation-policy.network.d/always-down.conf @@ -0,0 +1,2 @@ +[Link] +ActivationPolicy=always-down diff --git a/test/test-network/conf/25-activation-policy.network.d/always-up.conf b/test/test-network/conf/25-activation-policy.network.d/always-up.conf new file mode 100644 index 000000000..b8e0fffed --- /dev/null +++ b/test/test-network/conf/25-activation-policy.network.d/always-up.conf @@ -0,0 +1,2 @@ +[Link] +ActivationPolicy=always-up diff --git a/test/test-network/conf/25-activation-policy.network.d/down.conf b/test/test-network/conf/25-activation-policy.network.d/down.conf new file mode 100644 index 000000000..65af49f73 --- /dev/null +++ b/test/test-network/conf/25-activation-policy.network.d/down.conf @@ -0,0 +1,2 @@ +[Link] +ActivationPolicy=down diff --git a/test/test-network/conf/25-activation-policy.network.d/manual.conf b/test/test-network/conf/25-activation-policy.network.d/manual.conf new file mode 100644 index 000000000..8b81ccc54 --- /dev/null +++ b/test/test-network/conf/25-activation-policy.network.d/manual.conf @@ -0,0 +1,2 @@ +[Link] +ActivationPolicy=manual diff --git a/test/test-network/conf/25-activation-policy.network.d/up.conf b/test/test-network/conf/25-activation-policy.network.d/up.conf new file mode 100644 index 000000000..537380b74 --- /dev/null +++ b/test/test-network/conf/25-activation-policy.network.d/up.conf @@ -0,0 +1,2 @@ +[Link] +ActivationPolicy=up diff --git a/test/test-network/conf/25-address-preferred-lifetime-zero.network b/test/test-network/conf/25-address-preferred-lifetime-zero.network deleted file mode 100644 index d3d02d282..000000000 --- a/test/test-network/conf/25-address-preferred-lifetime-zero.network +++ /dev/null @@ -1,35 +0,0 @@ -[Match] -Name=dummy98 - -[Network] -IPv6AcceptRA=no - -# these lines are ignored -Address=hogehoge -Address=foofoo - -[Route] -Gateway=20.20.20.1 - -[Address] -Address=10.2.3.4/16 -PreferredLifetime=0 -Scope=link - -[Address] -Address=2001:0db8:0:f101::1/64 - -[Address] -Address=20.20.20.100/24 - -[Address] -# this section must be ignored -Peer=hoge -Address=10.10.0.1/16 -Label=30 - -[Address] -# this section must be ignored -Label=30 -Peer=hoge -Address=10.10.0.2/16 diff --git a/test/test-network/conf/25-address-static.network b/test/test-network/conf/25-address-static.network index 506cdd226..3227fe8df 100644 --- a/test/test-network/conf/25-address-static.network +++ b/test/test-network/conf/25-address-static.network @@ -52,6 +52,19 @@ Peer=2001:db8:0:f103::10/128 [Address] Address=::/64 +[Address] +Address=10.7.8.9/16 +PreferredLifetime=0 +Scope=link + +[Address] +Address=2001:0db8:1:f101::1/64 +PreferredLifetime=0 + +[Address] +Address=10.8.8.1/16 +Broadcast=no + # test for ENOBUFS issue #17012 [Network] Address=10.3.3.1/16 diff --git a/test/test-network/conf/25-batadv.netdev b/test/test-network/conf/25-batadv.netdev new file mode 100644 index 000000000..6197d701c --- /dev/null +++ b/test/test-network/conf/25-batadv.netdev @@ -0,0 +1,14 @@ +[NetDev] +Name=batadv99 +Kind=batadv +Description=Batman test + +[BatmanAdvanced] +GatewayMode=server +RoutingAlgorithm=batman-iv +DistributedArpTable=1 +Fragmentation=0 +HopPenalty=10 +OriginatorIntervalSec=1000ms +GatewayBandwithDown=205M +GatewayBandwithUp=2G diff --git a/test/test-network/conf/25-ipv6-proxy-ndp.network b/test/test-network/conf/25-ipv6-proxy-ndp.network new file mode 100644 index 000000000..acdcce819 --- /dev/null +++ b/test/test-network/conf/25-ipv6-proxy-ndp.network @@ -0,0 +1,24 @@ +[Match] +Name=dummy98 + +[Network] +IPv6ProxyNDPAddress=2607:5300:203:5215:5::1 +IPv6ProxyNDPAddress=2607:5300:203:5215:4::1 +IPv6ProxyNDPAddress=2607:5300:203:5215:3::1 +IPv6ProxyNDPAddress=2607:5300:203:5215:2::1 +IPv6ProxyNDPAddress=2607:5300:203:5215:1::1 +IPv6AcceptRA=no +IPForward=yes +Address=66.70.129.136/32 +Address=66.70.129.142/32 +Address=66.70.129.143/32 + +[Address] +Address=2607:5300:203:5215::1/64 + +[Route] +Destination=2607:5300:203:52ff:ff:ff:ff:ff + +[Route] +Gateway=2607:5300:203:52ff:ff:ff:ff:ff +Destination=::/0 diff --git a/test/test-network/conf/25-nexthop-nothing.network b/test/test-network/conf/25-nexthop-nothing.network new file mode 100644 index 000000000..fdaf32d53 --- /dev/null +++ b/test/test-network/conf/25-nexthop-nothing.network @@ -0,0 +1,8 @@ +[Match] +Name=veth99 + +[Network] +IPv6AcceptRA=no +Address=2001:1234:5:8f63::1/120 +Address=192.168.5.10/24 +Gateway=192.168.5.1 diff --git a/test/test-network/conf/25-nexthop.network b/test/test-network/conf/25-nexthop.network index 3eea07734..8b3e4b65c 100644 --- a/test/test-network/conf/25-nexthop.network +++ b/test/test-network/conf/25-nexthop.network @@ -3,9 +3,72 @@ Name=veth99 [Network] IPv6AcceptRA=no +Address=2001:1234:5:8f63::1/120 Address=192.168.5.10/24 Gateway=192.168.5.1 [NextHop] Id=1 Gateway=192.168.5.1 + +[NextHop] +Id=2 +Gateway=2001:1234:5:8f63::2 + +[NextHop] +Id=3 +Family=ipv6 + +[NextHop] +Id=4 +Family=ipv4 + +[NextHop] +Id=5 +Gateway=192.168.10.1 +OnLink=yes + +[NextHop] +Id=6 +Family=ipv4 +Blackhole=yes + +[NextHop] +Id=7 +Family=ipv6 +Blackhole=yes + +[NextHop] +Gateway=192.168.5.2 + +[NextHop] +Family=ipv4 +Blackhole=yes + +[NextHop] +Family=ipv6 +Blackhole=yes + +[Route] +NextHop=1 +Destination=10.10.10.10 + +[Route] +NextHop=2 +Destination=10.10.10.11 + +[Route] +NextHop=2 +Destination=2001:1234:5:8f62::1 + +[Route] +NextHop=5 +Destination=10.10.10.12 + +[Route] +NextHop=6 +Destination=10.10.10.13 + +[Route] +NextHop=7 +Destination=2001:1234:5:8f62::2 diff --git a/test/test-network/conf/25-route-static.network b/test/test-network/conf/25-route-static.network index bb485eb6b..a120daf10 100644 --- a/test/test-network/conf/25-route-static.network +++ b/test/test-network/conf/25-route-static.network @@ -36,6 +36,10 @@ InitialCongestionWindow=20 Destination=192.168.1.2 InitialAdvertisedReceiveWindow=30 +[Route] +Destination=192.168.1.3 +TCPAdvertisedMaximumSegmentSize=30 + [Route] Type=blackhole Destination=202.54.1.2 @@ -48,6 +52,18 @@ Destination=202.54.1.3 Type=prohibit Destination=202.54.1.4 +[Route] +Type=blackhole +Destination=2001:1234:5678::2 + +[Route] +Type=unreachable +Destination=2001:1234:5678::3 + +[Route] +Type=prohibit +Destination=2001:1234:5678::4 + [Route] Type=local Destination=149.10.123.1 diff --git a/test/test-network/conf/25-wireguard-23-peers.network b/test/test-network/conf/25-wireguard-23-peers.network index 4dc87f8d4..033ffa155 100644 --- a/test/test-network/conf/25-wireguard-23-peers.network +++ b/test/test-network/conf/25-wireguard-23-peers.network @@ -2,6 +2,7 @@ Name=wg98 [Network] +Address=192.168.123.123/24 Address=fd8d:4d6d:3ccb:0500::1/64 # nat64 via 1 diff --git a/test/test-network/conf/25-wireguard.netdev b/test/test-network/conf/25-wireguard.netdev index 4866c31cc..a95ae205d 100644 --- a/test/test-network/conf/25-wireguard.netdev +++ b/test/test-network/conf/25-wireguard.netdev @@ -3,7 +3,6 @@ Name=wg99 Kind=wireguard [WireGuard] -PrivateKey=EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong= ListenPort=51820 FwMark=1234 diff --git a/test/test-network/conf/25-wireguard.netdev.d/peer1.conf b/test/test-network/conf/25-wireguard.netdev.d/peer1.conf new file mode 100644 index 000000000..47848fcde --- /dev/null +++ b/test/test-network/conf/25-wireguard.netdev.d/peer1.conf @@ -0,0 +1,5 @@ +[WireGuardPeer] +PublicKey=TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10= +PresharedKey=it7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA= + +AllowedIPs=192.168.124.2 diff --git a/test/test-network/conf/25-wireguard.netdev.d/peer2.conf b/test/test-network/conf/25-wireguard.netdev.d/peer2.conf new file mode 100644 index 000000000..bf99a5ab0 --- /dev/null +++ b/test/test-network/conf/25-wireguard.netdev.d/peer2.conf @@ -0,0 +1,5 @@ +[WireGuardPeer] +PublicKey=9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c= +PresharedKey=6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I= + +AllowedIPs=192.168.124.3 diff --git a/test/test-network/conf/25-wireguard.netdev.d/private-key.conf b/test/test-network/conf/25-wireguard.netdev.d/private-key.conf new file mode 100644 index 000000000..9b04cf72a --- /dev/null +++ b/test/test-network/conf/25-wireguard.netdev.d/private-key.conf @@ -0,0 +1,2 @@ +[WireGuard] +PrivateKey=EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong= diff --git a/test/test-network/conf/25-wireguard.network b/test/test-network/conf/25-wireguard.network index ab3052391..163a56ff2 100644 --- a/test/test-network/conf/25-wireguard.network +++ b/test/test-network/conf/25-wireguard.network @@ -1,2 +1,5 @@ [Match] Name=wg99 + +[Network] +Address=192.168.124.1/24 diff --git a/test/test-network/conf/dhcp-client-vrf.network b/test/test-network/conf/dhcp-client-vrf.network index bb1d2e09c..a277d5ecb 100644 --- a/test/test-network/conf/dhcp-client-vrf.network +++ b/test/test-network/conf/dhcp-client-vrf.network @@ -4,5 +4,4 @@ Name=veth99 [Network] DHCP=yes IPv6AcceptRA=yes -LinkLocalAddressing=yes VRF=vrf99 diff --git a/test/test-network/conf/dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network b/test/test-network/conf/dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network deleted file mode 100644 index 5489c62a5..000000000 --- a/test/test-network/conf/dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network +++ /dev/null @@ -1,10 +0,0 @@ -[Match] -Name=veth99 - -[Network] -DHCP=ipv4 -LinkLocalAddressing=fallback -IPv6AcceptRA=no - -[DHCPv4] -MaxAttempts=1 diff --git a/test/test-network/conf/dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network b/test/test-network/conf/dhcp-client-with-ipv4ll.network similarity index 66% rename from test/test-network/conf/dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network rename to test/test-network/conf/dhcp-client-with-ipv4ll.network index 9ebdbb4f8..0455e09b4 100644 --- a/test/test-network/conf/dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network +++ b/test/test-network/conf/dhcp-client-with-ipv4ll.network @@ -3,5 +3,5 @@ Name=veth99 [Network] DHCP=ipv4 -LinkLocalAddressing=fallback +LinkLocalAddressing=yes IPv6AcceptRA=no diff --git a/test/test-network/conf/ipv6-prefix.network b/test/test-network/conf/ipv6-prefix.network index 7813c2c1b..a06f100c3 100644 --- a/test/test-network/conf/ipv6-prefix.network +++ b/test/test-network/conf/ipv6-prefix.network @@ -2,6 +2,7 @@ Name=veth-peer [Network] +IPv6AcceptRA=no IPv6SendRA=yes [IPv6SendRA] diff --git a/test/test-network/conf/ipv6ra-prefix-client-deny-list.network b/test/test-network/conf/ipv6ra-prefix-client-deny-list.network new file mode 100644 index 000000000..ce7a76f70 --- /dev/null +++ b/test/test-network/conf/ipv6ra-prefix-client-deny-list.network @@ -0,0 +1,11 @@ +[Match] +Name=veth-peer + +[Network] +DHCP=no +IPv6AcceptRA=yes + +[IPv6AcceptRA] +RouterDenyList=2001::1 +PrefixDenyList=2001:db8:0:2:: +RouteDenyList=2001:db1:fff:: diff --git a/test/test-network/conf/ipv6ra-prefix-client.network b/test/test-network/conf/ipv6ra-prefix-client.network index bc40b123c..58883658f 100644 --- a/test/test-network/conf/ipv6ra-prefix-client.network +++ b/test/test-network/conf/ipv6ra-prefix-client.network @@ -4,3 +4,10 @@ Name=veth-peer [Network] DHCP=no IPv6AcceptRA=yes + +[IPv6AcceptRA] +# PrefixDenyList= and RouteDenyList= will be ignored. +PrefixAllowList=2001:db8:0:1:: 2001:db8:0:1:: +PrefixDenyList=2001:db8:0:1:: 2001:db8:0:1:: +RouteAllowList=2001:db0:fff:: 2001:db0:fff:: +RouteDenyList=2001:db0:fff:: 2001:db0:fff:: diff --git a/test/test-network/conf/ipv6ra-prefix.network b/test/test-network/conf/ipv6ra-prefix.network index a0ac1e453..cfb03f50c 100644 --- a/test/test-network/conf/ipv6ra-prefix.network +++ b/test/test-network/conf/ipv6ra-prefix.network @@ -15,3 +15,7 @@ Assign=yes [IPv6RoutePrefix] Route=2001:db0:fff::/64 LifetimeSec=1000 + +[IPv6RoutePrefix] +Route=2001:db1:fff::/64 +LifetimeSec=1000 diff --git a/test/test-network/conf/netdev-link-local-addressing-yes.network b/test/test-network/conf/netdev-link-local-addressing-yes.network index 1a22390a3..ee18bea72 100644 --- a/test/test-network/conf/netdev-link-local-addressing-yes.network +++ b/test/test-network/conf/netdev-link-local-addressing-yes.network @@ -1,5 +1,6 @@ [Match] Name=bareudp99 +Name=batadv99 Name=ipvlan99 Name=ipvtap99 Name=macvlan99 diff --git a/test/test-network/conf/routing-policy-rule-reconfigure.network b/test/test-network/conf/routing-policy-rule-reconfigure1.network similarity index 96% rename from test/test-network/conf/routing-policy-rule-reconfigure.network rename to test/test-network/conf/routing-policy-rule-reconfigure1.network index ca38b78f1..96650c255 100644 --- a/test/test-network/conf/routing-policy-rule-reconfigure.network +++ b/test/test-network/conf/routing-policy-rule-reconfigure1.network @@ -21,7 +21,7 @@ OutgoingInterface=test1 # iif [RoutingPolicyRule] Table=1011 -Family=ipv4 +Family=both Priority=10113 IncomingInterface=test1 diff --git a/test/test-network/conf/routing-policy-rule-reconfigure2.network b/test/test-network/conf/routing-policy-rule-reconfigure2.network new file mode 100644 index 000000000..d12fe0402 --- /dev/null +++ b/test/test-network/conf/routing-policy-rule-reconfigure2.network @@ -0,0 +1,33 @@ +[Match] +Name=test1 + +[Network] +IPv6AcceptRA=no + +# fwmark +[RoutingPolicyRule] +Table=1011 +Family=ipv4 +Priority=10111 +FirewallMark=1011 + +# oif +[RoutingPolicyRule] +Table=1011 +Family=both +Priority=10112 +OutgoingInterface=test1 + +# iif +[RoutingPolicyRule] +Table=1011 +Family=ipv4 +Priority=10113 +IncomingInterface=test1 + +# source +[RoutingPolicyRule] +Table=1011 +Family=ipv4 +Priority=10114 +From=192.168.8.254 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 1062f93e5..fc88fefd0 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -404,6 +404,13 @@ def remove_routes(routes): for route_type, addr in routes: call('ip route del', route_type, addr, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) +def remove_blackhole_nexthops(): + ret = run('ip nexthop show dev lo', stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) + if ret.returncode == 0: + for line in ret.stdout.rstrip().splitlines(): + id = line.split()[1] + call(f'ip nexthop del id {id}') + def remove_l2tp_tunnels(tunnel_ids): output = check_output('ip l2tp show tunnel') for tid in tunnel_ids: @@ -589,8 +596,18 @@ class Utilities(): output = check_output(f'ip {ipv} address show dev {link} scope {scope}') if re.search(address_regex, output) and 'tentative' not in output: break - else: - self.assertRegex(output, address_regex) + + self.assertRegex(output, address_regex) + + def wait_address_dropped(self, link, address_regex, scope='global', ipv='', timeout_sec=100): + for i in range(timeout_sec): + if i > 0: + time.sleep(1) + output = check_output(f'ip {ipv} address show dev {link} scope {scope}') + if not re.search(address_regex, output): + break + + self.assertNotRegex(output, address_regex) class NetworkctlTests(unittest.TestCase, Utilities): @@ -762,6 +779,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): links = [ '6rdtun99', 'bareudp99', + 'batadv99', 'bond98', 'bond99', 'bridge99', @@ -838,6 +856,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): '21-vlan.network', '25-6rd-tunnel.netdev', '25-bareudp.netdev', + '25-batadv.netdev', '25-bond.netdev', '25-bond-balanced-tlb.netdev', '25-bridge.netdev', @@ -997,6 +1016,17 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): self.assertRegex(output, 'dstport 1000 ') self.assertRegex(output, 'ethertype ip ') + @expectedFailureIfModuleIsNotAvailable('batman-adv') + def test_batadv(self): + copy_unit_to_networkd_unit_path('25-batadv.netdev', 'netdev-link-local-addressing-yes.network') + start_networkd() + + self.wait_online(['batadv99:degraded']) + + output = check_output('ip -d link show batadv99') + print(output) + self.assertRegex(output, 'batadv') + def test_bridge(self): copy_unit_to_networkd_unit_path('25-bridge.netdev', '25-bridge-configure-without-carrier.network') start_networkd() @@ -1208,35 +1238,57 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities): '25-wireguard-preshared-key.txt', '25-wireguard-private-key.txt', '25-wireguard-no-peer.netdev', '25-wireguard-no-peer.network') start_networkd() - self.wait_online(['wg99:carrier', 'wg98:routable', 'wg97:carrier']) + self.wait_online(['wg99:routable', 'wg98:routable', 'wg97:carrier']) + + output = check_output('ip -4 address show dev wg99') + print(output) + self.assertIn('inet 192.168.124.1/24 scope global wg99', output) + + output = check_output('ip -4 address show dev wg98') + print(output) + self.assertIn('inet 192.168.123.123/24 scope global wg98', output) + + output = check_output('ip -6 address show dev wg98') + print(output) + self.assertIn('inet6 fd8d:4d6d:3ccb:500::1/64 scope global', output) if shutil.which('wg'): call('wg') output = check_output('wg show wg99 listen-port') - self.assertRegex(output, '51820') + self.assertEqual(output, '51820') output = check_output('wg show wg99 fwmark') - self.assertRegex(output, '0x4d2') - output = check_output('wg show wg99 allowed-ips') - self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48') - self.assertRegex(output, r'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128') - output = check_output('wg show wg99 persistent-keepalive') - self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20') - output = check_output('wg show wg99 endpoints') - self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820') + self.assertEqual(output, '0x4d2') output = check_output('wg show wg99 private-key') - self.assertRegex(output, r'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=') + self.assertEqual(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=') + output = check_output('wg show wg99 allowed-ips') + self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t192.168.124.3/32', output) + self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t192.168.124.2/32', output) + self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128', output) + self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48', output) + output = check_output('wg show wg99 persistent-keepalive') + self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\toff', output) + self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\toff', output) + self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\toff', output) + self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20', output) + output = check_output('wg show wg99 endpoints') + self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t(none)', output) + self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\t(none)', output) + self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\t(none)', output) + self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820', output) output = check_output('wg show wg99 preshared-keys') - self.assertRegex(output, r'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=') - self.assertRegex(output, r'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=') + self.assertIn('9uioxkGzjvGjkse3V35I9AhorWfIjBcrf3UPMS0bw2c=\t6Fsg8XN0DE6aPQgAX4r2oazEYJOGqyHUz3QRH/jCB+I=', output) + self.assertIn('TTiCUpCxS7zDn/ax4p5W6Evg41r8hOrnWQw2Sq6Nh10=\tit7nd33chCT/tKT2ZZWfYyp43Zs+6oif72hexnSNMqA=', output) + self.assertIn('lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tcPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=', output) + self.assertIn('RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\tIIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=', output) output = check_output('wg show wg98 private-key') - self.assertRegex(output, r'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=') + self.assertEqual(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=') output = check_output('wg show wg97 listen-port') - self.assertRegex(output, '51821') + self.assertEqual(output, '51821') output = check_output('wg show wg97 fwmark') - self.assertRegex(output, '0x4d3') + self.assertEqual(output, '0x4d3') def test_geneve(self): copy_unit_to_networkd_unit_path('25-geneve.netdev', 'netdev-link-local-addressing-yes.network') @@ -1743,8 +1795,8 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): '25-address-dad-veth99.network', '25-address-link-section.network', '25-address-peer-ipv4.network', - '25-address-preferred-lifetime-zero.network', '25-address-static.network', + '25-activation-policy.network', '25-bind-carrier.network', '25-bond-active-backup-slave.netdev', '25-fibrule-invert.network', @@ -1753,6 +1805,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): '25-gre-tunnel-remote-any.netdev', '25-ip6gre-tunnel-remote-any.netdev', '25-ipv6-address-label-section.network', + '25-ipv6-proxy-ndp.network', '25-link-local-addressing-no.network', '25-link-local-addressing-yes.network', '25-link-section-unmanaged.network', @@ -1761,6 +1814,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): '25-neighbor-ipv6.network', '25-neighbor-ip-dummy.network', '25-neighbor-ip.network', + '25-nexthop-nothing.network', '25-nexthop.network', '25-qdisc-cake.network', '25-qdisc-clsact-and-htb.network', @@ -1790,19 +1844,22 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): '26-link-local-addressing-ipv6.network', 'routing-policy-rule-dummy98.network', 'routing-policy-rule-test1.network', - 'routing-policy-rule-reconfigure.network', + 'routing-policy-rule-reconfigure1.network', + 'routing-policy-rule-reconfigure2.network', ] routing_policy_rule_tables = ['7', '8', '9', '1011'] routes = [['blackhole', '202.54.1.2'], ['unreachable', '202.54.1.3'], ['prohibit', '202.54.1.4']] def setUp(self): + remove_blackhole_nexthops() remove_routing_policy_rule_tables(self.routing_policy_rule_tables) remove_routes(self.routes) remove_links(self.links) stop_networkd(show_logs=False) def tearDown(self): + remove_blackhole_nexthops() remove_routing_policy_rule_tables(self.routing_policy_rule_tables) remove_routes(self.routes) remove_links(self.links) @@ -1817,38 +1874,41 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip -4 address show dev dummy98') print(output) - self.assertRegex(output, 'inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98') - self.assertRegex(output, 'inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98') - self.assertRegex(output, 'inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98') + self.assertIn('inet 10.1.2.3/16 brd 10.1.255.255 scope global dummy98', output) + self.assertIn('inet 10.1.2.4/16 brd 10.1.255.255 scope global secondary dummy98', output) + self.assertIn('inet 10.2.2.4/16 brd 10.2.255.255 scope global dummy98', output) + self.assertIn('inet 10.7.8.9/16 brd 10.7.255.255 scope link deprecated dummy98', output) + self.assertIn('inet 10.8.8.1/16 scope global dummy98', output) # test for ENOBUFS issue #17012 for i in range(1,254): - self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255') + self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) # invalid sections - self.assertNotRegex(output, '10.10.0.1/16') - self.assertNotRegex(output, '10.10.0.2/16') + self.assertNotIn('10.10.0.1/16', output) + self.assertNotIn('10.10.0.2/16', output) output = check_output('ip -4 address show dev dummy98 label 32') - self.assertRegex(output, 'inet 10.3.2.3/16 brd 10.3.255.255 scope global 32') + self.assertIn('inet 10.3.2.3/16 brd 10.3.255.255 scope global 32', output) output = check_output('ip -4 address show dev dummy98 label 33') - self.assertRegex(output, 'inet 10.4.2.3 peer 10.4.2.4/16 scope global 33') + self.assertIn('inet 10.4.2.3 peer 10.4.2.4/16 scope global 33', output) output = check_output('ip -4 address show dev dummy98 label 34') - self.assertRegex(output, 'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34') + self.assertRegex(output, r'inet 192.168.[0-9]*.1/24 brd 192.168.[0-9]*.255 scope global 34') output = check_output('ip -4 address show dev dummy98 label 35') - self.assertRegex(output, 'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35') + self.assertRegex(output, r'inet 172.[0-9]*.0.1/16 brd 172.[0-9]*.255.255 scope global 35') output = check_output('ip -6 address show dev dummy98') print(output) - self.assertRegex(output, 'inet6 2001:db8:0:f101::15/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f101::16/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f102::15/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f102::16/64 scope global') - self.assertRegex(output, 'inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global') - self.assertRegex(output, 'inet6 fd[0-9a-f:]*1/64 scope global') + self.assertIn('inet6 2001:db8:0:f101::15/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f101::16/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f102::15/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f102::16/64 scope global', output) + self.assertIn('inet6 2001:db8:0:f103::20 peer 2001:db8:0:f103::10/128 scope global', output) + self.assertIn('inet6 2001:db8:1:f101::1/64 scope global deprecated', output) + self.assertRegex(output, r'inet6 fd[0-9a-f:]*1/64 scope global') restart_networkd() self.wait_online(['dummy98:routable']) @@ -1856,22 +1916,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): # test for ENOBUFS issue #17012 output = check_output('ip -4 address show dev dummy98') for i in range(1,254): - self.assertRegex(output, f'inet 10.3.3.{i}/16 brd 10.3.255.255') - - def test_address_preferred_lifetime_zero_ipv6(self): - copy_unit_to_networkd_unit_path('25-address-preferred-lifetime-zero.network', '12-dummy.netdev') - start_networkd(5) - - self.wait_online(['dummy98:routable']) - - output = check_output('ip address show dummy98') - print(output) - self.assertRegex(output, 'inet 10.2.3.4/16 brd 10.2.255.255 scope link deprecated dummy98') - self.assertRegex(output, 'inet6 2001:db8:0:f101::1/64 scope global') - - output = check_output('ip route show dev dummy98') - print(output) - self.assertRegex(output, 'default via 20.20.20.1 proto static') + self.assertIn(f'inet 10.3.3.{i}/16 brd 10.3.255.255', output) def test_address_dad(self): copy_unit_to_networkd_unit_path('25-address-dad-veth99.network', '25-address-dad-veth-peer.network', @@ -1939,7 +1984,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'local fdde:11:44::1 proto kernel metric 0 pref medium') self.assertRegex(output, 'local fdde:11:55::1 proto kernel metric 0 pref medium') self.assertRegex(output, 'fe80::/64 proto kernel metric 256 pref medium') - self.assertRegex(output, 'ff00::/8 metric 256 pref medium') + self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium') print() @@ -1971,7 +2016,7 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'local fdde:12:33::1 proto kernel metric 0 pref medium') self.assertRegex(output, 'local fdde:12:44::1 proto kernel metric 0 pref medium') self.assertRegex(output, 'local fdde:12:55::1 proto kernel metric 0 pref medium') - self.assertRegex(output, 'ff00::/8 metric 256 pref medium') + self.assertRegex(output, 'ff00::/8 (proto kernel )?metric 256 (linkdown )?pref medium') def test_configure_without_carrier(self): copy_unit_to_networkd_unit_path('11-dummy.netdev') @@ -2074,37 +2119,65 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): stop_networkd(remove_state_files=False) def test_routing_policy_rule_reconfigure(self): - copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure.network', '11-dummy.netdev') + copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure2.network', '11-dummy.netdev') start_networkd() self.wait_online(['test1:degraded']) output = check_output('ip rule list table 1011') print(output) - self.assertRegex(output, '10111: from all fwmark 0x3f3 lookup 1011') - self.assertRegex(output, '10112: from all oif test1 lookup 1011') - self.assertRegex(output, '10113: from all iif test1 lookup 1011') - self.assertRegex(output, '10114: from 192.168.8.254 lookup 1011') + self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output) + self.assertIn('10112: from all oif test1 lookup 1011', output) + self.assertIn('10113: from all iif test1 lookup 1011', output) + self.assertIn('10114: from 192.168.8.254 lookup 1011', output) + + output = check_output('ip -6 rule list table 1011') + print(output) + self.assertIn('10112: from all oif test1 lookup 1011', output) + + copy_unit_to_networkd_unit_path('routing-policy-rule-reconfigure1.network', '11-dummy.netdev') + run(*networkctl_cmd, 'reload', env=env) + time.sleep(1) + self.wait_online(['test1:degraded']) + + output = check_output('ip rule list table 1011') + print(output) + self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output) + self.assertIn('10112: from all oif test1 lookup 1011', output) + self.assertIn('10113: from all iif test1 lookup 1011', output) + self.assertIn('10114: from 192.168.8.254 lookup 1011', output) + + output = check_output('ip -6 rule list table 1011') + print(output) + self.assertNotIn('10112: from all oif test1 lookup 1011', output) + self.assertIn('10113: from all iif test1 lookup 1011', output) run('ip rule delete priority 10111') run('ip rule delete priority 10112') run('ip rule delete priority 10113') run('ip rule delete priority 10114') - run('ip rule delete priority 10115') + run('ip -6 rule delete priority 10113') output = check_output('ip rule list table 1011') print(output) self.assertEqual(output, '') - run(*networkctl_cmd, 'reconfigure', 'test1', env=env) + output = check_output('ip -6 rule list table 1011') + print(output) + self.assertEqual(output, '') + run(*networkctl_cmd, 'reconfigure', 'test1', env=env) self.wait_online(['test1:degraded']) output = check_output('ip rule list table 1011') print(output) - self.assertRegex(output, '10111: from all fwmark 0x3f3 lookup 1011') - self.assertRegex(output, '10112: from all oif test1 lookup 1011') - self.assertRegex(output, '10113: from all iif test1 lookup 1011') - self.assertRegex(output, '10114: from 192.168.8.254 lookup 1011') + self.assertIn('10111: from all fwmark 0x3f3 lookup 1011', output) + self.assertIn('10112: from all oif test1 lookup 1011', output) + self.assertIn('10113: from all iif test1 lookup 1011', output) + self.assertIn('10114: from 192.168.8.254 lookup 1011', output) + + output = check_output('ip -6 rule list table 1011') + print(output) + self.assertIn('10113: from all iif test1 lookup 1011', output) @expectedFailureIfRoutingPolicyPortRangeIsNotAvailable() def test_routing_policy_rule_port_range(self): @@ -2158,80 +2231,97 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print('### ip -6 route show dev dummy98') output = check_output('ip -6 route show dev dummy98') print(output) - self.assertRegex(output, '2001:1234:5:8fff:ff:ff:ff:ff proto static') - self.assertRegex(output, '2001:1234:5:8f63::1 proto kernel') + self.assertIn('2001:1234:5:8fff:ff:ff:ff:ff proto static', output) + self.assertIn('2001:1234:5:8f63::1 proto kernel', output) print('### ip -6 route show default') output = check_output('ip -6 route show default') print(output) - self.assertRegex(output, 'default') - self.assertRegex(output, 'via 2001:1234:5:8fff:ff:ff:ff:ff') + self.assertIn('default', output) + self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff', output) print('### ip -4 route show dev dummy98') output = check_output('ip -4 route show dev dummy98') print(output) - self.assertRegex(output, '149.10.124.48/28 proto kernel scope link src 149.10.124.58') - self.assertRegex(output, '149.10.124.64 proto static scope link') - self.assertRegex(output, '169.254.0.0/16 proto static scope link metric 2048') - self.assertRegex(output, '192.168.1.1 proto static initcwnd 20') - self.assertRegex(output, '192.168.1.2 proto static initrwnd 30') - self.assertRegex(output, 'multicast 149.10.123.4 proto static') + self.assertIn('149.10.124.48/28 proto kernel scope link src 149.10.124.58', output) + self.assertIn('149.10.124.64 proto static scope link', output) + self.assertIn('169.254.0.0/16 proto static scope link metric 2048', output) + self.assertIn('192.168.1.1 proto static initcwnd 20', output) + self.assertIn('192.168.1.2 proto static initrwnd 30', output) + self.assertIn('192.168.1.3 proto static advmss 30', output) + self.assertIn('multicast 149.10.123.4 proto static', output) print('### ip -4 route show dev dummy98 default') output = check_output('ip -4 route show dev dummy98 default') print(output) - self.assertRegex(output, 'default via 149.10.125.65 proto static onlink') - self.assertRegex(output, 'default via 149.10.124.64 proto static') - self.assertRegex(output, 'default proto static') + self.assertIn('default via 149.10.125.65 proto static onlink', output) + self.assertIn('default via 149.10.124.64 proto static', output) + self.assertIn('default proto static', output) print('### ip -4 route show table local dev dummy98') output = check_output('ip -4 route show table local dev dummy98') print(output) - self.assertRegex(output, 'local 149.10.123.1 proto static scope host') - self.assertRegex(output, 'anycast 149.10.123.2 proto static scope link') - self.assertRegex(output, 'broadcast 149.10.123.3 proto static scope link') + self.assertIn('local 149.10.123.1 proto static scope host', output) + self.assertIn('anycast 149.10.123.2 proto static scope link', output) + self.assertIn('broadcast 149.10.123.3 proto static scope link', output) print('### ip route show type blackhole') output = check_output('ip route show type blackhole') print(output) - self.assertRegex(output, 'blackhole 202.54.1.2 proto static') + self.assertIn('blackhole 202.54.1.2 proto static', output) print('### ip route show type unreachable') output = check_output('ip route show type unreachable') print(output) - self.assertRegex(output, 'unreachable 202.54.1.3 proto static') + self.assertIn('unreachable 202.54.1.3 proto static', output) print('### ip route show type prohibit') output = check_output('ip route show type prohibit') print(output) - self.assertRegex(output, 'prohibit 202.54.1.4 proto static') + self.assertIn('prohibit 202.54.1.4 proto static', output) + + print('### ip -6 route show type blackhole') + output = check_output('ip -6 route show type blackhole') + print(output) + self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output) + + print('### ip -6 route show type unreachable') + output = check_output('ip -6 route show type unreachable') + print(output) + self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output) + + print('### ip -6 route show type prohibit') + output = check_output('ip -6 route show type prohibit') + print(output) + self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output) print('### ip route show 192.168.10.1') output = check_output('ip route show 192.168.10.1') print(output) - self.assertRegex(output, '192.168.10.1 proto static') - self.assertRegex(output, 'nexthop via 149.10.124.59 dev dummy98 weight 10') - self.assertRegex(output, 'nexthop via 149.10.124.60 dev dummy98 weight 5') + self.assertIn('192.168.10.1 proto static', output) + self.assertIn('nexthop via 149.10.124.59 dev dummy98 weight 10', output) + self.assertIn('nexthop via 149.10.124.60 dev dummy98 weight 5', output) print('### ip route show 192.168.10.2') output = check_output('ip route show 192.168.10.2') print(output) # old ip command does not show IPv6 gateways... - self.assertRegex(output, '192.168.10.2 proto static') - self.assertRegex(output, 'nexthop') - self.assertRegex(output, 'dev dummy98 weight 10') - self.assertRegex(output, 'dev dummy98 weight 5') + self.assertIn('192.168.10.2 proto static', output) + self.assertIn('nexthop', output) + self.assertIn('dev dummy98 weight 10', output) + self.assertIn('dev dummy98 weight 5', output) print('### ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff') output = check_output('ip -6 route show 2001:1234:5:7fff:ff:ff:ff:ff') print(output) # old ip command does not show 'nexthop' keyword and weight... - self.assertRegex(output, '2001:1234:5:7fff:ff:ff:ff:ff') - self.assertRegex(output, 'via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98') - self.assertRegex(output, 'via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98') + self.assertIn('2001:1234:5:7fff:ff:ff:ff:ff', output) + self.assertIn('via 2001:1234:5:8fff:ff:ff:ff:ff dev dummy98', output) + self.assertIn('via 2001:1234:5:9fff:ff:ff:ff:ff dev dummy98', output) copy_unit_to_networkd_unit_path('25-address-static.network') check_output(*networkctl_cmd, 'reload', env=env) + time.sleep(1) self.wait_online(['dummy98:routable']) # check all routes managed by Manager are removed @@ -2250,25 +2340,56 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertEqual(output, '') + print('### ip -6 route show type blackhole') + output = check_output('ip -6 route show type blackhole') + print(output) + self.assertEqual(output, '') + + print('### ip -6 route show type unreachable') + output = check_output('ip -6 route show type unreachable') + print(output) + self.assertEqual(output, '') + + print('### ip -6 route show type prohibit') + output = check_output('ip -6 route show type prohibit') + print(output) + self.assertEqual(output, '') + remove_unit_from_networkd_path(['25-address-static.network']) check_output(*networkctl_cmd, 'reload', env=env) + time.sleep(1) self.wait_online(['dummy98:routable']) # check all routes managed by Manager are reconfigured print('### ip route show type blackhole') output = check_output('ip route show type blackhole') print(output) - self.assertRegex(output, 'blackhole 202.54.1.2 proto static') + self.assertIn('blackhole 202.54.1.2 proto static', output) print('### ip route show type unreachable') output = check_output('ip route show type unreachable') print(output) - self.assertRegex(output, 'unreachable 202.54.1.3 proto static') + self.assertIn('unreachable 202.54.1.3 proto static', output) print('### ip route show type prohibit') output = check_output('ip route show type prohibit') print(output) - self.assertRegex(output, 'prohibit 202.54.1.4 proto static') + self.assertIn('prohibit 202.54.1.4 proto static', output) + + print('### ip -6 route show type blackhole') + output = check_output('ip -6 route show type blackhole') + print(output) + self.assertIn('blackhole 2001:1234:5678::2 dev lo proto static', output) + + print('### ip -6 route show type unreachable') + output = check_output('ip -6 route show type unreachable') + print(output) + self.assertIn('unreachable 2001:1234:5678::3 dev lo proto static', output) + + print('### ip -6 route show type prohibit') + output = check_output('ip -6 route show type prohibit') + print(output) + self.assertIn('prohibit 2001:1234:5678::4 dev lo proto static', output) rc = call("ip link del dummy98") self.assertEqual(rc, 0) @@ -2290,6 +2411,21 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertEqual(output, '') + print('### ip -6 route show type blackhole') + output = check_output('ip -6 route show type blackhole') + print(output) + self.assertEqual(output, '') + + print('### ip -6 route show type unreachable') + output = check_output('ip -6 route show type unreachable') + print(output) + self.assertEqual(output, '') + + print('### ip -6 route show type prohibit') + output = check_output('ip -6 route show type prohibit') + print(output) + self.assertEqual(output, '') + @expectedFailureIfRTA_VIAIsNotSupported() def test_route_via_ipv6(self): copy_unit_to_networkd_unit_path('25-route-via-ipv6.network', '12-dummy.netdev') @@ -2386,6 +2522,17 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, '2004:da8:1::/64') + def test_ipv6_proxy_ndp(self): + copy_unit_to_networkd_unit_path('25-ipv6-proxy-ndp.network', '12-dummy.netdev') + start_networkd() + + self.wait_online(['dummy98:routable']) + + output = check_output('ip neighbor show proxy dev dummy98') + print(output) + for i in range(1,5): + self.assertRegex(output, f'2607:5300:203:5215:{i}::1 *proxy') + def test_neighbor_section(self): copy_unit_to_networkd_unit_path('25-neighbor-section.network', '12-dummy.netdev') start_networkd() @@ -2609,6 +2756,53 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): self.assertRegex(output, 'inet 192.168.10.30/24 brd 192.168.10.255 scope global test1') self.wait_operstate('test1', 'routable') + def _test_activation_policy(self, test): + self.setUp() + conffile = '25-activation-policy.network' + if test: + conffile = f'{conffile}.d/{test}.conf' + copy_unit_to_networkd_unit_path('11-dummy.netdev', conffile, dropins=False) + start_networkd() + + always = test.startswith('always') + if test == 'manual': + initial_up = 'UP' in check_output('ip link show test1') + else: + initial_up = not test.endswith('down') # note: default is up + expect_up = initial_up + next_up = not expect_up + + # if initial expected state is down, must wait for setup_state to reach configuring + # so systemd-networkd considers it 'activated' + setup_state = None if initial_up else 'configuring' + + for iteration in range(4): + with self.subTest(iteration=iteration, expect_up=expect_up): + operstate = 'routable' if expect_up else 'off' + self.wait_operstate('test1', operstate, setup_state=setup_state, setup_timeout=20) + setup_state = None + + if expect_up: + self.assertIn('UP', check_output('ip link show test1')) + self.assertIn('192.168.10.30/24', check_output('ip address show test1')) + self.assertIn('default via 192.168.10.1', check_output('ip route show')) + else: + self.assertIn('DOWN', check_output('ip link show test1')) + + if next_up: + check_output('ip link set dev test1 up') + else: + check_output('ip link set dev test1 down') + expect_up = initial_up if always else next_up + next_up = not next_up + + self.tearDown() + + def test_activation_policy(self): + for test in ['up', 'always-up', 'manual', 'always-down', 'down', '']: + with self.subTest(test=test): + self._test_activation_policy(test) + def test_domain(self): copy_unit_to_networkd_unit_path('12-dummy.netdev', '24-search-domain.network') start_networkd() @@ -2651,7 +2845,69 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): output = check_output('ip nexthop list dev veth99') print(output) - self.assertRegex(output, '192.168.5.1') + self.assertIn('id 1 via 192.168.5.1 dev veth99', output) + self.assertIn('id 2 via 2001:1234:5:8f63::2 dev veth99', output) + self.assertIn('id 3 dev veth99', output) + self.assertIn('id 4 dev veth99', output) + self.assertRegex(output, 'id 5 via 192.168.10.1 dev veth99 .*onlink') + self.assertRegex(output, r'id [0-9]* via 192.168.5.2 dev veth99') + + # kernel manages blackhole nexthops on lo + output = check_output('ip nexthop list dev lo') + print(output) + self.assertIn('id 6 blackhole', output) + self.assertIn('id 7 blackhole', output) + + output = check_output('ip route show dev veth99 10.10.10.10') + print(output) + self.assertEqual('10.10.10.10 nhid 1 via 192.168.5.1 proto static', output) + + output = check_output('ip route show dev veth99 10.10.10.11') + print(output) + self.assertEqual('10.10.10.11 nhid 2 via inet6 2001:1234:5:8f63::2 proto static', output) + + output = check_output('ip route show dev veth99 10.10.10.12') + print(output) + self.assertEqual('10.10.10.12 nhid 5 via 192.168.10.1 proto static onlink', output) + + output = check_output('ip -6 route show dev veth99 2001:1234:5:8f62::1') + print(output) + self.assertEqual('2001:1234:5:8f62::1 nhid 2 via 2001:1234:5:8f63::2 proto static metric 1024 pref medium', output) + + output = check_output('ip route show 10.10.10.13') + print(output) + self.assertEqual('blackhole 10.10.10.13 nhid 6 dev lo proto static', output) + + output = check_output('ip -6 route show 2001:1234:5:8f62::2') + print(output) + self.assertEqual('blackhole 2001:1234:5:8f62::2 nhid 7 dev lo proto static metric 1024 pref medium', output) + + remove_unit_from_networkd_path(['25-nexthop.network']) + copy_unit_to_networkd_unit_path('25-nexthop-nothing.network') + rc = call(*networkctl_cmd, 'reload', env=env) + self.assertEqual(rc, 0) + time.sleep(1) + + output = check_output('ip nexthop list dev veth99') + print(output) + self.assertEqual(output, '') + output = check_output('ip nexthop list dev lo') + print(output) + self.assertEqual(output, '') + + remove_unit_from_networkd_path(['25-nexthop-nothing.network']) + copy_unit_to_networkd_unit_path('25-nexthop.network') + rc = call(*networkctl_cmd, 'reload', env=env) + self.assertEqual(rc, 0) + time.sleep(1) + + rc = call('ip link del veth99') + self.assertEqual(rc, 0) + time.sleep(2) + + output = check_output('ip nexthop list dev lo') + print(output) + self.assertEqual(output, '') def test_qdisc(self): copy_unit_to_networkd_unit_path('25-qdisc-clsact-and-htb.network', '12-dummy.netdev', @@ -2883,6 +3139,7 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'OPER_STATE=routable') self.assertRegex(data, r'REQUIRED_FOR_ONLINE=yes') self.assertRegex(data, r'REQUIRED_OPER_STATE_FOR_ONLINE=routable') + self.assertRegex(data, r'ACTIVATION_POLICY=up') self.assertRegex(data, r'NETWORK_FILE=/run/systemd/network/state-file-tests.network') self.assertRegex(data, r'DNS=10.10.10.10#aaa.com 10.10.10.11:1111#bbb.com \[1111:2222::3333\]:1234#ccc.com') self.assertRegex(data, r'NTP=0.fedora.pool.ntp.org 1.fedora.pool.ntp.org') @@ -2891,7 +3148,6 @@ class NetworkdStateFileTests(unittest.TestCase, Utilities): self.assertRegex(data, r'LLMNR=no') self.assertRegex(data, r'MDNS=yes') self.assertRegex(data, r'DNSSEC=no') - self.assertRegex(data, r'ADDRESSES=192.168.(10.10|12.12)/24 192.168.(12.12|10.10)/24') check_output(*resolvectl_cmd, 'dns', 'dummy98', '10.10.10.12#ccc.com', '10.10.10.13', '1111:2222::3333', env=env) check_output(*resolvectl_cmd, 'domain', 'dummy98', 'hogehogehoge', '~foofoofoo', env=env) @@ -3146,7 +3402,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): print('### ip -6 route list table all dev bridge99') output = check_output('ip -6 route list table all dev bridge99') print(output) - self.assertRegex(output, 'ff00::/8 table local metric 256 pref medium') + self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium') self.assertEqual(call('ip link del test1'), 0) @@ -3165,7 +3421,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): print('### ip -6 route list table all dev bridge99') output = check_output('ip -6 route list table all dev bridge99') print(output) - self.assertRegex(output, 'ff00::/8 table local metric 256 (linkdown )?pref medium') + self.assertRegex(output, 'ff00::/8 table local (proto kernel )?metric 256 (linkdown )?pref medium') def test_bridge_configure_without_carrier(self): copy_unit_to_networkd_unit_path('26-bridge.netdev', '26-bridge-configure-without-carrier.network', @@ -3255,7 +3511,7 @@ class NetworkdBridgeTests(unittest.TestCase, Utilities): output = check_output('ip rule list table 100') print(output) - self.assertEqual(output, '0: from all to 8.8.8.8 lookup 100') + self.assertIn('0: from all to 8.8.8.8 lookup 100', output) class NetworkdLLDPTests(unittest.TestCase, Utilities): links = ['veth99'] @@ -3279,10 +3535,16 @@ class NetworkdLLDPTests(unittest.TestCase, Utilities): start_networkd() self.wait_online(['veth99:degraded', 'veth-peer:degraded']) - output = check_output(*networkctl_cmd, 'lldp', env=env) - print(output) - self.assertRegex(output, 'veth-peer') - self.assertRegex(output, 'veth99') + for trial in range(10): + if trial > 0: + time.sleep(1) + + output = check_output(*networkctl_cmd, 'lldp', env=env) + print(output) + if re.search(r'veth99 .* veth-peer', output): + break + else: + self.fail() class NetworkdRATests(unittest.TestCase, Utilities): links = ['veth99'] @@ -3429,8 +3691,7 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): 'dhcp-client-use-dns-yes.network', 'dhcp-client-use-domains.network', 'dhcp-client-vrf.network', - 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network', - 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network', + 'dhcp-client-with-ipv4ll.network', 'dhcp-client-with-static-address.network', 'dhcp-client.network', 'dhcp-server-decline.network', @@ -3926,7 +4187,6 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print('## ip address show vrf vrf99') output = check_output('ip address show vrf vrf99') print(output) - self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99') self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)') self.assertRegex(output, 'inet6 .* scope link') @@ -3934,7 +4194,6 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print('## ip address show dev veth99') output = check_output('ip address show dev veth99') print(output) - self.assertRegex(output, 'inet 169.254.[0-9]*.[0-9]*/16 brd 169.254.255.255 scope link veth99') self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') self.assertRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global (dynamic noprefixroute|noprefixroute dynamic)') self.assertRegex(output, 'inet6 .* scope link') @@ -3943,7 +4202,6 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): output = check_output('ip route show vrf vrf99') print(output) self.assertRegex(output, 'default via 192.168.5.1 dev veth99 proto dhcp src 192.168.5.') - self.assertRegex(output, '169.254.0.0/16 dev veth99 proto kernel scope link src 169.254') self.assertRegex(output, '192.168.5.0/24 dev veth99 proto kernel scope link src 192.168.5') self.assertRegex(output, '192.168.5.0/24 via 192.168.5.5 dev veth99 proto dhcp') self.assertRegex(output, '192.168.5.1 dev veth99 proto dhcp scope link src 192.168.5') @@ -3996,9 +4254,9 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print(output) self.assertRegex(output, 'onlink') - def test_dhcp_client_with_ipv4ll_fallback_with_dhcp_server(self): + def test_dhcp_client_with_ipv4ll_with_dhcp_server(self): copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', - 'dhcp-client-with-ipv4ll-fallback-with-dhcp-server.network') + 'dhcp-client-with-ipv4ll.network') start_networkd() self.wait_online(['veth-peer:carrier']) start_dnsmasq(lease_time='2m') @@ -4008,13 +4266,13 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print(output) output = check_output('ip -6 address show dev veth99 scope global dynamic') - self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic') + self.assertNotRegex(output, r'inet6 2600::[0-9a-f]+/128 scope global dynamic') output = check_output('ip -6 address show dev veth99 scope link') - self.assertRegex(output, 'inet6 .* scope link') + self.assertRegex(output, r'inet6 .* scope link') output = check_output('ip -4 address show dev veth99 scope global dynamic') - self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') + self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99') output = check_output('ip -4 address show dev veth99 scope link') - self.assertNotRegex(output, 'inet .* scope link') + self.assertNotRegex(output, r'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link') print('Wait for the dynamic address to be expired') time.sleep(130) @@ -4023,33 +4281,39 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities): print(output) output = check_output('ip -6 address show dev veth99 scope global dynamic') - self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic') + self.assertNotRegex(output, r'inet6 2600::[0-9a-f]+/128 scope global dynamic') output = check_output('ip -6 address show dev veth99 scope link') - self.assertRegex(output, 'inet6 .* scope link') + self.assertRegex(output, r'inet6 .* scope link') output = check_output('ip -4 address show dev veth99 scope global dynamic') - self.assertRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') + self.assertRegex(output, r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99') output = check_output('ip -4 address show dev veth99 scope link') - self.assertNotRegex(output, 'inet .* scope link') + self.assertNotRegex(output, r'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link') search_words_in_dnsmasq_log('DHCPOFFER', show_all=True) - def test_dhcp_client_with_ipv4ll_fallback_without_dhcp_server(self): + def test_dhcp_client_with_ipv4ll_without_dhcp_server(self): copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', - 'dhcp-client-with-ipv4ll-fallback-without-dhcp-server.network') + 'dhcp-client-with-ipv4ll.network') start_networkd() - self.wait_online(['veth99:degraded', 'veth-peer:routable']) + # we need to increase timeout above default, as this will need to wait for + # systemd-networkd to get the dhcpv4 transient failure event + self.wait_online(['veth99:degraded', 'veth-peer:routable'], timeout='60s') output = check_output('ip address show dev veth99') print(output) output = check_output('ip -6 address show dev veth99 scope global dynamic') - self.assertNotRegex(output, 'inet6 2600::[0-9a-f]*/128 scope global dynamic') + self.assertNotRegex(output, r'inet6 2600::[0-9a-f]+/128 scope global dynamic') output = check_output('ip -6 address show dev veth99 scope link') - self.assertRegex(output, 'inet6 .* scope link') + self.assertRegex(output, r'inet6 .* scope link') output = check_output('ip -4 address show dev veth99 scope global dynamic') - self.assertNotRegex(output, 'inet 192.168.5.[0-9]*/24 brd 192.168.5.255 scope global dynamic veth99') + self.assertNotRegex(output, r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic veth99') output = check_output('ip -4 address show dev veth99 scope link') - self.assertRegex(output, 'inet .* scope link') + self.assertRegex(output, r'inet 169\.254\.\d+\.\d+/16 brd 169\.254\.255\.255 scope link') + + start_dnsmasq(lease_time='2m') + self.wait_address('veth99', r'inet 192\.168\.5\.\d+/24 brd 192\.168\.5\.255 scope global dynamic', ipv='-4') + self.wait_address_dropped('veth99', r'inet 169\.254\.\d+\.\d+/16 brd 169\.255\.255\.255 scope link', scope='link', ipv='-4') def test_dhcp_client_route_remove_on_renew(self): copy_unit_to_networkd_unit_path('25-veth.netdev', 'dhcp-server-veth-peer.network', @@ -4201,6 +4465,7 @@ class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities): units = [ '25-veth.netdev', + 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix-client.network', 'ipv6ra-prefix.network' ] @@ -4221,14 +4486,45 @@ class NetworkdIPv6PrefixTests(unittest.TestCase, Utilities): start_networkd() self.wait_online(['veth99:routable', 'veth-peer:routable']) + output = check_output('ip address show dev veth-peer') + print(output) + self.assertIn('inet6 2001:db8:0:1:', output) + self.assertNotIn('inet6 2001:db8:0:2:', output) + output = check_output('ip -6 route show dev veth-peer') print(output) - self.assertRegex(output, '2001:db8:0:1::/64 proto ra') + self.assertIn('2001:db8:0:1::/64 proto ra', output) + self.assertNotIn('2001:db8:0:2::/64 proto ra', output) + self.assertIn('2001:db0:fff::/64 via ', output) + self.assertNotIn('2001:db1:fff::/64 via ', output) - output = check_output('ip addr show dev veth99') + output = check_output('ip address show dev veth99') print(output) - self.assertNotRegex(output, '2001:db8:0:1') - self.assertRegex(output, '2001:db8:0:2') + self.assertNotIn('inet6 2001:db8:0:1:', output) + self.assertIn('inet6 2001:db8:0:2:', output) + + def test_ipv6_route_prefix_deny_list(self): + copy_unit_to_networkd_unit_path('25-veth.netdev', 'ipv6ra-prefix-client-deny-list.network', 'ipv6ra-prefix.network') + + start_networkd() + self.wait_online(['veth99:routable', 'veth-peer:routable']) + + output = check_output('ip address show dev veth-peer') + print(output) + self.assertIn('inet6 2001:db8:0:1:', output) + self.assertNotIn('inet6 2001:db8:0:2:', output) + + output = check_output('ip -6 route show dev veth-peer') + print(output) + self.assertIn('2001:db8:0:1::/64 proto ra', output) + self.assertNotIn('2001:db8:0:2::/64 proto ra', output) + self.assertIn('2001:db0:fff::/64 via ', output) + self.assertNotIn('2001:db1:fff::/64 via ', output) + + output = check_output('ip address show dev veth99') + print(output) + self.assertNotIn('inet6 2001:db8:0:1:', output) + self.assertIn('inet6 2001:db8:0:2:', output) class NetworkdMTUTests(unittest.TestCase, Utilities): links = ['dummy98'] diff --git a/test/test-path-util/script.sh b/test/test-path-util/script.sh new file mode 100755 index 000000000..57c93e747 --- /dev/null +++ b/test/test-path-util/script.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +echo "$0 $@" +test "$(basename $0)" = "script.sh" || exit 1 +test "$1" = "--version" || exit 2 +echo "Life is good" diff --git a/src/test/test-systemd-tmpfiles.py b/test/test-systemd-tmpfiles.py similarity index 100% rename from src/test/test-systemd-tmpfiles.py rename to test/test-systemd-tmpfiles.py diff --git a/test/testsuite-06.units/load-systemd-test-module.service b/test/testsuite-06.units/load-systemd-test-module.service index 323a76c68..335f38c5b 100644 --- a/test/testsuite-06.units/load-systemd-test-module.service +++ b/test/testsuite-06.units/load-systemd-test-module.service @@ -8,7 +8,7 @@ Before=sysinit.target shutdown.target autorelabel.service ConditionSecurity=selinux [Service] -ExecStart=sh -x -c 'echo 0 >/sys/fs/selinux/enforce && cd /systemd-test-module && make -f /usr/share/selinux/devel/Makefile load' +ExecStart=sh -x -c 'echo 0 >/sys/fs/selinux/enforce && cd /systemd-test-module && make -f /usr/share/selinux/devel/Makefile clean load' Type=oneshot TimeoutSec=0 RemainAfterExit=yes diff --git a/test/udev-dmi-memory-id-test.sh b/test/udev-dmi-memory-id-test.sh new file mode 100755 index 000000000..e8b69245d --- /dev/null +++ b/test/udev-dmi-memory-id-test.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later + +set -e + +dmi_memory_id="$1" +input="$2" +expected="$3" + +output=$(mktemp --tmpdir "test-udev-dmi-memory-id.XXXXXXXXXX") +trap "rm '$output'" EXIT INT QUIT PIPE + +( + set -x + "$dmi_memory_id" -F "$input" >$output + diff -u "$output" "$expected" +) diff --git a/test/units/testsuite-13.sh b/test/units/testsuite-13.sh index 969ca4a8d..1844323d2 100755 --- a/test/units/testsuite-13.sh +++ b/test/units/testsuite-13.sh @@ -93,6 +93,29 @@ if echo test >> /run/host/os-release; then exit 1; fi fi } +function check_machinectl_bind { + local _cmd='for i in $(seq 1 20); do if test -f /tmp/marker; then exit 0; fi; sleep 0.5; done; exit 1;' + + cat < /run/systemd/system/nspawn_machinectl_bind.service +[Service] +Type=notify +ExecStart=systemd-nspawn $SUSE_OPTS -D /testsuite-13.nc-container --notify-ready=no /bin/sh -x -e -c "$_cmd" +EOF + + systemctl start nspawn_machinectl_bind.service + + touch /tmp/marker + + machinectl bind --mkdir testsuite-13.nc-container /tmp/marker + + while systemctl show -P SubState nspawn_machinectl_bind.service | grep -q running + do + sleep 0.1 + done + + return $(systemctl show -P ExecMainStatus nspawn_machinectl_bind.service) +} + function run { if [[ "$1" = "yes" && "$is_v2_supported" = "no" ]]; then printf "Unified cgroup hierarchy is not supported. Skipping.\n" >&2 @@ -186,4 +209,6 @@ for api_vfs_writable in yes no network; do run yes yes $api_vfs_writable done +check_machinectl_bind + touch /testok diff --git a/test/units/testsuite-15.sh b/test/units/testsuite-15.sh index b872a24c2..23a39bf09 100755 --- a/test/units/testsuite-15.sh +++ b/test/units/testsuite-15.sh @@ -124,6 +124,33 @@ EOF clear_services test15-a test15-b test15-c } +test_linked_units () { + echo "Testing linked units..." + echo "*** test linked unit (same basename)" + + create_service test15-a + mv /etc/systemd/system/test15-a.service / + ln -s /test15-a.service /etc/systemd/system/ + ln -s test15-a.service /etc/systemd/system/test15-b.service + + check_ok test15-a Names test15-a.service + check_ok test15-a Names test15-b.service + + echo "*** test linked unit (cross basename)" + + mv /test15-a.service /test15-a@.scope + ln -fs /test15-a@.scope /etc/systemd/system/test15-a.service + systemctl daemon-reload + + check_ok test15-a Names test15-a.service + check_ok test15-a Names test15-b.service + check_ko test15-a Names test15-a@ # test15-a@.scope is the symlink target. + # Make sure it is completely ignored. + + rm /test15-a@.scope + clear_services test15-a test15-b +} + test_hierarchical_dropins () { echo "Testing hierarchical dropins..." echo "*** test service.d/ top level drop-in" @@ -465,6 +492,7 @@ test_invalid_dropins () { } test_basic_dropins +test_linked_units test_hierarchical_dropins test_template_dropins test_alias_dropins diff --git a/test/units/testsuite-16.sh b/test/units/testsuite-16.sh index 68e556124..8388ef7a5 100755 --- a/test/units/testsuite-16.sh +++ b/test/units/testsuite-16.sh @@ -37,7 +37,7 @@ wait_for success_runtime wait_for success_stop # These ensure that EXTEND_TIMEOUT_USEC will still timeout in the -# approprate stage, after the stage limit, when the EXTEND_TIMEOUT_USEC +# appropriate stage, after the stage limit, when the EXTEND_TIMEOUT_USEC # message isn't sent within the extend timeout interval. wait_for fail_start startfail diff --git a/test/units/testsuite-17.01.sh b/test/units/testsuite-17.01.sh new file mode 100755 index 000000000..573ad4107 --- /dev/null +++ b/test/units/testsuite-17.01.sh @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +set -ex +set -o pipefail + +mkdir -p /run/udev/rules.d/ + +rm -f /run/udev/rules.d/50-testsuite.rules +udevadm control --reload +udevadm trigger /dev/sda + +while : ; do + ( + udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=foobar.service + udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=waldo.service + systemctl show -p WantedBy foobar.service | grep -q -v sda + systemctl show -p WantedBy waldo.service | grep -q -v sda + ) && break + + sleep .5 +done + +cat > /run/udev/rules.d/50-testsuite.rules < /run/udev/rules.d/50-testsuite.rules < /run/udev/rules.d/50-testsuite.rules < "${test_rule}" + echo "event_timeout=30" >> /etc/udev/udev.conf + echo "timeout_signal=SIGABRT" >> /etc/udev/udev.conf + + systemctl restart systemd-udevd.service +} + +teardown() { + set +e + + mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf + rm -f "$test_rule" + systemctl restart systemd-udevd.service +} + +run_test() { + since="$(date +%T)" + + echo add > /sys/class/net/lo/uevent + + for n in {1..20}; do + sleep 5 + if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then + return 0 + fi + done + + return 1 +} + +trap teardown EXIT + +setup +run_test + +exit 0 diff --git a/test/units/testsuite-17.04.sh b/test/units/testsuite-17.04.sh new file mode 100755 index 000000000..c799936c0 --- /dev/null +++ b/test/units/testsuite-17.04.sh @@ -0,0 +1,64 @@ +#!/bin/bash +set -ex +set -o pipefail + +mkdir -p /run/udev/rules.d/ + +! test -f /run/udev/tags/added/c1:3 && + ! test -f /run/udev/tags/changed/c1:3 && + udevadm info /dev/null | grep -q -v 'E: TAGS=.*:added:.*' && + udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' && + udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' && + udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' + +cat > /run/udev/rules.d/50-testsuite.rules < /run/udev/rules.d/50-testsuite.rules </failed -while : ; do - ( - udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=foobar.service - udevadm info /dev/sda | grep -q -v SYSTEMD_WANTS=waldo.service - systemctl show -p WantedBy foobar.service | grep -q -v sda - systemctl show -p WantedBy waldo.service | grep -q -v sda - ) && break - - sleep .5 +for t in ${0%.sh}.*.sh; do + echo "Running $t"; ./$t done -cat > /run/udev/rules.d/50-testsuite.rules < /run/udev/rules.d/50-testsuite.rules </testok - -exit 0 +touch /testok +rm /failed diff --git a/test/units/testsuite-22.10.sh b/test/units/testsuite-22.10.sh new file mode 100755 index 000000000..5ec297fbf --- /dev/null +++ b/test/units/testsuite-22.10.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +set -e +set -x +set -o pipefail + +systemd-tmpfiles --create - <&2' +cmp /tmp/stdout </testok diff --git a/test/units/testsuite-29.service b/test/units/testsuite-29.service index 90c2187bd..900b99f77 100644 --- a/test/units/testsuite-29.service +++ b/test/units/testsuite-29.service @@ -1,5 +1,5 @@ [Unit] -Description=TEST-29-UDEV-ID_RENAMING +Description=TEST-29-PORTABLE [Service] ExecStartPre=rm -f /failed /testok diff --git a/test/units/testsuite-29.sh b/test/units/testsuite-29.sh index 5c6255689..b5b05b42d 100755 --- a/test/units/testsuite-29.sh +++ b/test/units/testsuite-29.sh @@ -1,58 +1,67 @@ #!/usr/bin/env bash +# -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*- +# ex: ts=8 sw=4 sts=4 et filetype=sh set -ex set -o pipefail -mkdir -p /run/udev/rules.d/ +export SYSTEMD_LOG_LEVEL=debug -cat > /run/udev/rules.d/50-testsuite.rules < /testok diff --git a/test/units/testsuite-36.sh b/test/units/testsuite-36.sh index aed938437..f5579ce82 100755 --- a/test/units/testsuite-36.sh +++ b/test/units/testsuite-36.sh @@ -221,7 +221,7 @@ else pid1StartUnitWithStrace $testUnit systemctlCheckNUMAProperties $testUnit "default" "0" pid1StopUnit $testUnit - # Maks must be ignored + # Mask must be ignored grep "set_mempolicy(MPOL_DEFAULT, NULL" $straceLog echo "Unit file NUMAPolicy support - Bind policy w/o mask" @@ -276,7 +276,7 @@ else pid1StartUnitWithStrace $testUnit systemctlCheckNUMAProperties $testUnit "local" "0" pid1StopUnit $testUnit - # Maks must be ignored + # Mask must be ignored grep -E "set_mempolicy\((MPOL_LOCAL|0x4 [^,]*), NULL" $straceLog echo "Unit file CPUAffinity=NUMA support" diff --git a/test/units/testsuite-49-namespaced.service b/test/units/testsuite-49-namespaced.service new file mode 100644 index 000000000..722dbe246 --- /dev/null +++ b/test/units/testsuite-49-namespaced.service @@ -0,0 +1,12 @@ +[Service] +RuntimeMaxSec=300 +# Adding a new mounts at runtime works if the unit is in the active state, +# so use Type=notify to make sure there's no race condition in the test +Type=notify +RemainAfterExit=yes +MountAPIVFS=yes +PrivateTmp=yes +BindPaths=/run/testservice-49-fixed:/tmp/testfile_fixed +InaccessiblePaths=/run/inaccessible +ExecStartPre=grep -q -F MARKER_FIXED /tmp/testfile_fixed +ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER_RUNTIME /tmp/testfile_runtime; do sleep 0.1; done; test ! -f /run/inaccessible/testfile_fixed' diff --git a/test/units/testsuite-49-non-namespaced.service b/test/units/testsuite-49-non-namespaced.service new file mode 100644 index 000000000..e86c64d12 --- /dev/null +++ b/test/units/testsuite-49-non-namespaced.service @@ -0,0 +1,5 @@ +[Service] +RuntimeMaxSec=10 +Type=notify +RemainAfterExit=yes +ExecStart=/bin/sh -c 'systemd-notify --ready; while ! grep -q -F MARKER_RUNTIME /tmp/testfile_runtime; do sleep 0.1; done; exit 0' diff --git a/test/units/testsuite-49.service b/test/units/testsuite-49.service index f47177106..9475109ca 100644 --- a/test/units/testsuite-49.service +++ b/test/units/testsuite-49.service @@ -1,6 +1,7 @@ [Unit] -Description=TEST-49-UDEV-EVENT-TIMEOUT +Description=TEST-49-RUNTIME-BIND-PATHS [Service] +ExecStartPre=rm -f /failed /testok ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh Type=oneshot diff --git a/test/units/testsuite-49.sh b/test/units/testsuite-49.sh index ffa980164..07bb20d99 100755 --- a/test/units/testsuite-49.sh +++ b/test/units/testsuite-49.sh @@ -1,46 +1,42 @@ #!/usr/bin/env bash - set -ex -test_rule="/run/udev/rules.d/49-test.rules" +echo "MARKER_FIXED" > /run/testservice-49-fixed +mkdir -p /run/inaccessible -setup() { - mkdir -p "${test_rule%/*}" - cp -f /etc/udev/udev.conf /etc/udev/udev.conf.bckp - echo 'KERNEL=="lo", SUBSYSTEM=="net", PROGRAM=="/bin/sleep 60"' > "${test_rule}" - echo "event_timeout=30" >> /etc/udev/udev.conf - echo "timeout_signal=SIGABRT" >> /etc/udev/udev.conf +systemctl start testsuite-49-namespaced.service - systemctl restart systemd-udevd.service -} +# Ensure that inaccessible paths aren't bypassed by the runtime setup +set +e +systemctl bind --mkdir testsuite-49-namespaced.service /run/testservice-49-fixed /run/inaccessible/testfile_fixed && exit 1 +set -e -teardown() { - set +e +echo "MARKER_RUNTIME" > /run/testservice-49-runtime - mv -f /etc/udev/udev.conf.bckp /etc/udev/udev.conf - rm -f "$test_rule" - systemctl restart systemd-udevd.service -} +systemctl bind --mkdir testsuite-49-namespaced.service /run/testservice-49-runtime /tmp/testfile_runtime -run_test() { - since="$(date +%T)" +while systemctl show -P SubState testsuite-49-namespaced.service | grep -q running +do + sleep 0.1 +done - echo add > /sys/class/net/lo/uevent +systemctl is-active testsuite-49-namespaced.service - for n in {1..20}; do - sleep 5 - if coredumpctl --since "$since" --no-legend --no-pager | grep /bin/udevadm ; then - return 0 - fi - done +# Now test that systemctl bind fails when attempted on a non-namespaced unit +systemctl start testsuite-49-non-namespaced.service - return 1 -} +set +e +systemctl bind --mkdir testsuite-49-non-namespaced.service /run/testservice-49-runtime /tmp/testfile_runtime && exit 1 +set -e -trap teardown EXIT +while systemctl show -P SubState testsuite-49-non-namespaced.service | grep -q running +do + sleep 0.1 +done -setup -run_test +set +e +systemctl is-active testsuite-49-non-namespaced.service && exit 1 +set -e echo OK > /testok diff --git a/test/units/testsuite-50.sh b/test/units/testsuite-50.sh index d615ac2ea..b4a5fee84 100755 --- a/test/units/testsuite-50.sh +++ b/test/units/testsuite-50.sh @@ -24,8 +24,8 @@ fi trap cleanup EXIT -cp /usr/share/minimal.* "${image_dir}/" -image="${image_dir}/minimal" +cp /usr/share/minimal* "${image_dir}/" +image="${image_dir}/minimal_0" roothash="$(cat ${image}.roothash)" os_release=$(test -e /etc/os-release && echo /etc/os-release || echo /usr/lib/os-release) @@ -205,6 +205,51 @@ grep -q -F "MARKER=1" ${image_dir}/result/c grep -F "squashfs" ${image_dir}/result/c | grep -q -F "noatime" grep -F "squashfs" ${image_dir}/result/c | grep -q -F -v "nosuid" +# Adding a new mounts at runtime works if the unit is in the active state, +# so use Type=notify to make sure there's no race condition in the test +cat > /run/systemd/system/testservice-50d.service </run/systemd/system/testservice-50e.service </testok exit 0 diff --git a/test/units/testsuite-56-slowgrowth.sh b/test/units/testsuite-55-slowgrowth.sh similarity index 100% rename from test/units/testsuite-56-slowgrowth.sh rename to test/units/testsuite-55-slowgrowth.sh diff --git a/test/units/testsuite-55-testbloat.service b/test/units/testsuite-55-testbloat.service new file mode 100644 index 000000000..7aa794b9f --- /dev/null +++ b/test/units/testsuite-55-testbloat.service @@ -0,0 +1,9 @@ +[Unit] +Description=Create a lot of memory pressure + +[Service] +# A VERY small memory.high will cause the script (trying to use a lot of memory) +# to throttle and be put under heavy pressure. +MemoryHigh=1M +Slice=testsuite-55-workload.slice +ExecStart=/usr/lib/systemd/tests/testdata/units/testsuite-55-slowgrowth.sh diff --git a/test/units/testsuite-56-testchill.service b/test/units/testsuite-55-testchill.service similarity index 68% rename from test/units/testsuite-56-testchill.service rename to test/units/testsuite-55-testchill.service index 6cae3d852..aca6bc4ab 100644 --- a/test/units/testsuite-56-testchill.service +++ b/test/units/testsuite-55-testchill.service @@ -2,5 +2,5 @@ Description=No memory pressure [Service] -Slice=testsuite-56-workload.slice +Slice=testsuite-55-workload.slice ExecStart=sleep infinity diff --git a/test/units/testsuite-55-testmunch.service b/test/units/testsuite-55-testmunch.service new file mode 100644 index 000000000..457e4a587 --- /dev/null +++ b/test/units/testsuite-55-testmunch.service @@ -0,0 +1,7 @@ +[Unit] +Description=Create some memory pressure + +[Service] +MemoryHigh=2M +Slice=testsuite-55-workload.slice +ExecStart=/usr/lib/systemd/tests/testdata/units/testsuite-55-slowgrowth.sh diff --git a/test/units/testsuite-56-workload.slice b/test/units/testsuite-55-workload.slice similarity index 81% rename from test/units/testsuite-56-workload.slice rename to test/units/testsuite-55-workload.slice index 3d542ec2b..8c32b2809 100644 --- a/test/units/testsuite-56-workload.slice +++ b/test/units/testsuite-55-workload.slice @@ -7,4 +7,4 @@ MemoryAccounting=true IOAccounting=true TasksAccounting=true ManagedOOMMemoryPressure=kill -ManagedOOMMemoryPressureLimitPercent=50% +ManagedOOMMemoryPressureLimit=1% diff --git a/test/units/testsuite-55.service b/test/units/testsuite-55.service index 2127a4db7..592e9d5be 100644 --- a/test/units/testsuite-55.service +++ b/test/units/testsuite-55.service @@ -1,7 +1,7 @@ [Unit] -Description=TESTSUITE-55-UDEV-TAGS +Description=TESTSUITE-55-OOMD [Service] -ExecStartPre=rm -f /failed /testok +ExecStartPre=rm -f /failed /skipped /testok ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh Type=oneshot diff --git a/test/units/testsuite-55.sh b/test/units/testsuite-55.sh index ffceefb6a..f7896ada4 100755 --- a/test/units/testsuite-55.sh +++ b/test/units/testsuite-55.sh @@ -1,65 +1,75 @@ -#!/bin/bash +#!/usr/bin/env bash set -ex set -o pipefail -mkdir -p /run/udev/rules.d/ +systemd-analyze log-level debug +systemd-analyze log-target console -! test -f /run/udev/tags/added/c1:3 && - ! test -f /run/udev/tags/changed/c1:3 && - udevadm info /dev/null | grep -q -v 'E: TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' && - udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' +# Loose checks to ensure the environment has the necessary features for systemd-oomd +[[ -e /proc/pressure ]] || echo "no PSI" >> /skipped +cgroup_type=$(stat -fc %T /sys/fs/cgroup/) +if [[ "$cgroup_type" != *"cgroup2"* ]] && [[ "$cgroup_type" != *"0x63677270"* ]]; then + echo "no cgroup2" >> /skipped +fi +if [ ! -f /usr/lib/systemd/systemd-oomd ] && [ ! -f /lib/systemd/systemd-oomd ]; then + echo "no oomd" >> /skipped +fi +[[ -e /skipped ]] && exit 0 || true -cat > /run/udev/rules.d/50-testsuite.rules <> /etc/systemd/oomd.conf -while : ; do - test -f /run/udev/tags/added/c1:3 && - ! test -f /run/udev/tags/changed/c1:3 && - udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' && - udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' && +systemctl start testsuite-55-testchill.service +systemctl start testsuite-55-testbloat.service + +# Verify systemd-oomd is monitoring the expected units +oomctl | grep "/testsuite-55-workload.slice" +oomctl | grep "1.00%" +oomctl | grep "Default Memory Pressure Duration: 5s" + +# systemd-oomd watches for elevated pressure for 5 seconds before acting. +# It can take time to build up pressure so either wait 2 minutes or for the service to fail. +timeout=$(date -ud "2 minutes" +%s) +while [[ $(date -u +%s) -le $timeout ]]; do + if ! systemctl status testsuite-55-testbloat.service; then break - - sleep .5 + fi + sleep 5 done -udevadm control --reload -udevadm trigger -c change /dev/null +# testbloat should be killed and testchill should be fine +if systemctl status testsuite-55-testbloat.service; then exit 42; fi +if ! systemctl status testsuite-55-testchill.service; then exit 24; fi -while : ; do - test -f /run/udev/tags/added/c1:3 && - test -f /run/udev/tags/changed/c1:3 && - udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' && - udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' && - break +# only run this portion of the test if we can set xattrs +if setfattr -n user.xattr_test -v 1 /sys/fs/cgroup/; then + sleep 120 # wait for systemd-oomd kill cool down and elevated memory pressure to come down - sleep .5 -done + mkdir -p /etc/systemd/system/testsuite-55-testbloat.service.d/ + echo "[Service]" > /etc/systemd/system/testsuite-55-testbloat.service.d/override.conf + echo "ManagedOOMPreference=avoid" >> /etc/systemd/system/testsuite-55-testbloat.service.d/override.conf -udevadm control --reload -udevadm trigger -c add /dev/null + systemctl daemon-reload + systemctl start testsuite-55-testchill.service + systemctl start testsuite-55-testmunch.service + systemctl start testsuite-55-testbloat.service -while : ; do - test -f /run/udev/tags/added/c1:3 && - test -f /run/udev/tags/changed/c1:3 && - udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' && - udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' && - udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' && - break + timeout=$(date -ud "2 minutes" +%s) + while [[ $(date -u +%s) -le $timeout ]]; do + if ! systemctl status testsuite-55-testmunch.service; then + break + fi + sleep 5 + done - sleep .5 -done + # testmunch should be killed since testbloat had the avoid xattr on it + if ! systemctl status testsuite-55-testbloat.service; then exit 25; fi + if systemctl status testsuite-55-testmunch.service; then exit 43; fi + if ! systemctl status testsuite-55-testchill.service; then exit 24; fi +fi + +systemd-analyze log-level info echo OK > /testok diff --git a/test/units/testsuite-56-testbloat.service b/test/units/testsuite-56-testbloat.service deleted file mode 100644 index 40cf5a9f3..000000000 --- a/test/units/testsuite-56-testbloat.service +++ /dev/null @@ -1,9 +0,0 @@ -[Unit] -Description=Create a lot of memory pressure - -[Service] -# A very small memory.high will cause the script (trying to use a lot of memory) -# to throttle and be put under heavy pressure -MemoryHigh=2M -Slice=testsuite-56-workload.slice -ExecStart=/usr/lib/systemd/tests/testdata/units/testsuite-56-slowgrowth.sh diff --git a/test/units/testsuite-56.service b/test/units/testsuite-56.service deleted file mode 100644 index b53b0905d..000000000 --- a/test/units/testsuite-56.service +++ /dev/null @@ -1,7 +0,0 @@ -[Unit] -Description=TESTSUITE-56-OOMD - -[Service] -ExecStartPre=rm -f /failed /skipped /testok -ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh -Type=oneshot diff --git a/test/units/testsuite-56.sh b/test/units/testsuite-56.sh deleted file mode 100755 index 37d62d943..000000000 --- a/test/units/testsuite-56.sh +++ /dev/null @@ -1,42 +0,0 @@ -#!/usr/bin/env bash -set -ex -set -o pipefail - -systemd-analyze log-level debug -systemd-analyze log-target console - -# Loose checks to ensure the environment has the necessary features for systemd-oomd -[[ "$( awk '/SwapTotal/ { print $2 }' /proc/meminfo )" != "0" ]] || echo "no swap" >> /skipped -[[ -e /proc/pressure ]] || echo "no PSI" >> /skipped -cgroup_type=$(stat -fc %T /sys/fs/cgroup/) -if [[ "$cgroup_type" != *"cgroup2"* ]] && [[ "$cgroup_type" != *"0x63677270"* ]]; then - echo "no cgroup2" >> /skipped -fi -[[ -e /skipped ]] && exit 0 || true - -systemctl start testsuite-56-testbloat.service -systemctl start testsuite-56-testchill.service - -# Verify systemd-oomd is monitoring the expected units -oomctl | grep "/testsuite-56-workload.slice" -oomctl | grep "50%" - -# systemd-oomd watches for elevated pressure for 30 seconds before acting. -# It can take time to build up pressure so either wait 5 minutes or for the service to fail. -timeout=$(date -ud "5 minutes" +%s) -while [[ $(date -u +%s) -le $timeout ]]; do - if ! systemctl status testsuite-56-testbloat.service; then - break - fi - sleep 15 -done - -# testbloat should be killed and testchill should be fine -if systemctl status testsuite-56-testbloat.service; then exit 42; fi -if ! systemctl status testsuite-56-testchill.service; then exit 24; fi - -systemd-analyze log-level info - -echo OK > /testok - -exit 0 diff --git a/tmpfiles.d/README b/tmpfiles.d/README new file mode 100644 index 000000000..b42cec274 --- /dev/null +++ b/tmpfiles.d/README @@ -0,0 +1,8 @@ +Files in this directory contain configuration for systemd-tmpfiles, a program +to create, delete, and clean up volatile and temporary files and directories. + +See man:tmpfiles.d(5) for explanation of the configuration file format, and +man:systemd-tmpfiles(8) for a description of when and how this configuration is +applied. + +Use 'systemd-analyze cat-config tmpfiles.d' to display the effective config. diff --git a/tmpfiles.d/meson.build b/tmpfiles.d/meson.build index 7322460db..d5d4bbc9e 100644 --- a/tmpfiles.d/meson.build +++ b/tmpfiles.d/meson.build @@ -2,19 +2,20 @@ enable_tmpfiles = conf.get('ENABLE_TMPFILES') == 1 -tmpfiles = [['home.conf', ''], - ['journal-nocow.conf', ''], - ['systemd-nologin.conf', 'HAVE_PAM'], - ['systemd-nspawn.conf', 'ENABLE_MACHINED'], - ['systemd-tmp.conf', ''], - ['portables.conf', 'ENABLE_PORTABLED'], - ['systemd-pstore.conf', 'ENABLE_PSTORE'], - ['tmp.conf', ''], - ['x11.conf', ''], - ['legacy.conf', 'HAVE_SYSV_COMPAT'], - ] +files = [['README', ''], + ['home.conf', ''], + ['journal-nocow.conf', ''], + ['systemd-nologin.conf', 'HAVE_PAM'], + ['systemd-nspawn.conf', 'ENABLE_MACHINED'], + ['systemd-tmp.conf', ''], + ['portables.conf', 'ENABLE_PORTABLED'], + ['systemd-pstore.conf', 'ENABLE_PSTORE'], + ['tmp.conf', ''], + ['x11.conf', ''], + ['legacy.conf', 'HAVE_SYSV_COMPAT'], + ] -foreach pair : tmpfiles +foreach pair : files if not enable_tmpfiles # do nothing elif pair[1] == '' or conf.get(pair[1]) == 1 diff --git a/tmpfiles.d/static-nodes-permissions.conf.in b/tmpfiles.d/static-nodes-permissions.conf.in index 50cffe2cd..e5aa8fdb2 100644 --- a/tmpfiles.d/static-nodes-permissions.conf.in +++ b/tmpfiles.d/static-nodes-permissions.conf.in @@ -15,3 +15,5 @@ z /dev/loop-control 0660 - disk - z /dev/net/tun 0666 - - - z /dev/fuse 0666 - - - z /dev/kvm @DEV_KVM_MODE@ - kvm - +z /dev/vhost-net @DEV_KVM_MODE@ - kvm - +z /dev/vhost-vsock @DEV_KVM_MODE@ - kvm - diff --git a/tools/add-git-hook.sh b/tools/add-git-hook.sh index 5b1bf1721..66bbcd64e 100755 --- a/tools/add-git-hook.sh +++ b/tools/add-git-hook.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu cd "$MESON_SOURCE_ROOT" diff --git a/tools/autosuspend-update.sh b/tools/autosuspend-update.sh deleted file mode 100755 index a4f99eb6b..000000000 --- a/tools/autosuspend-update.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh -set -eu - -cd "$1" - -(curl -L 'https://chromium.googlesource.com/chromiumos/platform2/+/master/power_manager/udev/gen_autosuspend_rules.py?format=TEXT'; echo) \ - | base64 -d > gen_autosuspend_rules.py diff --git a/tools/check-api-docs.sh b/tools/check-api-docs.sh index 1094101e0..283e7a64d 100755 --- a/tools/check-api-docs.sh +++ b/tools/check-api-docs.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu sd_good=0 diff --git a/tools/check-compilation.sh b/tools/check-compilation.sh index ce39e1684..c2fe3aa5c 100755 --- a/tools/check-compilation.sh +++ b/tools/check-compilation.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu "$@" '-' -o/dev/null /dev/null || exit 77 diff --git a/tools/check-help.sh b/tools/check-help.sh index efe7ed4e5..721dec4c6 100755 --- a/tools/check-help.sh +++ b/tools/check-help.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu export SYSTEMD_LOG_LEVEL=info diff --git a/tools/choose-default-locale.sh b/tools/choose-default-locale.sh index da9768ad7..a5158cf7c 100755 --- a/tools/choose-default-locale.sh +++ b/tools/choose-default-locale.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -e # Fedora uses C.utf8 but Debian uses C.UTF-8 diff --git a/tools/chromiumos/gen_autosuspend_rules.py b/tools/chromiumos/gen_autosuspend_rules.py index 8bb25a1cc..6e167f60f 100644 --- a/tools/chromiumos/gen_autosuspend_rules.py +++ b/tools/chromiumos/gen_autosuspend_rules.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright 2017 The Chromium OS Authors. All rights reserved. @@ -12,8 +12,6 @@ resulting rules file is installed on the device, the script itself is not. """ -from __future__ import print_function - # List of USB devices (vendorid:productid) for which it is safe to enable # autosuspend. USB_IDS = [] diff --git a/tools/coverity.sh b/tools/coverity.sh index 5d3b7e291..f140b7817 100755 --- a/tools/coverity.sh +++ b/tools/coverity.sh @@ -1,4 +1,5 @@ #!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later # The official unmodified version of the script can be found at # https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh @@ -22,17 +23,11 @@ echo -e "\033[33;1mNote: COVERITY_SCAN_PROJECT_NAME and COVERITY_SCAN_TOKEN are [ -z "$COVERITY_SCAN_BUILD_COMMAND" ] && echo "ERROR: COVERITY_SCAN_BUILD_COMMAND must be set" && exit 1 [ -z "$COVERITY_SCAN_TOKEN" ] && echo "ERROR: COVERITY_SCAN_TOKEN must be set" && exit 1 -# Do not run on pull requests -if [ "${TRAVIS_PULL_REQUEST}" = "true" ]; then - echo -e "\033[33;1mINFO: Skipping Coverity Analysis: branch is a pull request.\033[0m" - exit 0 -fi - # Verify this branch should run -if [[ "${TRAVIS_BRANCH^^}" =~ "${COVERITY_SCAN_BRANCH_PATTERN^^}" ]]; then - echo -e "\033[33;1mCoverity Scan configured to run on branch ${TRAVIS_BRANCH}\033[0m" +if [[ "${CURRENT_REF^^}" =~ "${COVERITY_SCAN_BRANCH_PATTERN^^}" ]]; then + echo -e "\033[33;1mCoverity Scan configured to run on branch ${CURRENT_REF}\033[0m" else - echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${TRAVIS_BRANCH}\033[0m" + echo -e "\033[33;1mCoverity Scan NOT configured to run on branch ${CURRENT_REF}\033[0m" exit 1 fi diff --git a/tools/find-build-dir.sh b/tools/find-build-dir.sh index fb8a1c17a..e449b6e86 100755 --- a/tools/find-build-dir.sh +++ b/tools/find-build-dir.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -e # Try to guess the build directory: diff --git a/travis-ci/tools/get-coverity.sh b/tools/get-coverity.sh similarity index 96% rename from travis-ci/tools/get-coverity.sh rename to tools/get-coverity.sh index 3634e57ad..8f84aec80 100755 --- a/travis-ci/tools/get-coverity.sh +++ b/tools/get-coverity.sh @@ -1,4 +1,5 @@ #!/bin/bash +# SPDX-License-Identifier: LGPL-2.1-or-later # Download and extract coverity tool diff --git a/tools/git-contrib.sh b/tools/git-contrib.sh index f6fccd604..4b680d280 100755 --- a/tools/git-contrib.sh +++ b/tools/git-contrib.sh @@ -1,6 +1,8 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu -git shortlog -s `git describe --abbrev=0 --match 'v[0-9][0-9][0-9]'`.. | \ - awk '{ $1=""; print $0 "," }' | \ +tag="$(git describe --abbrev=0 --match 'v[0-9][0-9][0-9]')" +git log --pretty=tformat:%aN --author=noreply@weblate.org --invert-grep -s "${tag}.." | \ + sed 's/ / /g; s/--/-/g; s/.*/ \0,/' | sort -u diff --git a/tools/hwdb-update.sh b/tools/hwdb-update.sh deleted file mode 100755 index 39efd7519..000000000 --- a/tools/hwdb-update.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/sh -set -eu - -cd "$1" - -unset permissive -if [ "${2:-}" = "-p" ]; then - permissive=1 - shift -else - permissive=0 -fi - -if [ "${2:-}" != "-n" ]; then ( - [ -z "$permissive" ] || set +e - set -x - - curl -L -o usb.ids 'http://www.linux-usb.org/usb.ids' - curl -L -o pci.ids 'http://pci-ids.ucw.cz/v2.2/pci.ids' - curl -L -o ma-large.txt 'http://standards-oui.ieee.org/oui/oui.txt' - curl -L -o ma-medium.txt 'http://standards-oui.ieee.org/oui28/mam.txt' - curl -L -o ma-small.txt 'http://standards-oui.ieee.org/oui36/oui36.txt' - curl -L -o pnp_id_registry.html 'https://uefi.org/uefi-pnp-export' - curl -L -o acpi_id_registry.html 'https://uefi.org/uefi-acpi-export' -) fi - -set -x -./acpi-update.py >20-acpi-vendor.hwdb.base -patch -p0 -o- 20-acpi-vendor.hwdb.base <20-acpi-vendor.hwdb.patch >20-acpi-vendor.hwdb -! diff -u 20-acpi-vendor.hwdb.base 20-acpi-vendor.hwdb >20-acpi-vendor.hwdb.patch - -./ids_parser.py diff --git a/tools/meson-apply-m4.sh b/tools/meson-apply-m4.sh index 5fad8cd94..7b4801ff9 100755 --- a/tools/meson-apply-m4.sh +++ b/tools/meson-apply-m4.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu CONFIG=$1 diff --git a/tools/meson-build.sh b/tools/meson-build.sh index dea554177..26f995dfc 100755 --- a/tools/meson-build.sh +++ b/tools/meson-build.sh @@ -1,4 +1,5 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eux src="$1" diff --git a/tools/meson-make-symlink.sh b/tools/meson-make-symlink.sh index cdd521412..96f589228 100755 --- a/tools/meson-make-symlink.sh +++ b/tools/meson-make-symlink.sh @@ -1,12 +1,19 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu +if [ "${MESON_INSTALL_QUIET:-0}" = 1 ] ; then + VERBOSE="" +else + VERBOSE="v" +fi + # this is needed mostly because $DESTDIR is provided as a variable, # and we need to create the target directory... -mkdir -vp "$(dirname "${DESTDIR:-}$2")" +mkdir -${VERBOSE}p "$(dirname "${DESTDIR:-}$2")" if [ "$(dirname $1)" = . -o "$(dirname $1)" = .. ]; then - ln -vfs -T -- "$1" "${DESTDIR:-}$2" + ln -${VERBOSE}fs -T -- "$1" "${DESTDIR:-}$2" else - ln -vfs -T --relative -- "${DESTDIR:-}$1" "${DESTDIR:-}$2" + ln -${VERBOSE}fs -T --relative -- "${DESTDIR:-}$1" "${DESTDIR:-}$2" fi diff --git a/tools/meson-vcs-tag.sh b/tools/meson-vcs-tag.sh index 1c3814d48..1ec04c76b 100755 --- a/tools/meson-vcs-tag.sh +++ b/tools/meson-vcs-tag.sh @@ -1,16 +1,11 @@ #!/usr/bin/env bash +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu set -o pipefail dir="$1" -tag="$2" -fallback="$3" - -if [ -n "$tag" ]; then - echo "$tag" - exit 0 -fi +fallback="$2" # Apparently git describe has a bug where it always considers the work-tree # dirty when invoked with --git-dir (even though 'git status' is happy). Work diff --git a/tools/oss-fuzz.sh b/tools/oss-fuzz.sh index 491246b32..767da15f7 100755 --- a/tools/oss-fuzz.sh +++ b/tools/oss-fuzz.sh @@ -38,7 +38,11 @@ else fi fi -meson $build -D$fuzzflag -Db_lundef=false +if ! meson $build -D$fuzzflag -Db_lundef=false; then + cat $build/meson-logs/meson-log.txt + exit 1 +fi + ninja -v -C $build fuzzers # The seed corpus is a separate flat archive for each fuzzer, diff --git a/tools/syscall-names-update.sh b/tools/syscall-names-update.sh deleted file mode 100755 index c884b93cd..000000000 --- a/tools/syscall-names-update.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh -set -eu - -cd "$1" - -curl -L -o syscall-names.text 'https://raw.githubusercontent.com/hrw/syscalls-table/master/syscall-names.text' diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index ea05f5dc3..397d131be 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -31,6 +31,10 @@ BORING_INTERFACES = [ 'org.freedesktop.DBus.Introspectable', 'org.freedesktop.DBus.Properties', ] +RED = '\x1b[31m' +GREEN = '\x1b[32m' +YELLOW = '\x1b[33m' +RESET = '\x1b[39m' def xml_parser(): return etree.XMLParser(no_network=True, @@ -289,7 +293,7 @@ def process(page): with open(page, 'w') as out: out.write(out_text) - return dict(stats=stats, outdated=(out_text != src)) + return dict(stats=stats, modified=(out_text != src)) def parse_args(): p = argparse.ArgumentParser() @@ -317,17 +321,19 @@ if __name__ == '__main__': # Let's print all statistics at the end mlen = max(len(page) for page in stats) total = sum((item['stats'] for item in stats.values()), collections.Counter()) - total = 'total', dict(stats=total, outdated=False) - outdated = [] + total = 'total', dict(stats=total, modified=False) + modified = [] + classification = 'OUTDATED' if opts.test else 'MODIFIED' for page, info in sorted(stats.items()) + [total]: m = info['stats']['missing'] t = info['stats']['total'] p = page + ':' - c = 'OUTDATED' if info['outdated'] else '' + c = classification if info['modified'] else '' if c: - outdated.append(page) - print(f'{p:{mlen + 1}} {t - m}/{t} {c}') + modified.append(page) + color = RED if m > t/2 else (YELLOW if m else GREEN) + print(f'{color}{p:{mlen + 1}} {t - m}/{t} {c}{RESET}') - if opts.test and outdated: - exit(f'Outdated pages: {", ".join(outdated)}\n' - f'Hint: ninja -C {opts.build_dir} man/update-dbus-docs') + if opts.test and modified: + exit(f'Outdated pages: {", ".join(modified)}\n' + f'Hint: ninja -C {opts.build_dir} update-dbus-docs') diff --git a/tools/update-hwdb-autosuspend.sh b/tools/update-hwdb-autosuspend.sh new file mode 100755 index 000000000..7d5a9a8cf --- /dev/null +++ b/tools/update-hwdb-autosuspend.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eu + +cd "$1" + +(curl --fail -L 'https://chromium.googlesource.com/chromiumos/platform2/+/master/power_manager/udev/gen_autosuspend_rules.py?format=TEXT'; echo) \ + | base64 -d > tools/chromiumos/gen_autosuspend_rules.py + +(cat <<%EOF +# This file is part of systemd. +# +# Rules to autosuspend known fingerprint readers (pulled from libfprint). +# +%EOF +curl --fail -L 'https://gitlab.freedesktop.org/libfprint/libfprint/-/raw/master/data/autosuspend.hwdb') \ + > hwdb.d/60-autosuspend-fingerprint-reader.hwdb diff --git a/tools/update-hwdb.sh b/tools/update-hwdb.sh new file mode 100755 index 000000000..773a959dc --- /dev/null +++ b/tools/update-hwdb.sh @@ -0,0 +1,33 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eu + +cd "$1" + +unset permissive +if [ "${2:-}" = "-p" ]; then + permissive=1 + shift +else + permissive=0 +fi + +if [ "${2:-}" != "-n" ]; then ( + [ -z "$permissive" ] || set +e + set -x + + curl --fail -L -o usb.ids 'http://www.linux-usb.org/usb.ids' + curl --fail -L -o pci.ids 'http://pci-ids.ucw.cz/v2.2/pci.ids' + curl --fail -L -o ma-large.txt 'http://standards-oui.ieee.org/oui/oui.txt' + curl --fail -L -o ma-medium.txt 'http://standards-oui.ieee.org/oui28/mam.txt' + curl --fail -L -o ma-small.txt 'http://standards-oui.ieee.org/oui36/oui36.txt' + curl --fail -L -o pnp_id_registry.html 'https://uefi.org/uefi-pnp-export' + curl --fail -L -o acpi_id_registry.html 'https://uefi.org/uefi-acpi-export' +) fi + +set -x +./acpi-update.py >20-acpi-vendor.hwdb.base +patch -p0 -o- 20-acpi-vendor.hwdb.base <20-acpi-vendor.hwdb.patch >20-acpi-vendor.hwdb +! diff -u 20-acpi-vendor.hwdb.base 20-acpi-vendor.hwdb >20-acpi-vendor.hwdb.patch + +./ids_parser.py diff --git a/tools/update-man-rules.py b/tools/update-man-rules.py index 9e1660c12..31ed91c43 100755 --- a/tools/update-man-rules.py +++ b/tools/update-man-rules.py @@ -47,9 +47,11 @@ def mjoin(files): return ' \\\n\t'.join(sorted(files) or '#') MESON_HEADER = '''\ +# SPDX-License-Identifier: LGPL-2.1-or-later + # Do not edit. Generated by update-man-rules.py. # Update with: -# ninja -C build man/update-man-rules +# ninja -C build update-man-rules manpages = [''' MESON_FOOTER = '''\ diff --git a/tools/update-syscall-tables.sh b/tools/update-syscall-tables.sh new file mode 100755 index 000000000..4f56aeced --- /dev/null +++ b/tools/update-syscall-tables.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later +set -eu + +cd "$1" && shift + +curl --fail -L -o syscall-list.txt 'https://raw.githubusercontent.com/hrw/syscalls-table/master/syscall-names.text' + +for arch in "$@"; do + curl --fail -L -o syscalls-$arch.txt "https://raw.githubusercontent.com/hrw/syscalls-table/master/tables/syscalls-$arch" +done diff --git a/travis-ci/.dockerignore b/travis-ci/.dockerignore deleted file mode 100644 index 039215886..000000000 --- a/travis-ci/.dockerignore +++ /dev/null @@ -1,30 +0,0 @@ -*.a -*.cache -*.gch -*.log -*.o -*.plist -*.py[co] -*.stamp -*.swp -*.trs -*~ -.config.args -.deps/ -/*.gcda -/*.gcno -/GPATH -/GRTAGS -/GSYMS -/GTAGS -/TAGS -/ID -/build* -/coverage/ -/install-tree -/mkosi.builddir/ -/tags -image.raw -image.raw.cache-pre-dev -image.raw.cache-pre-inst -__pycache__/ diff --git a/travis-ci/Dockerfile b/travis-ci/Dockerfile deleted file mode 100644 index daf0ea9c6..000000000 --- a/travis-ci/Dockerfile +++ /dev/null @@ -1,37 +0,0 @@ -## Create Dockerfile that builds container suitable for systemd build -## This container runs as non-root user by default - -FROM fedora:27 - -# Demand the specification of non-root username -ARG DOCKER_USER -ARG DOCKER_USER_UID -ARG DOCKER_USER_GID - -# Copy the requirements into the container at /tmp -COPY requirements.txt /tmp/ - -# Install the requirements -# RUN dnf -y update FIXME -RUN dnf -y install $(cat '/tmp/requirements.txt') -# clean step to prevent cache and metadata corruption -RUN dnf clean all -RUN dnf -y builddep systemd - -# Add non-root user and chown the project dir -RUN groupadd -g $DOCKER_USER_GID $DOCKER_USER -RUN useradd --create-home --shell /bin/bash -u $DOCKER_USER_UID -g $DOCKER_USER_GID -G wheel $DOCKER_USER -ENV HOME /home/$DOCKER_USER -ENV PROJECTDIR $HOME/systemd - -# Copy content to the project directory -COPY . $PROJECTDIR - -# Greant user all permissions to the project dir -RUN chown -R $DOCKER_USER $PROJECTDIR - -# Switch to noroot user by default -USER $DOCKER_USER - -# Update workdir to user home dir -WORKDIR $PROJECTDIR diff --git a/travis-ci/managers/debian.sh b/travis-ci/managers/debian.sh deleted file mode 100755 index 558a55a0a..000000000 --- a/travis-ci/managers/debian.sh +++ /dev/null @@ -1,96 +0,0 @@ -#!/bin/bash - -# Run this script from the root of the systemd's git repository -# or set REPO_ROOT to a correct path. -# -# Example execution on Fedora: -# dnf install docker -# systemctl start docker -# export CONT_NAME="my-fancy-container" -# travis-ci/managers/debian.sh SETUP RUN CLEANUP - -PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP}) -DEBIAN_RELEASE="${DEBIAN_RELEASE:-testing}" -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=( - 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" -} - -set -e - -source "$(dirname $0)/travis_wait.bash" - -for phase in "${PHASES[@]}"; do - case $phase in - SETUP) - info "Setup phase" - info "Using Debian $DEBIAN_RELEASE" - printf "FROM debian:$DEBIAN_RELEASE\nRUN bash -c 'apt-get -y update && apt-get install -y systemd'\n" | docker build -t debian-with-systemd/latest - - info "Starting container $CONT_NAME" - $DOCKER_RUN -v $REPO_ROOT:/build:rw -e container=docker \ - -w /build --privileged=true --name $CONT_NAME \ - -dit --net=host debian-with-systemd/latest /bin/systemd - $DOCKER_EXEC bash -c "echo deb-src http://deb.debian.org/debian $DEBIAN_RELEASE main >>/etc/apt/sources.list" - # Wait for the container to properly boot up, otherwise we were - # running following apt-get commands during the initializing/starting - # (early/late bootup) phase, which caused nasty race conditions - $DOCKER_EXEC bash -c 'systemctl is-system-running --wait || :' - $DOCKER_EXEC apt-get -y update - $DOCKER_EXEC apt-get -y build-dep systemd - $DOCKER_EXEC apt-get -y install "${ADDITIONAL_DEPS[@]}" - ;; - RUN|RUN_GCC|RUN_CLANG) - if [[ "$phase" = "RUN_CLANG" ]]; then - ENV_VARS="-e CC=clang -e CXX=clang++" - MESON_ARGS="--optimization=1" - fi - docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true -Dsplit-usr=true -Dman=true $MESON_ARGS build - $DOCKER_EXEC ninja -v -C build - docker exec -e "TRAVIS=$TRAVIS" -it $CONT_NAME ninja -C build test - ;; - 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 - # -Db_lundef=false: See https://github.com/mesonbuild/meson/issues/764 - MESON_ARGS="-Db_lundef=false -Dfuzz-tests=true --optimization=1" - fi - docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Db_sanitize=address,undefined -Dsplit-usr=true $MESON_ARGS build - $DOCKER_EXEC ninja -v -C build - - # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb. - travis_wait docker exec --interactive=false \ - -e UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 \ - -e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \ - -e "TRAVIS=$TRAVIS" \ - -t $CONT_NAME \ - meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs - ;; - CLEANUP) - info "Cleanup phase" - docker stop $CONT_NAME - docker rm -f $CONT_NAME - ;; - *) - echo >&2 "Unknown phase '$phase'" - exit 1 - esac -done diff --git a/travis-ci/managers/fedora.sh b/travis-ci/managers/fedora.sh deleted file mode 100755 index 463696a32..000000000 --- a/travis-ci/managers/fedora.sh +++ /dev/null @@ -1,120 +0,0 @@ -#!/bin/bash - -# Run this script from the root of the systemd's git repository -# or set REPO_ROOT to a correct path. -# -# Example execution on Fedora: -# dnf install docker -# systemctl start docker -# export CONT_NAME="my-fancy-container" -# travis-ci/managers/fedora.sh SETUP RUN CLEANUP - -PHASES=(${@:-SETUP RUN RUN_ASAN_UBSAN CLEANUP}) -FEDORA_RELEASE="${FEDORA_RELEASE:-rawhide}" -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=( - clang - dnf-plugins-core - hostname - iputils - jq - libasan - libfdisk-devel - libfido2-devel - libpwquality-devel - libubsan - libzstd-devel - llvm - openssl-devel - p11-kit-devel - perl - python3-evdev - python3-pyparsing -) - -info() { - echo -e "\033[33;1m$1\033[0m" -} - -# Simple wrapper which retries given command up to five times -_retry() { - local EC=1 - - for i in {1..5}; do - if "$@"; then - EC=0 - break - fi - - sleep $((i * 5)) - done - - return $EC -} - -set -e - -source "$(dirname $0)/travis_wait.bash" - -for phase in "${PHASES[@]}"; do - case $phase in - SETUP) - info "Setup phase" - info "Using Fedora $FEDORA_RELEASE" - # Pull a Docker image and start a new container - printf "FROM fedora:$FEDORA_RELEASE\nRUN bash -c 'dnf install -y systemd'\n" | docker build -t fedora-with-systemd/latest - - info "Starting container $CONT_NAME" - $DOCKER_RUN -v $REPO_ROOT:/build:rw \ - -w /build --privileged=true --name $CONT_NAME \ - -dit --net=host fedora-with-systemd/latest /sbin/init - # Wait for the container to properly boot up, otherwise we were - # running following dnf commands during the initializing/starting - # (early/late bootup) phase, which caused nasty race conditions - $DOCKER_EXEC bash -c 'systemctl is-system-running --wait || :' - _retry $DOCKER_EXEC dnf makecache - # Install necessary build/test requirements - _retry $DOCKER_EXEC dnf -y --exclude selinux-policy\* upgrade - _retry $DOCKER_EXEC dnf -y install "${ADDITIONAL_DEPS[@]}" - _retry $DOCKER_EXEC dnf -y builddep systemd - ;; - RUN) - info "Run phase" - # Build systemd - $DOCKER_EXEC meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true build - $DOCKER_EXEC ninja -v -C build - $DOCKER_EXEC ninja -C build test - ;; - RUN_CLANG) - docker exec -e CC=clang -e CXX=clang++ -it $CONT_NAME meson --werror -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true -Dman=true build - $DOCKER_EXEC ninja -v -C build - $DOCKER_EXEC ninja -C build test - ;; - 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 - docker exec $ENV_VARS -it $CONT_NAME meson --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS build - $DOCKER_EXEC ninja -v -C build - - # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb. - travis_wait docker exec --interactive=false \ - -e UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 \ - -e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \ - -e "TRAVIS=$TRAVIS" \ - -t $CONT_NAME \ - meson test --timeout-multiplier=3 -C ./build/ --print-errorlogs - ;; - CLEANUP) - info "Cleanup phase" - docker stop $CONT_NAME - docker rm -f $CONT_NAME - ;; - *) - error "Unknown phase '$phase'" - exit 1 - esac -done diff --git a/travis-ci/managers/fuzzbuzz.sh b/travis-ci/managers/fuzzbuzz.sh deleted file mode 100755 index b69197f0b..000000000 --- a/travis-ci/managers/fuzzbuzz.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -set -e -set -x -set -u - -REPO_ROOT=${REPO_ROOT:-$(pwd)} - -sudo bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs) main restricted universe multiverse' >>/etc/apt/sources.list" -sudo apt-get update -y -sudo apt-get build-dep systemd -y -sudo apt-get install -y ninja-build python3-pip python3-setuptools quota -# The following should be dropped when debian packaging has been updated to include them -sudo apt-get install -y libfdisk-dev libp11-kit-dev libssl-dev libpwquality-dev -pip3 install meson - -cd $REPO_ROOT -export PATH="$HOME/.local/bin/:$PATH" -tools/oss-fuzz.sh -./out/fuzz-unit-file -max_total_time=5 -git clean -dxff diff --git a/travis-ci/managers/travis_wait.bash b/travis-ci/managers/travis_wait.bash deleted file mode 100644 index 59de6638d..000000000 --- a/travis-ci/managers/travis_wait.bash +++ /dev/null @@ -1,61 +0,0 @@ -# This was borrowed from https://github.com/travis-ci/travis-build/tree/master/lib/travis/build/bash -# to get around https://github.com/travis-ci/travis-ci/issues/9979. It should probably be removed -# as soon as Travis CI has started to provide an easy way to export the functions to bash scripts. - -travis_jigger() { - local cmd_pid="${1}" - shift - local timeout="${1}" - shift - local count=0 - - echo -e "\\n" - - while [[ "${count}" -lt "${timeout}" ]]; do - count="$((count + 1))" - echo -ne "Still running (${count} of ${timeout}): ${*}\\r" - sleep 60 - done - - echo -e "\\n${ANSI_RED}Timeout (${timeout} minutes) reached. Terminating \"${*}\"${ANSI_RESET}\\n" - kill -9 "${cmd_pid}" -} - -travis_wait() { - local timeout="${1}" - - if [[ "${timeout}" =~ ^[0-9]+$ ]]; then - shift - else - timeout=20 - fi - - local cmd=("${@}") - local log_file="travis_wait_${$}.log" - - "${cmd[@]}" &>"${log_file}" & - local cmd_pid="${!}" - - travis_jigger "${!}" "${timeout}" "${cmd[@]}" & - local jigger_pid="${!}" - local result - - { - set +e - wait "${cmd_pid}" 2>/dev/null - result="${?}" - ps -p"${jigger_pid}" &>/dev/null && kill "${jigger_pid}" - set -e - } - - if [[ "${result}" -eq 0 ]]; then - echo -e "\\n${ANSI_GREEN}The command ${cmd[*]} exited with ${result}.${ANSI_RESET}" - else - echo -e "\\n${ANSI_RED}The command ${cmd[*]} exited with ${result}.${ANSI_RESET}" - fi - - echo -e "\\n${ANSI_GREEN}Log:${ANSI_RESET}\\n" - cat "${log_file}" - - return "${result}" -} diff --git a/travis-ci/requirements.txt b/travis-ci/requirements.txt deleted file mode 100644 index 5ef30d5d3..000000000 --- a/travis-ci/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -dnf-plugins-core -meson -ninja-build -perl -python diff --git a/travis-ci/scripts/build-docker-image.sh b/travis-ci/scripts/build-docker-image.sh deleted file mode 100755 index 69f9d69ce..000000000 --- a/travis-ci/scripts/build-docker-image.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -# Check environment -[ -z "$TRAVIS_COMMIT" ] && echo "ERROR: TRAVIS_COMMIT must be set" && exit 1 - -# Build docker image -echo -e "\n\033[33;1mBuilding docker image: coverity-$TRAVIS_COMMIT.\033[0m" - -docker build \ - --build-arg DOCKER_USER=$USER \ - --build-arg DOCKER_USER_UID=`id -u` \ - --build-arg DOCKER_USER_GID=`id -g` \ - --force-rm -t coverity-${TRAVIS_COMMIT} --pull=true . diff --git a/units/meson-add-wants.sh b/units/meson-add-wants.sh index a483d75b8..f6424fe29 100755 --- a/units/meson-add-wants.sh +++ b/units/meson-add-wants.sh @@ -1,28 +1,40 @@ #!/bin/sh +# SPDX-License-Identifier: LGPL-2.1-or-later set -eu -unitdir="$1" -target="$2" -unit="$3" +i=1 +while [ $i -lt $# ] ; do + eval unitdir="\${$i}" + eval target="\${$((i + 1))}" + eval unit="\${$((i + 2))}" -case "$target" in - */?*) # a path, but not just a slash at the end - dir="${DESTDIR:-}${target}" - ;; - *) - dir="${DESTDIR:-}${unitdir}/${target}" - ;; -esac + if [ "${MESON_INSTALL_QUIET:-0}" = 1 ] ; then + VERBOSE="" + else + VERBOSE="v" + fi -unitpath="${DESTDIR:-}${unitdir}/${unit}" + case "$target" in + */?*) # a path, but not just a slash at the end + dir="${DESTDIR:-}${target}" + ;; + *) + dir="${DESTDIR:-}${unitdir}/${target}" + ;; + esac -case "$target" in - */) - mkdir -vp -m 0755 "$dir" - ;; - *) - mkdir -vp -m 0755 "$(dirname "$dir")" - ;; -esac + unitpath="${DESTDIR:-}${unitdir}/${unit}" -ln -vfs --relative "$unitpath" "$dir" + case "$target" in + */) + mkdir -${VERBOSE}p -m 0755 "$dir" + ;; + *) + mkdir -${VERBOSE}p -m 0755 "$(dirname "$dir")" + ;; + esac + + ln -${VERBOSE}fs --relative "$unitpath" "$dir" + + i=$((i + 3)) +done diff --git a/units/meson.build b/units/meson.build index ba60eb7fc..0d0eeea75 100644 --- a/units/meson.build +++ b/units/meson.build @@ -10,6 +10,9 @@ units = [ ['cryptsetup-pre.target', 'HAVE_LIBCRYPTSETUP'], ['cryptsetup.target', 'HAVE_LIBCRYPTSETUP', 'sysinit.target.wants/'], + ['veritysetup-pre.target', 'HAVE_LIBCRYPTSETUP'], + ['veritysetup.target', 'HAVE_LIBCRYPTSETUP', + 'sysinit.target.wants/'], ['dev-hugepages.mount', '', 'sysinit.target.wants/'], ['dev-mqueue.mount', '', @@ -62,6 +65,8 @@ units = [ 'ctrl-alt-del.target' + (with_runlevels ? ' runlevel6.target' : '')], ['remote-cryptsetup.target', 'HAVE_LIBCRYPTSETUP', 'initrd-root-device.target.wants/'], + ['remote-veritysetup.target', 'HAVE_LIBCRYPTSETUP', + 'initrd-root-device.target.wants/'], ['remote-fs-pre.target', ''], ['remote-fs.target', ''], ['rescue.target', '', @@ -128,6 +133,7 @@ units = [ ['systemd-poweroff.service', ''], ['systemd-reboot.service', ''], ['systemd-rfkill.socket', 'ENABLE_RFKILL'], + ['systemd-sysext.service', 'ENABLE_SYSEXT'], ['systemd-sysusers.service', 'ENABLE_SYSUSERS', 'sysinit.target.wants/'], ['systemd-tmpfiles-clean.service', 'ENABLE_TMPFILES'], @@ -247,6 +253,8 @@ m4_units = [ ['serial-getty@.service', ''], ] +add_wants = [] + foreach tuple : in_units file = tuple[0] @@ -270,7 +278,7 @@ foreach tuple : in_units if install and tuple.length() > 2 foreach target : tuple[2].split() - meson.add_install_script('meson-add-wants.sh', systemunitdir, target, file) + add_wants += [systemunitdir, target, file] endforeach endif endforeach @@ -295,7 +303,7 @@ foreach tuple : m4_units if tuple.length() > 2 and install foreach target : tuple[2].split() - meson.add_install_script('meson-add-wants.sh', systemunitdir, target, file) + add_wants += [systemunitdir, target, file] endforeach endif endforeach @@ -314,13 +322,14 @@ foreach tuple : units if tuple.length() > 2 foreach target : tuple[2].split() - meson.add_install_script( - 'meson-add-wants.sh', systemunitdir, target, file) + add_wants += [systemunitdir, target, file] endforeach endif endif endforeach +meson.add_install_script('meson-add-wants.sh', add_wants) + install_data('user-.slice.d/10-defaults.conf', install_dir : systemunitdir + '/user-.slice.d') diff --git a/units/remote-veritysetup.target b/units/remote-veritysetup.target new file mode 100644 index 000000000..bd9f71ace --- /dev/null +++ b/units/remote-veritysetup.target @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Remote Verity Integrity Protected Volumes +Documentation=man:systemd.special(7) +After=remote-fs-pre.target veritysetup-pre.target +DefaultDependencies=no +Conflicts=shutdown.target + +[Install] +WantedBy=multi-user.target diff --git a/units/systemd-hostnamed.service.in b/units/systemd-hostnamed.service.in index d3d0efebd..222700564 100644 --- a/units/systemd-hostnamed.service.in +++ b/units/systemd-hostnamed.service.in @@ -32,7 +32,7 @@ ProtectKernelLogs=yes ProtectKernelModules=yes ProtectKernelTunables=yes ProtectSystem=strict -ReadWritePaths=/etc +ReadWritePaths=/etc /run/systemd RestrictAddressFamilies=AF_UNIX RestrictNamespaces=yes RestrictRealtime=yes diff --git a/units/systemd-localed.service.in b/units/systemd-localed.service.in index 652b956a3..e60a17359 100644 --- a/units/systemd-localed.service.in +++ b/units/systemd-localed.service.in @@ -33,7 +33,7 @@ ProtectKernelLogs=yes ProtectKernelModules=yes ProtectKernelTunables=yes ProtectSystem=strict -ReadWritePaths=/etc +ReadWritePaths=/etc@SERVICE_LOCALEGEN_WRITABLE@ RestrictAddressFamilies=AF_UNIX RestrictNamespaces=yes RestrictRealtime=yes diff --git a/units/systemd-networkd.service.in b/units/systemd-networkd.service.in index 9834b06a4..d5b0a9b96 100644 --- a/units/systemd-networkd.service.in +++ b/units/systemd-networkd.service.in @@ -24,6 +24,7 @@ BusName=org.freedesktop.network1 CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW DeviceAllow=char-* rw ExecStart=!!@rootlibexecdir@/systemd-networkd +ExecReload=networkctl reload LockPersonality=yes MemoryDenyWriteExecute=yes NoNewPrivileges=yes diff --git a/units/systemd-oomd.service.in b/units/systemd-oomd.service.in index fd7c8d213..f264a1bef 100644 --- a/units/systemd-oomd.service.in +++ b/units/systemd-oomd.service.in @@ -13,6 +13,10 @@ Documentation=man:systemd-oomd.service(8) DefaultDependencies=no Before=multi-user.target shutdown.target Conflicts=shutdown.target +ConditionControlGroupController=v2 +ConditionPathExists=/proc/pressure/cpu +ConditionPathExists=/proc/pressure/io +ConditionPathExists=/proc/pressure/memory [Service] AmbientCapabilities=CAP_KILL CAP_DAC_OVERRIDE diff --git a/units/systemd-sysext.service b/units/systemd-sysext.service new file mode 100644 index 000000000..35b5edca1 --- /dev/null +++ b/units/systemd-sysext.service @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Merge System Extension Images into /usr/ and /opt/ +Documentation=man:systemd-sysext.service(8) +DefaultDependencies=no +Conflicts=shutdown.target +After=local-fs.target +Before=sysinit.target shutdown.target systemd-tmpfiles.service +ConditionCapability=CAP_SYS_ADMIN +ConditionDirectoryNotEmpty=|/etc/extensions +ConditionDirectoryNotEmpty=|/run/extensions +ConditionDirectoryNotEmpty=|/var/lib/extensions +ConditionDirectoryNotEmpty=|/usr/local/lib/extensions +ConditionDirectoryNotEmpty=|/usr/lib/extensions + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=systemd-sysext merge +ExecStop=systemd-sysext unmerge + +[Install] +WantedBy=sysinit.target diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in index 62120d819..6226ab7a4 100644 --- a/units/systemd-timesyncd.service.in +++ b/units/systemd-timesyncd.service.in @@ -16,12 +16,16 @@ DefaultDependencies=no After=systemd-sysusers.service Before=time-set.target sysinit.target shutdown.target Conflicts=shutdown.target -Wants=time-set.target time-sync.target +Wants=time-set.target [Service] AmbientCapabilities=CAP_SYS_TIME BusName=org.freedesktop.timesync1 CapabilityBoundingSet=CAP_SYS_TIME +# Turn off DNSSEC validation for hostname look-ups, since those need the +# correct time to work, but we likely won't acquire that without NTP. Let's +# break this chicken-and-egg cycle here. +Environment=SYSTEMD_NSS_RESOLVE_VALIDATE=0 ExecStart=!!@rootlibexecdir@/systemd-timesyncd LockPersonality=yes MemoryDenyWriteExecute=yes diff --git a/units/systemd-udev-trigger.service b/units/systemd-udev-trigger.service index 8b2d88e18..3d0f7b4f2 100644 --- a/units/systemd-udev-trigger.service +++ b/units/systemd-udev-trigger.service @@ -19,5 +19,5 @@ ConditionPathIsReadWrite=/sys [Service] Type=oneshot RemainAfterExit=yes -ExecStart=udevadm trigger --type=subsystems --action=add -ExecStart=udevadm trigger --type=devices --action=add +ExecStart=-udevadm trigger --type=subsystems --action=add +ExecStart=-udevadm trigger --type=devices --action=add diff --git a/units/veritysetup-pre.target b/units/veritysetup-pre.target new file mode 100644 index 000000000..be065f335 --- /dev/null +++ b/units/veritysetup-pre.target @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Local Verity Integrity Protected Volumes (Pre) +Documentation=man:systemd.special(7) +RefuseManualStart=yes +Before=veritysetup.target diff --git a/units/veritysetup.target b/units/veritysetup.target new file mode 100644 index 000000000..0ac3ad3bd --- /dev/null +++ b/units/veritysetup.target @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This file is part of systemd. +# +# systemd is free software; you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation; either version 2.1 of the License, or +# (at your option) any later version. + +[Unit] +Description=Local Verity Integrity Protected Volumes +Documentation=man:systemd.special(7) diff --git a/zanata.xml b/zanata.xml deleted file mode 100644 index 02fe72f1c..000000000 --- a/zanata.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - https://fedora.zanata.org/ - systemd - master - gettext - po - po -