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

Compare commits

..

59 Commits

Author SHA1 Message Date
Daan De Meyer
869b44e0f7
Several follow-ups for recent SELinux changes (#38161) 2025-07-11 09:01:00 +02:00
Yu Watanabe
78738adf88 network/bridge-vlan: allow to configure bridge vlan on stacked bridge master interface
Fixes #38157.
2025-07-11 08:59:28 +02:00
Yu Watanabe
4d7851380a
Cleanups for missing_xyz.h headers (#37904)
Continuation of #37960.

The same concern as expalined in #37960 exists also in
missing_syscall.h. If we use enough new glibc, a function we want to use
may be already provided by glibc, but our baseline glibc may not. And it
is hard to detect in our daily development.

This moves all prototypes of syscalls to relevant headers, and missing
syscall functions are defined in relevant .c files of libc wrapper. This
way, we can use usual header as is, e.g. when we want to write code with
`move_mount()`, we can simply use sys/mount.h without checking if it is
supported by our baseline glibc.
2025-07-11 15:20:10 +09:00
Yu Watanabe
7b869ff949 journal: fix typo
Follow-up for df5b3426f60bb626f46f93fbdacecae274c1645b.
2025-07-11 14:12:42 +09:00
Yu Watanabe
369f311686 man: fix typo
Follow-up for 7aefb194e754cae9c166539a103e9fd6b7e59798.
2025-07-11 14:11:04 +09:00
Yu Watanabe
b1ce0a2b50
conf-files: make conf-file enumerators provide more detailed information of enumerated files (#38006)
This introduces `struct ConfFile` that stores detailed information of an
enumerated file, and introduces `conf_files_list_full()` and friends
that provide results in `ConfFile`.
Then make udev, hwdb, catalog, and cat-files use the new function and
struct to make them not read files outside of specified root directory.
2025-07-11 13:50:47 +09:00
Yu Watanabe
531e6a2091 raw-clone: move definition to .c file
Then, we can decrease the number of headers to be indirectly included
by including raw-clone.h. No functional change.
2025-07-11 13:05:46 +09:00
Yu Watanabe
0939d5c360 reboot-util: merge with raw-reboot.h
The header raw-reboot.h is only used with reboot-util. Let's merge them.
2025-07-11 13:05:46 +09:00
Yu Watanabe
1d81c3a74e docs: mention src/include/ directories 2025-07-11 13:05:46 +09:00
Yu Watanabe
c35606b272 include: use unit8_t for uuid
To emphasize it is an array of bytes.
This also align variables.
No functional changes. Just refactoring.
2025-07-11 13:05:46 +09:00
Yu Watanabe
3fc2a44043 include: move trivial kernel header wrappers to src/include/override/ 2025-07-11 13:05:46 +09:00
Yu Watanabe
543a48b653 libc-wrapper: introduce a tiny libc wrapper
Then, move syscall definitions to the wrapper, and prototypes are moved
to relevant headers.

This also adds checks for add_key() and request_key(), as one day
glibc may be going to add some of them separatedly.

The check for fspick in meson.build is dropped, as it is currently
unused in our code.

This also moves
- basic/missing_bpf.h -> include/override/linux/bpf.h,
- basic/missing_keyctl.h -> include/override/linux/keyctl.h.
2025-07-11 13:05:46 +09:00
Yu Watanabe
da522c9921 basic: move basic/missing_syscall_defs.h -> include/override/sys/syscall.h
This also moves syscall tables and generators to the same directory.

Note, inclusion of asm/sgidefs.h is dropped, as it is already included
by unistd.h and sys/syscall.h.
2025-07-11 13:05:46 +09:00
Yu Watanabe
2b912d2066 tree-wide: several cleanups for generating symbol lists and gperf files
- pass our system include directories to make generators use our libc
  wrappers and latest kernel headers,
- include relevant headers in generated gperf file,
- use files() rather than find_program(), as the result of
  find_program() cannot be passed to 'input' of custom_target(),
- move generate-bpf-delegate-configs.py to src/core/, as it is only used
  by libcore.
2025-07-11 13:05:42 +09:00
Yu Watanabe
1a60b97524 include: move libc header wrappers to src/include/override/, and kernel headers to src/include/uapi/
Preparation for later changes.
2025-07-11 12:44:26 +09:00
Yu Watanabe
98751cf16e
mkosi: various improvements (#38156) 2025-07-11 12:40:22 +09:00
Yu Watanabe
090c3f924c core/selinux-access: insert an empty line after function arguments
Follow-ups for fe3f2ac0734e64dcd729b00992a6261cbf4cc846 and
e3fef210c8903a9a3871ea5ba9b558b6cdbabea3.
2025-07-11 12:19:51 +09:00
Yu Watanabe
a1518f0a94 selinux-util: downgrade log level to LOG_DEBUG when error code is zero
Previously, the logger is only used in error paths, but since
fe3f2ac0734e64dcd729b00992a6261cbf4cc846, the logger is also used in a
success path. Let's not log loudly on success.

This also drops unused log_selinux_enforcing().
2025-07-11 11:46:20 +09:00
Yu Watanabe
1e29a967c7 catalog: do not read catalog files outside of specified root directory 2025-07-11 10:42:08 +09:00
Yu Watanabe
683efcf649 hwdb-util: do not read hwdb files outside of specified root directory 2025-07-11 10:42:08 +09:00
Yu Watanabe
4d000c4853 hwdb-util: coding style update
- use 'r' for storing results,
- use RET_GATHER().
2025-07-11 10:42:08 +09:00
Yu Watanabe
ab1333b2b7 udev-rules: do not read udev rules files outside of specified root directory 2025-07-11 10:42:08 +09:00
Yu Watanabe
bdfb884237 TEST-17-UDEV: conditionalize test cases for testuser
Then, we can also run the test script in our local machine.
2025-07-11 10:42:08 +09:00
Yu Watanabe
a4a6e21673 udevadm: do not read udev rules files outside of the specified root directory
With this change, an invalid symlink and an empty file is silently
ignored. Hence, the test code is slightly updated.
2025-07-11 10:42:08 +09:00
Yu Watanabe
661b5bfd21 pretty-print: make conf_files_cat() not show files outside of the specified root.
Then, make the function show the original and resolved path if they are
different.

With this change, procfs needs to be mounted on /proc/, hence the test
code is slightly updated.
2025-07-11 10:42:08 +09:00
Yu Watanabe
86c4e42380 pretty-print: several cleanups for cat_files()
- drop redundant error messages in cat_files(), as cat_file() internally
  logs errors,
- show an empty line and filename before opening file, to make not mix
  any error messages with the previous file,
- drop unnecessary fflush(),
- use RET_GATHER() and continue to show files even if some files cannot
  be shown.
2025-07-11 10:42:08 +09:00
Yu Watanabe
0e0b482a71 conf-files: introduce conf_files_list_full() and friends that provides results in ConfFile 2025-07-11 10:42:08 +09:00
Yu Watanabe
d38f87c56c conf-files: make conf_files_list() and friends internally use struct ConfFile
No functional change, just refactoring.
2025-07-11 10:41:50 +09:00
Yu Watanabe
31b7616420 conf-files: introduce struct ConfFile to store information of found conf file
It is currently unused, will be used later. Preparation for later changes.
2025-07-11 10:41:07 +09:00
Yu Watanabe
628f45f4a3 chase: allow to request O_PATH fd even with CHASE_NONEXISTENT 2025-07-11 10:39:55 +09:00
Yu Watanabe
99ae2ae328
test-cgroup: Ignore ENOENT from cg_create(); test-cgroup-util: Ignore ENXIO in one more place (#38158)
This was the only test failure building systemd-252-51.el9 in a
container, also previously reported against 252-rc1 under Gentoo in
#25015

This is a forward-port of the patch we actually started using for CIQ's
builds of the EL9-derived package, which was:

```diff
--- systemd-252/src/test/test-cgroup.c	2022-10-31 18:59:18.000000000 +0000
+++ systemd-252-test/src/test/test-cgroup.c	2025-07-10 00:47:07.541000000 +0000
@@ -62,7 +62,7 @@
         log_info("Paths for test:\n%s\n%s", test_a, test_b);
 
         r = cg_create(SYSTEMD_CGROUP_CONTROLLER, test_a);
-        if (IN_SET(r, -EPERM, -EACCES, -EROFS)) {
+        if (IN_SET(r, -EPERM, -EACCES, -EROFS, -ENOENT)) {
                 log_info_errno(r, "Skipping %s: %m", __func__);
                 return;
         }
```

I confirmed that the `ERRNO_IS_NEG_FS_WRITE_REFUSED` macro is equivalent
to checking the first 3 error codes above, so the addition of the check
for `ENOENT` is still just as relevant as it was in 252, but adding it
into the macro would be inconsistent with its name, description, and
possible other uses. Hence, in this PR I'm adding the extra check into
the `if`.
2025-07-11 10:38:04 +09:00
Yu Watanabe
878fa7d26e
journalctl: do not fail on SIGTERM/SIGINT or STDOUT disconnect when running with --follow (#38116)
Closes #38114.
2025-07-11 10:36:31 +09:00
Yu Watanabe
0c0b4d544c
io.systemd.Manager.Describe fix context/runtime split (#38135)
This PR rearranges fields in io.systemd.Manager.Describe according to
the guidance by Lennart:

> If a property can be set in a unit file, ever, then it belongs in context.
> Otherwise, it belongs to runtime.

Closes #38124.
2025-07-11 10:26:57 +09:00
Yu Watanabe
b3337feb55
Plumbing to perform SELinux checks in varlink API (#38146)
This PR does minimal changes to introduce varlink support. Ideally, the
code should switch to using `mac_selinux_get_our_label()` and new
`mac_selinux_get_peer_label()`. But I leave it for now to minimize
breakage. `mac_selinux_get_peer_label()` remains unused.

This is a prep step to merge
https://github.com/systemd/systemd/pull/38032
2025-07-11 10:20:36 +09:00
Solar Designer
52fe0a490d test-cgroup-util: Ignore ENXIO in one more place 2025-07-11 01:49:36 +02:00
Yu Watanabe
49bdc8b1e8 NEWS: mention about the exit code change in journalctl --follow 2025-07-11 08:45:46 +09:00
Yu Watanabe
d6b3793704 test: drop unnecessary disablement of pipefail 2025-07-11 08:45:46 +09:00
Yu Watanabe
054464ad52 main-func: drop unused DEFINE_MAIN_FUNCTION_WITH_POSITIVE_SIGNAL() 2025-07-11 08:44:43 +09:00
Yu Watanabe
390097724b journalctl: do not fail on SIGTERM/SIGINT, or when STDOUT is disconnected
The current behavior is not useful when e.g. pipefail is enabled.
Let's exit cleanly in such cases.

Closes #38114.
2025-07-11 08:41:10 +09:00
Solar Designer
470da65110 test-cgroup: Ignore ENOENT from cg_create()
which was the only test failure building systemd-252-51.el9 in a
container, also previously reported against 252-rc1 under Gentoo
in #25015
2025-07-11 00:28:14 +02:00
Ivan Kruglov
d5f4bd3700 selinux: mac_selinux_unit_access_check_varlink macros 2025-07-10 21:16:32 +02:00
Ivan Kruglov
e3fef210c8 selinux: mac_selinux_access_check_varlink_internal() 2025-07-10 21:16:32 +02:00
Ivan Kruglov
fe3f2ac073 selinux: check_access() 2025-07-10 21:16:32 +02:00
Ivan Kruglov
5dc3096efb core: leave a comment about context/runtime split 2025-07-10 21:08:11 +02:00
Ivan Kruglov
79eec46dfd core: move ControlGroup move runtime to context 2025-07-10 21:08:11 +02:00
Ivan Kruglov
89701e02ac core: move ConfirmSpawn from runtime to context 2025-07-10 21:08:11 +02:00
Ivan Kruglov
303d1b6b57 core: move ShowStatus/Log* from runtime to context 2025-07-10 21:08:11 +02:00
Ivan Kruglov
712f763036 core: move WatchdogDevice from runtime to context 2025-07-10 21:08:11 +02:00
Ivan Kruglov
545fde151a core: move RuntimeWatchdog* + RebootWatchdog + KExecWatchdog from runtime to spec 2025-07-10 21:08:11 +02:00
Ivan Kruglov
afa9992429 core: fix double Environment present in both context and runtime 2025-07-10 21:08:11 +02:00
Ivan Kruglov
a5d8520f86 core: move Version/Arch/Features/Taints/UnitPath from context to runtime 2025-07-10 21:08:11 +02:00
Ivan Kruglov
84c05ec632 selinux: get_our_contexts() 2025-07-10 21:06:51 +02:00
Ivan Kruglov
3484af2800 selinux: rename mac_selinux_access_check_internal() -> mac_selinux_access_check_bus_internal() 2025-07-10 21:06:51 +02:00
Ivan Kruglov
5a1cb174f8 selinux-utils: rename and expose log_selinux_enforcing_errno() 2025-07-10 21:06:51 +02:00
Ivan Kruglov
204e3cb6c8 selinux-util: mac_selinux_get_peer_label() 2025-07-10 21:06:51 +02:00
DaanDeMeyer
7f76ff2821 tree-wide: Use "mkosi box" instead of "mkosi sandbox"
The box verb was added as a synonym for sandbox. sandbox still works,
but let's switch to box as it's shorter.
2025-07-10 16:24:34 +02:00
DaanDeMeyer
a4488ae6ae mkosi: Drop unnecessary [Match] sections
These are already satisfied in every path that includes pkgenv.conf.
2025-07-10 16:24:34 +02:00
DaanDeMeyer
3800adc9e5 mkosi: Simplify centos/fedora configuration
Both EPEL 9 and 10 now have the packages we need except for dhcp-server
so let's get rid of the EPEL conditionals and simply skip the tests that
require dhcp-server on CentOS.

While we're at it, make sure we use the new Architecture=uefi match in
mkosi to simplify the uefi checks.
2025-07-10 16:24:34 +02:00
DaanDeMeyer
24a14e9050 mkosi: update mkosi commit reference to 184472f0f1f831ca29953546ec01fd941ff763a6
* 184472f0f1 mkosi-tools: make sure p11-kit dir exists when configuring module
* 9fb807884e mkosi-tools: Explicitly install p11-kit
* 9131877d60 Support matching against architectures with uefi support
* f1eab5a783 Rename sandbox verb to box
* d609f55d98 Fix /var/tmp directory cleanup
* 4997b9495c build(deps): bump github/codeql-action from 3.28.18 to 3.29.2
2025-07-10 16:24:34 +02:00
316 changed files with 2260 additions and 1620 deletions

View File

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

View File

@ -38,10 +38,10 @@ jobs:
LINTER_RULES_PATH: .github/linters LINTER_RULES_PATH: .github/linters
GITHUB_ACTIONS_CONFIG_FILE: actionlint.yml GITHUB_ACTIONS_CONFIG_FILE: actionlint.yml
- uses: systemd/mkosi@0d1143150835b21c1bfe64428df5f45b558280b1 - uses: systemd/mkosi@184472f0f1f831ca29953546ec01fd941ff763a6
- name: Check that tabs are not used in Python code - name: Check that tabs are not used in Python code
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' 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'
- name: Build tools tree - name: Build tools tree
run: | run: |
@ -51,29 +51,29 @@ jobs:
ToolsTreeRelease=rawhide ToolsTreeRelease=rawhide
EOF EOF
mkosi -f sandbox -- true mkosi -f box -- true
- name: Run mypy - name: Run mypy
run: | run: |
mkosi sandbox -- mypy --version mkosi box -- 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 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
- name: Run ruff check - name: Run ruff check
run: | run: |
mkosi sandbox -- ruff --version mkosi box -- 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 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
- name: Run ruff format - name: Run ruff format
run: | run: |
mkosi sandbox -- ruff --version mkosi box -- 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 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
then then
echo "Please run 'ruff format' on the above files or apply the diffs below manually" echo "Please run 'ruff format' on the above files or apply the diffs below manually"
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 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
fi fi
- name: Configure meson - name: Configure meson
run: mkosi sandbox -- env CC=clang CXX=clang++ meson setup -Dlocalegen-path=/usr/bin/locale-gen -Dcompat-mutable-uid-boundaries=true build run: mkosi box -- env CC=clang CXX=clang++ meson setup -Dlocalegen-path=/usr/bin/locale-gen -Dcompat-mutable-uid-boundaries=true build
- name: Run clang-tidy - name: Run clang-tidy
run: mkosi sandbox -- meson test -C build --suite=clang-tidy --print-errorlogs --no-stdsplit run: mkosi box -- meson test -C build --suite=clang-tidy --print-errorlogs --no-stdsplit

View File

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

3
NEWS
View File

@ -135,6 +135,9 @@ CHANGES WITH 258 in spe:
incompatible with PrivateDevices= and resulted in automatic extension incompatible with PrivateDevices= and resulted in automatic extension
of the DeviceAllow= list. The latter behaviour has been removed. 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: Announcements of Future Feature Removals:
* Support for System V service scripts is deprecated and will be * Support for System V service scripts is deprecated and will be

View File

@ -20,6 +20,9 @@ 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: 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/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. `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/`. 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/`.
@ -43,6 +46,12 @@ Any code that is used only for EFI goes under `src/boot/efi/`, and `src/fundamen
To summarize: To summarize:
`src/include/uapi/`
- copy of kernel headers
`src/include/override/`
- wrappers for libc and kernel headers
`src/fundamental/` `src/fundamental/`
- may be used by all code in the tree - may be used by all code in the tree
- may not use any code outside of `src/fundamental/` - 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 ```sh
$ mkosi -f genkey # Generate signing keys once. $ mkosi -f genkey # Generate signing keys once.
$ mkosi -f sandbox -- meson setup -Dbpf-framework=disabled build # bpftool detection inside mkosi sandbox is broken on Ubuntu Noble and older $ mkosi -f box -- meson setup -Dbpf-framework=disabled build # bpftool detection inside mkosi box is broken on Ubuntu Noble and older
$ mkosi -f sandbox -- meson compile -C build $ mkosi -f box -- meson compile -C build
$ mkosi -f sandbox -- build/systemctl --version $ mkosi -f box -- build/systemctl --version
$ mkosi -f sandbox -- meson test -C build # Run the unit tests $ mkosi -f box -- meson test -C build # Run the unit tests
``` ```
To build and boot an OS image with the latest systemd installed: To build and boot an OS image with the latest systemd installed:
```sh ```sh
$ mkosi -f sandbox -- meson compile -C build mkosi # (re-)build the OS image $ mkosi -f box -- meson compile -C build mkosi # (re-)build the OS image
$ mkosi boot # Boot the image with systemd-nspawn. $ mkosi boot # Boot the image with systemd-nspawn.
$ mkosi vm # Boot the image with qemu. $ 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 $ 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 $ $EDITOR src/core/main.c # or wherever you'd like to make your changes
$ mkosi -f genkey # Generate signing keys once. $ mkosi -f genkey # Generate signing keys once.
$ mkosi -f sandbox -- meson setup build # Set up meson $ mkosi -f box -- meson setup build # Set up meson
$ mkosi -f sandbox -- meson compile -C build mkosi # (re-)build the test image $ mkosi -f box -- meson compile -C build mkosi # (re-)build the test image
$ mkosi vm # Boot the image in qemu $ mkosi vm # Boot the image in qemu
$ git add -p # interactively put together your patch $ git add -p # interactively put together your patch
$ git commit # commit it $ git commit # commit it
@ -85,7 +85,7 @@ not required to write basic patches.
## Building the OS image without a tools tree ## Building the OS image without a tools tree
By default, `mkosi` will first build a tools tree and use it build the image and By default, `mkosi` will first build a tools tree and use it build the image and
provide the environment for `mkosi sandbox`. To disable the tools tree and use provide the environment for `mkosi box`. To disable the tools tree and use
binaries from your host instead, write the following to `mkosi/mkosi.local.conf`: binaries from your host instead, write the following to `mkosi/mkosi.local.conf`:
```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 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. mkosi tools tree to avoid needing to install clangd on the host machine.
All that is required is to run `mkosi -f sandbox true` once to make sure the tools tree is available and to modify All that is required is to run `mkosi -f box 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. 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: 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: compilation database used by clangd to use clang as the compiler as well:
```sh ```sh
$ mkosi sandbox -- env CC=clang CXX=clang++ meson setup build $ mkosi box -- env CC=clang CXX=clang++ meson setup build
``` ```
Additionally, the `gensources` target can be used to make sure all generated 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. exist.
```sh ```sh
$ mkosi sandbox -- ninja -C build gensources $ mkosi box -- ninja -C build gensources
``` ```

View File

@ -20,9 +20,10 @@ xsltproc_flags = [
'--stringparam', 'man.copyright.section.enabled', '0', '--stringparam', 'man.copyright.section.enabled', '0',
'--stringparam', 'systemd.version', '@0@'.format(meson.project_version()), '--stringparam', 'systemd.version', '@0@'.format(meson.project_version()),
'--path', '--path',
'@0@:@1@:@2@'.format(meson.current_build_dir(), '@0@:@1@:@2@:@3@'.format(meson.current_build_dir(),
meson.current_source_dir(), meson.current_source_dir(),
libshared_build_dir)] libshared_build_dir,
libcore_build_dir)]
custom_man_xsl = files('custom-man.xsl') custom_man_xsl = files('custom-man.xsl')
custom_html_xsl = files('custom-html.xsl') custom_html_xsl = files('custom-html.xsl')
@ -35,17 +36,6 @@ custom_entities_ent = custom_target(
man_page_depends += custom_entities_ent 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 = [] man_pages = []
html_pages = [] html_pages = []
source_xml_files = [] 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 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 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 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 choosen upon bpffs mount. get a token which will enable for that user namespace the BPF functionalities chosen upon bpffs mount.
A more detailed explanation of the feature can be found in this A more detailed explanation of the feature can be found in this
<ulink url="https://lwn.net/Articles/947173/">LWN post</ulink>.</para> <ulink url="https://lwn.net/Articles/947173/">LWN post</ulink>.</para>

View File

@ -580,7 +580,6 @@ foreach ident : [
['fsconfig', '''#include <sys/mount.h>'''], # since glibc-2.36 ['fsconfig', '''#include <sys/mount.h>'''], # since glibc-2.36
['fsmount', '''#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 ['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 ['mount_setattr', '''#include <sys/mount.h>'''], # since glibc-2.36
['move_mount', '''#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 ['open_tree', '''#include <sys/mount.h>'''], # since glibc-2.36
@ -591,15 +590,17 @@ foreach ident : [
['ioprio_get', '''#include <sched.h>'''], # no known header declares ioprio_get ['ioprio_get', '''#include <sched.h>'''], # no known header declares ioprio_get
['ioprio_set', '''#include <sched.h>'''], # no known header declares ioprio_set ['ioprio_set', '''#include <sched.h>'''], # no known header declares ioprio_set
['rt_tgsigqueueinfo', '''#include <signal.h>'''], # no known header declares rt_tgsigqueueinfo ['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 ['quotactl_fd', '''#include <sys/quota.h>'''], # no known header declares quotactl_fd
['fchmodat2', '''#include <sys/stat.h>'''], # no known header declares fchmodat2 ['fchmodat2', '''#include <sys/stat.h>'''], # no known header declares fchmodat2
['bpf', '''#include <sys/syscall.h>'''], # no known header declares bpf ['bpf', '''#include <sys/syscall.h>'''], # no known header declares bpf
['kcmp', '''#include <sys/syscall.h>'''], # no known header declares kcmp ['kcmp', '''#include <sys/syscall.h>'''], # no known header declares kcmp
['keyctl', '''#include <sys/syscall.h>'''], # no known header declares keyctl ['keyctl', '''#include <sys/syscall.h>'''], # no known header declares keyctl
['pivot_root', '''#include <sys/syscall.h>'''], # no known header declares pivot_root ['add_key', '''#include <sys/syscall.h>'''], # no known header declares add_key
['request_key', '''#include <sys/syscall.h>'''], # no known header declares request_key
['setxattrat', '''#include <sys/xattr.h>'''], # no known header declares setxattrat ['setxattrat', '''#include <sys/xattr.h>'''], # no known header declares setxattrat
['removexattrat', '''#include <sys/xattr.h>'''], # no known header declares removexattrat ['removexattrat', '''#include <sys/xattr.h>'''], # no known header declares removexattrat
['open_tree_attr', '''#include <sys/mount.h>'''], # no known header declares open_tree_attr ['pivot_root', '''#include <unistd.h>'''], # no known header declares pivot_root
] ]
have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE') have = cc.has_function(ident[0], prefix : ident[1], args : '-D_GNU_SOURCE')
@ -2008,16 +2009,33 @@ dbus_programs = []
# A list of boot stubs. Required for testing of ukify. # A list of boot stubs. Required for testing of ukify.
boot_stubs = [] 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 = [ basic_includes = [
include_directories( include_directories(
'src/basic', 'src/basic',
'src/fundamental', 'src/fundamental',
'src/systemd', 'src/systemd',
), ),
include_directories( system_includes,
'src/basic/include',
is_system : true,
),
version_include, version_include,
] ]
@ -2039,6 +2057,8 @@ includes = [libsystemd_includes, include_directories('src/shared')]
subdir('po') subdir('po')
subdir('catalog') subdir('catalog')
subdir('src/include')
subdir('src/libc')
subdir('src/fundamental') subdir('src/fundamental')
subdir('src/basic') subdir('src/basic')
subdir('src/libsystemd') subdir('src/libsystemd')
@ -2054,7 +2074,8 @@ 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. # Make sure our library is never deleted from memory, so that our open logging fds don't leak on dlopen/dlclose cycles.
'-z', 'nodelete', '-z', 'nodelete',
'-Wl,--version-script=' + libsystemd_sym_path], '-Wl,--version-script=' + libsystemd_sym_path],
link_with : [libbasic_static], link_with : [libc_wrapper_static,
libbasic_static],
link_whole : [libsystemd_static], link_whole : [libsystemd_static],
dependencies : [librt, dependencies : [librt,
threads, threads,
@ -2067,6 +2088,7 @@ libsystemd = shared_library(
if static_libsystemd != 'false' if static_libsystemd != 'false'
install_libsystemd_static = static_library( install_libsystemd_static = static_library(
'systemd', 'systemd',
libc_wrapper_sources,
libsystemd_sources, libsystemd_sources,
basic_sources, basic_sources,
fundamental_sources, fundamental_sources,
@ -2112,6 +2134,7 @@ libudev = shared_library(
if static_libudev != 'false' if static_libudev != 'false'
install_libudev_static = static_library( install_libudev_static = static_library(
'udev', 'udev',
libc_wrapper_sources,
basic_sources, basic_sources,
fundamental_sources, fundamental_sources,
shared_sources, shared_sources,
@ -2216,6 +2239,7 @@ nss_template = {
# Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned # Note that we link NSS modules with '-z nodelete' so that mempools never get orphaned
'link_args' : ['-z', 'nodelete'], 'link_args' : ['-z', 'nodelete'],
'link_with' : [ 'link_with' : [
libc_wrapper_static,
libsystemd_static, libsystemd_static,
libshared_static, libshared_static,
libbasic_static, libbasic_static,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,18 +0,0 @@
# 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

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,18 +0,0 @@
# 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,13 +4,7 @@
Environment=WITH_DEBUG=1 Environment=WITH_DEBUG=1
[Match] [Match]
Architecture=|x86 Architecture=uefi
Architecture=|x86-64
Architecture=|arm
Architecture=|arm64
Architecture=|riscv32
Architecture=|riscv64
Architecture=|loongarch64
[Content] [Content]
VolatilePackages= VolatilePackages=

View File

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

View File

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

View File

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

View File

@ -126,10 +126,6 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME)); assert(!FLAGS_SET(flags, CHASE_STEP|CHASE_EXTRACT_FILENAME));
assert(dir_fd >= 0 || dir_fd == AT_FDCWD); 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)) if (FLAGS_SET(flags, CHASE_STEP))
assert(!ret_fd); assert(!ret_fd);
@ -552,11 +548,13 @@ int chaseat(int dir_fd, const char *path, ChaseFlags flags, char **ret_path, int
} }
if (ret_fd) { if (ret_fd) {
/* Return the O_PATH fd we currently are looking to the caller. It can translate it to a if (exists) {
* 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); assert(fd >= 0);
*ret_fd = TAKE_FD(fd); *ret_fd = TAKE_FD(fd);
} else
*ret_fd = -EBADF;
} }
if (FLAGS_SET(flags, CHASE_STEP)) if (FLAGS_SET(flags, CHASE_STEP))

View File

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

View File

@ -20,316 +20,24 @@
#include "string-util.h" #include "string-util.h"
#include "strv.h" #include "strv.h"
static int files_add( ConfFile* conf_file_free(ConfFile *c) {
DIR *dir, if (!c)
const char *dirpath, return NULL;
int rfd,
const char *root, /* for logging, can be NULL */
Hashmap **files,
Set **masked,
const char *suffix,
ConfFilesFlags flags) {
int r; free(c->name);
free(c->result);
free(c->original_path);
free(c->resolved_path);
safe_close(c->fd);
assert(dir); return mfree(c);
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;
} }
static int copy_and_sort_files_from_hashmap(Hashmap *fh, const char *root, ConfFilesFlags flags, char ***ret) { void conf_file_free_many(ConfFile **array, size_t n) {
_cleanup_free_ char **sv = NULL; FOREACH_ARRAY(i, array, n)
_cleanup_strv_free_ char **files = NULL; conf_file_free(*i);
size_t n = 0;
int r;
assert(ret); free(array);
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) { static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char **ret_root, char ***ret_dirs) {
@ -339,25 +47,27 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char
assert(ret_rfd); assert(ret_rfd);
assert(ret_root); assert(ret_root);
assert(ret_dirs); assert(ret_dirs || strv_isempty(dirs));
r = empty_or_root_harder_to_null(&root); r = empty_or_root_harder_to_null(&root);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to determine if '%s' points to the root directory: %m", strempty(root)); 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); dirs_abs = strv_copy(dirs);
if (!dirs_abs) if (!dirs_abs)
return log_oom(); return log_oom();
}
if (root) { 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. */ * necessary to modify each config directories here. but needs to normalize the root directory. */
r = path_make_absolute_cwd(root, &root_abs); r = path_make_absolute_cwd(root, &root_abs);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to make '%s' absolute: %m", root); return log_debug_errno(r, "Failed to make '%s' absolute: %m", root);
path_simplify(root_abs); path_simplify(root_abs);
} else { } else if (ret_dirs) {
/* When an empty root or "/" is specified, we will open "/" below, hence we need to make /* When an empty root or "/" is specified, we will open "/" below, hence we need to make
* each config directory absolute if relative. */ * each config directory absolute if relative. */
r = path_strv_make_absolute_cwd(dirs_abs); r = path_strv_make_absolute_cwd(dirs_abs);
@ -371,10 +81,465 @@ static int prepare_dirs(const char *root, char * const *dirs, int *ret_rfd, char
*ret_rfd = TAKE_FD(rfd); *ret_rfd = TAKE_FD(rfd);
*ret_root = TAKE_PTR(root_abs); *ret_root = TAKE_PTR(root_abs);
if (ret_dirs)
*ret_dirs = TAKE_PTR(dirs_abs); *ret_dirs = TAKE_PTR(dirs_abs);
return 0; 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( int conf_files_list_strv(
char ***ret, char ***ret,
const char *suffix, const char *suffix,
@ -402,6 +567,35 @@ int conf_files_list_strv(
return copy_and_sort_files_from_hashmap(fh, empty_to_root(root_abs), flags, ret); 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( int conf_files_list_strv_at(
char ***ret, char ***ret,
const char *suffix, const char *suffix,
@ -426,14 +620,48 @@ int conf_files_list_strv_at(
return copy_and_sort_files_from_hashmap(fh, /* root = */ NULL, flags, ret); 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) { 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)); 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) { 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)); 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) { int conf_files_list_nulstr(char ***ret, const char *suffix, const char *root, ConfFilesFlags flags, const char *dirs) {
_cleanup_strv_free_ char **d = NULL; _cleanup_strv_free_ char **d = NULL;
@ -446,6 +674,19 @@ 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); 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) { int conf_files_list_nulstr_at(char ***ret, const char *suffix, int rfd, ConfFilesFlags flags, const char *dirs) {
_cleanup_strv_free_ char **d = NULL; _cleanup_strv_free_ char **d = NULL;
@ -458,6 +699,19 @@ 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); 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( int conf_files_list_with_replacement(
const char *root, const char *root,
char **config_dirs, char **config_dirs,
@ -471,6 +725,7 @@ int conf_files_list_with_replacement(
_cleanup_close_ int rfd = -EBADF; _cleanup_close_ int rfd = -EBADF;
_cleanup_free_ char *root_abs = NULL; _cleanup_free_ char *root_abs = NULL;
_cleanup_strv_free_ char **dirs_abs = NULL; _cleanup_strv_free_ char **dirs_abs = NULL;
const ConfFile *c = NULL;
int r; int r;
assert(ret_files); assert(ret_files);
@ -480,18 +735,14 @@ int conf_files_list_with_replacement(
return r; return r;
r = conf_files_list_impl(".conf", rfd, root_abs, flags, (const char * const *) dirs_abs, r = conf_files_list_impl(".conf", rfd, root_abs, flags, (const char * const *) dirs_abs,
replacement, &fh, ret_inserted ? &inserted : NULL); replacement, &fh, ret_inserted ? &c : NULL);
if (r < 0) if (r < 0)
return r; return r;
if (inserted) { if (c) {
char *p; r = chaseat_prefix_root(c->result, root_abs, &inserted);
r = chaseat_prefix_root(inserted, root_abs, &p);
if (r < 0) if (r < 0)
return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", inserted, empty_to_root(root_abs)); return log_debug_errno(r, "Failed to prefix '%s' with root '%s': %m", c->result, 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); r = copy_and_sort_files_from_hashmap(fh, empty_to_root(root_abs), flags, ret_files);

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <sys/stat.h>
#include "forward.h" #include "forward.h"
typedef enum ConfFilesFlags { typedef enum ConfFilesFlags {
@ -13,12 +15,36 @@ typedef enum ConfFilesFlags {
CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY, CONF_FILES_FILTER_MASKED = CONF_FILES_FILTER_MASKED_BY_SYMLINK | CONF_FILES_FILTER_MASKED_BY_EMPTY,
} ConfFilesFlags; } 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(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_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(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_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(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_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( int conf_files_list_with_replacement(
const char *root, const char *root,
char **config_dirs, char **config_dirs,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,8 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* To make struct xattr_args defined, which is used by setxattrat(). Note, the kernel header must be
* included before the glibc header, otherwise the struct will not be defined. */
#include <linux/xattr.h>
#include_next <sys/xattr.h>

View File

@ -3,7 +3,6 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "keyring-util.h" #include "keyring-util.h"
#include "log.h" #include "log.h"
#include "missing_syscall.h"
int keyring_read(key_serial_t serial, void **ret, size_t *ret_size) { int keyring_read(key_serial_t serial, void **ret, size_t *ret_size) {
size_t bufsize = 100; size_t bufsize = 100;

View File

@ -1,8 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <sys/keyctl.h> /* IWYU pragma: export */
#include "forward.h" #include "forward.h"
#include "missing_keyctl.h"
/* Like TAKE_PTR() but for key_serial_t, resetting them to -1 */ /* Like TAKE_PTR() but for key_serial_t, resetting them to -1 */
#define TAKE_KEY_SERIAL(key_serial) TAKE_GENERIC(key_serial, key_serial_t, -1) #define TAKE_KEY_SERIAL(key_serial) TAKE_GENERIC(key_serial, key_serial_t, -1)

View File

@ -84,6 +84,7 @@ basic_sources = files(
'psi-util.c', 'psi-util.c',
'random-util.c', 'random-util.c',
'ratelimit.c', 'ratelimit.c',
'raw-clone.c',
'recurse-dir.c', 'recurse-dir.c',
'replace-var.c', 'replace-var.c',
'rlimit-util.c', 'rlimit-util.c',
@ -119,44 +120,26 @@ basic_sources = files(
sources += basic_sources sources += basic_sources
missing_audit_h = files('missing_audit.h')
missing_syscall_def_h = files('missing_syscall_def.h')
basic_sources += missing_syscall_def_h
generate_af_list = find_program('generate-af-list.sh')
af_list_txt = custom_target(
output : 'af-list.txt',
command : [generate_af_list, cpp, files('include/sys/socket.h')],
capture : true)
generate_arphrd_list = find_program('generate-arphrd-list.sh')
arphrd_list_txt = custom_target(
output : 'arphrd-list.txt',
command : [generate_arphrd_list, cpp, files('include/linux/if_arp.h')],
capture : true)
generate_cap_list = find_program('generate-cap-list.sh')
cap_list_txt = custom_target(
output : 'cap-list.txt',
command : [generate_cap_list, cpp, files('include/linux/capability.h')],
capture : true)
generate_errno_list = find_program('generate-errno-list.sh')
errno_list_txt = custom_target(
output : 'errno-list.txt',
command : [generate_errno_list, cpp],
capture : true)
generated_gperf_headers = [] generated_gperf_headers = []
foreach item : [['af', af_list_txt, 'af', '', ['<sys/socket.h>']], foreach item : [
['arphrd', arphrd_list_txt, 'arphrd', 'ARPHRD_', []], # name, source, struct name, prefix, headers
['cap', cap_list_txt, 'capability', '', []], ['af', af_sources, 'af', '', ['<sys/socket.h>'], ],
['errno', errno_list_txt, 'errno', '', []]] ['arphrd', arphrd_sources, 'arphrd', 'ARPHRD_', ['<linux/if_arp.h>'], ],
['cap', cap_sources, 'capability', '', ['<linux/capability.h>'], ],
['errno', [], 'errno', '', ['<errno.h>'], ],
]
fname = '@0@-list.txt'.format(item[0])
generate_list = files('generate-@0@-list.sh'.format(item[0]))
list_txt = custom_target(
input : [generate_list, item[1]],
output : fname,
command : [env, 'bash', generate_list, cpp, system_include_args],
capture : true)
fname = '@0@-from-name.gperf'.format(item[0]) fname = '@0@-from-name.gperf'.format(item[0])
gperf_file = custom_target( gperf_file = custom_target(
input : item[1], input : list_txt,
output : fname, output : fname,
command : [generate_gperfs, item[2], item[3], '@INPUT@'] + item[4], command : [generate_gperfs, item[2], item[3], '@INPUT@'] + item[4],
capture : true) capture : true)
@ -176,7 +159,7 @@ foreach item : [['af', af_list_txt, 'af', '', ['<sys/sock
fname = '@0@-to-name.inc'.format(item[0]) fname = '@0@-to-name.inc'.format(item[0])
awkscript = '@0@-to-name.awk'.format(item[0]) awkscript = '@0@-to-name.awk'.format(item[0])
target2 = custom_target( target2 = custom_target(
input : [awkscript, item[1]], input : [awkscript, list_txt],
output : fname, output : fname,
command : [awk, '-f', '@INPUT0@', '@INPUT1@'], command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
capture : true) capture : true)
@ -189,61 +172,13 @@ basic_sources += generated_gperf_headers
############################################################ ############################################################
arch_list = [
'alpha',
'arc',
'arm',
'arm64',
'i386',
'ia64',
'loongarch64',
'm68k',
'mips64',
'mips64n32',
'mipso32',
'parisc',
'powerpc',
'powerpc64',
'riscv32',
'riscv64',
's390',
's390x',
'sparc',
'x86_64'
]
run_target(
'update-syscall-tables',
command : [update_syscall_tables_sh, meson.current_source_dir()] + arch_list)
syscall_list_txt = files('syscall-list.txt')
syscall_lists = []
foreach arch: arch_list
syscall_lists += files('syscalls-@0@.txt'.format(arch))
endforeach
missing_syscalls_py = find_program('missing_syscalls.py')
run_target(
'update-syscall-header',
command : [missing_syscalls_py,
missing_syscall_def_h,
syscall_lists])
############################################################
filesystem_includes = files(
'include/linux/magic.h',
'missing_magic.h',
)
check_filesystems = find_program('check-filesystems.sh') check_filesystems = find_program('check-filesystems.sh')
r = run_command( r = run_command(
[ [
'env', '--chdir', meson.project_build_root(), 'env', '--chdir', meson.project_build_root(),
check_filesystems, cpp, files('filesystems-gperf.gperf') check_filesystems, cpp, files('filesystems-gperf.gperf'),
] + filesystem_includes, system_include_args,
],
check: false, check: false,
) )
if r.returncode() != 0 if r.returncode() != 0
@ -273,17 +208,8 @@ filesystem_switch_case_inc = custom_target(
'@INPUT@'], '@INPUT@'],
capture : true) capture : true)
generate_bpf_delegate_configs = find_program('generate-bpf-delegate-configs.py') generated_sources += [filesystem_list_inc, filesystem_switch_case_inc, filesystems_gperf_h]
bpf_delegate_configs_inc = custom_target( basic_sources += [filesystem_list_inc, filesystem_switch_case_inc, filesystems_gperf_h]
input : files('include/linux/bpf.h'),
output : 'bpf-delegate-configs.inc',
command : [generate_bpf_delegate_configs,
'code',
'@INPUT@'],
capture : true)
generated_sources += [filesystem_list_inc, filesystem_switch_case_inc, filesystems_gperf_h, bpf_delegate_configs_inc]
basic_sources += [filesystem_list_inc, filesystem_switch_case_inc, filesystems_gperf_h, bpf_delegate_configs_inc]
libbasic_static = static_library( libbasic_static = static_library(
'basic', 'basic',

View File

@ -1,249 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
/* Missing glibc definitions to access certain kernel APIs */
#include <linux/mempolicy.h>
#include <sched.h>
#include <signal.h>
#include <sys/syscall.h>
#include <sys/xattr.h>
#include <unistd.h>
#ifdef ARCH_MIPS
#include <asm/sgidefs.h>
#endif
#include "forward.h"
#include "missing_keyctl.h"
#include "missing_syscall_def.h"
/* ======================================================================= */
#if !HAVE_FCHMODAT2
/* since kernel v6.6 (78252deb023cf0879256fcfbafe37022c390762b) */
static inline int missing_fchmodat2(int dirfd, const char *path, mode_t mode, int flags) {
return syscall(__NR_fchmodat2, dirfd, path, mode, flags);
}
# define fchmodat2 missing_fchmodat2
#endif
/* ======================================================================= */
#if !HAVE_PIVOT_ROOT
static inline int missing_pivot_root(const char *new_root, const char *put_old) {
return syscall(__NR_pivot_root, new_root, put_old);
}
# define pivot_root missing_pivot_root
#endif
/* ======================================================================= */
#if !HAVE_IOPRIO_GET
static inline int missing_ioprio_get(int which, int who) {
return syscall(__NR_ioprio_get, which, who);
}
# define ioprio_get missing_ioprio_get
#endif
/* ======================================================================= */
#if !HAVE_IOPRIO_SET
static inline int missing_ioprio_set(int which, int who, int ioprio) {
return syscall(__NR_ioprio_set, which, who, ioprio);
}
# define ioprio_set missing_ioprio_set
#endif
/* ======================================================================= */
#if !HAVE_KCMP
static inline int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2) {
return syscall(__NR_kcmp, pid1, pid2, type, idx1, idx2);
}
# define kcmp missing_kcmp
#endif
/* ======================================================================= */
#if !HAVE_KEYCTL
static inline long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) {
return syscall(__NR_keyctl, cmd, arg2, arg3, arg4, arg5);
# define keyctl missing_keyctl
}
/* ======================================================================= */
static inline key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid) {
return syscall(__NR_add_key, type, description, payload, plen, ringid);
# define add_key missing_add_key
}
/* ======================================================================= */
static inline key_serial_t missing_request_key(const char *type, const char *description, const char * callout_info, key_serial_t destringid) {
return syscall(__NR_request_key, type, description, callout_info, destringid);
# define request_key missing_request_key
}
#endif
/* ======================================================================= */
#if !HAVE_BPF
union bpf_attr;
static inline int missing_bpf(int cmd, union bpf_attr *attr, size_t size) {
return (int) syscall(__NR_bpf, cmd, attr, size);
}
# define bpf missing_bpf
#endif
/* ======================================================================= */
#if !HAVE_SET_MEMPOLICY
static inline long missing_set_mempolicy(int mode, const unsigned long *nodemask,
unsigned long maxnode) {
return syscall(__NR_set_mempolicy, mode, nodemask, maxnode);
}
# define set_mempolicy missing_set_mempolicy
#endif
#if !HAVE_GET_MEMPOLICY
static inline long missing_get_mempolicy(int *mode, unsigned long *nodemask,
unsigned long maxnode, void *addr,
unsigned long flags) {
return syscall(__NR_get_mempolicy, mode, nodemask, maxnode, addr, flags);
}
# define get_mempolicy missing_get_mempolicy
#endif
/* ======================================================================= */
#if !HAVE_PIDFD_SEND_SIGNAL
/* since kernel v5.1 (3eb39f47934f9d5a3027fe00d906a45fe3a15fad) */
static inline int missing_pidfd_send_signal(int fd, int sig, siginfo_t *info, unsigned flags) {
return syscall(__NR_pidfd_send_signal, fd, sig, info, flags);
}
# define pidfd_send_signal missing_pidfd_send_signal
#endif
/* ======================================================================= */
#if !HAVE_PIDFD_OPEN
/* since kernel v5.3 (7615d9e1780e26e0178c93c55b73309a5dc093d7) */
static inline int missing_pidfd_open(pid_t pid, unsigned flags) {
return syscall(__NR_pidfd_open, pid, flags);
}
# define pidfd_open missing_pidfd_open
#endif
/* ======================================================================= */
#if !HAVE_RT_TGSIGQUEUEINFO
static inline int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info) {
return syscall(__NR_rt_tgsigqueueinfo, tgid, tid, sig, info);
}
# define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo
#endif
/* ======================================================================= */
#if !HAVE_EXECVEAT
/* since kernel v3.19 (51f39a1f0cea1cacf8c787f652f26dfee9611874) */
static inline int missing_execveat(int dirfd, const char *pathname,
char *const argv[], char *const envp[],
int flags) {
return syscall(__NR_execveat, dirfd, pathname, argv, envp, flags);
}
# define execveat missing_execveat
#endif
/* ======================================================================= */
#if !HAVE_CLOSE_RANGE
/* since kernel v5.9 (9b4feb630e8e9801603f3cab3a36369e3c1cf88d) */
static inline int missing_close_range(unsigned first_fd, unsigned end_fd, unsigned flags) {
/* Kernel-side the syscall expects fds as unsigned integers (just like close() actually), while
* userspace exclusively uses signed integers for fds. glibc chose to expose it 1:1 however, hence we
* do so here too, even if we end up passing signed fds to it most of the time. */
return syscall(__NR_close_range,
first_fd,
end_fd,
flags);
}
# define close_range missing_close_range
#endif
/* ======================================================================= */
#if !HAVE_SCHED_SETATTR
/* since kernel 3.14 (e6cfc0295c7d51b008999a8b13a44fb43f8685ea) */
static inline ssize_t missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned int flags) {
return syscall(__NR_sched_setattr, pid, attr, flags);
}
# define sched_setattr missing_sched_setattr
#endif
/* ======================================================================= */
/* glibc does not provide clone() on ia64, only clone2(). Not only that, but it also doesn't provide a
* prototype, only the symbol in the shared library (it provides a prototype for clone(), but not the
* symbol in the shared library). */
#if defined(__ia64__)
int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags, void *arg);
#define HAVE_CLONE 0
#else
/* We know that everywhere else clone() is available, so we don't bother with a meson check (that takes time
* at build time) and just define it. Once the kernel drops ia64 support, we can drop this too. */
#define HAVE_CLONE 1
#endif
/* ======================================================================= */
#if !HAVE_QUOTACTL_FD
/* since kernel v5.14 (64c2c2c62f92339b176ea24403d8db16db36f9e6) */
static inline int missing_quotactl_fd(int fd, int cmd, int id, void *addr) {
return syscall(__NR_quotactl_fd, fd, cmd, id, addr);
}
# define quotactl_fd missing_quotactl_fd
#endif
/* ======================================================================= */
#if !HAVE_SETXATTRAT
/* since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394) */
static inline int missing_setxattrat(int fd, const char *path, int at_flags, const char *name, const struct xattr_args *args, size_t size) {
return syscall(__NR_setxattrat, fd, path, at_flags, name, args, size);
}
# define setxattrat missing_setxattrat
#endif
/* ======================================================================= */
#if !HAVE_REMOVEXATTRAT
/* since kernel v6.13 (6140be90ec70c39fa844741ca3cc807dd0866394) */
static inline int missing_removexattrat(int fd, const char *path, int at_flags, const char *name) {
return syscall(__NR_removexattrat, fd, path, at_flags, name);
}
# define removexattrat missing_removexattrat
#endif

View File

@ -1,6 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h> #include <fcntl.h>
#include <linux/magic.h>
#include <linux/nsfs.h>
#include <sched.h> #include <sched.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mount.h> #include <sys/mount.h>
@ -10,8 +12,6 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "log.h" #include "log.h"
#include "missing_magic.h"
#include "missing_namespace.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "namespace-util.h" #include "namespace-util.h"
#include "parse-util.h" #include "parse-util.h"

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/fs.h>
#include <linux/magic.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <threads.h> #include <threads.h>
#include <unistd.h> #include <unistd.h>
@ -7,8 +9,6 @@
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "missing_fs.h"
#include "missing_magic.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "pidfd-util.h" #include "pidfd-util.h"

View File

@ -4,7 +4,6 @@
#include <sys/pidfd.h> /* IWYU pragma: export */ #include <sys/pidfd.h> /* IWYU pragma: export */
#include "forward.h" #include "forward.h"
#include "missing_syscall.h" /* IWYU pragma: export */
int pidfd_get_namespace(int fd, unsigned long ns_type_cmd); int pidfd_get_namespace(int fd, unsigned long ns_type_cmd);

View File

@ -34,7 +34,6 @@
#include "locale-util.h" #include "locale-util.h"
#include "log.h" #include "log.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_syscall.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "namespace-util.h" #include "namespace-util.h"
#include "nulstr-util.h" #include "nulstr-util.h"

84
src/basic/raw-clone.c Normal file
View File

@ -0,0 +1,84 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
/***
Copyright © 2016 Michael Karcher
***/
#include <errno.h>
#include <sched.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "process-util.h"
#include "raw-clone.h"
/**
* raw_clone() - uses clone to create a new process with clone flags
* @flags: Flags to pass to the clone system call
*
* Uses the clone system call to create a new process with the cloning flags and termination signal passed in the flags
* parameter. Opposed to glibc's clone function, using this function does not set up a separate stack for the child, but
* relies on copy-on-write semantics on the one stack at a common virtual address, just as fork does.
*
* To obtain copy-on-write semantics, flags must not contain CLONE_VM, and thus CLONE_THREAD and CLONE_SIGHAND
* (which require CLONE_VM) are not usable.
*
* Additionally, as this function does not pass the ptid (pidfd in the case of CLONE_PIDFD), newtls and ctid
* parameters to the kernel, flags must not contain CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID,
* CLONE_SETTLS, or CLONE_PIDFD.
*
* WARNING: 💣 this call (just like glibc's own clone() wrapper) will not synchronize on glibc's malloc
* locks, which means they will be in an undefined state in the child if the parent is
* threaded. This means: the parent must either never use threads, or the child cannot use memory
* allocation itself. This is a major pitfall, hence be careful! 💣
*
* Returns: 0 in the child process and the child process id in the parent.
*/
pid_t raw_clone(unsigned long flags) {
pid_t ret;
assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID|CLONE_SETTLS|CLONE_PIDFD)) == 0);
#if defined(__s390x__) || defined(__s390__) || defined(__CRIS__)
/* On s390/s390x and cris the order of the first and second arguments
* of the raw clone() system call is reversed. */
ret = (pid_t) syscall(__NR_clone, NULL, flags);
#elif defined(__sparc__)
{
/**
* sparc always returns the other process id in %o0, and
* a boolean flag whether this is the child or the parent in
* %o1. Inline assembly is needed to get the flag returned
* in %o1.
*/
int in_child, child_pid, error;
asm volatile("mov %3, %%g1\n\t"
"mov %4, %%o0\n\t"
"mov 0 , %%o1\n\t"
#if defined(__arch64__)
"t 0x6d\n\t"
#else
"t 0x10\n\t"
#endif
"addx %%g0, 0, %2\n\t"
"mov %%o1, %0\n\t"
"mov %%o0, %1" :
"=r"(in_child), "=r"(child_pid), "=r"(error) :
"i"(__NR_clone), "r"(flags) :
"%o1", "%o0", "%g1", "cc" );
if (error) {
errno = child_pid;
ret = -1;
} else
ret = in_child ? 0 : child_pid;
}
#else
ret = (pid_t) syscall(__NR_clone, flags, NULL);
#endif
if (ret == 0)
reset_cached_pid();
return ret;
}

View File

@ -1,85 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
/*** #include <sched.h> /* IWYU pragma: export */
Copyright © 2016 Michael Karcher
***/
#include <errno.h> #include "forward.h"
#include <sched.h>
#include <sys/syscall.h>
#include "log.h" pid_t raw_clone(unsigned long flags);
#include "macro.h"
#include "process-util.h"
/**
* raw_clone() - uses clone to create a new process with clone flags
* @flags: Flags to pass to the clone system call
*
* Uses the clone system call to create a new process with the cloning flags and termination signal passed in the flags
* parameter. Opposed to glibc's clone function, using this function does not set up a separate stack for the child, but
* relies on copy-on-write semantics on the one stack at a common virtual address, just as fork does.
*
* To obtain copy-on-write semantics, flags must not contain CLONE_VM, and thus CLONE_THREAD and CLONE_SIGHAND
* (which require CLONE_VM) are not usable.
*
* Additionally, as this function does not pass the ptid (pidfd in the case of CLONE_PIDFD), newtls and ctid
* parameters to the kernel, flags must not contain CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID,
* CLONE_SETTLS, or CLONE_PIDFD.
*
* WARNING: 💣 this call (just like glibc's own clone() wrapper) will not synchronize on glibc's malloc
* locks, which means they will be in an undefined state in the child if the parent is
* threaded. This means: the parent must either never use threads, or the child cannot use memory
* allocation itself. This is a major pitfall, hence be careful! 💣
*
* Returns: 0 in the child process and the child process id in the parent.
*/
static inline pid_t raw_clone(unsigned long flags) {
pid_t ret;
assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID|CLONE_SETTLS|CLONE_PIDFD)) == 0);
#if defined(__s390x__) || defined(__s390__) || defined(__CRIS__)
/* On s390/s390x and cris the order of the first and second arguments
* of the raw clone() system call is reversed. */
ret = (pid_t) syscall(__NR_clone, NULL, flags);
#elif defined(__sparc__)
{
/**
* sparc always returns the other process id in %o0, and
* a boolean flag whether this is the child or the parent in
* %o1. Inline assembly is needed to get the flag returned
* in %o1.
*/
int in_child, child_pid, error;
asm volatile("mov %3, %%g1\n\t"
"mov %4, %%o0\n\t"
"mov 0 , %%o1\n\t"
#if defined(__arch64__)
"t 0x6d\n\t"
#else
"t 0x10\n\t"
#endif
"addx %%g0, 0, %2\n\t"
"mov %%o1, %0\n\t"
"mov %%o0, %1" :
"=r"(in_child), "=r"(child_pid), "=r"(error) :
"i"(__NR_clone), "r"(flags) :
"%o1", "%o0", "%g1", "cc" );
if (error) {
errno = child_pid;
ret = -1;
} else
ret = in_child ? 0 : child_pid;
}
#else
ret = (pid_t) syscall(__NR_clone, flags, NULL);
#endif
if (ret == 0)
reset_cached_pid();
return ret;
}

View File

@ -1,15 +0,0 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/reboot.h>
#include <sys/reboot.h>
#include <sys/syscall.h>
#include <unistd.h>
/* glibc defines the reboot() API call, which is a wrapper around the system call of the same name, but without the
* extra "arg" parameter. Since we need that parameter for some calls, let's add a "raw" wrapper that is defined the
* same way, except it takes the additional argument. */
static inline int raw_reboot(int cmd, const void *arg) {
return (int) syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, arg);
}

View File

@ -4,7 +4,6 @@
#include <unistd.h> #include <unistd.h>
#include "errno-util.h" #include "errno-util.h"
#include "missing_syscall.h"
#include "parse-util.h" #include "parse-util.h"
#include "signal-util.h" #include "signal-util.h"
#include "stdio-util.h" #include "stdio-util.h"

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fcntl.h> #include <fcntl.h>
#include <linux/magic.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
#include <unistd.h> #include <unistd.h>
@ -13,7 +14,6 @@
#include "fs-util.h" #include "fs-util.h"
#include "hash-funcs.h" #include "hash-funcs.h"
#include "log.h" #include "log.h"
#include "missing_magic.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"
#include "path-util.h" #include "path-util.h"
#include "siphash24.h" #include "siphash24.h"

View File

@ -2,6 +2,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <linux/kd.h> #include <linux/kd.h>
#include <linux/magic.h>
#include <linux/tiocl.h> #include <linux/tiocl.h>
#include <linux/vt.h> #include <linux/vt.h>
#include <poll.h> #include <poll.h>
@ -27,7 +28,6 @@
#include "inotify-util.h" #include "inotify-util.h"
#include "io-util.h" #include "io-util.h"
#include "log.h" #include "log.h"
#include "missing_magic.h"
#include "namespace-util.h" #include "namespace-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h" #include "path-util.h"

View File

@ -8,7 +8,6 @@
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
#include "fs-util.h" #include "fs-util.h"
#include "missing_syscall.h"
#include "nulstr-util.h" #include "nulstr-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "sparse-endian.h" #include "sparse-endian.h"

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <fnmatch.h> #include <fnmatch.h>
#include <linux/bpf.h>
#include <linux/bpf_insn.h> #include <linux/bpf_insn.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -12,7 +13,6 @@
#include "fd-util.h" #include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "log.h" #include "log.h"
#include "missing_bpf.h"
#include "nulstr-util.h" #include "nulstr-util.h"
#include "parse-util.h" #include "parse-util.h"
#include "path-util.h" #include "path-util.h"

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/bpf.h> #include <linux/bpf.h>
#include <linux/magic.h>
#include "alloc-util.h" #include "alloc-util.h"
#include "bpf-foreign.h" #include "bpf-foreign.h"
@ -8,7 +9,6 @@
#include "cgroup.h" #include "cgroup.h"
#include "hash-funcs.h" #include "hash-funcs.h"
#include "hashmap.h" #include "hashmap.h"
#include "missing_magic.h"
#include "siphash24.h" #include "siphash24.h"
#include "stat-util.h" #include "stat-util.h"
#include "unit.h" #include "unit.h"

View File

@ -1,12 +1,10 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <sys/reboot.h>
#include <unistd.h> #include <unistd.h>
#include "ansi-color.h" #include "ansi-color.h"
#include "emergency-action.h" #include "emergency-action.h"
#include "manager.h" #include "manager.h"
#include "raw-reboot.h"
#include "reboot-util.h" #include "reboot-util.h"
#include "special.h" #include "special.h"
#include "string-table.h" #include "string-table.h"

View File

@ -1,13 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <grp.h> #include <grp.h>
#include <linux/ioprio.h>
#include <linux/prctl.h> #include <linux/prctl.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/securebits.h> #include <linux/securebits.h>
#include <poll.h> #include <poll.h>
#include <sys/eventfd.h> #include <sys/eventfd.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/ioprio.h>
#include <sys/keyctl.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <sys/prctl.h> #include <sys/prctl.h>
#include <sys/statvfs.h> #include <sys/statvfs.h>
@ -54,7 +55,6 @@
#include "journal-send.h" #include "journal-send.h"
#include "manager.h" #include "manager.h"
#include "memfd-util.h" #include "memfd-util.h"
#include "missing_syscall.h"
#include "mkdir-label.h" #include "mkdir-label.h"
#include "mount-util.h" #include "mount-util.h"
#include "namespace-util.h" #include "namespace-util.h"

View File

@ -100,15 +100,34 @@ load_fragment_gperf_nulstr_c = custom_target(
command : [awk, '-f', '@INPUT0@', '@INPUT1@'], command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
capture : true) capture : true)
generated_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c] generate_bpf_delegate_configs = files('generate-bpf-delegate-configs.py')
bpf_delegate_configs_inc = custom_target(
input : [generate_bpf_delegate_configs, bpf_delegate_sources],
output : 'bpf-delegate-configs.inc',
command : [python,
generate_bpf_delegate_configs,
'code',
bpf_delegate_sources],
capture : true)
bpf_delegate_xml = custom_target(
input : [generate_bpf_delegate_configs, bpf_delegate_sources],
output : 'bpf-delegate.xml',
command : [python,
generate_bpf_delegate_configs,
'doc',
bpf_delegate_sources],
capture : true)
man_page_depends += bpf_delegate_xml
generated_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c, bpf_delegate_configs_inc]
libcore_sources += [load_fragment_gperf_c, load_fragment_gperf_nulstr_c, bpf_delegate_configs_inc]
libcore_build_dir = meson.current_build_dir()
libcore_name = 'systemd-core-@0@'.format(shared_lib_tag) libcore_name = 'systemd-core-@0@'.format(shared_lib_tag)
libcore_static = static_library( libcore_static = static_library(
libcore_name, libcore_name,
libcore_sources, libcore_sources,
load_fragment_gperf_c,
load_fragment_gperf_nulstr_c,
include_directories : [includes, include_directories('.')], include_directories : [includes, include_directories('.')],
implicit_include_directories : false, implicit_include_directories : false,
c_args : ['-fvisibility=default'], c_args : ['-fvisibility=default'],
@ -162,6 +181,7 @@ executor_libs = get_option('link-executor-shared') ? \
libcore, libcore,
libshared, libshared,
] : [ ] : [
libc_wrapper_static,
libcore_static, libcore_static,
libshared_static, libshared_static,
libbasic_static, libbasic_static,

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/loop.h> #include <linux/loop.h>
#include <linux/magic.h>
#include <sched.h> #include <sched.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -29,7 +30,6 @@
#include "log.h" #include "log.h"
#include "loop-util.h" #include "loop-util.h"
#include "loopback-setup.h" #include "loopback-setup.h"
#include "missing_magic.h"
#include "mkdir-label.h" #include "mkdir-label.h"
#include "mount-util.h" #include "mount-util.h"
#include "mountpoint-util.h" #include "mountpoint-util.h"

View File

@ -9,6 +9,7 @@
#include <unistd.h> #include <unistd.h>
#include "sd-bus.h" #include "sd-bus.h"
#include "sd-varlink.h"
#include "alloc-util.h" #include "alloc-util.h"
#include "audit-fd.h" #include "audit-fd.h"
@ -26,6 +27,7 @@ static bool initialized = false;
struct audit_info { struct audit_info {
sd_bus_creds *creds; sd_bus_creds *creds;
sd_varlink *link;
const char *path; const char *path;
const char *cmdline; const char *cmdline;
const char *function; const char *function;
@ -48,12 +50,23 @@ static int audit_callback(
char uid_buf[DECIMAL_STR_MAX(uid_t) + 1] = "n/a"; char uid_buf[DECIMAL_STR_MAX(uid_t) + 1] = "n/a";
char gid_buf[DECIMAL_STR_MAX(gid_t) + 1] = "n/a"; char gid_buf[DECIMAL_STR_MAX(gid_t) + 1] = "n/a";
if (audit->creds) {
/* DBus case */
if (sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid) >= 0) if (sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid) >= 0)
xsprintf(login_uid_buf, UID_FMT, login_uid); xsprintf(login_uid_buf, UID_FMT, login_uid);
if (sd_bus_creds_get_euid(audit->creds, &uid) >= 0) if (sd_bus_creds_get_euid(audit->creds, &uid) >= 0)
xsprintf(uid_buf, UID_FMT, uid); xsprintf(uid_buf, UID_FMT, uid);
if (sd_bus_creds_get_egid(audit->creds, &gid) >= 0) if (sd_bus_creds_get_egid(audit->creds, &gid) >= 0)
xsprintf(gid_buf, GID_FMT, gid); xsprintf(gid_buf, GID_FMT, gid);
}
if (audit->link) {
/* varlink */
if (sd_varlink_get_peer_uid(audit->link, &uid) >= 0)
xsprintf(uid_buf, UID_FMT, uid);
if (sd_varlink_get_peer_gid(audit->link, &gid) >= 0)
xsprintf(gid_buf, GID_FMT, gid);
}
(void) snprintf(msgbuf, msgbufsize, (void) snprintf(msgbuf, msgbufsize,
"auid=%s uid=%s gid=%s%s%s%s%s%s%s%s%s%s", "auid=%s uid=%s gid=%s%s%s%s%s%s%s%s%s%s",
@ -164,13 +177,85 @@ static int access_init(sd_bus_error *error) {
return 1; return 1;
} }
static int get_our_contexts(const Unit *unit, const char **ret_acon, const char **ret_tclass, char **ret_fcon) {
_cleanup_freecon_ char *fcon = NULL;
assert(ret_acon);
assert(ret_tclass);
assert(ret_fcon);
if (unit && unit->access_selinux_context) {
/* Nice! The unit comes with a SELinux context read from the unit file */
*ret_acon = unit->access_selinux_context;
*ret_tclass = "service";
*ret_fcon = NULL;
return 0;
}
/* If no unit context is known, use our own */
/* Ideally, we should call mac_selinux_get_our_label() here because it
* does exactly the same - call getcon_raw(). However, it involves
* selinux_init() which opens label DB. It was not part of the
* original code. I don't want to change it for now. */
if (getcon_raw(&fcon) < 0)
return log_debug_errno(errno, "SELinux getcon_raw() failed: %m");
if (!fcon)
return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "SELinux returned no context of the current process");
*ret_acon = fcon;
*ret_tclass = "system";
*ret_fcon = TAKE_PTR(fcon);
return 0;
}
static int check_access(
const char *scon,
const char *tcon,
const char *tclass,
const char *permission,
struct audit_info *audit_info,
sd_bus_error *error) {
bool enforce = mac_selinux_enforcing();
int r;
assert(scon);
assert(tcon);
assert(tclass);
assert(permission);
assert(audit_info);
assert(audit_info->function);
r = selinux_check_access(scon, tcon, tclass, permission, &audit_info);
if (r < 0) {
errno = -(r = errno_or_else(EPERM));
if (enforce)
sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access: %m");
}
return log_selinux_enforcing_errno(
r,
"SELinux access check scon=%s tcon=%s tclass=%s perm=%s state=%s function=%s path=%s cmdline=%s: %m",
scon,
tcon,
tclass,
permission,
enforce ? "enforcing" : "permissive",
audit_info->function,
empty_to_na(audit_info->path),
empty_to_na(audit_info->cmdline));
}
/* /*
This function communicates with the kernel to check whether or not it should This function communicates with the kernel to check whether or not it should
allow the access. allow the access.
If the machine is in permissive mode it will return ok. Audit messages will If the machine is in permissive mode it will return ok. Audit messages will
still be generated if the access would be denied in enforcing mode. still be generated if the access would be denied in enforcing mode.
*/ */
int mac_selinux_access_check_internal( int mac_selinux_access_check_bus_internal(
sd_bus_message *message, sd_bus_message *message,
const Unit *unit, const Unit *unit,
const char *permission, const char *permission,
@ -216,31 +301,22 @@ int mac_selinux_access_check_internal(
if (r < 0) if (r < 0)
return r; return r;
if (unit && unit->access_selinux_context) { r = get_our_contexts(unit, &acon, &tclass, &fcon);
/* Nice! The unit comes with a SELinux context read from the unit file */ if (r < 0) {
acon = unit->access_selinux_context; log_selinux_enforcing_errno(
tclass = "service"; r,
} else { "Failed to retrieves SELinux context of current process (perm=%s)%s: %m",
/* If no unit context is known, use our own */ permission,
if (getcon_raw(&fcon) < 0) { enforce ? "" : ", ignoring");
log_warning_errno(errno, "SELinux getcon_raw() failed%s (perm=%s): %m",
enforce ? "" : ", ignoring",
permission);
if (!enforce) if (!enforce)
return 0; return 0;
if (r == -EOPNOTSUPP)
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "We appear not to have any SELinux context: %m");
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context: %m"); return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context: %m");
} }
if (!fcon) {
if (!enforce)
return 0;
return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "We appear not to have any SELinux context: %m");
}
acon = fcon;
tclass = "system";
}
(void) sd_bus_creds_get_cmdline(creds, &cmdline); (void) sd_bus_creds_get_cmdline(creds, &cmdline);
cl = strv_join(cmdline, " "); cl = strv_join(cmdline, " ");
@ -252,23 +328,67 @@ int mac_selinux_access_check_internal(
.function = function, .function = function,
}; };
r = selinux_check_access(scon, acon, tclass, permission, &audit_info); return check_access(scon, acon, tclass, permission, &audit_info, error);
if (r < 0) { }
errno = -(r = errno_or_else(EPERM));
if (enforce) int mac_selinux_access_check_varlink_internal(
sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access: %m"); sd_varlink *link,
} const Unit *unit,
const char *permission,
const char *function) {
log_full_errno_zerook(LOG_DEBUG, r, _cleanup_freecon_ char *fcon = NULL, *scon = NULL;
"SELinux access check scon=%s tcon=%s tclass=%s perm=%s state=%s function=%s path=%s cmdline=%s: %m", const char *tclass, *acon;
scon, acon, tclass, permission, enforce ? "enforcing" : "permissive", function, strna(unit ? unit->fragment_path : NULL), empty_to_na(cl)); int r;
return enforce ? r : 0;
assert(link);
assert(permission);
assert(function);
r = access_init(/* error= */ NULL);
if (r <= 0)
return log_debug_errno(r, "Failed to init SELinux: %m");
/* delay call until we checked in `access_init()` if SELinux is actually enabled */
bool enforce = mac_selinux_enforcing();
int fd = sd_varlink_get_fd(link);
if (fd < 0)
return log_debug_errno(fd, "Failed to get varlink peer fd: %m");
/* We should call mac_selinux_get_peer_label() here similarly to get_our_contexts().
* See the explanation there why not. */
if (getpeercon_raw(fd, &scon) < 0)
return log_selinux_enforcing_errno(
errno,
"Failed to get peer SELinux context%s: %m",
enforce ? "" : ", ignoring");
if (!scon)
return log_selinux_enforcing_errno(
SYNTHETIC_ERRNO(EOPNOTSUPP),
"Peer does not have SELinux context");
r = get_our_contexts(unit, &acon, &tclass, &fcon);
if (r < 0)
return log_selinux_enforcing_errno(
r,
"Failed to retrieves SELinux context of current process (perm=%s)%s: %m",
permission,
enforce ? "" : ", ignoring");
struct audit_info audit_info = {
.link = link,
.path = unit ? unit->fragment_path : NULL,
.function = function,
};
return check_access(scon, acon, tclass, permission, &audit_info, /* error= */ NULL);
} }
#else /* HAVE_SELINUX */ #else /* HAVE_SELINUX */
int mac_selinux_access_check_internal( int mac_selinux_access_check_bus_internal(
sd_bus_message *message, sd_bus_message *message,
const Unit *unit, const Unit *unit,
const char *permission, const char *permission,
@ -278,4 +398,12 @@ int mac_selinux_access_check_internal(
return 0; return 0;
} }
int mac_selinux_access_check_varlink_internal(
sd_varlink *link,
const Unit *unit,
const char *permission,
const char *function) {
return 0;
}
#endif /* HAVE_SELINUX */ #endif /* HAVE_SELINUX */

View File

@ -3,10 +3,17 @@
#include "core-forward.h" #include "core-forward.h"
int mac_selinux_access_check_internal(sd_bus_message *message, const Unit *unit, const char *permission, const char *function, sd_bus_error *error); int mac_selinux_access_check_bus_internal(sd_bus_message *message, const Unit *unit, const char *permission, const char *function, sd_bus_error *error);
int mac_selinux_access_check_varlink_internal(sd_varlink *link, const Unit *unit, const char *permission, const char *function);
#define mac_selinux_access_check(message, permission, error) \ #define mac_selinux_access_check(message, permission, error) \
mac_selinux_access_check_internal((message), NULL, (permission), __func__, (error)) mac_selinux_access_check_bus_internal((message), NULL, (permission), __func__, (error))
#define mac_selinux_unit_access_check(unit, message, permission, error) \ #define mac_selinux_unit_access_check(unit, message, permission, error) \
mac_selinux_access_check_internal((message), (unit), (permission), __func__, (error)) mac_selinux_access_check_bus_internal((message), (unit), (permission), __func__, (error))
#define mac_selinux_access_check_varlink(link, permission) \
mac_selinux_access_check_varlink_internal((link), NULL, (permission), __func__)
#define mac_selinux_unit_access_check_varlink(unit, link, permission) \
mac_selinux_access_check_bus_internal((link), (unit), (permission), __func__)

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/audit.h>
#include <math.h> #include <math.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <unistd.h> #include <unistd.h>
@ -31,7 +32,6 @@
#include "image-policy.h" #include "image-policy.h"
#include "log.h" #include "log.h"
#include "manager.h" #include "manager.h"
#include "missing_audit.h"
#include "mount-util.h" #include "mount-util.h"
#include "namespace.h" #include "namespace.h"
#include "open-file.h" #include "open-file.h"

View File

@ -39,48 +39,7 @@ static int manager_environment_build_json(sd_json_variant **ret, const char *nam
return sd_json_variant_new_array_strv(ret, l); return sd_json_variant_new_array_strv(ret, l);
} }
static int manager_context_build_json(sd_json_variant **ret, const char *name, void *userdata) { static int log_level_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
_cleanup_strv_free_ char **taints = NULL;
taints = taint_strv();
if (!taints)
return -ENOMEM;
return sd_json_buildo(
ASSERT_PTR(ret),
SD_JSON_BUILD_PAIR_STRING("Version", GIT_VERSION),
SD_JSON_BUILD_PAIR_STRING("Architecture", architecture_to_string(uname_architecture())),
SD_JSON_BUILD_PAIR_STRING("Features", systemd_features),
JSON_BUILD_PAIR_STRV_NON_EMPTY("Taints", taints),
SD_JSON_BUILD_PAIR_STRV("UnitPath", m->lookup_paths.search_path),
JSON_BUILD_PAIR_STRV_NON_EMPTY("Environment", m->transient_environment),
SD_JSON_BUILD_PAIR_STRING("DefaultStandardOutput", exec_output_to_string(m->defaults.std_output)),
SD_JSON_BUILD_PAIR_STRING("DefaultStandardError", exec_output_to_string(m->defaults.std_error)),
SD_JSON_BUILD_PAIR_BOOLEAN("ServiceWatchdogs", m->service_watchdogs),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimerAccuracyUSec", m->defaults.timer_accuracy_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutStartUSec", m->defaults.timeout_start_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutStopUSec", m->defaults.timeout_stop_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutAbortUSec", manager_default_timeout_abort_usec(m)),
JSON_BUILD_PAIR_FINITE_USEC("DefaultDeviceTimeoutUSec", m->defaults.device_timeout_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultRestartUSec", m->defaults.restart_usec),
JSON_BUILD_PAIR_RATELIMIT("DefaultStartLimit", &m->defaults.start_limit),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultIOAccounting", m->defaults.io_accounting),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultIPAccounting", m->defaults.ip_accounting),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultMemoryAccounting", m->defaults.memory_accounting),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultTasksAccounting", m->defaults.tasks_accounting),
SD_JSON_BUILD_PAIR_CALLBACK("DefaultLimits", rlimit_table_build_json, m->defaults.rlimit),
SD_JSON_BUILD_PAIR_UNSIGNED("DefaultTasksMax", cgroup_tasks_max_resolve(&m->defaults.tasks_max)),
JSON_BUILD_PAIR_FINITE_USEC("DefaultMemoryPressureThresholdUSec", m->defaults.memory_pressure_threshold_usec),
SD_JSON_BUILD_PAIR_STRING("DefaultMemoryPressureWatch", cgroup_pressure_watch_to_string(m->defaults.memory_pressure_watch)),
JSON_BUILD_PAIR_FINITE_USEC("TimerSlackNSec", (uint64_t) prctl(PR_GET_TIMERSLACK)),
SD_JSON_BUILD_PAIR_STRING("DefaultOOMPolicy", oom_policy_to_string(m->defaults.oom_policy)),
SD_JSON_BUILD_PAIR_INTEGER("DefaultOOMScoreAdjust", m->defaults.oom_score_adjust),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultRestrictSUIDSGID", m->defaults.restrict_suid_sgid),
SD_JSON_BUILD_PAIR_STRING("CtrlAltDelBurstAction", emergency_action_to_string(m->cad_burst_action)));
}
static int log_level_build_runtime_json(sd_json_variant **ret, const char *name, void *userdata) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
int log_max_level = log_get_max_level(); int log_max_level = log_get_max_level();
int r; int r;
@ -107,15 +66,70 @@ static int log_level_build_runtime_json(sd_json_variant **ret, const char *name,
return 0; return 0;
} }
static int manager_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) { static int manager_context_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Manager *m = ASSERT_PTR(userdata); Manager *m = ASSERT_PTR(userdata);
dual_timestamp watchdog_last_ping;
/* The main principle behind context/runtime split is the following:
* If it make sense to place a property into a config/unit file it belongs to Context.
* Otherwise it's a 'Runtime'. */
return sd_json_buildo( return sd_json_buildo(
ASSERT_PTR(ret), ASSERT_PTR(ret),
SD_JSON_BUILD_PAIR_BOOLEAN("ShowStatus", manager_get_show_status_on(m)),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("LogLevel", log_level_build_json, m),
SD_JSON_BUILD_PAIR_STRING("LogTarget", log_target_to_string(log_get_target())),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("Environment", manager_environment_build_json, m),
SD_JSON_BUILD_PAIR_STRING("DefaultStandardOutput", exec_output_to_string(m->defaults.std_output)),
SD_JSON_BUILD_PAIR_STRING("DefaultStandardError", exec_output_to_string(m->defaults.std_error)),
SD_JSON_BUILD_PAIR_BOOLEAN("ServiceWatchdogs", m->service_watchdogs),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimerAccuracyUSec", m->defaults.timer_accuracy_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutStartUSec", m->defaults.timeout_start_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutStopUSec", m->defaults.timeout_stop_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultTimeoutAbortUSec", manager_default_timeout_abort_usec(m)),
JSON_BUILD_PAIR_FINITE_USEC("DefaultDeviceTimeoutUSec", m->defaults.device_timeout_usec),
JSON_BUILD_PAIR_FINITE_USEC("DefaultRestartUSec", m->defaults.restart_usec),
JSON_BUILD_PAIR_RATELIMIT("DefaultStartLimit", &m->defaults.start_limit),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultIOAccounting", m->defaults.io_accounting),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultIPAccounting", m->defaults.ip_accounting),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultMemoryAccounting", m->defaults.memory_accounting),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultTasksAccounting", m->defaults.tasks_accounting),
SD_JSON_BUILD_PAIR_CALLBACK("DefaultLimits", rlimit_table_build_json, m->defaults.rlimit),
SD_JSON_BUILD_PAIR_UNSIGNED("DefaultTasksMax", cgroup_tasks_max_resolve(&m->defaults.tasks_max)),
JSON_BUILD_PAIR_FINITE_USEC("DefaultMemoryPressureThresholdUSec", m->defaults.memory_pressure_threshold_usec),
SD_JSON_BUILD_PAIR_STRING("DefaultMemoryPressureWatch", cgroup_pressure_watch_to_string(m->defaults.memory_pressure_watch)),
JSON_BUILD_PAIR_FINITE_USEC("RuntimeWatchdogUSec", manager_get_watchdog(m, WATCHDOG_RUNTIME)),
JSON_BUILD_PAIR_FINITE_USEC("RebootWatchdogUSec", manager_get_watchdog(m, WATCHDOG_REBOOT)),
JSON_BUILD_PAIR_FINITE_USEC("KExecWatchdogUSec", manager_get_watchdog(m, WATCHDOG_KEXEC)),
JSON_BUILD_PAIR_FINITE_USEC("RuntimeWatchdogPreUSec", manager_get_watchdog(m, WATCHDOG_PRETIMEOUT)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("RuntimeWatchdogPreGovernor", m->watchdog_pretimeout_governor),
JSON_BUILD_PAIR_STRING_NON_EMPTY("WatchdogDevice", watchdog_get_device()),
JSON_BUILD_PAIR_FINITE_USEC("TimerSlackNSec", (uint64_t) prctl(PR_GET_TIMERSLACK)),
SD_JSON_BUILD_PAIR_STRING("DefaultOOMPolicy", oom_policy_to_string(m->defaults.oom_policy)),
SD_JSON_BUILD_PAIR_INTEGER("DefaultOOMScoreAdjust", m->defaults.oom_score_adjust),
SD_JSON_BUILD_PAIR_BOOLEAN("DefaultRestrictSUIDSGID", m->defaults.restrict_suid_sgid),
SD_JSON_BUILD_PAIR_STRING("CtrlAltDelBurstAction", emergency_action_to_string(m->cad_burst_action)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("ConfirmSpawn", manager_get_confirm_spawn(m)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("ControlGroup", m->cgroup_root));
}
static int manager_runtime_build_json(sd_json_variant **ret, const char *name, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
dual_timestamp watchdog_last_ping;
_cleanup_strv_free_ char **taints = NULL;
taints = taint_strv();
if (!taints)
return -ENOMEM;
return sd_json_buildo(
ASSERT_PTR(ret),
SD_JSON_BUILD_PAIR_STRING("Version", GIT_VERSION),
SD_JSON_BUILD_PAIR_STRING("Architecture", architecture_to_string(uname_architecture())),
SD_JSON_BUILD_PAIR_STRING("Features", systemd_features),
JSON_BUILD_PAIR_STRV_NON_EMPTY("Taints", taints),
SD_JSON_BUILD_PAIR_STRV("UnitPath", m->lookup_paths.search_path),
SD_JSON_BUILD_PAIR_STRING("Virtualization", virtualization_to_string(detect_virtualization())), SD_JSON_BUILD_PAIR_STRING("Virtualization", virtualization_to_string(detect_virtualization())),
SD_JSON_BUILD_PAIR_STRING("ConfidentialVirtualization", confidential_virtualization_to_string(detect_confidential_virtualization())), SD_JSON_BUILD_PAIR_STRING("ConfidentialVirtualization", confidential_virtualization_to_string(detect_confidential_virtualization())),
JSON_BUILD_PAIR_STRING_NON_EMPTY("ConfirmSpawn", manager_get_confirm_spawn(m)),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("FirmwareTimestamp", &m->timestamps[MANAGER_TIMESTAMP_FIRMWARE]), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("FirmwareTimestamp", &m->timestamps[MANAGER_TIMESTAMP_FIRMWARE]),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("LoaderTimestamp", &m->timestamps[MANAGER_TIMESTAMP_LOADER]), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("LoaderTimestamp", &m->timestamps[MANAGER_TIMESTAMP_LOADER]),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("KernelTimestamp", &m->timestamps[MANAGER_TIMESTAMP_KERNEL]), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("KernelTimestamp", &m->timestamps[MANAGER_TIMESTAMP_KERNEL]),
@ -135,26 +149,15 @@ static int manager_runtime_build_json(sd_json_variant **ret, const char *name, v
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDGeneratorsFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH]), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDGeneratorsFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_GENERATORS_FINISH]),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDUnitsLoadStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START]), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDUnitsLoadStartTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_START]),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDUnitsLoadFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH]), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("InitRDUnitsLoadFinishTimestamp", &m->timestamps[MANAGER_TIMESTAMP_INITRD_UNITS_LOAD_FINISH]),
SD_JSON_BUILD_PAIR_BOOLEAN("ShowStatus", manager_get_show_status_on(m)),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("LogLevel", log_level_build_runtime_json, m),
SD_JSON_BUILD_PAIR_STRING("LogTarget", log_target_to_string(log_get_target())),
SD_JSON_BUILD_PAIR_UNSIGNED("NNames", hashmap_size(m->units)), SD_JSON_BUILD_PAIR_UNSIGNED("NNames", hashmap_size(m->units)),
SD_JSON_BUILD_PAIR_UNSIGNED("NFailedUnits", set_size(m->failed_units)), SD_JSON_BUILD_PAIR_UNSIGNED("NFailedUnits", set_size(m->failed_units)),
SD_JSON_BUILD_PAIR_UNSIGNED("NJobs", hashmap_size(m->jobs)), SD_JSON_BUILD_PAIR_UNSIGNED("NJobs", hashmap_size(m->jobs)),
SD_JSON_BUILD_PAIR_UNSIGNED("NInstalledJobs", m->n_installed_jobs), SD_JSON_BUILD_PAIR_UNSIGNED("NInstalledJobs", m->n_installed_jobs),
SD_JSON_BUILD_PAIR_UNSIGNED("NFailedJobs", m->n_failed_jobs), SD_JSON_BUILD_PAIR_UNSIGNED("NFailedJobs", m->n_failed_jobs),
SD_JSON_BUILD_PAIR_REAL("Progress", manager_get_progress(m)), SD_JSON_BUILD_PAIR_REAL("Progress", manager_get_progress(m)),
JSON_BUILD_PAIR_CALLBACK_NON_NULL("Environment", manager_environment_build_json, m),
JSON_BUILD_PAIR_STRING_NON_EMPTY("WatchdogDevice", watchdog_get_device()),
JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("WatchdogLastPingTimestamp", watchdog_get_last_ping_as_dual_timestamp(&watchdog_last_ping)), JSON_BUILD_PAIR_DUAL_TIMESTAMP_NON_NULL("WatchdogLastPingTimestamp", watchdog_get_last_ping_as_dual_timestamp(&watchdog_last_ping)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("ControlGroup", m->cgroup_root),
SD_JSON_BUILD_PAIR_STRING("SystemState", manager_state_to_string(manager_state(m))), SD_JSON_BUILD_PAIR_STRING("SystemState", manager_state_to_string(manager_state(m))),
SD_JSON_BUILD_PAIR_UNSIGNED("ExitCode", m->return_value), SD_JSON_BUILD_PAIR_UNSIGNED("ExitCode", m->return_value),
JSON_BUILD_PAIR_FINITE_USEC("RuntimeWatchdogUSec", manager_get_watchdog(m, WATCHDOG_RUNTIME)),
JSON_BUILD_PAIR_FINITE_USEC("RuntimeWatchdogPreUSec", manager_get_watchdog(m, WATCHDOG_PRETIMEOUT)),
JSON_BUILD_PAIR_STRING_NON_EMPTY("RuntimeWatchdogPreGovernor", m->watchdog_pretimeout_governor),
JSON_BUILD_PAIR_FINITE_USEC("RebootWatchdogUSec", manager_get_watchdog(m, WATCHDOG_REBOOT)),
JSON_BUILD_PAIR_FINITE_USEC("KExecWatchdogUSec", manager_get_watchdog(m, WATCHDOG_KEXEC)),
SD_JSON_BUILD_PAIR_UNSIGNED("SoftRebootsCount", m->soft_reboots_count)); SD_JSON_BUILD_PAIR_UNSIGNED("SoftRebootsCount", m->soft_reboots_count));
} }

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <getopt.h> #include <getopt.h>
#include <linux/magic.h>
#include <unistd.h> #include <unistd.h>
#include "sd-json.h" #include "sd-json.h"
@ -23,7 +24,6 @@
#include "log.h" #include "log.h"
#include "main-func.h" #include "main-func.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_magic.h"
#include "pager.h" #include "pager.h"
#include "parse-argument.h" #include "parse-argument.h"
#include "parse-util.h" #include "parse-util.h"

View File

@ -19,7 +19,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
assert_se(fd >= 0); assert_se(fd >= 0);
assert_se(write(fd, data, size) == (ssize_t) size); assert_se(write(fd, data, size) == (ssize_t) size);
(void) catalog_import_file(&h, name); (void) catalog_import_file(&h, fd, name);
return 0; return 0;
} }

View File

@ -22,8 +22,6 @@
#include "keyring-util.h" #include "keyring-util.h"
#include "log.h" #include "log.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_keyctl.h"
#include "missing_syscall.h"
#include "mkdir.h" #include "mkdir.h"
#include "mount-util.h" #include "mount-util.h"
#include "nulstr-util.h" #include "nulstr-util.h"

View File

@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/loop.h> #include <linux/loop.h>
#include <linux/magic.h>
#include <poll.h> #include <poll.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -45,8 +46,6 @@
#include "keyring-util.h" #include "keyring-util.h"
#include "loop-util.h" #include "loop-util.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_magic.h"
#include "missing_syscall.h"
#include "mkdir.h" #include "mkdir.h"
#include "mkfs-util.h" #include "mkfs-util.h"
#include "openssl-util.h" #include "openssl-util.h"

View File

@ -4,7 +4,6 @@
#include "homework-password-cache.h" #include "homework-password-cache.h"
#include "keyring-util.h" #include "keyring-util.h"
#include "log.h" #include "log.h"
#include "missing_syscall.h"
#include "string-util.h" #include "string-util.h"
#include "user-record.h" #include "user-record.h"

View File

@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/magic.h>
#include "btrfs-util.h" #include "btrfs-util.h"
#include "errno-util.h" #include "errno-util.h"
#include "fd-util.h" #include "fd-util.h"
@ -7,7 +9,6 @@
#include "homework-quota.h" #include "homework-quota.h"
#include "log.h" #include "log.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_magic.h"
#include "quota-util.h" #include "quota-util.h"
#include "stat-util.h" #include "stat-util.h"
#include "user-record.h" #include "user-record.h"

View File

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/magic.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/mount.h> #include <sys/mount.h>
#include <unistd.h> #include <unistd.h>
@ -35,8 +36,6 @@
#include "loop-util.h" #include "loop-util.h"
#include "main-func.h" #include "main-func.h"
#include "memory-util.h" #include "memory-util.h"
#include "missing_magic.h"
#include "missing_syscall.h"
#include "mount-util.h" #include "mount-util.h"
#include "path-util.h" #include "path-util.h"
#include "recovery-key.h" #include "recovery-key.h"

View File

@ -2,11 +2,11 @@
#pragma once #pragma once
#include <linux/fscrypt.h> #include <linux/fscrypt.h>
#include <sys/keyctl.h>
#include "sd-id128.h" #include "sd-id128.h"
#include "homework-forward.h" #include "homework-forward.h"
#include "missing_keyctl.h"
#include "user-record-util.h" #include "user-record-util.h"
typedef struct HomeSetup { typedef struct HomeSetup {

45
src/include/meson.build Normal file
View File

@ -0,0 +1,45 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
subdir('override/sys')
# Source files that provides AF_XYZ
af_sources = files(
'override/sys/socket.h',
)
# Source files that provides ARPHRD_XYZ
arphrd_sources = files(
'uapi/linux/if_arp.h',
)
# Source files that provides CAP_XYZ
cap_sources = files(
'uapi/linux/capability.h',
)
# Source files that provides BPF delegate options
bpf_delegate_sources = files(
'uapi/linux/bpf.h',
)
# Source files that provides ETHTOOL_LINK_MODE_XYZ
ethtool_link_mode_sources = files(
'uapi/linux/ethtool.h',
)
# Source files that provides IPPROTO_XYZ
ipproto_sources = files(
'override/netinet/in.h',
'uapi/linux/in.h',
)
# Source files that provides AUDIT_XYZ
audit_sources = files(
'override/linux/audit.h',
)
# Source files that provides KEY_XYZ
keyboard_sources = files(
'uapi/linux/input.h',
'uapi/linux/input-event-codes.h',
)

View File

@ -1,13 +1,15 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <linux/audit.h> /* IWYU pragma: export */ #include_next <linux/audit.h> /* IWYU pragma: export */
#if HAVE_AUDIT #if HAVE_AUDIT
# include <libaudit.h> /* IWYU pragma: export */ # include <libaudit.h> /* IWYU pragma: export */
#endif #endif
/* We use _Static_assert() directly here instead of assert_cc() #include <assert.h>
/* We use static_assert() directly here instead of assert_cc()
* because if we include macro.h in this header, the invocation * because if we include macro.h in this header, the invocation
* of generate-audit_type-list.sh becomes more complex. * of generate-audit_type-list.sh becomes more complex.
*/ */
@ -15,17 +17,17 @@
#ifndef AUDIT_SERVICE_START #ifndef AUDIT_SERVICE_START
# define AUDIT_SERVICE_START 1130 /* Service (daemon) start */ # define AUDIT_SERVICE_START 1130 /* Service (daemon) start */
#else #else
_Static_assert(AUDIT_SERVICE_START == 1130, ""); static_assert(AUDIT_SERVICE_START == 1130, "");
#endif #endif
#ifndef AUDIT_SERVICE_STOP #ifndef AUDIT_SERVICE_STOP
# define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */ # define AUDIT_SERVICE_STOP 1131 /* Service (daemon) stop */
#else #else
_Static_assert(AUDIT_SERVICE_STOP == 1131, ""); static_assert(AUDIT_SERVICE_STOP == 1131, "");
#endif #endif
#ifndef MAX_AUDIT_MESSAGE_LENGTH #ifndef MAX_AUDIT_MESSAGE_LENGTH
# define MAX_AUDIT_MESSAGE_LENGTH 8970 # define MAX_AUDIT_MESSAGE_LENGTH 8970
#else #else
_Static_assert(MAX_AUDIT_MESSAGE_LENGTH == 8970, ""); static_assert(MAX_AUDIT_MESSAGE_LENGTH == 8970, "");
#endif #endif

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <linux/bpf.h> /* IWYU pragma: export */ #include_next <linux/bpf.h> /* IWYU pragma: export */
/* defined in linux/filter.h */ /* defined in linux/filter.h */
/* Unconditional jumps, goto pc + off16 */ /* Unconditional jumps, goto pc + off16 */

View File

@ -1,7 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <linux/fs.h> /* IWYU pragma: export */ #include_next <linux/fs.h> /* IWYU pragma: export */
/* Not exposed yet. Defined at fs/ext4/ext4.h */ /* Not exposed yet. Defined at fs/ext4/ext4.h */
#ifndef EXT4_IOC_RESIZE_FS #ifndef EXT4_IOC_RESIZE_FS

View File

@ -1,9 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <linux/keyctl.h> /* IWYU pragma: export */ #include_next <linux/keyctl.h> /* IWYU pragma: export */
#include "forward.h" #include <stdint.h>
/* From linux/key.h */ /* From linux/key.h */
#ifndef KEY_POS_VIEW #ifndef KEY_POS_VIEW
@ -42,5 +42,5 @@ typedef int32_t key_serial_t;
# define KEY_OTH_SETATTR 0x00000020 # define KEY_OTH_SETATTR 0x00000020
# define KEY_OTH_ALL 0x0000003f # define KEY_OTH_ALL 0x0000003f
#else #else
assert_cc(KEY_OTH_ALL == 0x0000003f); static_assert(KEY_OTH_ALL == 0x0000003f, "");
#endif #endif

View File

@ -1,102 +1,104 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <linux/magic.h> /* IWYU pragma: export */ #include_next <linux/magic.h> /* IWYU pragma: export */
#include <assert.h>
/* Not exposed yet (4.20). Defined at ipc/mqueue.c */ /* Not exposed yet (4.20). Defined at ipc/mqueue.c */
#ifndef MQUEUE_MAGIC #ifndef MQUEUE_MAGIC
# define MQUEUE_MAGIC 0x19800202 # define MQUEUE_MAGIC 0x19800202
#else #else
assert_cc(MQUEUE_MAGIC == 0x19800202); static_assert(MQUEUE_MAGIC == 0x19800202, "");
#endif #endif
/* b1123ea6d3b3da25af5c8a9d843bd07ab63213f4 (4.8), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */ /* b1123ea6d3b3da25af5c8a9d843bd07ab63213f4 (4.8), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */
#ifndef BALLOON_KVM_MAGIC #ifndef BALLOON_KVM_MAGIC
# define BALLOON_KVM_MAGIC 0x13661366 # define BALLOON_KVM_MAGIC 0x13661366
#else #else
assert_cc(BALLOON_KVM_MAGIC == 0x13661366); static_assert(BALLOON_KVM_MAGIC == 0x13661366, "");
#endif #endif
/* 48b4800a1c6af2cdda344ea4e2c843dcc1f6afc9 (4.8), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */ /* 48b4800a1c6af2cdda344ea4e2c843dcc1f6afc9 (4.8), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */
#ifndef ZSMALLOC_MAGIC #ifndef ZSMALLOC_MAGIC
# define ZSMALLOC_MAGIC 0x58295829 # define ZSMALLOC_MAGIC 0x58295829
#else #else
assert_cc(ZSMALLOC_MAGIC == 0x58295829); static_assert(ZSMALLOC_MAGIC == 0x58295829, "");
#endif #endif
/* ea8157ab2ae5e914dd427e5cfab533b6da3819cd (5.3), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */ /* ea8157ab2ae5e914dd427e5cfab533b6da3819cd (5.3), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */
#ifndef Z3FOLD_MAGIC #ifndef Z3FOLD_MAGIC
# define Z3FOLD_MAGIC 0x33 # define Z3FOLD_MAGIC 0x33
#else #else
assert_cc(Z3FOLD_MAGIC == 0x33); static_assert(Z3FOLD_MAGIC == 0x33, "");
#endif #endif
/* fe030c9b85e6783bc52fe86449c0a4b8aa16c753 (5.5), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */ /* fe030c9b85e6783bc52fe86449c0a4b8aa16c753 (5.5), dropped by 68f2736a858324c3ec852f6c2cddd9d1c777357d (v6.0) */
#ifndef PPC_CMM_MAGIC #ifndef PPC_CMM_MAGIC
# define PPC_CMM_MAGIC 0xc7571590 # define PPC_CMM_MAGIC 0xc7571590
#else #else
assert_cc(PPC_CMM_MAGIC == 0xc7571590); static_assert(PPC_CMM_MAGIC == 0xc7571590, "");
#endif #endif
/* Not in mainline but included in Ubuntu */ /* Not in mainline but included in Ubuntu */
#ifndef SHIFTFS_MAGIC #ifndef SHIFTFS_MAGIC
# define SHIFTFS_MAGIC 0x6a656a62 # define SHIFTFS_MAGIC 0x6a656a62
#else #else
assert_cc(SHIFTFS_MAGIC == 0x6a656a62); static_assert(SHIFTFS_MAGIC == 0x6a656a62, "");
#endif #endif
/* Not exposed yet. Defined at fs/fuse/control.c */ /* Not exposed yet. Defined at fs/fuse/control.c */
#ifndef FUSE_CTL_SUPER_MAGIC #ifndef FUSE_CTL_SUPER_MAGIC
# define FUSE_CTL_SUPER_MAGIC 0x65735543 # define FUSE_CTL_SUPER_MAGIC 0x65735543
#else #else
assert_cc(FUSE_CTL_SUPER_MAGIC == 0x65735543); static_assert(FUSE_CTL_SUPER_MAGIC == 0x65735543, "");
#endif #endif
/* Not exposed yet. Defined at fs/orangefs/orangefs-kernel.h */ /* Not exposed yet. Defined at fs/orangefs/orangefs-kernel.h */
#ifndef ORANGEFS_DEVREQ_MAGIC #ifndef ORANGEFS_DEVREQ_MAGIC
# define ORANGEFS_DEVREQ_MAGIC 0x20030529 # define ORANGEFS_DEVREQ_MAGIC 0x20030529
#else #else
assert_cc(ORANGEFS_DEVREQ_MAGIC == 0x20030529); static_assert(ORANGEFS_DEVREQ_MAGIC == 0x20030529, "");
#endif #endif
/* linux/gfs2_ondisk.h */ /* linux/gfs2_ondisk.h */
#ifndef GFS2_MAGIC #ifndef GFS2_MAGIC
# define GFS2_MAGIC 0x01161970 # define GFS2_MAGIC 0x01161970
#else #else
assert_cc(GFS2_MAGIC == 0x01161970); static_assert(GFS2_MAGIC == 0x01161970, "");
#endif #endif
/* Not exposed yet. Defined at fs/configfs/mount.c */ /* Not exposed yet. Defined at fs/configfs/mount.c */
#ifndef CONFIGFS_MAGIC #ifndef CONFIGFS_MAGIC
# define CONFIGFS_MAGIC 0x62656570 # define CONFIGFS_MAGIC 0x62656570
#else #else
assert_cc(CONFIGFS_MAGIC == 0x62656570); static_assert(CONFIGFS_MAGIC == 0x62656570, "");
#endif #endif
/* Not exposed yet. Defined at fs/vboxsf/super.c */ /* Not exposed yet. Defined at fs/vboxsf/super.c */
#ifndef VBOXSF_SUPER_MAGIC #ifndef VBOXSF_SUPER_MAGIC
# define VBOXSF_SUPER_MAGIC 0x786f4256 # define VBOXSF_SUPER_MAGIC 0x786f4256
#else #else
assert_cc(VBOXSF_SUPER_MAGIC == 0x786f4256); static_assert(VBOXSF_SUPER_MAGIC == 0x786f4256, "");
#endif #endif
/* Not exposed yet, internally actually called RPCAUTH_GSSMAGIC. Defined in net/sunrpc/rpc_pipe.c */ /* Not exposed yet, internally actually called RPCAUTH_GSSMAGIC. Defined in net/sunrpc/rpc_pipe.c */
#ifndef RPC_PIPEFS_SUPER_MAGIC #ifndef RPC_PIPEFS_SUPER_MAGIC
# define RPC_PIPEFS_SUPER_MAGIC 0x67596969 # define RPC_PIPEFS_SUPER_MAGIC 0x67596969
#else #else
assert_cc(RPC_PIPEFS_SUPER_MAGIC == 0x67596969); static_assert(RPC_PIPEFS_SUPER_MAGIC == 0x67596969, "");
#endif #endif
/* Not exposed yet, defined at fs/ntfs/ntfs.h */ /* Not exposed yet, defined at fs/ntfs/ntfs.h */
#ifndef NTFS_SB_MAGIC #ifndef NTFS_SB_MAGIC
# define NTFS_SB_MAGIC 0x5346544e # define NTFS_SB_MAGIC 0x5346544e
#else #else
assert_cc(NTFS_SB_MAGIC == 0x5346544e); static_assert(NTFS_SB_MAGIC == 0x5346544e, "");
#endif #endif
/* Not exposed yet, encoded literally in fs/ntfs3/super.c. */ /* Not exposed yet, encoded literally in fs/ntfs3/super.c. */
#ifndef NTFS3_SUPER_MAGIC #ifndef NTFS3_SUPER_MAGIC
# define NTFS3_SUPER_MAGIC 0x7366746e # define NTFS3_SUPER_MAGIC 0x7366746e
#else #else
assert_cc(NTFS3_SUPER_MAGIC == 0x7366746e); static_assert(NTFS3_SUPER_MAGIC == 0x7366746e, "");
#endif #endif

View File

@ -1,8 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include <linux/nsfs.h> /* IWYU pragma: export */ #include_next <linux/nsfs.h> /* IWYU pragma: export */
#include <linux/types.h>
/* Root namespace inode numbers, as per include/linux/proc_ns.h in the kernel source tree, since v3.8: /* Root namespace inode numbers, as per include/linux/proc_ns.h in the kernel source tree, since v3.8:
* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=98f842e675f96ffac96e6c50315790912b2812be */ * https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=98f842e675f96ffac96e6c50315790912b2812be */

View File

@ -1,7 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once #pragma once
#include "forward.h" #include <linux/ioctl.h>
#include <stdint.h>
/* This is currently not exported in the public kernel headers, but the libxfs library code part of xfsprogs /* This is currently not exported in the public kernel headers, but the libxfs library code part of xfsprogs
* defines it as public header */ * defines it as public header */
@ -22,7 +23,7 @@ typedef struct xfs_fsop_geom {
uint64_t rtblocks; uint64_t rtblocks;
uint64_t rtextents; uint64_t rtextents;
uint64_t logstart; uint64_t logstart;
unsigned char uuid[16]; uint8_t uuid[16];
uint32_t sunit; uint32_t sunit;
uint32_t swidth; uint32_t swidth;
int32_t version; int32_t version;

View File

@ -35,3 +35,22 @@ static_assert(PF_KTHREAD == 0x00200000, "");
#else #else
static_assert(TASK_COMM_LEN == 16, ""); static_assert(TASK_COMM_LEN == 16, "");
#endif #endif
/* glibc does not provide clone() on ia64, only clone2(). Not only that, but it also doesn't provide a
* prototype, only the symbol in the shared library (it provides a prototype for clone(), but not the
* symbol in the shared library). */
#if defined(__ia64__)
int __clone2(int (*fn)(void *), void *stack_base, size_t stack_size, int flags, void *arg);
#define HAVE_CLONE 0
#else
/* We know that everywhere else clone() is available, so we don't bother with a meson check (that takes time
* at build time) and just define it. Once the kernel drops ia64 support, we can drop this too. */
#define HAVE_CLONE 1
#endif
/* Defined since glibc-2.41.
* Supported since kernel 3.14 (e6cfc0295c7d51b008999a8b13a44fb43f8685ea). */
#if !HAVE_SCHED_SETATTR
int missing_sched_setattr(pid_t pid, struct sched_attr *attr, unsigned flags);
# define sched_setattr missing_sched_setattr
#endif

View File

@ -0,0 +1,9 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include_next <signal.h>
#if !HAVE_RT_TGSIGQUEUEINFO
int missing_rt_tgsigqueueinfo(pid_t tgid, pid_t tid, int sig, siginfo_t *info);
# define rt_tgsigqueueinfo missing_rt_tgsigqueueinfo
#endif

View File

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/bpf.h> /* IWYU pragma: export */
#include <stddef.h>
/* Supported since kernel v3.18 (749730ce42a2121e1c88350d69478bff3994b10a). */
#if !HAVE_BPF
int missing_bpf(int cmd, union bpf_attr *attr, size_t size);
# define bpf missing_bpf
#endif

View File

@ -33,6 +33,20 @@ def parse_syscall_tables(filenames):
return {filename.split('-')[-1][:-4]: parse_syscall_table(filename) return {filename.split('-')[-1][:-4]: parse_syscall_table(filename)
for filename in filenames} for filename in filenames}
HEADER = '''\
/* SPDX-License-Identifier: LGPL-2.1-or-later
* This file is generated by src/include/override/sys/generate-syscall.py. Do not edit!
*
* Use 'ninja -C build update-syscall-tables' to download new syscall tables,
* and 'ninja -C build update-syscall-header' to regenerate this file.
*/
#pragma once
#include_next <sys/syscall.h>
#include <assert.h>
'''
DEF_TEMPLATE_A = '''\ DEF_TEMPLATE_A = '''\
#ifndef __IGNORE_{syscall} #ifndef __IGNORE_{syscall}
@ -97,7 +111,7 @@ DEF_TEMPLATE_C = '''\
/* may be an (invalid) negative number due to libseccomp, see PR 13319 */ /* may be an (invalid) negative number due to libseccomp, see PR 13319 */
# if defined __NR_{syscall} && __NR_{syscall} >= 0 # if defined __NR_{syscall} && __NR_{syscall} >= 0
# if defined systemd_NR_{syscall} # if defined systemd_NR_{syscall}
_Static_assert(__NR_{syscall} == systemd_NR_{syscall}, ""); static_assert(__NR_{syscall} == systemd_NR_{syscall}, "");
# endif # endif
# else # else
# if defined __NR_{syscall} # if defined __NR_{syscall}
@ -128,16 +142,7 @@ def print_syscall_def(syscall, tables, out):
file=out) file=out)
def print_syscall_defs(syscalls, tables, out): def print_syscall_defs(syscalls, tables, out):
print('''\ print(HEADER, file=out)
/* SPDX-License-Identifier: LGPL-2.1-or-later
* This file is generated by src/basic/missing_syscalls.py. Do not edit!
*
* Use 'ninja -C build update-syscall-tables' to download new syscall tables,
* and 'ninja -C build update-syscall-header' to regenerate this file.
*/
#pragma once
''',
file=out)
print(ARCH_CHECK, file=out) print(ARCH_CHECK, file=out)
for syscall in syscalls: for syscall in syscalls:
print_syscall_def(syscall, tables, out) print_syscall_def(syscall, tables, out)

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/ioprio.h> /* IWYU pragma: export */
#if !HAVE_IOPRIO_GET
int missing_ioprio_get(int which, int who);
# define ioprio_get missing_ioprio_get
#endif
#if !HAVE_IOPRIO_SET
int missing_ioprio_set(int which, int who, int ioprio);
# define ioprio_set missing_ioprio_set
#endif

View File

@ -0,0 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/kcmp.h> /* IWYU pragma: export */
#include <sys/types.h>
/* Supported since kernel v3.5 (d97b46a64674a267bc41c9e16132ee2a98c3347d). */
#if !HAVE_KCMP
int missing_kcmp(pid_t pid1, pid_t pid2, int type, unsigned long idx1, unsigned long idx2);
# define kcmp missing_kcmp
#endif

View File

@ -0,0 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/keyctl.h> /* IWYU pragma: export */
#include <stddef.h>
#if !HAVE_KEYCTL
long missing_keyctl(int cmd, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5);
# define keyctl missing_keyctl
#endif
#if !HAVE_ADD_KEY
key_serial_t missing_add_key(const char *type, const char *description, const void *payload, size_t plen, key_serial_t ringid);
# define add_key missing_add_key
#endif
#if !HAVE_REQUEST_KEY
key_serial_t missing_request_key(const char *type, const char *description, const char *callout_info, key_serial_t destringid);
# define request_key missing_request_key
#endif

View File

@ -0,0 +1,14 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include <linux/mempolicy.h> /* IWYU pragma: export */
#if !HAVE_SET_MEMPOLICY
int missing_set_mempolicy(int mode, const unsigned long *nodemask, unsigned long maxnode);
# define set_mempolicy missing_set_mempolicy
#endif
#if !HAVE_GET_MEMPOLICY
int missing_get_mempolicy(int *mode, unsigned long *nodemask, unsigned long maxnode, void *addr, unsigned long flags);
# define get_mempolicy missing_get_mempolicy
#endif

View File

@ -0,0 +1,41 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
arch_list = [
'alpha',
'arc',
'arm',
'arm64',
'i386',
'ia64',
'loongarch64',
'm68k',
'mips64',
'mips64n32',
'mipso32',
'parisc',
'powerpc',
'powerpc64',
'riscv32',
'riscv64',
's390',
's390x',
'sparc',
'x86_64'
]
run_target(
'update-syscall-tables',
command : [update_syscall_tables_sh, meson.current_source_dir()] + arch_list)
syscall_list_txt = files('syscall-list.txt')
syscall_lists = []
foreach arch: arch_list
syscall_lists += files('syscalls-@0@.txt'.format(arch))
endforeach
generate_syscall_py = find_program('generate-syscall.py')
run_target(
'update-syscall-header',
command : [generate_syscall_py, files('syscall.h')] + syscall_lists)

View File

@ -8,10 +8,6 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "missing_syscall_def.h"
/* Since glibc-2.37 (774058d72942249f71d74e7f2b639f77184160a6), sys/mount.h includes linux/mount.h, and /* Since glibc-2.37 (774058d72942249f71d74e7f2b639f77184160a6), sys/mount.h includes linux/mount.h, and
* we can safely include both headers in the same source file. However, we cannot do that with older glibc. * we can safely include both headers in the same source file. However, we cannot do that with older glibc.
@ -43,67 +39,56 @@ extern int umount2(const char *__special_file, int __flags) __THROW;
/* Open the filesystem referenced by FS_NAME so it can be configured for /* Open the filesystem referenced by FS_NAME so it can be configured for
mouting. */ mouting. */
/* Defined since glibc-2.36.
* Supported since kernel v5.2 (24dcb3d90a1f67fe08c68a004af37df059d74005). */
#if HAVE_FSOPEN #if HAVE_FSOPEN
extern int fsopen(const char *__fs_name, unsigned int __flags) __THROW; extern int fsopen(const char *__fs_name, unsigned int __flags) __THROW;
#else #else
static inline int missing_fsopen(const char *fsname, unsigned flags) { int missing_fsopen(const char *fsname, unsigned flags);
return syscall(__NR_fsopen, fsname, flags);
}
# define fsopen missing_fsopen # define fsopen missing_fsopen
#endif #endif
/* Create a mount representation for the FD created by fsopen using /* Create a mount representation for the FD created by fsopen using
FLAGS with ATTR_FLAGS describing how the mount is to be performed. */ FLAGS with ATTR_FLAGS describing how the mount is to be performed. */
/* Defined since glibc-2.36.
* Supported since kernel v5.2 (93766fbd2696c2c4453dd8e1070977e9cd4e6b6d). */
#if HAVE_FSMOUNT #if HAVE_FSMOUNT
extern int fsmount(int __fd, unsigned int __flags, unsigned int __ms_flags) __THROW; extern int fsmount(int __fd, unsigned int __flags, unsigned int __ms_flags) __THROW;
#else #else
static inline int missing_fsmount(int fd, unsigned flags, unsigned ms_flags) { int missing_fsmount(int fd, unsigned flags, unsigned ms_flags);
return syscall(__NR_fsmount, fd, flags, ms_flags);
}
# define fsmount missing_fsmount # define fsmount missing_fsmount
#endif #endif
/* Add the mounted FROM_DFD referenced by FROM_PATHNAME filesystem returned /* Add the mounted FROM_DFD referenced by FROM_PATHNAME filesystem returned
by fsmount in the hierarchy in the place TO_DFD reference by TO_PATHNAME by fsmount in the hierarchy in the place TO_DFD reference by TO_PATHNAME
using FLAGS. */ using FLAGS. */
/* Defined since glibc-2.36.
* Supported since kernel v5.2 (2db154b3ea8e14b04fee23e3fdfd5e9d17fbc6ae). */
#if HAVE_MOVE_MOUNT #if HAVE_MOVE_MOUNT
extern int move_mount(int __from_dfd, const char *__from_pathname, int __to_dfd, const char *__to_pathname, unsigned int flags) __THROW; extern int move_mount(int __from_dfd, const char *__from_pathname, int __to_dfd, const char *__to_pathname, unsigned int flags) __THROW;
#else #else
static inline int missing_move_mount( int missing_move_mount(int from_dfd, const char *from_pathname, int to_dfd, const char *to_pathname, unsigned flags);
int from_dfd,
const char *from_pathname,
int to_dfd,
const char *to_pathname,
unsigned flags) {
return syscall(__NR_move_mount, from_dfd, from_pathname, to_dfd, to_pathname, flags);
}
# define move_mount missing_move_mount # define move_mount missing_move_mount
#endif #endif
/* Set parameters and trigger CMD action on the FD context. KEY, VALUE, /* Set parameters and trigger CMD action on the FD context. KEY, VALUE,
and AUX are used depending ng of the CMD. */ and AUX are used depending ng of the CMD. */
/* Defined since glibc-2.36.
* Supported since kernel v5.2 (ecdab150fddb42fe6a739335257949220033b782). */
#if HAVE_FSCONFIG #if HAVE_FSCONFIG
extern int fsconfig(int __fd, unsigned int __cmd, const char *__key, const void *__value, int __aux) __THROW; extern int fsconfig(int __fd, unsigned int __cmd, const char *__key, const void *__value, int __aux) __THROW;
#else #else
static inline int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux) { int missing_fsconfig(int fd, unsigned cmd, const char *key, const void *value, int aux);
return syscall(__NR_fsconfig, fd, cmd, key, value, aux);
}
# define fsconfig missing_fsconfig # define fsconfig missing_fsconfig
#endif #endif
/* Equivalent of fopen for an existing mount point. */
#if HAVE_FSPICK
extern int fspick(int __dfd, const char *__path, unsigned int __flags) __THROW;
#endif
/* Open the mount point FILENAME in directory DFD using FLAGS. */ /* Open the mount point FILENAME in directory DFD using FLAGS. */
/* Defined since glibc-2.36.
* Supported since kernel v5.2 (a07b20004793d8926f78d63eb5980559f7813404). */
#if HAVE_OPEN_TREE #if HAVE_OPEN_TREE
extern int open_tree(int __dfd, const char *__filename, unsigned int __flags) __THROW; extern int open_tree(int __dfd, const char *__filename, unsigned int __flags) __THROW;
#else #else
static inline int missing_open_tree(int dfd, const char *filename, unsigned flags) { int missing_open_tree(int dfd, const char *filename, unsigned flags);
return syscall(__NR_open_tree, dfd, filename, flags);
}
# define open_tree missing_open_tree # define open_tree missing_open_tree
#endif #endif
@ -112,21 +97,20 @@ static inline int missing_open_tree(int dfd, const char *filename, unsigned flag
directory referred to by the file descriptor dirfd. Otherwise if DFD is directory referred to by the file descriptor dirfd. Otherwise if DFD is
the special value AT_FDCWD then PATH is interpreted relative to the current the special value AT_FDCWD then PATH is interpreted relative to the current
working directory of the calling process. */ working directory of the calling process. */
/* Defined since glibc-2.36.
* Supported since kernel v5.12 (2a1867219c7b27f928e2545782b86daaf9ad50bd). */
#if HAVE_MOUNT_SETATTR #if HAVE_MOUNT_SETATTR
extern int mount_setattr(int __dfd, const char *__path, unsigned int __flags, struct mount_attr *__uattr, size_t __usize) __THROW; extern int mount_setattr(int __dfd, const char *__path, unsigned int __flags, struct mount_attr *__uattr, size_t __usize) __THROW;
#else #else
static inline int missing_mount_setattr(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size) { int missing_mount_setattr(int dfd, const char *path, unsigned flags, struct mount_attr *attr, size_t size);
return syscall(__NR_mount_setattr, dfd, path, flags, attr, size);
}
# define mount_setattr missing_mount_setattr # define mount_setattr missing_mount_setattr
#endif #endif
/* Not defined in glibc yet as of glibc-2.41.
* Supported since kernel v6.15 (c4a16820d90199409c9bf01c4f794e1e9e8d8fd8). */
#if HAVE_OPEN_TREE_ATTR #if HAVE_OPEN_TREE_ATTR
extern int open_tree_attr(int __dfd, const char *__filename, unsigned int __flags, struct mount_attr *__uattr, size_t __usize) __THROW; extern int open_tree_attr(int __dfd, const char *__filename, unsigned int __flags, struct mount_attr *__uattr, size_t __usize) __THROW;
#else #else
static inline int missing_open_tree_attr(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size) { int missing_open_tree_attr(int dfd, const char *filename, unsigned int flags, struct mount_attr *attr, size_t size);
return syscall(__NR_open_tree_attr, dfd, filename, flags, attr, size);
}
# define open_tree_attr missing_open_tree_attr # define open_tree_attr missing_open_tree_attr
#endif #endif

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