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.
869b44e0f7
...
7aefb194e7
16
.github/workflows/coverage.yml
vendored
16
.github/workflows/coverage.yml
vendored
@ -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
|
||||
|
24
.github/workflows/linter.yml
vendored
24
.github/workflows/linter.yml
vendored
@ -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
|
||||
|
12
.github/workflows/mkosi.yml
vendored
12
.github/workflows/mkosi.yml
vendored
@ -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
3
NEWS
@ -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
|
||||
|
@ -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/`
|
||||
|
@ -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
|
||||
```
|
||||
|
@ -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 = []
|
||||
|
@ -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>
|
||||
|
||||
|
40
meson.build
40
meson.build
@ -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,
|
||||
|
@ -9,7 +9,7 @@ else
|
||||
fi
|
||||
|
||||
exec "${SPAWN[@]}" \
|
||||
mkosi box -- \
|
||||
mkosi sandbox -- \
|
||||
clangd \
|
||||
--compile-commands-dir=build \
|
||||
--path-mappings="\
|
||||
|
@ -1,7 +1,7 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
[Config]
|
||||
MinimumVersion=commit:184472f0f1f831ca29953546ec01fd941ff763a6
|
||||
MinimumVersion=commit:0d1143150835b21c1bfe64428df5f45b558280b1
|
||||
Dependencies=
|
||||
exitrd
|
||||
initrd
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -1,11 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
[Match]
|
||||
Architecture=uefi
|
||||
|
||||
[Content]
|
||||
Packages=
|
||||
sbsigntools
|
||||
|
||||
VolatilePackages=
|
||||
systemd-boot
|
@ -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
|
||||
|
@ -5,7 +5,6 @@ Distribution=centos
|
||||
|
||||
[Distribution]
|
||||
Release=10
|
||||
Repositories=epel,epel-next
|
||||
|
||||
[Build]
|
||||
Environment=
|
||||
|
9
mkosi/mkosi.conf.d/centos/mkosi.conf.d/10-epel.conf
Normal file
9
mkosi/mkosi.conf.d/centos/mkosi.conf.d/10-epel.conf
Normal file
@ -0,0 +1,9 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
[Match]
|
||||
Release=9
|
||||
|
||||
[Distribution]
|
||||
Repositories=
|
||||
epel
|
||||
epel-next
|
18
mkosi/mkosi.conf.d/centos/mkosi.conf.d/20-efi.conf
Normal file
18
mkosi/mkosi.conf.d/centos/mkosi.conf.d/20-efi.conf
Normal 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
|
12
mkosi/mkosi.conf.d/centos/mkosi.conf.d/20-epel-packages.conf
Normal file
12
mkosi/mkosi.conf.d/centos/mkosi.conf.d/20-epel-packages.conf
Normal 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
|
@ -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=
|
||||
|
@ -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=
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
18
mkosi/mkosi.conf.d/fedora/mkosi.conf.d/efi.conf
Normal file
18
mkosi/mkosi.conf.d/fedora/mkosi.conf.d/efi.conf
Normal 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
|
@ -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=
|
||||
|
@ -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=
|
||||
|
@ -1,5 +1,8 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
|
||||
[Match]
|
||||
Distribution=opensuse
|
||||
|
||||
[Build]
|
||||
Environment=
|
||||
GIT_URL=https://github.com/bmwiedemann/openSUSE
|
||||
|
@ -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"
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
_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;
|
||||
}
|
||||
|
||||
void conf_file_free_many(ConfFile **array, size_t n) {
|
||||
FOREACH_ARRAY(i, array, n)
|
||||
conf_file_free(*i);
|
||||
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;
|
||||
|
||||
free(array);
|
||||
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);
|
||||
|
@ -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,
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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"
|
||||
|
@ -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; }'
|
||||
|
@ -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_//'
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user