1
0
mirror of https://github.com/systemd/systemd synced 2025-10-07 20:54:45 +02:00

Compare commits

..

No commits in common. "869b44e0f7a1fa501c2e7b6774228c31d9caac61" and "7aefb194e754cae9c166539a103e9fd6b7e59798" have entirely different histories.

316 changed files with 1620 additions and 2260 deletions

View File

@ -25,7 +25,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@184472f0f1f831ca29953546ec01fd941ff763a6
- uses: systemd/mkosi@0d1143150835b21c1bfe64428df5f45b558280b1
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
@ -83,22 +83,22 @@ jobs:
run: mkosi summary
- name: Build tools tree
run: sudo mkosi -f box -- true
run: sudo mkosi -f sandbox -- true
- name: Configure meson
run: |
sudo mkosi box -- \
sudo mkosi sandbox -- \
meson setup \
--buildtype=debugoptimized \
build
- name: Build image
run: sudo mkosi box -- meson compile -C build mkosi
run: sudo mkosi sandbox -- meson compile -C build mkosi
- name: Initial coverage report
run: |
sudo mkdir -p build/test/coverage
sudo mkosi box -- \
sudo mkosi sandbox -- \
lcov \
--directory build/mkosi.builddir/arch~rolling~x86-64 \
--capture \
@ -115,7 +115,7 @@ jobs:
# --preserve-env makes sure all the github actions environment variables are propagated which are
# used in integration-test-wrapper.py to construct the `gh` command line to download the journals
# of failed tests.
sudo --preserve-env mkosi box -- \
sudo --preserve-env mkosi sandbox -- \
env \
TEST_RUNNER=ubuntu-24.04 \
meson test \
@ -147,10 +147,10 @@ jobs:
lcov_args+=(--add-tracefile "${file}")
done < <(find build/test/coverage -name "TEST-*.coverage-info")
sudo mkosi box -- lcov --ignore-errors inconsistent,inconsistent "${lcov_args[@]}" --output-file build/test/coverage/everything.coverage-info
sudo mkosi sandbox -- lcov --ignore-errors inconsistent,inconsistent "${lcov_args[@]}" --output-file build/test/coverage/everything.coverage-info
- name: List coverage report
run: sudo mkosi box -- lcov --ignore-errors inconsistent,inconsistent --list build/test/coverage/everything.coverage-info
run: sudo mkosi sandbox -- lcov --ignore-errors inconsistent,inconsistent --list build/test/coverage/everything.coverage-info
- name: Coveralls
uses: coverallsapp/github-action@648a8eb78e6d50909eff900e4ec85cab4524a45b

View File

@ -38,10 +38,10 @@ jobs:
LINTER_RULES_PATH: .github/linters
GITHUB_ACTIONS_CONFIG_FILE: actionlint.yml
- uses: systemd/mkosi@184472f0f1f831ca29953546ec01fd941ff763a6
- uses: systemd/mkosi@0d1143150835b21c1bfe64428df5f45b558280b1
- name: Check that tabs are not used in Python code
run: sh -c '! git grep -P "\\t" -- src/core/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py'
run: sh -c '! git grep -P "\\t" -- src/basic/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py'
- name: Build tools tree
run: |
@ -51,29 +51,29 @@ jobs:
ToolsTreeRelease=rawhide
EOF
mkosi -f box -- true
mkosi -f sandbox -- true
- name: Run mypy
run: |
mkosi box -- mypy --version
mkosi box -- mypy src/core/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
mkosi sandbox -- mypy --version
mkosi sandbox -- mypy src/basic/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
- name: Run ruff check
run: |
mkosi box -- ruff --version
mkosi box -- ruff check src/core/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
mkosi sandbox -- ruff --version
mkosi sandbox -- ruff check src/basic/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
- name: Run ruff format
run: |
mkosi box -- ruff --version
if ! mkosi box -- ruff format --check src/core/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
mkosi sandbox -- ruff --version
if ! mkosi sandbox -- ruff format --check src/basic/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
then
echo "Please run 'ruff format' on the above files or apply the diffs below manually"
mkosi box -- ruff format --check --quiet --diff src/core/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
mkosi sandbox -- ruff format --check --quiet --diff src/basic/generate-bpf-delegate-configs.py src/boot/generate-hwids-section.py src/test/generate-sym-test.py src/ukify/ukify.py test/integration-tests/integration-test-wrapper.py
fi
- name: Configure meson
run: mkosi box -- env CC=clang CXX=clang++ meson setup -Dlocalegen-path=/usr/bin/locale-gen -Dcompat-mutable-uid-boundaries=true build
run: mkosi sandbox -- env CC=clang CXX=clang++ meson setup -Dlocalegen-path=/usr/bin/locale-gen -Dcompat-mutable-uid-boundaries=true build
- name: Run clang-tidy
run: mkosi box -- meson test -C build --suite=clang-tidy --print-errorlogs --no-stdsplit
run: mkosi sandbox -- meson test -C build --suite=clang-tidy --print-errorlogs --no-stdsplit

View File

@ -147,7 +147,7 @@ jobs:
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- uses: systemd/mkosi@184472f0f1f831ca29953546ec01fd941ff763a6
- uses: systemd/mkosi@0d1143150835b21c1bfe64428df5f45b558280b1
# Freeing up disk space with rm -rf can take multiple minutes. Since we don't need the extra free space
# immediately, we remove the files in the background. However, we first move them to a different location
@ -214,21 +214,21 @@ jobs:
run: mkosi summary
- name: Build tools tree
run: sudo mkosi -f box -- true
run: sudo mkosi -f sandbox -- true
- name: Configure meson
run: |
# /usr/sbin/bpftool is completely broken inside containers on Ubuntu which makes meson blow up so
# disable the bpf-framework stuff to avoid the issue.
# TODO: Drop when we move off Ubuntu Noble as this will be fixed in the next Ubuntu LTS release.
sudo mkosi box -- \
sudo mkosi sandbox -- \
meson setup \
--buildtype=debugoptimized \
-Dbpf-framework=disabled \
build
- name: Build image
run: sudo mkosi box -- meson compile -C build mkosi
run: sudo mkosi sandbox -- meson compile -C build mkosi
- name: Make sure sources weren't polluted by package build scripts
run: |
@ -243,7 +243,7 @@ jobs:
- name: Run integration tests
run: |
if [[ "$(sudo mkosi box -- meson test --help)" == *"--max-lines"* ]]; then
if [[ "$(sudo mkosi sandbox -- meson test --help)" == *"--max-lines"* ]]; then
MAX_LINES=(--max-lines 300)
else
MAX_LINES=()
@ -256,7 +256,7 @@ jobs:
# --preserve-env makes sure all the github actions environment variables are propagated which are
# used in integration-test-wrapper.py to construct the `gh` command line to download the journals
# of failed tests.
sudo --preserve-env mkosi box -- \
sudo --preserve-env mkosi sandbox -- \
env \
TEST_PREFER_QEMU=${{ matrix.vm }} \
TEST_NO_QEMU=${{ matrix.no_qemu }} \

3
NEWS
View File

@ -135,9 +135,6 @@ CHANGES WITH 258 in spe:
incompatible with PrivateDevices= and resulted in automatic extension
of the DeviceAllow= list. The latter behaviour has been removed.
* The command 'journalctl --follow' now exits with success on
SIGTERM/SIGINT, or its pipe STDOUT is disconnected.
Announcements of Future Feature Removals:
* Support for System V service scripts is deprecated and will be

View File

@ -20,9 +20,6 @@ There are many, and more are constantly added, so we will not enumerate them all
The code that is shared between components is split into a few directories, each with a different purpose:
- 'src/include/uapi/' contains copy of kernel headers we use.
'src/include/override/' contains wrappers for libc and kernel headers, to provide several missing symbols.
- `src/basic/` and `src/fundamental/` — those directories contain code primitives that are used by all other code.
`src/fundamental/` is stricter, because it used for EFI and user-space code, while `src/basic/` is only used for user-space code.
The code in `src/fundamental/` cannot depend on any other code in the tree, and `src/basic/` can depend only on itself and `src/fundamental/`.
@ -46,12 +43,6 @@ Any code that is used only for EFI goes under `src/boot/efi/`, and `src/fundamen
To summarize:
`src/include/uapi/`
- copy of kernel headers
`src/include/override/`
- wrappers for libc and kernel headers
`src/fundamental/`
- may be used by all code in the tree
- may not use any code outside of `src/fundamental/`

View File

@ -40,16 +40,16 @@ Then, you can build, run and test systemd executables as follows:
```sh
$ mkosi -f genkey # Generate signing keys once.
$ mkosi -f box -- meson setup -Dbpf-framework=disabled build # bpftool detection inside mkosi box is broken on Ubuntu Noble and older
$ mkosi -f box -- meson compile -C build
$ mkosi -f box -- build/systemctl --version
$ mkosi -f box -- meson test -C build # Run the unit tests
$ mkosi -f sandbox -- meson setup -Dbpf-framework=disabled build # bpftool detection inside mkosi sandbox is broken on Ubuntu Noble and older
$ mkosi -f sandbox -- meson compile -C build
$ mkosi -f sandbox -- build/systemctl --version
$ mkosi -f sandbox -- meson test -C build # Run the unit tests
```
To build and boot an OS image with the latest systemd installed:
```sh
$ mkosi -f box -- meson compile -C build mkosi # (re-)build the OS image
$ mkosi -f sandbox -- meson compile -C build mkosi # (re-)build the OS image
$ mkosi boot # Boot the image with systemd-nspawn.
$ mkosi vm # Boot the image with qemu.
```
@ -65,8 +65,8 @@ $ cd systemd
$ git checkout -b <BRANCH> # where BRANCH is the name of the branch
$ $EDITOR src/core/main.c # or wherever you'd like to make your changes
$ mkosi -f genkey # Generate signing keys once.
$ mkosi -f box -- meson setup build # Set up meson
$ mkosi -f box -- meson compile -C build mkosi # (re-)build the test image
$ mkosi -f sandbox -- meson setup build # Set up meson
$ mkosi -f sandbox -- meson compile -C build mkosi # (re-)build the test image
$ mkosi vm # Boot the image in qemu
$ git add -p # interactively put together your patch
$ git commit # commit it
@ -85,7 +85,7 @@ not required to write basic patches.
## Building the OS image without a tools tree
By default, `mkosi` will first build a tools tree and use it build the image and
provide the environment for `mkosi box`. To disable the tools tree and use
provide the environment for `mkosi sandbox`. To disable the tools tree and use
binaries from your host instead, write the following to `mkosi/mkosi.local.conf`:
```conf
@ -311,7 +311,7 @@ To debug systemd-boot in an IDE such as VSCode we can use a launch configuration
right in your editor of choice (with the right plugin installed). When using mkosi, we can run clangd in the
mkosi tools tree to avoid needing to install clangd on the host machine.
All that is required is to run `mkosi -f box true` once to make sure the tools tree is available and to modify
All that is required is to run `mkosi -f sandbox true` once to make sure the tools tree is available and to modify
the path of the clangd binary used by your editor to the `mkosi.clangd` script included in the systemd repository.
For example, for VScode, you'd have to add the following to the VSCode workspace settings of the systemd repository:
@ -329,7 +329,7 @@ When using clangd, it's recommended to setup the build directory containing the
compilation database used by clangd to use clang as the compiler as well:
```sh
$ mkosi box -- env CC=clang CXX=clang++ meson setup build
$ mkosi sandbox -- env CC=clang CXX=clang++ meson setup build
```
Additionally, the `gensources` target can be used to make sure all generated
@ -337,5 +337,5 @@ sources are generated to avoid clangd complaining that these source files don't
exist.
```sh
$ mkosi box -- ninja -C build gensources
$ mkosi sandbox -- ninja -C build gensources
```

View File

@ -20,10 +20,9 @@ xsltproc_flags = [
'--stringparam', 'man.copyright.section.enabled', '0',
'--stringparam', 'systemd.version', '@0@'.format(meson.project_version()),
'--path',
'@0@:@1@:@2@:@3@'.format(meson.current_build_dir(),
'@0@:@1@:@2@'.format(meson.current_build_dir(),
meson.current_source_dir(),
libshared_build_dir,
libcore_build_dir)]
libshared_build_dir)]
custom_man_xsl = files('custom-man.xsl')
custom_html_xsl = files('custom-html.xsl')
@ -36,6 +35,17 @@ custom_entities_ent = custom_target(
man_page_depends += custom_entities_ent
generate_bpf_delegate_configs = find_program('../src/basic/generate-bpf-delegate-configs.py')
bpf_delegate_xml = custom_target(
input : files('../src/basic/include/linux/bpf.h'),
output : 'bpf-delegate.xml',
command : [generate_bpf_delegate_configs,
'doc',
'@INPUT@'],
capture : true)
man_page_depends += bpf_delegate_xml
man_pages = []
html_pages = []
source_xml_files = []

View File

@ -2567,7 +2567,7 @@ RestrictNamespaces=~cgroup net</programlisting>
available to the unit's processes. When mounting the BPF filesystem with the fsopen() API, four mount
options can be specified to set a list of BPF commands, maps, programs and attachment types that are
allowed to be used. Processes needs to get a file descriptor for the bpffs mountpoint and use that to
get a token which will enable for that user namespace the BPF functionalities chosen upon bpffs mount.
get a token which will enable for that user namespace the BPF functionalities choosen upon bpffs mount.
A more detailed explanation of the feature can be found in this
<ulink url="https://lwn.net/Articles/947173/">LWN post</ulink>.</para>

View File

@ -580,6 +580,7 @@ foreach ident : [
['fsconfig', '''#include <sys/mount.h>'''], # since glibc-2.36
['fsmount', '''#include <sys/mount.h>'''], # since glibc-2.36
['fsopen', '''#include <sys/mount.h>'''], # since glibc-2.36
['fspick', '''#include <sys/mount.h>'''], # since glibc-2.36
['mount_setattr', '''#include <sys/mount.h>'''], # since glibc-2.36
['move_mount', '''#include <sys/mount.h>'''], # since glibc-2.36
['open_tree', '''#include <sys/mount.h>'''], # since glibc-2.36
@ -590,17 +591,15 @@ foreach ident : [
['ioprio_get', '''#include <sched.h>'''], # no known header declares ioprio_get
['ioprio_set', '''#include <sched.h>'''], # no known header declares ioprio_set
['rt_tgsigqueueinfo', '''#include <signal.h>'''], # no known header declares rt_tgsigqueueinfo
['open_tree_attr', '''#include <sys/mount.h>'''], # no known header declares open_tree_attr
['quotactl_fd', '''#include <sys/quota.h>'''], # no known header declares quotactl_fd
['fchmodat2', '''#include <sys/stat.h>'''], # no known header declares fchmodat2
['bpf', '''#include <sys/syscall.h>'''], # no known header declares bpf
['kcmp', '''#include <sys/syscall.h>'''], # no known header declares kcmp
['keyctl', '''#include <sys/syscall.h>'''], # no known header declares keyctl
['add_key', '''#include <sys/syscall.h>'''], # no known header declares add_key
['request_key', '''#include <sys/syscall.h>'''], # no known header declares request_key
['pivot_root', '''#include <sys/syscall.h>'''], # no known header declares pivot_root
['setxattrat', '''#include <sys/xattr.h>'''], # no known header declares setxattrat
['removexattrat', '''#include <sys/xattr.h>'''], # no known header declares removexattrat
['pivot_root', '''#include <unistd.h>'''], # no known header declares pivot_root
['open_tree_attr', '''#include <sys/mount.h>'''], # no known header declares open_tree_attr
]
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
@ -2009,33 +2008,16 @@ dbus_programs = []
# A list of boot stubs. Required for testing of ukify.
boot_stubs = []
# This is similar to system_includes below, but for passing custom_target().
system_include_args = [
'-isystem', meson.project_build_root() / 'src/include/override',
'-isystem', meson.project_source_root() / 'src/include/override',
'-isystem', meson.project_build_root() / 'src/include/uapi',
'-isystem', meson.project_source_root() / 'src/include/uapi',
]
system_includes = [
include_directories(
# gcc(1) says
# "Directories specified with -isystem options are scanned in left-to-right order",
# and meson puts the directories in the reversed order. Hence, a directory with a lower
# priority must be listed earlier.
'src/include/uapi',
'src/include/override',
is_system : true,
),
]
basic_includes = [
include_directories(
'src/basic',
'src/fundamental',
'src/systemd',
),
system_includes,
include_directories(
'src/basic/include',
is_system : true,
),
version_include,
]
@ -2057,8 +2039,6 @@ includes = [libsystemd_includes, include_directories('src/shared')]
subdir('po')
subdir('catalog')
subdir('src/include')
subdir('src/libc')
subdir('src/fundamental')
subdir('src/basic')
subdir('src/libsystemd')
@ -2074,8 +2054,7 @@ libsystemd = shared_library(
# Make sure our library is never deleted from memory, so that our open logging fds don't leak on dlopen/dlclose cycles.
'-z', 'nodelete',
'-Wl,--version-script=' + libsystemd_sym_path],
link_with : [libc_wrapper_static,
libbasic_static],
link_with : [libbasic_static],
link_whole : [libsystemd_static],
dependencies : [librt,
threads,
@ -2088,7 +2067,6 @@ libsystemd = shared_library(
if static_libsystemd != 'false'
install_libsystemd_static = static_library(
'systemd',
libc_wrapper_sources,
libsystemd_sources,
basic_sources,
fundamental_sources,
@ -2134,7 +2112,6 @@ libudev = shared_library(
if static_libudev != 'false'
install_libudev_static = static_library(
'udev',
libc_wrapper_sources,
basic_sources,
fundamental_sources,
shared_sources,
@ -2239,7 +2216,6 @@ nss_template = {
# Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned
'link_args' : ['-z', 'nodelete'],
'link_with' : [
libc_wrapper_static,
libsystemd_static,
libshared_static,
libbasic_static,

View File

@ -9,7 +9,7 @@ else
fi
exec "${SPAWN[@]}" \
mkosi box -- \
mkosi sandbox -- \
clangd \
--compile-commands-dir=build \
--path-mappings="\

View File

@ -1,7 +1,7 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Config]
MinimumVersion=commit:184472f0f1f831ca29953546ec01fd941ff763a6
MinimumVersion=commit:0d1143150835b21c1bfe64428df5f45b558280b1
Dependencies=
exitrd
initrd

View File

@ -1,5 +1,8 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=arch
[Build]
Environment=
GIT_URL=https://gitlab.archlinux.org/archlinux/packaging/packages/systemd.git

View File

@ -27,8 +27,6 @@ Packages=
cryptsetup
device-mapper-event
device-mapper-multipath
dfuzzer
erofs-utils
git-core
glibc-langpack-de
glibc-langpack-en
@ -40,7 +38,6 @@ Packages=
iputils
iscsi-initiator-utils
kernel-core
knot
libcap-ng-utils
man-db
nmap-ncat
@ -55,7 +52,6 @@ Packages=
python3-pexpect
# needed to upgrade and downgrade systemd-ukify in tests
python3-zstd
qrencode
quota
rpm
softhsm

View File

@ -1,11 +0,0 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Architecture=uefi
[Content]
Packages=
sbsigntools
VolatilePackages=
systemd-boot

View File

@ -1,5 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=|centos
Distribution=|fedora
[Build]
Environment=
GIT_URL=https://src.fedoraproject.org/rpms/systemd.git

View File

@ -5,7 +5,6 @@ Distribution=centos
[Distribution]
Release=10
Repositories=epel,epel-next
[Build]
Environment=

View File

@ -0,0 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Release=9
[Distribution]
Repositories=
epel
epel-next

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Repositories=epel
Architecture=|x86
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content]
Packages=
sbsigntools
VolatilePackages=
systemd-boot

View File

@ -0,0 +1,12 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Repositories=epel
[Content]
Packages=
dfuzzer
dhcp-server
erofs-utils
knot
qrencode

View File

@ -4,7 +4,13 @@
Environment=WITH_DEBUG=1
[Match]
Architecture=uefi
Architecture=|x86
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content]
VolatilePackages=

View File

@ -2,7 +2,13 @@
# sbsigntool exists only on UEFI architectures
[Match]
Architecture=uefi
Architecture=|x86
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content]
Packages=

View File

@ -1,5 +1,9 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=|debian
Distribution=|ubuntu
[Build]
Environment=
GIT_URL=https://salsa.debian.org/systemd-team/systemd.git

View File

@ -10,11 +10,15 @@ Release=rawhide
Packages=
btrfs-progs
compsize
dfuzzer
dhcp-server
dnf5
erofs-utils
f2fs-tools
# Required for systemd-networkd-tests.py (netdevsim and sch_xxx modules)
kernel-modules-extra
kernel-modules-internal
knot
qrencode
rpmautospec
scsi-target-utils

View File

@ -0,0 +1,18 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=fedora
Architecture=|x86
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content]
Packages=
sbsigntools
VolatilePackages=
systemd-boot

View File

@ -4,7 +4,13 @@
Environment=WITH_DEBUG=1
[Match]
Architecture=uefi
Architecture=|x86
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content]
VolatilePackages=

View File

@ -1,7 +1,14 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Architecture=uefi
Distribution=opensuse
Architecture=|x86
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content]
VolatilePackages=

View File

@ -1,5 +1,8 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
[Match]
Distribution=opensuse
[Build]
Environment=
GIT_URL=https://github.com/bmwiedemann/openSUSE

View File

@ -1,7 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/fs.h>
#include <linux/magic.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/xattr.h>
@ -20,6 +18,8 @@
#include "fs-util.h"
#include "log.h"
#include "login-util.h"
#include "missing_fs.h"
#include "missing_magic.h"
#include "parse-util.h"
#include "path-util.h"
#include "pidref.h"

View File

@ -126,6 +126,10 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
/* Either the file may be missing, or we return an fd to the final object, but both make no sense */
if (FLAGS_SET(flags, CHASE_NONEXISTENT))
assert(!ret_fd);
if (FLAGS_SET(flags, CHASE_STEP))
assert(!ret_fd);
@ -548,13 +552,11 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
}
if (ret_fd) {
if (exists) {
/* Return the O_PATH fd we currently are looking to the caller. It can translate it
* to a proper fd by opening /proc/self/fd/xyz. */
/* Return the O_PATH fd we currently are looking to the caller. It can translate it to a
* proper fd by opening /proc/self/fd/xyz. */
assert(fd >= 0);
*ret_fd = TAKE_FD(fd);
} else
*ret_fd = -EBADF;
}
if (FLAGS_SET(flags, CHASE_STEP))

View File

@ -3,14 +3,19 @@
set -eu
set -o pipefail
cpp="${1:?}"
filesystems_gperf="${2:?}"
cpp="$1"
filesystems_gperf="$2"
shift 2
includes=""
for i in "$@"; do
includes="$includes -include $i"
done
error=false
# shellcheck disable=SC2086
for fs in $($cpp -dM -include linux/magic.h "$@" - </dev/null | \
for fs in $($cpp -dM $includes - </dev/null | \
grep -E '_MAGIC' | \
grep -vE 'LINUX_MAGIC' | \
awk '/^#define[ \t]+[A-Z0-9_]+MAGIC[ \t]+/ { print $2; }'); do

View File

@ -20,24 +20,316 @@
#include "string-util.h"
#include "strv.h"
ConfFile* conf_file_free(ConfFile *c) {
if (!c)
return NULL;
static int files_add(
DIR *dir,
const char *dirpath,
int rfd,
const char *root, /* for logging, can be NULL */
Hashmap **files,
Set **masked,
const char *suffix,
ConfFilesFlags flags) {
free(c->name);
free(c->result);
free(c->original_path);
free(c->resolved_path);
safe_close(c->fd);
int r;
return mfree(c);
assert(dir);
assert(dirpath);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(files);
assert(masked);
root = strempty(root);
FOREACH_DIRENT(de, dir, return log_debug_errno(errno, "Failed to read directory '%s/%s': %m",
root, skip_leading_slash(dirpath))) {
/* Does this match the suffix? */
if (suffix && !endswith(de->d_name, suffix))
continue;
/* Has this file already been found in an earlier directory? */
if (hashmap_contains(*files, de->d_name)) {
log_debug("Skipping overridden file '%s/%s/%s'.",
root, skip_leading_slash(dirpath), de->d_name);
continue;
}
void conf_file_free_many(ConfFile **array, size_t n) {
FOREACH_ARRAY(i, array, n)
conf_file_free(*i);
/* Has this been masked in an earlier directory? */
if ((flags & CONF_FILES_FILTER_MASKED) != 0 && set_contains(*masked, de->d_name)) {
log_debug("File '%s/%s/%s' is masked by previous entry.",
root, skip_leading_slash(dirpath), de->d_name);
continue;
}
free(array);
_cleanup_free_ char *p = path_join(dirpath, de->d_name);
if (!p)
return log_oom_debug();
_cleanup_free_ char *resolved_path = NULL;
bool need_stat = (flags & (CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_DIRECTORY | CONF_FILES_EXECUTABLE)) != 0;
struct stat st;
if (!need_stat || FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
/* Even if no verification is requested, let's unconditionally call chaseat(),
* to drop unsafe symlinks. */
r = chaseat(rfd, p, CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &resolved_path, /* ret_fd = */ NULL);
if (r < 0) {
log_debug_errno(r, "Failed to chase '%s/%s', ignoring: %m",
root, skip_leading_slash(p));
continue;
}
if (r == 0 && FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
/* If the path points to /dev/null in a image or so, then the device node may not exist. */
if (path_equal(skip_leading_slash(resolved_path), "dev/null")) {
/* Mark this one as masked */
r = set_put_strdup(masked, de->d_name);
if (r < 0)
return log_oom_debug();
log_debug("File '%s/%s' is a mask (symlink to /dev/null).",
root, skip_leading_slash(p));
continue;
}
/* If the flag is set, we need to have stat, hence, skip the entry. */
log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to chase '%s/%s', ignoring: %m",
root, skip_leading_slash(p));
continue;
}
if (need_stat && fstatat(rfd, resolved_path, &st, AT_SYMLINK_NOFOLLOW) < 0) {
log_debug_errno(errno, "Failed to stat '%s/%s', ignoring: %m",
root, skip_leading_slash(p));
continue;
}
} else {
r = chase_and_statat(rfd, p, CHASE_AT_RESOLVE_IN_ROOT, &resolved_path, &st);
if (r < 0) {
log_debug_errno(r, "Failed to chase and stat '%s/%s', ignoring: %m",
root, skip_leading_slash(p));
continue;
}
}
/* Is this a masking entry? */
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK) && stat_may_be_dev_null(&st)) {
/* Mark this one as masked */
r = set_put_strdup(masked, de->d_name);
if (r < 0)
return log_oom_debug();
log_debug("File '%s/%s' is a mask (symlink to /dev/null).", root, skip_leading_slash(p));
continue;
}
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_EMPTY) && stat_is_empty(&st)) {
/* Mark this one as masked */
r = set_put_strdup(masked, de->d_name);
if (r < 0)
return log_oom_debug();
log_debug("File '%s/%s' is a mask (an empty file).", root, skip_leading_slash(p));
continue;
}
if (FLAGS_SET(flags, CONF_FILES_REGULAR|CONF_FILES_DIRECTORY)) {
if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
log_debug("Ignoring '%s/%s', as it is neither a regular file or directory.", root, skip_leading_slash(p));
continue;
}
} else {
/* Is this node a regular file? */
if (FLAGS_SET(flags, CONF_FILES_REGULAR) && !S_ISREG(st.st_mode)) {
log_debug("Ignoring '%s/%s', as it is not a regular file.", root, skip_leading_slash(p));
continue;
}
/* Is this node a directory? */
if (FLAGS_SET(flags, CONF_FILES_DIRECTORY) && !S_ISDIR(st.st_mode)) {
log_debug("Ignoring '%s/%s', as it is not a directory.", root, skip_leading_slash(p));
continue;
}
}
/* Does this node have the executable bit set?
* As requested: check if the file is marked executable. Note that we don't check access(X_OK)
* here, as we care about whether the file is marked executable at all, and not whether it is
* executable for us, because if so, such errors are stuff we should log about. */
if (FLAGS_SET(flags, CONF_FILES_EXECUTABLE) && (st.st_mode & 0111) == 0) {
log_debug("Ignoring '%s/%s', as it is not marked executable.", root, skip_leading_slash(p));
continue;
}
_cleanup_free_ char *n = strdup(de->d_name);
if (!n)
return log_oom_debug();
r = hashmap_ensure_put(files, &string_hash_ops_free_free, n, p);
if (r < 0) {
assert(r == -ENOMEM);
return log_oom_debug();
}
assert(r > 0);
TAKE_PTR(n);
TAKE_PTR(p);
}
return 0;
}
static int copy_and_sort_files_from_hashmap(Hashmap *fh, const char *root, ConfFilesFlags flags, char ***ret) {
_cleanup_free_ char **sv = NULL;
_cleanup_strv_free_ char **files = NULL;
size_t n = 0;
int r;
assert(ret);
r = hashmap_dump_sorted(fh, (void***) &sv, /* ret_n = */ NULL);
if (r < 0)
return log_oom_debug();
/* The entries in the array given by hashmap_dump_sorted() are still owned by the hashmap. */
STRV_FOREACH(s, sv) {
_cleanup_free_ char *p = NULL;
if (FLAGS_SET(flags, CONF_FILES_BASENAME)) {
r = path_extract_filename(*s, &p);
if (r < 0)
return log_debug_errno(r, "Failed to extract filename from '%s': %m", *s);
} else if (root) {
r = chaseat_prefix_root(*s, root, &p);
if (r < 0)
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", *s, root);
}
if (p)
r = strv_consume_with_size(&files, &n, TAKE_PTR(p));
else
r = strv_extend_with_size(&files, &n, *s);
if (r < 0)
return log_oom_debug();
}
*ret = TAKE_PTR(files);
return 0;
}
static int insert_replacement(Hashmap **fh, char *filename_replacement, char *resolved_replacement, char **ret) {
_cleanup_free_ char *fname = ASSERT_PTR(filename_replacement), *path = ASSERT_PTR(resolved_replacement);
int r;
assert(fh);
/* This consumes the input filename and path. */
const char *existing = hashmap_get(*fh, fname);
if (existing) {
log_debug("An entry with higher priority already exists ('%s' -> '%s'), ignoring the replacement: %s",
fname, existing, path);
if (ret)
*ret = NULL;
return 0;
}
_cleanup_free_ char *copy = NULL;
if (ret) {
copy = strdup(path);
if (!copy)
return log_oom_debug();
}
r = hashmap_ensure_put(fh, &string_hash_ops_free_free, fname, path);
if (r < 0) {
assert(r == -ENOMEM);
return log_oom_debug();
}
assert(r > 0);
log_debug("Inserted replacement: '%s' -> '%s'", fname, path);
TAKE_PTR(fname);
TAKE_PTR(path);
if (ret)
*ret = TAKE_PTR(copy);
return 0;
}
static int conf_files_list_impl(
const char *suffix,
int rfd,
const char *root, /* for logging, can be NULL */
ConfFilesFlags flags,
const char * const *dirs,
const char *replacement,
Hashmap **ret,
char **ret_inserted) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
_cleanup_set_free_ Set *masked = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(ret);
_cleanup_free_ char *filename_replacement = NULL, *resolved_dirpath_replacement = NULL, *resolved_replacement = NULL, *inserted = NULL;
if (replacement) {
r = path_extract_filename(replacement, &filename_replacement);
if (r < 0)
return r;
_cleanup_free_ char *d = NULL;
r = path_extract_directory(replacement, &d);
if (r < 0)
return r;
r = chaseat(rfd, d, CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &resolved_dirpath_replacement, /* ret_fd = */ NULL);
if (r < 0)
return r;
resolved_replacement = path_join(resolved_dirpath_replacement, filename_replacement);
if (!resolved_replacement)
return log_oom_debug();
}
STRV_FOREACH(p, dirs) {
_cleanup_closedir_ DIR *dir = NULL;
_cleanup_free_ char *path = NULL;
r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir);
if (r < 0) {
if (r != -ENOENT)
log_debug_errno(r, "Failed to chase and open directory '%s%s', ignoring: %m", strempty(root), *p);
continue;
}
if (resolved_replacement && path_equal(resolved_dirpath_replacement, path)) {
r = insert_replacement(&fh, TAKE_PTR(filename_replacement), TAKE_PTR(resolved_replacement), ret_inserted ? &inserted : NULL);
if (r < 0)
return r;
}
r = files_add(dir, path, rfd, root, &fh, &masked, suffix, flags);
if (r == -ENOMEM)
return r;
}
if (resolved_replacement) {
r = insert_replacement(&fh, TAKE_PTR(filename_replacement), TAKE_PTR(resolved_replacement), ret_inserted ? &inserted : NULL);
if (r < 0)
return r;
}
*ret = TAKE_PTR(fh);
if (ret_inserted)
*ret_inserted = TAKE_PTR(inserted);
return 0;
}
static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char **ret_root, char ***ret_dirs) {
@ -47,27 +339,25 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char
assert(ret_rfd);
assert(ret_root);
assert(ret_dirs || strv_isempty(dirs));
assert(ret_dirs);
r = empty_or_root_harder_to_null(&root);
if (r < 0)
return log_debug_errno(r, "Failed to determine if '%s' points to the root directory: %m", strempty(root));
if (ret_dirs) {
dirs_abs = strv_copy(dirs);
if (!dirs_abs)
return log_oom();
}
if (root) {
/* When a non-trivial root is specified, we will prefix the result later. Hence, it is not
/* WHen a non-trivial root is specified, we will prefix the result later. Hence, it is not
* necessary to modify each config directories here. but needs to normalize the root directory. */
r = path_make_absolute_cwd(root, &root_abs);
if (r < 0)
return log_debug_errno(r, "Failed to make '%s' absolute: %m", root);
path_simplify(root_abs);
} else if (ret_dirs) {
} else {
/* When an empty root or "/" is specified, we will open "/" below, hence we need to make
* each config directory absolute if relative. */
r = path_strv_make_absolute_cwd(dirs_abs);
@ -81,465 +371,10 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char
*ret_rfd = TAKE_FD(rfd);
*ret_root = TAKE_PTR(root_abs);
if (ret_dirs)
*ret_dirs = TAKE_PTR(dirs_abs);
return 0;
}
static int conf_file_prefix_root(ConfFile *c, const char *root) {
char *p;
int r;
assert(c);
r = chaseat_prefix_root(c->result, root, &p);
if (r < 0)
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, root);
free_and_replace(c->result, p);
r = chaseat_prefix_root(c->resolved_path, root, &p);
if (r < 0)
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->resolved_path, root);
free_and_replace(c->resolved_path, p);
/* Do not use chaseat_prefix_root(), as it is for the result of chaseat(), but the path is not chased. */
p = path_join(empty_to_root(root), skip_leading_slash(c->original_path));
if (!p)
return log_oom_debug();
path_simplify(p);
free_and_replace(c->original_path, p);
return 0;
}
int conf_file_new_at(const char *path, int rfd, ChaseFlags chase_flags, ConfFile **ret) {
int r;
assert(path);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(ret);
_cleanup_free_ char *root = NULL;
if (rfd >= 0 && DEBUG_LOGGING)
(void) fd_get_path(rfd, &root);
_cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1);
if (!c)
return log_oom_debug();
*c = (ConfFile) {
.original_path = strdup(path),
.fd = -EBADF,
};
if (!c->original_path)
return log_oom_debug();
r = path_extract_filename(path, &c->name);
if (r < 0)
return log_debug_errno(r, "Failed to extract filename from '%s': %m", path);
_cleanup_free_ char *dirpath = NULL, *resolved_dirpath = NULL;
r = path_extract_directory(path, &dirpath);
if (r < 0 && r != -EDESTADDRREQ)
return log_debug_errno(r, "Failed to extract directory from '%s': %m", path);
if (r >= 0) {
r = chaseat(rfd, dirpath,
CHASE_AT_RESOLVE_IN_ROOT | (FLAGS_SET(chase_flags, CHASE_NONEXISTENT) ? CHASE_NONEXISTENT : CHASE_MUST_BE_DIRECTORY),
&resolved_dirpath, /* ret_fd = */ NULL);
if (r < 0)
return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(dirpath));
}
c->result = path_join(resolved_dirpath, c->name);
if (!c->result)
return log_oom_debug();
r = chaseat(rfd, c->result, CHASE_AT_RESOLVE_IN_ROOT | chase_flags, &c->resolved_path, &c->fd);
if (r < 0)
return log_debug_errno(r, "Failed to chase '%s%s': %m", empty_to_root(root), skip_leading_slash(c->original_path));
if (c->fd >= 0 && fstat(c->fd, &c->st) < 0)
return log_debug_errno(r, "Failed to stat '%s%s': %m", empty_to_root(root), skip_leading_slash(c->resolved_path));
*ret = TAKE_PTR(c);
return 0;
}
int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, ConfFile **ret) {
int r;
assert(path);
assert((chase_flags & (CHASE_PREFIX_ROOT | CHASE_STEP)) == 0);
assert(ret);
_cleanup_free_ char *root_abs = NULL;
_cleanup_close_ int rfd = -EBADF;
r = prepare_dirs(root, /* dirs = */ NULL, &rfd, &root_abs, /* ret_dirs = */ NULL);
if (r < 0)
return r;
_cleanup_free_ char *path_abs = NULL;
if (!root_abs) {
r = path_make_absolute_cwd(path, &path_abs);
if (r < 0)
return log_debug_errno(r, "Failed to make '%s' absolute: %m", path);
path = path_abs;
}
_cleanup_(conf_file_freep) ConfFile *c = NULL;
r = conf_file_new_at(path, rfd, chase_flags, &c);
if (r < 0)
return r;
r = conf_file_prefix_root(c, root_abs);
if (r < 0)
return r;
*ret = TAKE_PTR(c);
return 0;
}
DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
conf_file_hash_ops,
char, string_hash_func, string_compare_func,
ConfFile, conf_file_free);
static int files_add(
DIR *dir,
const char *original_dirpath,
const char *resolved_dirpath,
int rfd,
const char *root, /* for logging, can be NULL */
Hashmap **files,
Set **masked,
const char *suffix,
ConfFilesFlags flags) {
int r;
assert(dir);
assert(original_dirpath);
assert(resolved_dirpath);
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(files);
assert(masked);
root = strempty(root);
FOREACH_DIRENT(de, dir, return log_debug_errno(errno, "Failed to read directory '%s/%s': %m",
root, skip_leading_slash(original_dirpath))) {
_cleanup_free_ char *original_path = path_join(original_dirpath, de->d_name);
if (!original_path)
return log_oom_debug();
/* Does this match the suffix? */
if (suffix && !endswith(de->d_name, suffix)) {
log_debug("Skipping file '%s/%s' with unexpected suffix.", root, skip_leading_slash(original_path));
continue;
}
/* Has this file already been found in an earlier directory? */
if (hashmap_contains(*files, de->d_name)) {
log_debug("Skipping overridden file '%s/%s'.", root, skip_leading_slash(original_path));
continue;
}
/* Has this been masked in an earlier directory? */
if ((flags & CONF_FILES_FILTER_MASKED) != 0 && set_contains(*masked, de->d_name)) {
log_debug("File '%s/%s' is masked by previous entry.", root, skip_leading_slash(original_path));
continue;
}
_cleanup_free_ char *p = path_join(resolved_dirpath, de->d_name);
if (!p)
return log_oom_debug();
_cleanup_free_ char *resolved_path = NULL;
_cleanup_close_ int fd = -EBADF;
bool need_stat = (flags & (CONF_FILES_FILTER_MASKED | CONF_FILES_REGULAR | CONF_FILES_DIRECTORY | CONF_FILES_EXECUTABLE)) != 0;
ChaseFlags chase_flags = CHASE_AT_RESOLVE_IN_ROOT;
if (!need_stat || FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK))
/* Even if no verification is requested, let's unconditionally call chaseat(),
* to drop unsafe symlinks. */
chase_flags |= CHASE_NONEXISTENT;
r = chaseat(rfd, p, chase_flags, &resolved_path, &fd);
if (r < 0) {
log_debug_errno(r, "Failed to chase '%s/%s', ignoring: %m",
root, skip_leading_slash(original_path));
continue;
}
if (r == 0) {
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK)) {
/* If the path points to /dev/null in a image or so, then the device node may not exist. */
if (path_equal(skip_leading_slash(resolved_path), "dev/null")) {
/* Mark this one as masked */
r = set_put_strdup(masked, de->d_name);
if (r < 0)
return log_oom_debug();
log_debug("File '%s/%s' is a mask (symlink to /dev/null).",
root, skip_leading_slash(original_path));
continue;
}
}
if (need_stat) {
/* If we need to have stat, skip the entry. */
log_debug_errno(SYNTHETIC_ERRNO(ENOENT), "Failed to chase '%s/%s', ignoring: %m",
root, skip_leading_slash(original_path));
continue;
}
}
/* Even if we do not need stat, let's take stat now. The caller may use the info later. */
struct stat st = {};
if (fd >= 0 && fstat(fd, &st) < 0) {
log_debug_errno(errno, "Failed to stat '%s/%s', ignoring: %m",
root, skip_leading_slash(original_path));
continue;
}
/* Is this a masking entry? */
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_SYMLINK) && stat_may_be_dev_null(&st)) {
/* Mark this one as masked */
r = set_put_strdup(masked, de->d_name);
if (r < 0)
return log_oom_debug();
log_debug("File '%s/%s' is a mask (symlink to /dev/null).", root, skip_leading_slash(original_path));
continue;
}
if (FLAGS_SET(flags, CONF_FILES_FILTER_MASKED_BY_EMPTY) && stat_is_empty(&st)) {
/* Mark this one as masked */
r = set_put_strdup(masked, de->d_name);
if (r < 0)
return log_oom_debug();
log_debug("File '%s/%s' is a mask (an empty file).", root, skip_leading_slash(original_path));
continue;
}
if (FLAGS_SET(flags, CONF_FILES_REGULAR|CONF_FILES_DIRECTORY)) {
if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
log_debug("Ignoring '%s/%s', as it is neither a regular file or directory.", root, skip_leading_slash(original_path));
continue;
}
} else {
/* Is this node a regular file? */
if (FLAGS_SET(flags, CONF_FILES_REGULAR) && !S_ISREG(st.st_mode)) {
log_debug("Ignoring '%s/%s', as it is not a regular file.", root, skip_leading_slash(original_path));
continue;
}
/* Is this node a directory? */
if (FLAGS_SET(flags, CONF_FILES_DIRECTORY) && !S_ISDIR(st.st_mode)) {
log_debug("Ignoring '%s/%s', as it is not a directory.", root, skip_leading_slash(original_path));
continue;
}
}
/* Does this node have the executable bit set?
* As requested: check if the file is marked executable. Note that we don't check access(X_OK)
* here, as we care about whether the file is marked executable at all, and not whether it is
* executable for us, because if so, such errors are stuff we should log about. */
if (FLAGS_SET(flags, CONF_FILES_EXECUTABLE) && (st.st_mode & 0111) == 0) {
log_debug("Ignoring '%s/%s', as it is not marked executable.", root, skip_leading_slash(original_path));
continue;
}
_cleanup_(conf_file_freep) ConfFile *c = new(ConfFile, 1);
if (!c)
return log_oom_debug();
*c = (ConfFile) {
.name = strdup(de->d_name),
.result = TAKE_PTR(p),
.original_path = TAKE_PTR(original_path),
.resolved_path = TAKE_PTR(resolved_path),
.fd = TAKE_FD(fd),
.st = st,
};
if (!c->name)
return log_oom_debug();
r = hashmap_ensure_put(files, &conf_file_hash_ops, c->name, c);
if (r < 0) {
assert(r == -ENOMEM);
return log_oom_debug();
}
assert(r > 0);
TAKE_PTR(c);
}
return 0;
}
static int dump_files(Hashmap *fh, const char *root, ConfFile ***ret_files, size_t *ret_n_files) {
ConfFile **files = NULL;
size_t n_files = 0;
int r;
CLEANUP_ARRAY(files, n_files, conf_file_free_many);
assert(ret_files);
assert(ret_n_files);
/* The entries in the array given by hashmap_dump_sorted() are still owned by the hashmap. */
r = hashmap_dump_sorted(fh, (void***) &files, &n_files);
if (r < 0)
return log_oom_debug();
/* Hence, we need to remove them from the hashmap. */
FOREACH_ARRAY(i, files, n_files)
assert_se(hashmap_remove(fh, (*i)->name) == *i);
if (root)
FOREACH_ARRAY(i, files, n_files) {
r = conf_file_prefix_root(*i, root);
if (r < 0)
return r;
}
*ret_files = TAKE_PTR(files);
*ret_n_files = n_files;
return 0;
}
static int copy_and_sort_files_from_hashmap(Hashmap *fh, const char *root, ConfFilesFlags flags, char ***ret) {
_cleanup_strv_free_ char **results = NULL;
_cleanup_free_ ConfFile **files = NULL;
size_t n_files = 0, n_results = 0;
int r;
assert(ret);
/* The entries in the array given by hashmap_dump_sorted() are still owned by the hashmap.
* Hence, do not use conf_file_free_many() for 'entries' */
r = hashmap_dump_sorted(fh, (void***) &files, &n_files);
if (r < 0)
return log_oom_debug();
FOREACH_ARRAY(i, files, n_files) {
ConfFile *c = *i;
if (FLAGS_SET(flags, CONF_FILES_BASENAME))
r = strv_extend_with_size(&results, &n_results, c->name);
else if (root) {
char *p;
r = chaseat_prefix_root(c->result, root, &p);
if (r < 0)
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, root);
r = strv_consume_with_size(&results, &n_results, TAKE_PTR(p));
} else
r = strv_extend_with_size(&results, &n_results, c->result);
if (r < 0)
return log_oom_debug();
}
*ret = TAKE_PTR(results);
return 0;
}
static int insert_replacement(Hashmap **fh, ConfFile *replacement, const ConfFile **ret) {
_cleanup_(conf_file_freep) ConfFile *c = ASSERT_PTR(replacement);
int r;
assert(fh);
assert(ret);
/* This consumes the input ConfFile. */
ConfFile *existing = hashmap_get(*fh, c->name);
if (existing) {
log_debug("An entry with higher priority '%s' -> '%s' already exists, ignoring the replacement: %s",
existing->name, existing->result, c->original_path);
*ret = NULL;
return 0;
}
r = hashmap_ensure_put(fh, &conf_file_hash_ops, c->name, c);
if (r < 0) {
assert(r == -ENOMEM);
return log_oom_debug();
}
assert(r > 0);
log_debug("Inserted replacement: '%s' -> '%s'", c->name, c->result);
*ret = TAKE_PTR(c);
return 0;
}
static int conf_files_list_impl(
const char *suffix,
int rfd,
const char *root, /* for logging, can be NULL */
ConfFilesFlags flags,
const char * const *dirs,
const char *replacement,
Hashmap **ret,
const ConfFile **ret_inserted) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
_cleanup_set_free_ Set *masked = NULL;
_cleanup_(conf_file_freep) ConfFile *c = NULL;
const ConfFile *inserted = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(ret);
if (replacement) {
r = conf_file_new_at(replacement, rfd, CHASE_NONEXISTENT, &c);
if (r < 0)
return r;
}
STRV_FOREACH(p, dirs) {
_cleanup_closedir_ DIR *dir = NULL;
_cleanup_free_ char *path = NULL;
r = chase_and_opendirat(rfd, *p, CHASE_AT_RESOLVE_IN_ROOT, &path, &dir);
if (r < 0) {
if (r != -ENOENT)
log_debug_errno(r, "Failed to chase and open directory '%s/%s', ignoring: %m", strempty(root), skip_leading_slash(*p));
continue;
}
if (c && streq_ptr(path_startswith(c->result, path), c->name)) {
r = insert_replacement(&fh, TAKE_PTR(c), &inserted);
if (r < 0)
return r;
}
r = files_add(dir, *p, path, rfd, root, &fh, &masked, suffix, flags);
if (r == -ENOMEM)
return r;
}
if (c) {
r = insert_replacement(&fh, TAKE_PTR(c), &inserted);
if (r < 0)
return r;
}
*ret = TAKE_PTR(fh);
if (ret_inserted)
*ret_inserted = inserted;
return 0;
}
int conf_files_list_strv(
char ***ret,
const char *suffix,
@ -567,35 +402,6 @@ int conf_files_list_strv(
return copy_and_sort_files_from_hashmap(fh, empty_to_root(root_abs), flags, ret);
}
int conf_files_list_strv_full(
const char *suffix,
const char *root,
ConfFilesFlags flags,
const char * const *dirs,
ConfFile ***ret_files,
size_t *ret_n_files) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
_cleanup_close_ int rfd = -EBADF;
_cleanup_free_ char *root_abs = NULL;
_cleanup_strv_free_ char **dirs_abs = NULL;
int r;
assert(ret_files);
assert(ret_n_files);
r = prepare_dirs(root, (char**) dirs, &rfd, &root_abs, &dirs_abs);
if (r < 0)
return r;
r = conf_files_list_impl(suffix, rfd, root_abs, flags, (const char * const *) dirs_abs,
/* replacement = */ NULL, &fh, /* ret_inserted = */ NULL);
if (r < 0)
return r;
return dump_files(fh, empty_to_root(root_abs), ret_files, ret_n_files);
}
int conf_files_list_strv_at(
char ***ret,
const char *suffix,
@ -620,48 +426,14 @@ int conf_files_list_strv_at(
return copy_and_sort_files_from_hashmap(fh, /* root = */ NULL, flags, ret);
}
int conf_files_list_strv_at_full(
const char *suffix,
int rfd,
ConfFilesFlags flags,
const char * const *dirs,
ConfFile ***ret_files,
size_t *ret_n_files) {
_cleanup_hashmap_free_ Hashmap *fh = NULL;
_cleanup_free_ char *root = NULL;
int r;
assert(rfd >= 0 || rfd == AT_FDCWD);
assert(ret_files);
assert(ret_n_files);
if (rfd >= 0 && DEBUG_LOGGING)
(void) fd_get_path(rfd, &root); /* for logging */
r = conf_files_list_impl(suffix, rfd, root, flags, dirs, /* replacement = */ NULL, &fh, /* ret_inserted = */ NULL);
if (r < 0)
return r;
return dump_files(fh, /* root = */ NULL, ret_files, ret_n_files);
}
int conf_files_list(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dir) {
return conf_files_list_strv(ret, suffix, root, flags, STRV_MAKE_CONST(dir));
}
int conf_files_list_full(const char *suffix, const char *root, ConfFilesFlags flags, const char *dir, ConfFile ***ret_files, size_t *ret_n_files) {
return conf_files_list_strv_full(suffix, root, flags, STRV_MAKE_CONST(dir), ret_files, ret_n_files);
}
int conf_files_list_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dir) {
return conf_files_list_strv_at(ret, suffix, rfd, flags, STRV_MAKE_CONST(dir));
}
int conf_files_list_at_full(const char *suffix, int rfd, ConfFilesFlags flags, const char *dir, ConfFile ***ret_files, size_t *ret_n_files) {
return conf_files_list_strv_at_full(suffix, rfd, flags, STRV_MAKE_CONST(dir), ret_files, ret_n_files);
}
int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dirs) {
_cleanup_strv_free_ char **d = NULL;
@ -674,19 +446,6 @@ int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, Co
return conf_files_list_strv(ret, suffix, root, flags, (const char**) d);
}
int conf_files_list_nulstr_full(const char *suffix, const char *root, ConfFilesFlags flags, const char *dirs, ConfFile ***ret_files, size_t *ret_n_files) {
_cleanup_strv_free_ char **d = NULL;
assert(ret_files);
assert(ret_n_files);
d = strv_split_nulstr(dirs);
if (!d)
return -ENOMEM;
return conf_files_list_strv_full(suffix, root, flags, (const char**) d, ret_files, ret_n_files);
}
int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dirs) {
_cleanup_strv_free_ char **d = NULL;
@ -699,19 +458,6 @@ int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, ConfFile
return conf_files_list_strv_at(ret, suffix, rfd, flags, (const char**) d);
}
int conf_files_list_nulstr_at_full(const char *suffix, int rfd, ConfFilesFlags flags, const char *dirs, ConfFile ***ret_files, size_t *ret_n_files) {
_cleanup_strv_free_ char **d = NULL;
assert(ret_files);
assert(ret_n_files);
d = strv_split_nulstr(dirs);
if (!d)
return -ENOMEM;
return conf_files_list_strv_at_full(suffix, rfd, flags, (const char**) d, ret_files, ret_n_files);
}
int conf_files_list_with_replacement(
const char *root,
char **config_dirs,
@ -725,7 +471,6 @@ int conf_files_list_with_replacement(
_cleanup_close_ int rfd = -EBADF;
_cleanup_free_ char *root_abs = NULL;
_cleanup_strv_free_ char **dirs_abs = NULL;
const ConfFile *c = NULL;
int r;
assert(ret_files);
@ -735,14 +480,18 @@ int conf_files_list_with_replacement(
return r;
r = conf_files_list_impl(".conf", rfd, root_abs, flags, (const char * const *) dirs_abs,
replacement, &fh, ret_inserted ? &c : NULL);
replacement, &fh, ret_inserted ? &inserted : NULL);
if (r < 0)
return r;
if (c) {
r = chaseat_prefix_root(c->result, root_abs, &inserted);
if (inserted) {
char *p;
r = chaseat_prefix_root(inserted, root_abs, &p);
if (r < 0)
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, empty_to_root(root_abs));
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", inserted, empty_to_root(root_abs));
free_and_replace(inserted, p);
}
r = copy_and_sort_files_from_hashmap(fh, empty_to_root(root_abs), flags, ret_files);

View File

@ -1,8 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <sys/stat.h>
#include "forward.h"
typedef enum ConfFilesFlags {
@ -15,36 +13,12 @@ typedef enum ConfFilesFlags {
CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY,
} ConfFilesFlags;
typedef struct ConfFile {
char *name; /* name of a file found in config directories */
char *result; /* resolved config directory with the original file name found in the directory */
char *original_path; /* original config directory with the original file name found in the directory */
char *resolved_path; /* fully resolved path, where the filename part of the path may be different from the original name */
int fd; /* O_PATH fd to resolved_path, -EBADF if the resolved_path does not exist */
struct stat st; /* stat of the file. */
} ConfFile;
ConfFile* conf_file_free(ConfFile *c);
DEFINE_TRIVIAL_CLEANUP_FUNC(ConfFile*, conf_file_free);
void conf_file_free_many(ConfFile **array, size_t n);
int conf_file_new_at(const char *path, int rfd, ChaseFlags chase_flags, ConfFile **ret);
int conf_file_new(const char *path, const char *root, ChaseFlags chase_flags, ConfFile **ret);
int conf_files_list(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dir);
int conf_files_list_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dir);
int conf_files_list_strv(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char* const* dirs);
int conf_files_list_strv_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char * const *dirs);
int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dirs);
int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dirs);
int conf_files_list_full(const char *suffix, const char *root, ConfFilesFlags flags, const char *dir, ConfFile ***ret_files, size_t *ret_n_files);
int conf_files_list_at_full(const char *suffix, int rfd, ConfFilesFlags flags, const char *dir, ConfFile ***ret_files, size_t *ret_n_files);
int conf_files_list_strv_full(const char *suffix, const char *root, ConfFilesFlags flags, const char * const *dirs, ConfFile ***ret_files, size_t *ret_n_files);
int conf_files_list_strv_at_full(const char *suffix, int rfd, ConfFilesFlags flags, const char * const *dirs, ConfFile ***ret_files, size_t *ret_n_files);
int conf_files_list_nulstr_full(const char *suffix, const char *root, ConfFilesFlags flags, const char *dirs, ConfFile ***ret_files, size_t *ret_n_files);
int conf_files_list_nulstr_at_full(const char *suffix, int rfd, ConfFilesFlags flags, const char *dirs, ConfFile ***ret_files, size_t *ret_n_files);
int conf_files_list_with_replacement(
const char *root,
char **config_dirs,

View File

@ -2,8 +2,8 @@
#include <fcntl.h>
#include <linux/fs.h>
#include <linux/kcmp.h>
#include <sys/ioctl.h>
#include <sys/kcmp.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h>
@ -16,6 +16,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "log.h"
#include "missing_syscall.h"
#include "mountpoint-util.h"
#include "parse-util.h"
#include "path-util.h"

View File

@ -6,6 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
#include <linux/magic.h>
#include "filesystems.h"
#include "missing_magic.h"
#include "stat-util.h"
struct FilesystemMagic {

View File

@ -104,7 +104,6 @@ typedef struct Set Set;
typedef struct dual_timestamp dual_timestamp;
typedef struct triple_timestamp triple_timestamp;
typedef struct ConfFile ConfFile;
typedef struct LockFile LockFile;
typedef struct PidRef PidRef;
typedef struct Prioq Prioq;

View File

@ -16,6 +16,7 @@
#include "label.h"
#include "lock-util.h"
#include "log.h"
#include "missing_syscall.h"
#include "mkdir.h"
#include "path-util.h"
#include "process-util.h"

View File

@ -3,9 +3,6 @@
set -eu
set -o pipefail
CC=${1:?}
shift
$CC -E -dM -include sys/socket.h "$@" - </dev/null | \
${1:?} -E -dM -include sys/socket.h -include "${2:?}" - </dev/null | \
grep -Ev 'AF_UNSPEC|AF_MAX' | \
awk '/^#define[ \t]+AF_[^ \t]+[ \t]+[AP]F_[^ \t]/ { print $2; }'

View File

@ -3,9 +3,6 @@
set -eu
set -o pipefail
CC=${1:?}
shift
$CC -dM -include linux/if_arp.h "$@" - </dev/null | \
${1:?} -dM -include "${2:?}" - </dev/null | \
awk '/^#define[ \t]+ARPHRD_[^ \t]+[ \t]+[^ \t]/ { print $2; }' | \
sed -e 's/ARPHRD_//'

View File

@ -3,9 +3,6 @@
set -eu
set -o pipefail
CC=${1:?}
shift
$CC -dM -include linux/capability.h "$@" - </dev/null | \
${1:?} -dM -include "${2:?}" - </dev/null | \
awk '/^#define[ \t]+CAP_[A-Z_]+[ \t]+/ { print $2; }' | \
grep -v CAP_LAST_CAP

View File

@ -6,9 +6,6 @@ set -o pipefail
# In kernel's arch/parisc/include/uapi/asm/errno.h, ECANCELLED and EREFUSED are defined as aliases of
# ECANCELED and ECONNREFUSED, respectively. Let's drop them.
CC=${1:?}
shift
$CC -dM -include errno.h "$@" - </dev/null | \
${1:?} -dM -include errno.h - </dev/null | \
grep -Ev '^#define[[:space:]]+(ECANCELLED|EREFUSED)' | \
awk '/^#define[ \t]+E[^ _]+[ \t]+/ { print $2; }'

Some files were not shown because too many files have changed in this diff Show More