summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--catalog/systemd.pl.catalog.in14
-rw-r--r--docs/CODING_STYLE.md735
-rw-r--r--docs/TRANSIENT-SETTINGS.md3
-rw-r--r--hwdb/60-evdev.hwdb7
-rw-r--r--hwdb/60-keyboard.hwdb24
-rw-r--r--hwdb/60-sensor.hwdb4
-rw-r--r--man/busctl.xml10
-rw-r--r--man/rules/meson.build15
-rw-r--r--man/sd-bus.xml1
-rw-r--r--man/sd_bus_add_object_vtable.xml473
-rw-r--r--man/sd_notify.xml12
-rw-r--r--man/systemd-system.conf.xml12
-rw-r--r--man/systemd.exec.xml35
-rw-r--r--man/systemd.link.xml9
-rw-r--r--man/systemd.network.xml10
-rw-r--r--man/systemd.resource-control.xml4
-rw-r--r--man/systemd.service.xml29
-rw-r--r--man/udev.xml2
-rw-r--r--man/vtable-example.c70
-rw-r--r--man/vtable-example.xml54
-rw-r--r--network/99-default.link3
-rw-r--r--rules/50-udev-default.rules.in2
-rwxr-xr-xsemaphoreci/gcc-compilation.sh47
-rwxr-xr-xsemaphoreci/semaphore-runner.sh111
-rwxr-xr-xsemaphoreci/setup.sh57
-rw-r--r--shell-completion/bash/journalctl3
-rw-r--r--shell-completion/bash/systemctl.in12
-rw-r--r--src/activate/activate.c28
-rw-r--r--src/analyze/analyze-security.c33
-rw-r--r--src/analyze/analyze-verify.h6
-rw-r--r--src/analyze/analyze.c159
-rw-r--r--src/basic/fileio.c1
-rw-r--r--src/basic/linux/if_ether.h169
-rw-r--r--src/basic/linux/in.h305
-rw-r--r--src/basic/linux/in6.h299
-rw-r--r--src/basic/linux/l2tp.h201
-rw-r--r--src/basic/linux/netdevice.h (renamed from src/shared/linux/netdevice.h)0
-rw-r--r--src/basic/meson.build5
-rw-r--r--src/basic/ordered-set.h4
-rw-r--r--src/basic/socket-util.c27
-rw-r--r--src/busctl/busctl.c13
-rw-r--r--src/core/cgroup.c71
-rw-r--r--src/core/cgroup.h10
-rw-r--r--src/core/dbus-cgroup.c43
-rw-r--r--src/core/dbus-manager.c2
-rw-r--r--src/core/dbus-service.c2
-rw-r--r--src/core/load-fragment-gperf.gperf.m42
-rw-r--r--src/core/load-fragment.c56
-rw-r--r--src/core/load-fragment.h1
-rw-r--r--src/core/main.c39
-rw-r--r--src/core/manager.h7
-rw-r--r--src/core/service.c51
-rw-r--r--src/core/service.h7
-rw-r--r--src/core/system.conf.in1
-rw-r--r--src/core/user.conf1
-rw-r--r--src/journal/journald-server.c149
-rw-r--r--src/libsystemd-network/arp-util.h2
-rw-r--r--src/libsystemd/libsystemd.sym5
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.c21
-rw-r--r--src/libsystemd/sd-bus/bus-introspect.h2
-rw-r--r--src/libsystemd/sd-bus/bus-objects.c144
-rw-r--r--src/libsystemd/sd-bus/bus-objects.h11
-rw-r--r--src/libsystemd/sd-bus/test-bus-introspect.c44
-rw-r--r--src/libsystemd/sd-bus/test-bus-vtable.c130
-rw-r--r--src/libsystemd/sd-bus/test-vtable-data.h132
-rw-r--r--src/libsystemd/sd-netlink/generic-netlink.c8
-rw-r--r--src/network/netdev/bond.c252
-rw-r--r--src/network/netdev/bond.h44
-rw-r--r--src/network/netdev/macsec.c4
-rw-r--r--src/network/netdev/netdev.c1
-rw-r--r--src/network/netdev/wireguard.c19
-rw-r--r--src/network/networkd-link.c128
-rw-r--r--src/network/networkd-link.h15
-rw-r--r--src/network/networkd-manager.c7
-rw-r--r--src/network/networkd-network.c8
-rw-r--r--src/network/test-networkd-conf.c1
-rw-r--r--src/nspawn/nspawn-oci.c24
-rw-r--r--src/nspawn/nspawn.c2
-rw-r--r--src/resolve/resolved-dns-scope.c6
-rw-r--r--src/resolve/resolved-dns-server.c2
-rw-r--r--src/resolve/resolved-dns-transaction.c6
-rw-r--r--src/resolve/resolved-link-bus.c6
-rw-r--r--src/resolve/resolved-link.c28
-rw-r--r--src/resolve/resolved-link.h4
-rw-r--r--src/resolve/resolved-manager.c4
-rw-r--r--src/run/run.c20
-rw-r--r--src/shared/bootspec.c3
-rw-r--r--src/shared/bootspec.h6
-rw-r--r--src/shared/bus-unit-util.c6
-rw-r--r--src/shared/bus-util.c2
-rw-r--r--src/shared/conf-parser.h1
-rw-r--r--src/shared/efivars.h4
-rw-r--r--src/shared/json.h8
-rw-r--r--src/shared/meson.build1
-rw-r--r--src/systemctl/systemctl.c5
-rw-r--r--src/systemd/sd-bus-vtable.h13
-rwxr-xr-xsrc/test/generate-sym-test.py12
-rw-r--r--src/test/meson.build12
-rw-r--r--src/test/test-cgroup-unit-default.c145
-rw-r--r--src/test/test-socket-util.c62
-rw-r--r--src/udev/net/link-config.c8
-rw-r--r--src/udev/net/naming-scheme.c1
-rw-r--r--src/udev/net/naming-scheme.h2
-rw-r--r--src/udev/udev-builtin-net_id.c50
-rw-r--r--src/udev/udev-rules.c5
-rw-r--r--test/TEST-16-EXTEND-TIMEOUT/testsuite.service2
-rw-r--r--test/dml-discard-empty.service7
-rw-r--r--test/dml-discard-set-ml.service8
-rw-r--r--test/dml-discard.slice5
-rw-r--r--test/dml-override-empty.service7
-rw-r--r--test/dml-override.slice5
-rw-r--r--test/dml-passthrough-empty.service7
-rw-r--r--test/dml-passthrough-set-dml.service8
-rw-r--r--test/dml-passthrough-set-ml.service8
-rw-r--r--test/dml-passthrough.slice5
-rw-r--r--test/dml.slice5
-rw-r--r--test/fuzz/fuzz-unit-file/directives.service2
-rw-r--r--test/meson.build10
-rwxr-xr-xtest/test-network/systemd-networkd-tests.py46
-rw-r--r--tmpfiles.d/meson.build1
-rw-r--r--tmpfiles.d/systemd-tmp.conf18
-rw-r--r--tmpfiles.d/tmp.conf10
123 files changed, 3766 insertions, 1269 deletions
diff --git a/NEWS b/NEWS
index 4df29b90e9..f00ed13328 100644
--- a/NEWS
+++ b/NEWS
@@ -242,8 +242,9 @@ CHANGES WITH 242:
a different layout of the bootloader partitions (for example grub2).
* During package installation (with `ninja install`), we would create
- symlinks for systemd-networkd.service, systemd-networkd.socket,
- systemd-resolved.service, remote-cryptsetup.target, remote-fs.target,
+ symlinks for getty@tty1.service, systemd-networkd.service,
+ systemd-networkd.socket, systemd-resolved.service,
+ remote-cryptsetup.target, remote-fs.target,
systemd-networkd-wait-online.service, and systemd-timesyncd.service
in /etc, as if `systemctl enable` was called for those units, to make
the system usable immediately after installation. Now this is not
diff --git a/catalog/systemd.pl.catalog.in b/catalog/systemd.pl.catalog.in
index b6c6b54205..b007ad1f05 100644
--- a/catalog/systemd.pl.catalog.in
+++ b/catalog/systemd.pl.catalog.in
@@ -388,3 +388,17 @@ Możliwe są następujące „etykiety”:
użytkowników (przy wykorzystaniu przestrzeni nazw użytkowników lub NFS)
nie wynosi 65534.
Obecny system ma etykietę „@TAINT@”.
+
+-- fe6faa94e7774663a0da52717891d8ef
+Subject: Proces jednostki @UNIT@ został zakończony przez OOM Killer
+Defined-By: systemd
+Support: %SUPPORT_URL%
+
+Proces jednostki @UNIT został zakończony przez mechanizm kończenia
+procesów przy braku pamięci (OOM) jądra Linux. Zwykle wskazuje to,
+że system ma mało pamięci i należało ją zwolnić. Proces powiązany
+z jednostką @UNIT@ został uznany za najlepszy do zakończenia
+i jądro wymusiło zakończenie jego działania.
+
+Proszę zauważyć, że brak pamięci mógł nie zostać spowodowany
+przez jednostkę @UNIT@.
diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md
index 71642bdf9b..d945f8cdbe 100644
--- a/docs/CODING_STYLE.md
+++ b/docs/CODING_STYLE.md
@@ -4,14 +4,16 @@ title: Coding Style
# Coding Style
+## Formatting
+
- 8ch indent, no tabs, except for files in `man/` which are 2ch indent, and
still no tabs, and shell scripts, which are 4ch indent, and no tabs either.
-- We prefer `/* comments */` over `// comments` in code you commit, please. This
- way `// comments` are left for developers to use for local, temporary
- commenting of code for debug purposes (i.e. uncommittable stuff), making such
- comments easily discernible from explanatory, documenting code comments
- (i.e. committable stuff).
+- We prefer `/* comments */` over `// comments` in code you commit,
+ please. This way `// comments` are left for developers to use for local,
+ temporary commenting of code for debug purposes (i.e. uncommittable stuff),
+ making such comments easily discernible from explanatory, documenting code
+ comments (i.e. committable stuff).
- Don't break code lines too eagerly. We do **not** force line breaks at 80ch,
all of today's screens should be much larger than that. But then again, don't
@@ -21,69 +23,7 @@ title: Coding Style
note that emacs loads `.dir-locals.el` automatically, but vim needs to be
configured to load `.vimrc`, see that file for instructions.
-- Variables and functions **must** be static, unless they have a
- prototype, and are supposed to be exported.
-
-- structs in `PascalCase` (with exceptions, such as public API structs),
- variables and functions in `snake_case`.
-
-- The destructors always deregister the object from the next bigger
- object, not the other way around.
-
-- To minimize strict aliasing violations, we prefer unions over casting.
-
-- For robustness reasons, destructors should be able to destruct
- half-initialized objects, too.
-
-- Error codes are returned as negative `Exxx`. e.g. `return -EINVAL`. There
- are some exceptions: for constructors, it is OK to return `NULL` on
- OOM. For lookup functions, `NULL` is fine too for "not found".
-
- Be strict with this. When you write a function that can fail due to
- more than one cause, it *really* should have an `int` as the return value
- for the error code.
-
-- Do not bother with error checking whether writing to stdout/stderr
- worked.
-
-- Do not log errors from "library" code, only do so from "main
- program" code. (With one exception: it is OK to log with DEBUG level
- from any code, with the exception of maybe inner loops).
-
-- Always check OOM. There is no excuse. In program code, you can use
- `log_oom()` for then printing a short message, but not in "library" code.
-
-- Do not issue NSS requests (that includes user name and host name
- lookups) from PID 1 as this might trigger deadlocks when those
- lookups involve synchronously talking to services that we would need
- to start up.
-
-- Do not synchronously talk to any other service from PID 1, due to
- risk of deadlocks.
-
-- Avoid fixed-size string buffers, unless you really know the maximum
- size and that maximum size is small. They are a source of errors,
- since they possibly result in truncated strings. It is often nicer
- to use dynamic memory, `alloca()` or VLAs. If you do allocate fixed-size
- strings on the stack, then it is probably only OK if you either
- use a maximum size such as `LINE_MAX`, or count in detail the maximum
- size a string can have. (`DECIMAL_STR_MAX` and `DECIMAL_STR_WIDTH`
- macros are your friends for this!)
-
- Or in other words, if you use `char buf[256]` then you are likely
- doing something wrong!
-
-- Stay uniform. For example, always use `usec_t` for time
- values. Do not mix `usec` and `msec`, and `usec` and whatnot.
-
-- Make use of `_cleanup_free_` and friends. It makes your code much
- nicer to read (and shorter)!
-
-- Be exceptionally careful when formatting and parsing floating point
- numbers. Their syntax is locale dependent (i.e. `5.000` in en_US is
- generally understood as 5, while in de_DE as 5000.).
-
-- Try to use this:
+- Try to write this:
```c
void foo() {
@@ -98,9 +38,7 @@ title: Coding Style
}
```
- But it is OK if you do not.
-
-- Single-line `if` blocks should not be enclosed in `{}`. Use this:
+- Single-line `if` blocks should not be enclosed in `{}`. Write this:
```c
if (foobar)
@@ -117,11 +55,85 @@ title: Coding Style
- Do not write `foo ()`, write `foo()`.
-- Please use `streq()` and `strneq()` instead of `strcmp()`, `strncmp()` where
- applicable (i.e. wherever you just care about equality/inequality, not about
- the sorting order).
+## Code Organization and Semantics
+
+- Please name structures in `PascalCase` (with exceptions, such as public API
+ structs), variables and functions in `snake_case`.
+
+- Avoid static variables, except for caches and very few other cases. Think
+ about thread-safety! While most of our code is never used in threaded
+ environments, at least the library code should make sure it works correctly
+ in them. Instead of doing a lot of locking for that, we tend to prefer using
+ TLS to do per-thread caching (which only works for small, fixed-size cache
+ objects), or we disable caching for any thread that is not the main
+ thread. Use `is_main_thread()` to detect whether the calling thread is the
+ main thread.
+
+- Do not write functions that clobber call-by-reference variables on
+ failure. Use temporary variables for these cases and change the passed in
+ variables only on success.
+
+- The order in which header files are included doesn't matter too
+ much. systemd-internal headers must not rely on an include order, so it is
+ safe to include them in any order possible. However, to not clutter global
+ includes, and to make sure internal definitions will not affect global
+ headers, please always include the headers of external components first
+ (these are all headers enclosed in <>), followed by our own exported headers
+ (usually everything that's prefixed by `sd-`), and then followed by internal
+ headers. Furthermore, in all three groups, order all includes alphabetically
+ so duplicate includes can easily be detected.
+
+- Please avoid using global variables as much as you can. And if you do use
+ them make sure they are static at least, instead of exported. Especially in
+ library-like code it is important to avoid global variables. Why are global
+ variables bad? They usually hinder generic reusability of code (since they
+ break in threaded programs, and usually would require locking there), and as
+ the code using them has side-effects make programs non-transparent. That
+ said, there are many cases where they explicitly make a lot of sense, and are
+ OK to use. For example, the log level and target in `log.c` is stored in a
+ global variable, and that's OK and probably expected by most. Also in many
+ cases we cache data in global variables. If you add more caches like this,
+ please be careful however, and think about threading. Only use static
+ variables if you are sure that thread-safety doesn't matter in your
+ case. Alternatively, consider using TLS, which is pretty easy to use with
+ gcc's `thread_local` concept. It's also OK to store data that is inherently
+ global in global variables, for example data parsed from command lines, see
+ below.
+
+- You might wonder what kind of common code belongs in `src/shared/` and what
+ belongs in `src/basic/`. The split is like this: anything that is used to
+ implement the public shared object we provide (sd-bus, sd-login, sd-id128,
+ nss-systemd, nss-mymachines, nss-resolve, nss-myhostname, pam_systemd), must
+ be located in `src/basic` (those objects are not allowed to link to
+ libsystemd-shared.so). Conversely, anything which is shared between multiple
+ components and does not need to be in `src/basic/`, should be in
+ `src/shared/`.
+
+ To summarize:
+
+ `src/basic/`
+ - may be used by all code in the tree
+ - may not use any code outside of `src/basic/`
+
+ `src/libsystemd/`
+ - may be used by all code in the tree, except for code in `src/basic/`
+ - may not use any code outside of `src/basic/`, `src/libsystemd/`
+
+ `src/shared/`
+ - may be used by all code in the tree, except for code in `src/basic/`,
+ `src/libsystemd/`, `src/nss-*`, `src/login/pam_systemd.*`, and files under
+ `src/journal/` that end up in `libjournal-client.a` convenience library.
+ - may not use any code outside of `src/basic/`, `src/libsystemd/`, `src/shared/`
+
+- Our focus is on the GNU libc (glibc), not any other libcs. If other libcs are
+ incompatible with glibc it's on them. However, if there are equivalent POSIX
+ and Linux/GNU-specific APIs, we generally prefer the POSIX APIs. If there
+ aren't, we are happy to use GNU or Linux APIs, and expect non-GNU
+ implementations of libc to catch up with glibc.
+
+## Using C Constructs
-- Preferably allocate stack variables on the top of the block:
+- Preferably allocate local variables on the top of the block:
```c
{
@@ -132,13 +144,7 @@ title: Coding Style
}
```
-- Unless you allocate an array, `double` is always a better choice
- than `float`. Processors speak `double` natively anyway, so there is
- no speed benefit, and on calls like `printf()` `float`s get promoted
- to `double`s anyway, so there is no point.
-
-- Do not mix function invocations with variable definitions in one
- line. Wrong:
+- Do not mix function invocations with variable definitions in one line. Wrong:
```c
{
@@ -158,119 +164,101 @@ title: Coding Style
}
```
-- Use `goto` for cleaning up, and only use it for that. i.e. you may
- only jump to the end of a function, and little else. Never jump
- backwards!
-
-- Think about the types you use. If a value cannot sensibly be
- negative, do not use `int`, but use `unsigned`.
-
-- Use `char` only for actual characters. Use `uint8_t` or `int8_t`
- when you actually mean a byte-sized signed or unsigned
- integers. When referring to a generic byte, we generally prefer the
- unsigned variant `uint8_t`. Do not use types based on `short`. They
- *never* make sense. Use `int`, `long`, `long long`, all in
- unsigned and signed fashion, and the fixed-size types
- `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `int8_t`, `int16_t`, `int32_t` and so on,
- as well as `size_t`, but nothing else. Do not use kernel types like
- `u32` and so on, leave that to the kernel.
+- Use `goto` for cleaning up, and only use it for that. i.e. you may only jump
+ to the end of a function, and little else. Never jump backwards!
-- Public API calls (i.e. functions exported by our shared libraries)
- must be marked `_public_` and need to be prefixed with `sd_`. No
- other functions should be prefixed like that.
+- To minimize strict aliasing violations, we prefer unions over casting.
-- In public API calls, you **must** validate all your input arguments for
- programming error with `assert_return()` and return a sensible return
- code. In all other calls, it is recommended to check for programming
- errors with a more brutal `assert()`. We are more forgiving to public
- users than for ourselves! Note that `assert()` and `assert_return()`
- really only should be used for detecting programming errors, not for
- runtime errors. `assert()` and `assert_return()` by usage of `_likely_()`
- inform the compiler that he should not expect these checks to fail,
- and they inform fellow programmers about the expected validity and
- range of parameters.
+- Instead of using `memzero()`/`memset()` to initialize structs allocated on
+ the stack, please try to use c99 structure initializers. It's short, prettier
+ and actually even faster at execution. Hence:
-- Never use `strtol()`, `atoi()` and similar calls. Use `safe_atoli()`,
- `safe_atou32()` and suchlike instead. They are much nicer to use in
- most cases and correctly check for parsing errors.
-
-- For every function you add, think about whether it is a "logging"
- function or a "non-logging" function. "Logging" functions do logging
- on their own, "non-logging" function never log on their own and
- expect their callers to log. All functions in "library" code,
- i.e. in `src/shared/` and suchlike must be "non-logging". Every time a
- "logging" function calls a "non-logging" function, it should log
- about the resulting errors. If a "logging" function calls another
- "logging" function, then it should not generate log messages, so
- that log messages are not generated twice for the same errors.
+ ```c
+ struct foobar t = {
+ .foo = 7,
+ .bar = "bazz",
+ };
+ ```
-- If possible, do a combined log & return operation:
+ instead of:
```c
- r = operation(...);
- if (r < 0)
- return log_(error|warning|notice|...)_errno(r, "Failed to ...: %m");
+ struct foobar t;
+ zero(t);
+ t.foo = 7;
+ t.bar = "bazz";
```
- If the error value is "synthetic", i.e. it was not received from
- the called function, use `SYNTHETIC_ERRNO` wrapper to tell the logging
- system to not log the errno value, but still return it:
+- To implement an endless loop, use `for (;;)` rather than `while (1)`. The
+ latter is a bit ugly anyway, since you probably really meant `while
+ (true)`. To avoid the discussion what the right always-true expression for an
+ infinite while loop is, our recommendation is to simply write it without any
+ such expression by using `for (;;)`.
+
+- To determine the length of a constant string `"foo"`, don't bother with
+ `sizeof("foo")-1`, please use `strlen()` instead (both gcc and clang optimize
+ the call away for fixed strings). The only exception is when declaring an
+ array. In that case use STRLEN, which evaluates to a static constant and
+ doesn't force the compiler to create a VLA.
+
+## Destructors
+
+- The destructors always deregister the object from the next bigger object, not
+ the other way around.
+
+- For robustness reasons, destructors should be able to destruct
+ half-initialized objects, too.
+
+- When you define a destructor or `unref()` call for an object, please accept a
+ `NULL` object and simply treat this as NOP. This is similar to how libc
+ `free()` works, which accepts `NULL` pointers and becomes a NOP for them. By
+ following this scheme a lot of `if` checks can be removed before invoking
+ your destructor, which makes the code substantially more readable and robust.
+
+- Related to this: when you define a destructor or `unref()` call for an
+ object, please make it return the same type it takes and always return `NULL`
+ from it. This allows writing code like this:
```c
- n = read(..., s, sizeof s);
- if (n != sizeof s)
- return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read ...");
+ p = foobar_unref(p);
```
-- Avoid static variables, except for caches and very few other
- cases. Think about thread-safety! While most of our code is never
- used in threaded environments, at least the library code should make
- sure it works correctly in them. Instead of doing a lot of locking
- for that, we tend to prefer using TLS to do per-thread caching (which
- only works for small, fixed-size cache objects), or we disable
- caching for any thread that is not the main thread. Use
- `is_main_thread()` to detect whether the calling thread is the main
- thread.
-
-- Command line option parsing:
- - Do not print full `help()` on error, be specific about the error.
- - Do not print messages to stdout on error.
- - Do not POSIX_ME_HARDER unless necessary, i.e. avoid `+` in option string.
+ which will always work regardless if `p` is initialized or not,x and
+ guarantees that `p` is `NULL` afterwards, all in just one line.
-- Do not write functions that clobber call-by-reference variables on
- failure. Use temporary variables for these cases and change the
- passed in variables only on success.
+## Error Handling
-- When you allocate a file descriptor, it should be made `O_CLOEXEC`
- right from the beginning, as none of our files should leak to forked
- binaries by default. Hence, whenever you open a file, `O_CLOEXEC` must
- be specified, right from the beginning. This also applies to
- sockets. Effectively, this means that all invocations to:
+- Error codes are returned as negative `Exxx`. e.g. `return -EINVAL`. There are
+ some exceptions: for constructors, it is OK to return `NULL` on OOM. For
+ lookup functions, `NULL` is fine too for "not found".
- - `open()` must get `O_CLOEXEC` passed,
- - `socket()` and `socketpair()` must get `SOCK_CLOEXEC` passed,
- - `recvmsg()` must get `MSG_CMSG_CLOEXEC` set,
- - `F_DUPFD_CLOEXEC` should be used instead of `F_DUPFD`, and so on,
- - invocations of `fopen()` should take `e`.
+ Be strict with this. When you write a function that can fail due to more than
+ one cause, it *really* should have an `int` as the return value for the error
+ code.
-- We never use the POSIX version of `basename()` (which glibc defines it in
- `libgen.h`), only the GNU version (which glibc defines in `string.h`).
- The only reason to include `libgen.h` is because `dirname()`
- is needed. Every time you need that please immediately undefine
- `basename()`, and add a comment about it, so that no code ever ends up
- using the POSIX version!
+- Do not bother with error checking whether writing to stdout/stderr worked.
-- Use the bool type for booleans, not integers. One exception: in public
- headers (i.e those in `src/systemd/sd-*.h`) use integers after all, as `bool`
- is C99 and in our public APIs we try to stick to C89 (with a few extension).
+- Do not log errors from "library" code, only do so from "main program"
+ code. (With one exception: it is OK to log with DEBUG level from any code,
+ with the exception of maybe inner loops).
-- When you invoke certain calls like `unlink()`, or `mkdir_p()` and you
- know it is safe to ignore the error it might return (because a later
- call would detect the failure anyway, or because the error is in an
- error path and you thus couldn't do anything about it anyway), then
- make this clear by casting the invocation explicitly to `(void)`. Code
- checks like Coverity understand that, and will not complain about
- ignored error codes. Hence, please use this:
+- In public API calls, you **must** validate all your input arguments for
+ programming error with `assert_return()` and return a sensible return
+ code. In all other calls, it is recommended to check for programming errors
+ with a more brutal `assert()`. We are more forgiving to public users than for
+ ourselves! Note that `assert()` and `assert_return()` really only should be
+ used for detecting programming errors, not for runtime errors. `assert()` and
+ `assert_return()` by usage of `_likely_()` inform the compiler that he should
+ not expect these checks to fail, and they inform fellow programmers about the
+ expected validity and range of parameters.
+
+- When you invoke certain calls like `unlink()`, or `mkdir_p()` and you know it
+ is safe to ignore the error it might return (because a later call would
+ detect the failure anyway, or because the error is in an error path and you
+ thus couldn't do anything about it anyway), then make this clear by casting
+ the invocation explicitly to `(void)`. Code checks like Coverity understand
+ that, and will not complain about ignored error codes. Hence, please use
+ this:
```c
(void) unlink("/foo/bar/baz");
@@ -283,231 +271,208 @@ title: Coding Style
```
Don't cast function calls to `(void)` that return no error
- conditions. Specifically, the various `xyz_unref()` calls that return a `NULL`
- object shouldn't be cast to `(void)`, since not using the return value does not
- hide any errors.
-
-- Don't invoke `exit()`, ever. It is not replacement for proper error
- handling. Please escalate errors up your call chain, and use normal
- `return` to exit from the main function of a process. If you
- `fork()`ed off a child process, please use `_exit()` instead of `exit()`,
- so that the exit handlers are not run.
-
-- Please never use `dup()`. Use `fcntl(fd, F_DUPFD_CLOEXEC, 3)`
- instead. For two reason: first, you want `O_CLOEXEC` set on the new `fd`
- (see above). Second, `dup()` will happily duplicate your `fd` as 0, 1,
- 2, i.e. stdin, stdout, stderr, should those `fd`s be closed. Given the
- special semantics of those `fd`s, it's probably a good idea to avoid
- them. `F_DUPFD_CLOEXEC` with `3` as parameter avoids them.
+ conditions. Specifically, the various `xyz_unref()` calls that return a
+ `NULL` object shouldn't be cast to `(void)`, since not using the return value
+ does not hide any errors.
-- When you define a destructor or `unref()` call for an object, please
- accept a `NULL` object and simply treat this as NOP. This is similar
- to how libc `free()` works, which accepts `NULL` pointers and becomes a
- NOP for them. By following this scheme a lot of `if` checks can be
- removed before invoking your destructor, which makes the code
- substantially more readable and robust.
-
-- Related to this: when you define a destructor or `unref()` call for an
- object, please make it return the same type it takes and always
- return `NULL` from it. This allows writing code like this:
-
- ```c
- p = foobar_unref(p);
- ```
-
- which will always work regardless if `p` is initialized or not, and
- guarantees that `p` is `NULL` afterwards, all in just one line.
+- When returning a return code from `main()`, please preferably use
+ `EXIT_FAILURE` and `EXIT_SUCCESS` as defined by libc.
-- Use `alloca()`, but never forget that it is not OK to invoke `alloca()`
- within a loop or within function call parameters. `alloca()` memory is
- released at the end of a function, and not at the end of a `{}`
- block. Thus, if you invoke it in a loop, you keep increasing the
- stack pointer without ever releasing memory again. (VLAs have better
- behavior in this case, so consider using them as an alternative.)
- Regarding not using `alloca()` within function parameters, see the
- BUGS section of the `alloca(3)` man page.
+## Logging
-- Use `memzero()` or even better `zero()` instead of `memset(..., 0, ...)`
+- For every function you add, think about whether it is a "logging" function or
+ a "non-logging" function. "Logging" functions do logging on their own,
+ "non-logging" function never log on their own and expect their callers to
+ log. All functions in "library" code, i.e. in `src/shared/` and suchlike must
+ be "non-logging". Every time a "logging" function calls a "non-logging"
+ function, it should log about the resulting errors. If a "logging" function
+ calls another "logging" function, then it should not generate log messages,
+ so that log messages are not generated twice for the same errors.
-- Instead of using `memzero()`/`memset()` to initialize structs allocated
- on the stack, please try to use c99 structure initializers. It's
- short, prettier and actually even faster at execution. Hence:
+- If possible, do a combined log & return operation:
```c
- struct foobar t = {
- .foo = 7,
- .bar = "bazz",
- };
+ r = operation(...);
+ if (r < 0)
+ return log_(error|warning|notice|...)_errno(r, "Failed to ...: %m");
```
- instead of:
+ If the error value is "synthetic", i.e. it was not received from
+ the called function, use `SYNTHETIC_ERRNO` wrapper to tell the logging
+ system to not log the errno value, but still return it:
```c
- struct foobar t;
- zero(t);
- t.foo = 7;
- t.bar = "bazz";
+ n = read(..., s, sizeof s);
+ if (n != sizeof s)
+ return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read ...");
```
-- When returning a return code from `main()`, please preferably use
- `EXIT_FAILURE` and `EXIT_SUCCESS` as defined by libc.
-
-- The order in which header files are included doesn't matter too
- much. systemd-internal headers must not rely on an include order, so
- it is safe to include them in any order possible.
- However, to not clutter global includes, and to make sure internal
- definitions will not affect global headers, please always include the
- headers of external components first (these are all headers enclosed
- in <>), followed by our own exported headers (usually everything
- that's prefixed by `sd-`), and then followed by internal headers.
- Furthermore, in all three groups, order all includes alphabetically
- so duplicate includes can easily be detected.
+## Memory Allocation
-- To implement an endless loop, use `for (;;)` rather than `while (1)`.
- The latter is a bit ugly anyway, since you probably really
- meant `while (true)`. To avoid the discussion what the right
- always-true expression for an infinite while loop is, our
- recommendation is to simply write it without any such expression by
- using `for (;;)`.
-
-- Never use the `off_t` type, and particularly avoid it in public
- APIs. It's really weirdly defined, as it usually is 64-bit and we
- don't support it any other way, but it could in theory also be
- 32-bit. Which one it is depends on a compiler switch chosen by the
- compiled program, which hence corrupts APIs using it unless they can
- also follow the program's choice. Moreover, in systemd we should
- parse values the same way on all architectures and cannot expose
- `off_t` values over D-Bus. To avoid any confusion regarding conversion
- and ABIs, always use simply `uint64_t` directly.
-
-- Commit message subject lines should be prefixed with an appropriate
- component name of some kind. For example "journal: ", "nspawn: " and
- so on.
+- Always check OOM. There is no excuse. In program code, you can use
+ `log_oom()` for then printing a short message, but not in "library" code.
-- Do not use "Signed-Off-By:" in your commit messages. That's a kernel
- thing we don't do in the systemd project.
+- Avoid fixed-size string buffers, unless you really know the maximum size and
+ that maximum size is small. They are a source of errors, since they possibly
+ result in truncated strings. It is often nicer to use dynamic memory,
+ `alloca()` or VLAs. If you do allocate fixed-size strings on the stack, then
+ it is probably only OK if you either use a maximum size such as `LINE_MAX`,
+ or count in detail the maximum size a string can have. (`DECIMAL_STR_MAX` and
+ `DECIMAL_STR_WIDTH` macros are your friends for this!)
-- Avoid leaving long-running child processes around, i.e. `fork()`s that
- are not followed quickly by an `execv()` in the child. Resource
- management is unclear in this case, and memory CoW will result in
- unexpected penalties in the parent much, much later on.
+ Or in other words, if you use `char buf[256]` then you are likely doing
+ something wrong!
-- Don't block execution for arbitrary amounts of time using `usleep()`
- or a similar call, unless you really know what you do. Just "giving
- something some time", or so is a lazy excuse. Always wait for the
- proper event, instead of doing time-based poll loops.
+- Make use of `_cleanup_free_` and friends. It makes your code much nicer to
+ read (and shorter)!
-- To determine the length of a constant string `"foo"`, don't bother with
- `sizeof("foo")-1`, please use `strlen()` instead (both gcc and clang optimize
- the call away for fixed strings). The only exception is when declaring an
- array. In that case use STRLEN, which evaluates to a static constant and
- doesn't force the compiler to create a VLA.
+- Use `alloca()`, but never forget that it is not OK to invoke `alloca()`
+ within a loop or within function call parameters. `alloca()` memory is
+ released at the end of a function, and not at the end of a `{}` block. Thus,
+ if you invoke it in a loop, you keep increasing the stack pointer without
+ ever releasing memory again. (VLAs have better behavior in this case, so
+ consider using them as an alternative.) Regarding not using `alloca()`
+ within function parameters, see the BUGS section of the `alloca(3)` man page.
- If you want to concatenate two or more strings, consider using `strjoina()`
or `strjoin()` rather than `asprintf()`, as the latter is a lot slower. This
matters particularly in inner loops (but note that `strjoina()` cannot be
used there).
-- Please avoid using global variables as much as you can. And if you
- do use them make sure they are static at least, instead of
- exported. Especially in library-like code it is important to avoid
- global variables. Why are global variables bad? They usually hinder
- generic reusability of code (since they break in threaded programs,
- and usually would require locking there), and as the code using them
- has side-effects make programs non-transparent. That said, there are
- many cases where they explicitly make a lot of sense, and are OK to
- use. For example, the log level and target in `log.c` is stored in a
- global variable, and that's OK and probably expected by most. Also
- in many cases we cache data in global variables. If you add more
- caches like this, please be careful however, and think about
- threading. Only use static variables if you are sure that
- thread-safety doesn't matter in your case. Alternatively, consider
- using TLS, which is pretty easy to use with gcc's `thread_local`
- concept. It's also OK to store data that is inherently global in
- global variables, for example data parsed from command lines, see
- below.
+## Runtime Behaviour
-- If you parse a command line, and want to store the parsed parameters
- in global variables, please consider prefixing their names with
- `arg_`. We have been following this naming rule in most of our
- tools, and we should continue to do so, as it makes it easy to
- identify command line parameter variables, and makes it clear why it
- is OK that they are global variables.
+- Avoid leaving long-running child processes around, i.e. `fork()`s that are
+ not followed quickly by an `execv()` in the child. Resource management is
+ unclear in this case, and memory CoW will result in unexpected penalties in
+ the parent much, much later on.
-- When exposing public C APIs, be careful what function parameters you make
- `const`. For example, a parameter taking a context object should probably not
- be `const`, even if you are writing an otherwise read-only accessor function
- for it. The reason is that making it `const` fixates the contract that your
- call won't alter the object ever, as part of the API. However, that's often
- quite a promise, given that this even prohibits object-internal caching or
- lazy initialization of object variables. Moreover, it's usually not too useful
- for client applications. Hence, please be careful and avoid `const` on object
- parameters, unless you are very sure `const` is appropriate.
+- Don't block execution for arbitrary amounts of time using `usleep()` or a
+ similar call, unless you really know what you do. Just "giving something some
+ time", or so is a lazy excuse. Always wait for the proper event, instead of
+ doing time-based poll loops.
+
+- Whenever installing a signal handler, make sure to set `SA_RESTART` for it,
+ so that interrupted system calls are automatically restarted, and we minimize
+ hassles with handling `EINTR` (in particular as `EINTR` handling is pretty
+ broken on Linux).
+
+- When applying C-style unescaping as well as specifier expansion on the same
+ string, always apply the C-style unescaping fist, followed by the specifier
+ expansion. When doing the reverse, make sure to escape `%` in specifier-style
+ first (i.e. `%` → `%%`), and then do C-style escaping where necessary.
+
+- Be exceptionally careful when formatting and parsing floating point
+ numbers. Their syntax is locale dependent (i.e. `5.000` in en_US is generally
+ understood as 5, while in de_DE as 5000.).
- Make sure to enforce limits on every user controllable resource. If the user
can allocate resources in your code, your code must enforce some form of
- limits after which it will refuse operation. It's fine if it is hard-coded (at
- least initially), but it needs to be there. This is particularly important
- for objects that unprivileged users may allocate, but also matters for
- everything else any user may allocated.
-
-- `htonl()`/`ntohl()` and `htons()`/`ntohs()` are weird. Please use `htobe32()` and
- `htobe16()` instead, it's much more descriptive, and actually says what really
- is happening, after all `htonl()` and `htons()` don't operate on `long`s and
- `short`s as their name would suggest, but on `uint32_t` and `uint16_t`. Also,
- "network byte order" is just a weird name for "big endian", hence we might
- want to call it "big endian" right-away.
+ limits after which it will refuse operation. It's fine if it is hard-coded
+ (at least initially), but it needs to be there. This is particularly
+ important for objects that unprivileged users may allocate, but also matters
+ for everything else any user may allocated.
+
+## Types
+
+- Think about the types you use. If a value cannot sensibly be negative, do not
+ use `int`, but use `unsigned`.
+
+- Use `char` only for actual characters. Use `uint8_t` or `int8_t` when you
+ actually mean a byte-sized signed or unsigned integers. When referring to a
+ generic byte, we generally prefer the unsigned variant `uint8_t`. Do not use
+ types based on `short`. They *never* make sense. Use `int`, `long`, `long
+ long`, all in unsigned and signed fashion, and the fixed-size types
+ `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t`, `int8_t`, `int16_t`, `int32_t`
+ and so on, as well as `size_t`, but nothing else. Do not use kernel types
+ like `u32` and so on, leave that to the kernel.
+
+- Stay uniform. For example, always use `usec_t` for time values. Do not mix
+ `usec` and `msec`, and `usec` and whatnot.
+
+- Never use the `off_t` type, and particularly avoid it in public APIs. It's
+ really weirdly defined, as it usually is 64-bit and we don't support it any
+ other way, but it could in theory also be 32-bit. Which one it is depends on
+ a compiler switch chosen by the compiled program, which hence corrupts APIs
+ using it unless they can also follow the program's choice. Moreover, in
+ systemd we should parse values the same way on all architectures and cannot
+ expose `off_t` values over D-Bus. To avoid any confusion regarding conversion
+ and ABIs, always use simply `uint64_t` directly.
-- You might wonder what kind of common code belongs in `src/shared/` and what
- belongs in `src/basic/`. The split is like this: anything that is used to
- implement the public shared object we provide (sd-bus, sd-login, sd-id128,
- nss-systemd, nss-mymachines, nss-resolve, nss-myhostname, pam_systemd), must
- be located in `src/basic` (those objects are not allowed to link to
- libsystemd-shared.so). Conversely, anything which is shared between multiple
- components and does not need to be in `src/basic/`, should be in
- `src/shared/`.
+- Unless you allocate an array, `double` is always a better choice than
+ `float`. Processors speak `double` natively anyway, so there is no speed
+ benefit, and on calls like `printf()` `float`s get promoted to `double`s
+ anyway, so there is no point.
- To summarize:
+- Use the bool type for booleans, not integers. One exception: in public
+ headers (i.e those in `src/systemd/sd-*.h`) use integers after all, as `bool`
+ is C99 and in our public APIs we try to stick to C89 (with a few extension).
- `src/basic/`
- - may be used by all code in the tree
- - may not use any code outside of `src/basic/`
+## Deadlocks
- `src/libsystemd/`
- - may be used by all code in the tree, except for code in `src/basic/`
- - may not use any code outside of `src/basic/`, `src/libsystemd/`
+- Do not issue NSS requests (that includes user name and host name lookups)
+ from PID 1 as this might trigger deadlocks when those lookups involve
+ synchronously talking to services that we would need to start up.
- `src/shared/`
- - may be used by all code in the tree, except for code in `src/basic/`,
- `src/libsystemd/`, `src/nss-*`, `src/login/pam_systemd.*`, and files under
- `src/journal/` that end up in `libjournal-client.a` convenience library.
- - may not use any code outside of `src/basic/`, `src/libsystemd/`, `src/shared/`
+- Do not synchronously talk to any other service from PID 1, due to risk of
+ deadlocks.
-- Our focus is on the GNU libc (glibc), not any other libcs. If other libcs are
- incompatible with glibc it's on them. However, if there are equivalent POSIX
- and Linux/GNU-specific APIs, we generally prefer the POSIX APIs. If there
- aren't, we are happy to use GNU or Linux APIs, and expect non-GNU
- implementations of libc to catch up with glibc.
+## File Descriptors
-- Whenever installing a signal handler, make sure to set `SA_RESTART` for it, so
- that interrupted system calls are automatically restarted, and we minimize
- hassles with handling `EINTR` (in particular as `EINTR` handling is pretty broken
- on Linux).
+- When you allocate a file descriptor, it should be made `O_CLOEXEC` right from
+ the beginning, as none of our files should leak to forked binaries by
+ default. Hence, whenever you open a file, `O_CLOEXEC` must be specified,
+ right from the beginning. This also applies to sockets. Effectively, this
+ means that all invocations to:
-- When applying C-style unescaping as well as specifier expansion on the same
- string, always apply the C-style unescaping fist, followed by the specifier
- expansion. When doing the reverse, make sure to escape `%` in specifier-style
- first (i.e. `%` → `%%`), and then do C-style escaping where necessary.
+ - `open()` must get `O_CLOEXEC` passed,
+ - `socket()` and `socketpair()` must get `SOCK_CLOEXEC` passed,
+ - `recvmsg()` must get `MSG_CMSG_CLOEXEC` set,
+ - `F_DUPFD_CLOEXEC` should be used instead of `F_DUPFD`, and so on,
+ - invocations of `fopen()` should take `e`.
-- It's a good idea to use `O_NONBLOCK` when opening 'foreign' regular files, i.e.
- file system objects that are supposed to be regular files whose paths where
- specified by the user and hence might actually refer to other types of file
- system objects. This is a good idea so that we don't end up blocking on
+- It's a good idea to use `O_NONBLOCK` when opening 'foreign' regular files,
+ i.e. file system objects that are supposed to be regular files whose paths
+ where specified by the user and hence might actually refer to other types of
+ file system objects. This is a good idea so that we don't end up blocking on
'strange' file nodes, for example if the user pointed us to a FIFO or device
node which may block when opening. Moreover even for actual regular files
`O_NONBLOCK` has a benefit: it bypasses any mandatory lock that might be in
- effect on the regular file. If in doubt consider turning off `O_NONBLOCK` again
- after opening.
+ effect on the regular file. If in doubt consider turning off `O_NONBLOCK`
+ again after opening.
+
+## Command Line
+
+- If you parse a command line, and want to store the parsed parameters in
+ global variables, please consider prefixing their names with `arg_`. We have
+ been following this naming rule in most of our tools, and we should continue
+ to do so, as it makes it easy to identify command line parameter variables,
+ and makes it clear why it is OK that they are global variables.
+
+- Command line option parsing:
+ - Do not print full `help()` on error, be specific about the error.
+ - Do not print messages to stdout on error.
+ - Do not POSIX_ME_HARDER unless necessary, i.e. avoid `+` in option string.
+
+## Exporting Symbols
+
+- Variables and functions **must** be static, unless they have a prototype, and
+ are supposed to be exported.
+
+- Public API calls (i.e. functions exported by our shared libraries)
+ must be marked `_public_` and need to be prefixed with `sd_`. No
+ other functions should be prefixed like that.
+
+- When exposing public C APIs, be careful what function parameters you make
+ `const`. For example, a parameter taking a context object should probably not
+ be `const`, even if you are writing an otherwise read-only accessor function
+ for it. The reason is that making it `const` fixates the contract that your
+ call won't alter the object ever, as part of the API. However, that's often
+ quite a promise, given that this even prohibits object-internal caching or
+ lazy initialization of object variables. Moreover, it's usually not too
+ useful for client applications. Hence, please be careful and avoid `const` on
+ object parameters, unless you are very sure `const` is appropriate.
+
+## Referencing Concepts
- When referring to a configuration file option in the documentation and such,
please always suffix it with `=`, to indicate that it is a configuration file
@@ -521,6 +486,52 @@ title: Coding Style
suffix it with `/`, to indicate that it is a directory, not a regular file
(or other file system object).
+## Functions to Avoid
+
+- Use `memzero()` or even better `zero()` instead of `memset(..., 0, ...)`
+
+- Please use `streq()` and `strneq()` instead of `strcmp()`, `strncmp()` where
+ applicable (i.e. wherever you just care about equality/inequality, not about
+ the sorting order).
+
+- Never use `strtol()`, `atoi()` and similar calls. Use `safe_atoli()`,
+ `safe_atou32()` and suchlike instead. They are much nicer to use in most
+ cases and correctly check for parsing errors.
+
+- `htonl()`/`ntohl()` and `htons()`/`ntohs()` are weird. Please use `htobe32()`
+ and `htobe16()` instead, it's much more descriptive, and actually says what
+ really is happening, after all `htonl()` and `htons()` don't operate on
+ `long`s and `short`s as their name would suggest, but on `uint32_t` and
+ `uint16_t`. Also, "network byte order" is just a weird name for "big endian",
+ hence we might want to call it "big endian" right-away.
+
+- Please never use `dup()`. Use `fcntl(fd, F_DUPFD_CLOEXEC, 3)` instead. For
+ two reason: first, you want `O_CLOEXEC` set on the new `fd` (see
+ above). Second, `dup()` will happily duplicate your `fd` as 0, 1, 2,
+ i.e. stdin, stdout, stderr, should those `fd`s be closed. Given the special
+ semantics of those `fd`s, it's probably a good idea to avoid
+ them. `F_DUPFD_CLOEXEC` with `3` as parameter avoids them.
+
- Don't use `fgets()`, it's too hard to properly handle errors such as overly
long lines. Use `read_line()` instead, which is our own function that handles
this much nicer.
+
+- Don't invoke `exit()`, ever. It is not replacement for proper error
+ handling. Please escalate errors up your call chain, and use normal `return`
+ to exit from the main function of a process. If you `fork()`ed off a child
+ process, please use `_exit()` instead of `exit()`, so that the exit handlers
+ are not run.
+
+- We never use the POSIX version of `basename()` (which glibc defines it in
+ `libgen.h`), only the GNU version (which glibc defines in `string.h`). The
+ only reason to include `libgen.h` is because `dirname()` is needed. Every
+ time you need that please immediately undefine `basename()`, and add a
+ comment about it, so that no code ever ends up using the POSIX version!
+
+# Committing to git
+
+- Commit message subject lines should be prefixed with an appropriate component
+ name of some kind. For example "journal: ", "nspawn: " and so on.
+
+- Do not use "Signed-Off-By:" in your commit messages. That's a kernel thing we
+ don't do in the systemd project.
diff --git a/docs/TRANSIENT-SETTINGS.md b/docs/TRANSIENT-SETTINGS.md
index f081fdb2ce..3aa68c0a26 100644
--- a/docs/TRANSIENT-SETTINGS.md
+++ b/docs/TRANSIENT-SETTINGS.md
@@ -228,6 +228,7 @@ All cgroup/resource control settings are available for transient units
✓ CPUQuotaPeriodSec=
✓ MemoryAccounting=
✓ MemoryMin=
+✓ DefaultMemoryLow=
✓ MemoryLow=
✓ MemoryHigh=
✓ MemoryMax=
@@ -252,6 +253,7 @@ All cgroup/resource control settings are available for transient units
✓ TasksAccounting=
✓ TasksMax=
✓ Delegate=
+✓ DisableControllers=
✓ IPAccounting=
✓ IPAddressAllow=
✓ IPAddressDeny=
@@ -285,6 +287,7 @@ Most service unit settings are available for transient units.
✓ RestartSec=
✓ TimeoutStartSec=
✓ TimeoutStopSec=
+✓ TimeoutAbortSec=
✓ TimeoutSec=
✓ RuntimeMaxSec=
✓ WatchdogSec=
diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb
index 4f94342a09..d3664f4f09 100644
--- a/hwdb/60-evdev.hwdb
+++ b/hwdb/60-evdev.hwdb
@@ -232,6 +232,13 @@ evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLati
EVDEV_ABS_35=79:1841:22
EVDEV_ABS_36=140:1325:29
+# Dell Latitude E7250
+evdev:name:AlpsPS/2 ALPS GlidePoint:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7250*
+ EVDEV_ABS_00=179:3903:38
+ EVDEV_ABS_01=277:1916:32
+ EVDEV_ABS_35=179:3903:38
+ EVDEV_ABS_36=277:1916:32
+
# Dell Latitude E7470
evdev:name:AlpsPS/2 ALPS DualPoint TouchPad:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE7470*
EVDEV_ABS_00=29:2930:30
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index 71aecd8a53..4762c68a1b 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -1036,8 +1036,12 @@ evdev:name:MSI Laptop hotkeys:dmi:bvn*:bvr*:bd*:svn*:pnM[iI][cC][rR][oO]-S[tT][a
# OLPC
###########################################################
-# XO
+# XO-1 and XO-1.5
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
+# XO-1.75 and XO-1.4 (sp/ is the Security Processor)
+evdev:name:AT Translated Set 2 keyboard:phys:sp/serio*/input*:ev:120013:*
+ KEYBOARD_LED_CAPSLOCK=0
+ KEYBOARD_LED_NUMLOCK=0
KEYBOARD_KEY_59=fn
KEYBOARD_KEY_81=fn_esc
KEYBOARD_KEY_f9=camera
@@ -1082,15 +1086,15 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
KEYBOARD_KEY_dc=rightmeta # right grab
KEYBOARD_KEY_85=rightmeta # Right grab releases on a different scancode
KEYBOARD_KEY_d6=kbdillumtoggle # Fn+Space
- KEYBOARD_KEY_69=switchvideomode # Brightness key
- KEYBOARD_KEY_65=kp8 # up
- KEYBOARD_KEY_66=kp2 # down
- KEYBOARD_KEY_67=kp4 # left
- KEYBOARD_KEY_68=kp6 # right
- KEYBOARD_KEY_e5=kp9 # pgup
- KEYBOARD_KEY_e6=kp3 # pgdn
- KEYBOARD_KEY_e7=kp7 # home
- KEYBOARD_KEY_e8=kp1 # end
+ KEYBOARD_KEY_69=rotate_display
+ KEYBOARD_KEY_65=btn_dpad_up
+ KEYBOARD_KEY_66=btn_dpad_down
+ KEYBOARD_KEY_67=btn_dpad_left
+ KEYBOARD_KEY_68=btn_dpad_right
+ KEYBOARD_KEY_e5=btn_north
+ KEYBOARD_KEY_e6=btn_south
+ KEYBOARD_KEY_e7=btn_west
+ KEYBOARD_KEY_e8=btn_east
###########################################################
# Onkyo
diff --git a/hwdb/60-sensor.hwdb b/hwdb/60-sensor.hwdb
index 1a6f2d875b..11d5e8349d 100644
--- a/hwdb/60-sensor.hwdb
+++ b/hwdb/60-sensor.hwdb
@@ -367,6 +367,10 @@ sensor:modalias:acpi:KIOX000A*:dmi:*:svnLINX*:pnLINX12X64:*
sensor:modalias:acpi:SMO8500*:dmi:*:svnMEDION:pnAkoyaE2212TMD99720:*
ACCEL_MOUNT_MATRIX=-1, 0, 0; 0, 1, 0; 0, 0, 1
+# Medion Akoya E3216 MD60900
+sensor:modalias:acpi:KIOX010A*:dmi:*:svnMEDION*:pnE3216*:*
+ ACCEL_MOUNT_MATRIX=0, -1, 0; -1, 0, 0; 0, 0, 1
+
#########################################
# MSI
#########################################
diff --git a/man/busctl.xml b/man/busctl.xml
index e4c7fcb283..328c101622 100644
--- a/man/busctl.xml
+++ b/man/busctl.xml
@@ -141,6 +141,16 @@
</varlistentry>
<varlistentry>
+ <term><option>--xml-interface</option></term>
+
+ <listitem>
+ <para>When used with the <command>introspect</command> call, dump the XML description received from
+ the D-Bus <constant>org.freedesktop.DBus.Introspectable.Introspect</constant> call instead of the
+ normal output.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>--json=</option><replaceable>MODE</replaceable></term>
<listitem>
diff --git a/man/rules/meson.build b/man/rules/meson.build
index 9674cbb30b..6894158466 100644
--- a/man/rules/meson.build
+++ b/man/rules/meson.build
@@ -115,6 +115,21 @@ manpages = [
'sd_bus_match_signal',
'sd_bus_match_signal_async'],
''],
+ ['sd_bus_add_object_vtable',
+ '3',
+ ['SD_BUS_METHOD',
+ 'SD_BUS_METHOD_WITH_NAMES',
+ 'SD_BUS_METHOD_WITH_NAMES_OFFSET',
+ 'SD_BUS_METHOD_WITH_OFFSET',
+ 'SD_BUS_PARAM',
+ 'SD_BUS_PROPERTY',
+ 'SD_BUS_SIGNAL',
+ 'SD_BUS_SIGNAL_WITH_NAMES',
+ 'SD_BUS_VTABLE_END',
+ 'SD_BUS_VTABLE_START',
+ 'SD_BUS_WRITABLE_PROPERTY',
+ 'sd_bus_add_fallback_vtable'],
+ ''],
['sd_bus_attach_event', '3', ['sd_bus_detach_event', 'sd_bus_get_event'], ''],
['sd_bus_close', '3', ['sd_bus_flush'], ''],
['sd_bus_creds_get_pid',
diff --git a/man/sd-bus.xml b/man/sd-bus.xml
index 6c925e3161..e9a66d87dd 100644
--- a/man/sd-bus.xml
+++ b/man/sd-bus.xml
@@ -41,6 +41,7 @@
<para>See
<literallayout><citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+<citerefentry><refentrytitle>sd_bus_add_object_vtable</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_attach_event</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_creds_get_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_creds_new_from_pid</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
diff --git a/man/sd_bus_add_object_vtable.xml b/man/sd_bus_add_object_vtable.xml
new file mode 100644
index 0000000000..92be236afd
--- /dev/null
+++ b/man/sd_bus_add_object_vtable.xml
@@ -0,0 +1,473 @@
+<?xml version='1.0'?> <!--*-nxml-*-->
+<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+<!-- SPDX-License-Identifier: LGPL-2.1+ -->
+
+<refentry id="sd_bus_add_object_vtable"
+ xmlns:xi="http://www.w3.org/2001/XInclude">
+
+ <refentryinfo>
+ <title>sd_bus_add_object_vtable</title>
+ <productname>systemd</productname>
+ </refentryinfo>
+
+ <refmeta>
+ <refentrytitle>sd_bus_add_object_vtable</refentrytitle>
+ <manvolnum>3</manvolnum>
+ </refmeta>
+
+ <refnamediv>
+ <refname>sd_bus_add_object_vtable</refname>
+ <refname>sd_bus_add_fallback_vtable</refname>
+ <refname>SD_BUS_VTABLE_START</refname>
+ <refname>SD_BUS_VTABLE_END</refname>
+ <refname>SD_BUS_METHOD_WITH_NAMES_OFFSET</refname>
+ <refname>SD_BUS_METHOD_WITH_NAMES</refname>
+ <refname>SD_BUS_METHOD_WITH_OFFSET</refname>
+ <refname>SD_BUS_METHOD</refname>
+ <refname>SD_BUS_SIGNAL_WITH_NAMES</refname>
+ <refname>SD_BUS_SIGNAL</refname>
+ <refname>SD_BUS_WRITABLE_PROPERTY</refname>
+ <refname>SD_BUS_PROPERTY</refname>
+ <refname>SD_BUS_PARAM</refname>
+
+ <refpurpose>Declare properties and methods for a D-Bus path</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcsynopsisinfo>#include &lt;systemd/sd-bus-vtable.h&gt;</funcsynopsisinfo>
+
+ <funcprototype>
+ <funcdef>typedef int (*<function>sd_bus_message_handler_t</function>)</funcdef>
+ <paramdef>sd_bus_message *<parameter>m</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>typedef int (*<function>sd_bus_property_get_t</function>)</funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>const char *<parameter>property</parameter></paramdef>
+ <paramdef>sd_bus_message *<parameter>reply</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>typedef int (*<function>sd_bus_property_set_t</function>)</funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>const char *<parameter>property</parameter></paramdef>
+ <paramdef>sd_bus_message *<parameter>value</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>typedef int (*<function>sd_bus_object_find_t</function>)</funcdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ <paramdef>void **<parameter>ret_found</parameter></paramdef>
+ <paramdef>sd_bus_error *<parameter>ret_error</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_add_object_vtable</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>path</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>const sd_bus_vtable *<parameter>vtable</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ </funcprototype>
+
+ <funcprototype>
+ <funcdef>int <function>sd_bus_add_fallback_vtable</function></funcdef>
+ <paramdef>sd_bus *<parameter>bus</parameter></paramdef>
+ <paramdef>sd_bus_slot **<parameter>slot</parameter></paramdef>
+ <paramdef>const char *<parameter>prefix</parameter></paramdef>
+ <paramdef>const char *<parameter>interface</parameter></paramdef>
+ <paramdef>const sd_bus_vtable *<parameter>vtable</parameter></paramdef>
+ <paramdef>sd_bus_object_find_t <parameter>find</parameter></paramdef>
+ <paramdef>void *<parameter>userdata</parameter></paramdef>
+ </funcprototype>
+
+ <para>
+ <constant>SD_BUS_VTABLE_START(<replaceable>flags</replaceable>)</constant>
+ </para>
+ <para>
+ <constant>SD_BUS_VTABLE_END</constant>
+ </para>
+ <para>
+ <constant>SD_BUS_METHOD_WITH_NAMES_OFFSET(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>in_names</replaceable>,
+ <replaceable>result</replaceable>,
+ <replaceable>out_names</replaceable>,
+ <replaceable>handler</replaceable>,
+ <replaceable>offset</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_METHOD_WITH_NAMES(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>in_names</replaceable>,
+ <replaceable>result</replaceable>,
+ <replaceable>out_names</replaceable>,
+ <replaceable>handler</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_METHOD_WITH_OFFSET(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>result</replaceable>,
+ <replaceable>handler</replaceable>,
+ <replaceable>offset</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_METHOD(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>result</replaceable>,
+ <replaceable>handler</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_SIGNAL_WITH_NAMES(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>names</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_SIGNAL(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_WRITABLE_PROPERTY(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>get</replaceable>,
+ <replaceable>set</replaceable>,
+ <replaceable>offset</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_PROPERTY(
+ <replaceable>member</replaceable>,
+ <replaceable>signature</replaceable>,
+ <replaceable>get</replaceable>,
+ <replaceable>offset</replaceable>,
+ <replaceable>flags</replaceable>)
+ </constant>
+ </para>
+ <para>
+ <constant>SD_BUS_PARAM(<replaceable>name</replaceable>)</constant>
+ </para>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para><function>sd_bus_add_object_vtable()</function> is used to declare attributes for the path object
+ path <parameter>path</parameter> connected to the bus connection <parameter>bus</parameter> under the
+ interface <parameter>interface</parameter>. The table <parameter>vtable</parameter> may contain property
+ declarations using <constant>SD_BUS_PROPERTY()</constant> or
+ <constant>SD_BUS_WRITABLE_PROPERTY()</constant>, method declarations using
+ <constant>SD_BUS_METHOD()</constant>, <constant>SD_BUS_METHOD_WITH_NAMES()</constant>,
+ <constant>SD_BUS_METHOD_WITH_OFFSET()</constant>, or
+ <constant>SD_BUS_METHOD_WITH_NAMES_OFFSET()</constant>, and signal declarations using
+ <constant>SD_BUS_SIGNAL_WITH_NAMES()</constant> or <constant>SD_BUS_SIGNAL()</constant>, see below. The
+ <replaceable>userdata</replaceable> parameter contains a pointer that will be passed to various callback
+ functions. It may be specified as <constant>NULL</constant> if no value is necessary.</para>
+
+ <para><function>sd_bus_add_object_vtable()</function> is similar to
+ <function>sd_bus_add_object_vtable()</function>, but is used to register "fallback" attributes. When
+ looking for an attribute declaration, bus object paths registered with
+ <function>sd_bus_add_object_vtable()</function> are checked first. If no match is found, the fallback
+ vtables are checked for each prefix of the bus object path, i.e. with the last slash-separated components
+ successively removed. This allows the vtable to be used for an arbitrary number of dynamically created
+ objects.</para>
+
+ <para>Parameter <replaceable>find</replaceable> is a function which is used to locate the target object
+ based on the bus object path <replaceable>path</replaceable>. It must return <constant>1</constant> and
+ set the <parameter>ret_found</parameter> output parameter if the object is found, return
+ <constant>0</constant> if the object was not found, and return a negative errno-style error code or
+ initialize the error structure <replaceable>ret_error</replaceable> on error. The pointer passed in
+ <parameter>ret_found</parameter> will be used as the <parameter>userdata</parameter> parameter for the
+ callback functions (offset by the <parameter>offset</parameter> offsets as specified in the vtable
+ entries).</para>
+
+ <para>For both functions, a match slot is created internally. If the output parameter
+ <replaceable>slot</replaceable> is <constant>NULL</constant>, a "floating" slot object is created, see
+ <citerefentry><refentrytitle>sd_bus_slot_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ Otherwise, a pointer to the slot object is returned. In that case, the reference to the slot object
+ should be dropped when the vtable is not needed anymore, see
+ <citerefentry><refentrytitle>sd_bus_slot_unref</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
+ </para>
+
+ <refsect2>
+ <title>The <structname>sd_bus_vtable</structname> array</title>
+
+ <para>The array consists of the structures of type <structname>sd_bus_vtable</structname>, but it
+ should never be filled in manually, but through one of the following macros:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_START()</constant></term>
+ <term><constant>SD_BUS_VTABLE_END</constant></term>
+
+ <listitem><para>Those must always be the first and last element.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_METHOD_WITH_NAMES_OFFSET()</constant></term>
+ <term><constant>SD_BUS_METHOD_WITH_NAMES()</constant></term>
+ <term><constant>SD_BUS_METHOD_WITH_OFFSET()</constant></term>
+ <term><constant>SD_BUS_METHOD()</constant></term>
+
+ <listitem><para>Declare a D-Bus method with the name <replaceable>member</replaceable>, parameter
+ signature <replaceable>signature</replaceable>, result signature <replaceable>result</replaceable>.
+ Parameters <replaceable>in_names</replaceable> and <replaceable>out_names</replaceable> specify the
+ argument names of the input and output arguments in the function signature. The handler function
+ <replaceable>handler</replaceable> must be of type <function>sd_bus_message_handler_t</function>.
+ It will be called to handle the incoming messages that call this method. It receives a pointer that
+ is the <replaceable>userdata</replaceable> parameter passed to the registration function offset by
+ <replaceable>offset</replaceable> bytes. This may be used to pass pointers to different fields in
+ the same data structure to different methods in the same
+ vtable. <replaceable>in_names</replaceable> and <replaceable>out_names</replaceable> should be
+ created using the <constant>SD_BUS_PARAM()</constant> macro, see below. Parameter
+ <replaceable>flags</replaceable> is a combination of flags, see below.</para>
+
+ <para><constant>SD_BUS_METHOD_WITH_NAMES()</constant>,
+ <constant>SD_BUS_METHOD_WITH_OFFSET()</constant>, and <constant>SD_BUS_METHOD()</constant> are
+ variants which specify zero offset (<replaceable>userdata</replaceable> parameter is passed with
+ no change), leave the names unset (i.e. no parameter names), or both.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_SIGNAL_WITH_NAMES()</constant></term>
+ <term><constant>SD_BUS_SIGNAL()</constant></term>
+
+ <listitem><para>Declare a D-Bus signal with the name <replaceable>member</replaceable>,
+ parameter signature <replaceable>signature</replaceable>, and argument names
+ <replaceable>names</replaceable>. <replaceable>names</replaceable> should be
+ created using the <constant>SD_BUS_PARAM()</constant> macro, see below.
+ Parameter <replaceable>flags</replaceable> is a combination of flags, see below.
+ </para>
+
+ <para>Equivalent to <constant>SD_BUS_SIGNAL_WITH_NAMES()</constant> with the
+ <replaceable>names</replaceable> paramater unset (i.e. no parameter names).</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_WRITABLE_PROPERTY()</constant></term>
+ <term><constant>SD_BUS_PROPERTY()</constant></term>
+
+ <listitem><para>Declare a D-Bus property with the name <replaceable>member</replaceable> and value
+ signature <replaceable>signature</replaceable>. Parameters <replaceable>get</replaceable> and
+ <replaceable>set</replaceable> are the getter and setter methods. They are called with a pointer
+ that is the <replaceable>userdata</replaceable> parameter passed to the registration function
+ offset by <replaceable>offset</replaceable> bytes. This may be used pass pointers to different
+ fields in the same data structure to different setters and getters in the same vtable. Parameter
+ <replaceable>flags</replaceable> is a combination of flags, see below.</para>
+
+ <para>The setter and getter methods may be omitted (specified as <constant>NULL</constant>), if the
+ property has one of the basic types or <literal>as</literal> in case of read-only properties. In
+ those cases, the <replaceable>userdata</replaceable> and <replaceable>offset</replaceable>
+ parameters must together point to valid variable of the corresponding type. A default setter and
+ getters will be provided, which simply copy the argument between this variable and the message.
+ </para>
+
+ <para><constant>SD_BUS_PROPERTY()</constant> is used to define a read-only property.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_PARAM()</constant></term>
+ <listitem><para>Parameter names should be wrapped in this macro, see the example below.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+
+ <refsect2>
+ <title>Flags</title>
+
+ <para>The <replaceable>flags</replaceable> parameter is used to specify a combination of
+ <ulink url="https://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format">D-Bus annotations</ulink>.
+ </para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_DEPRECATED</constant></term>
+
+ <listitem><para>Mark this vtable entry as deprecated using the
+ <constant>org.freedesktop.DBus.Deprecated</constant> annotation in introspection data. If
+ specified for <constant>SD_BUS_VTABLE_START()</constant>, the annotation is applied to the
+ enclosing interface.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_HIDDEN</constant></term>
+
+ <listitem><para>Make this vtable entry hidden. It will not be shown in introspection data. If
+ specified for <constant>SD_BUS_VTABLE_START()</constant>, all entries in the array are hidden.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_UNPRIVILEGED</constant></term>
+
+ <listitem><para>Mark this vtable entry as unprivileged. If not specified, the
+ <constant>org.freedesktop.systemd1.Privileged</constant> annotation with value
+ <literal>true</literal> will be shown in introspection data.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_METHOD_NO_REPLY</constant></term>
+
+ <listitem><para>Mark his vtable entry as a method that will not return a reply using the
+ <constant>org.freedesktop.DBus.Method.NoReply</constant> annotation in introspection data.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_CONST</constant></term>
+ <term><constant>SD_BUS_VTABLE_EMITS_CHANGE</constant></term>
+ <term><constant>SD_BUS_VTABLE_EMITS_INVALIDATION</constant></term>
+
+ <listitem><para>Those three flags correspond to different values of the
+ <constant>org.freedesktop.DBus.Property.EmitsChangedSignal</constant> annotation, which specifies
+ whether the <constant>org.freedesktop.DBus.Properties.PropertiesChanged</constant> signal is
+ emitted whenever the property changes. <constant>SD_BUS_VTABLE_CONST</constant> corresponds to
+ <constant>const</constant> and means that the property never changes during the lifetime of the
+ object it belongs to, so no signal needs to be emitted.
+ <constant>SD_BUS_VTABLE_EMITS_CHANGE</constant> corresponds to <constant>true</constant> and means
+ that the signal is emitted. <constant>SD_BUS_VTABLE_EMITS_INVALIDATION</constant> corresponds to
+ <constant>invalides</constant> and means that the signal is emitted, but the value is not included
+ in the signal.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>SD_BUS_VTABLE_PROPERTY_EXPLICIT</constant></term>
+
+ <listitem><para>Mark this vtable property entry as requiring explicit request to for the value to
+ be shown (generally because the value is large or slow to calculate). This entry cannot be combined
+ with <constant>SD_BUS_VTABLE_EMITS_CHANGE</constant>, and will not be shown in property listings by
+ default (e.g. <command>busctl introspect</command>). This corresponds to the
+ <constant>org.freedesktop.systemd1.Explicit</constant> annotation in introspection data.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <example>
+ <title>Create a simple listener on the bus</title>
+
+ <programlisting><xi:include href="vtable-example.c" parse="text" /></programlisting>
+
+ <para>This creates a simple client on the bus (the user bus, when run as normal user).
+ We may use the D-Bus <constant>org.freedesktop.DBus.Introspectable.Introspect</constant>
+ call to acquire the XML description of the interface:</para>
+
+ <programlisting><xi:include href="vtable-example.xml" parse="text" /></programlisting>
+ </example>
+ </refsect1>
+
+ <refsect1>
+ <title>Return Value</title>
+
+ <para>On success, <function>sd_bus_add_object_vtable</function> and
+ <function>sd_bus_add_fallback_vtable</function> calls return 0 or a positive integer. On failure, they
+ return a negative errno-style error code.</para>
+
+ <refsect2>
+ <title>Errors</title>
+
+ <para>Returned errors may indicate the following problems:</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><constant>-EINVAL</constant></term>
+
+ <listitem><para>One of the required parameters is <constant>NULL</constant> or invalid. A reserved
+ D-Bus interface was passed as the <replaceable>interface</replaceable> parameter.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOPKG</constant></term>
+
+ <listitem><para>The bus cannot be resolved.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ECHILD</constant></term>
+
+ <listitem><para>The bus was created in a different process.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-ENOMEM</constant></term>
+
+ <listitem><para>Memory allocation failed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EPROTOTYPE</constant></term>
+
+ <listitem><para><function>sd_bus_add_object_vtable</function> and
+ <function>sd_bus_add_fallback_vtable</function> have been both called
+ for the same bus object path, which is not allowed.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><constant>-EEXIST</constant></term>
+
+ <listitem><para>This vtable has already been registered for this
+ <replaceable>interface</replaceable> and <replaceable>path</replaceable>.
+ </para></listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
+ </refsect1>
+
+ <xi:include href="libsystemd-pkgconfig.xml" />
+
+ <refsect1>
+ <title>See Also</title>
+
+ <para>
+ <citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
+ <citerefentry><refentrytitle>busctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ </para>
+ </refsect1>
+</refentry>
diff --git a/man/sd_notify.xml b/man/sd_notify.xml
index 0084bf3882..00640cb290 100644
--- a/man/sd_notify.xml
+++ b/man/sd_notify.xml
@@ -174,6 +174,18 @@
</varlistentry>
<varlistentry>
+ <term>WATCHDOG=trigger</term>
+
+ <listitem><para>Tells the service manager that the service detected an internal error that should be handled by
+ the configured watchdog options. This will trigger the same behaviour as if <varname>WatchdogSec=</varname> is
+ enabled and the service did not send <literal>WATCHDOG=1</literal> in time. Note that
+ <varname>WatchdogSec=</varname> does not need to be enabled for <literal>WATCHDOG=trigger</literal> to trigger
+ the watchdog action. See
+ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ information about the watchdog behavior. </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>WATCHDOG_USEC=…</term>
<listitem><para>Reset <varname>watchdog_usec</varname> value during runtime.
diff --git a/man/systemd-system.conf.xml b/man/systemd-system.conf.xml
index 5d1e4d1b97..41baff8bfe 100644
--- a/man/systemd-system.conf.xml
+++ b/man/systemd-system.conf.xml
@@ -239,13 +239,15 @@
<varlistentry>
<term><varname>DefaultTimeoutStartSec=</varname></term>
<term><varname>DefaultTimeoutStopSec=</varname></term>
+ <term><varname>DefaultTimeoutAbortSec=</varname></term>
<term><varname>DefaultRestartSec=</varname></term>
- <listitem><para>Configures the default timeouts for starting
- and stopping of units, as well as the default time to sleep
+ <listitem><para>Configures the default timeouts for starting,
+ stopping and aborting of units, as well as the default time to sleep
between automatic restarts of units, as configured per-unit in
<varname>TimeoutStartSec=</varname>,
- <varname>TimeoutStopSec=</varname> and
+ <varname>TimeoutStopSec=</varname>,
+ <varname>TimeoutAbortSec=</varname> and
<varname>RestartSec=</varname> (for services, see
<citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>
for details on the per-unit settings). Disabled by default, when
@@ -255,7 +257,9 @@
<varname>TimeoutSec=</varname>
value. <varname>DefaultTimeoutStartSec=</varname> and
<varname>DefaultTimeoutStopSec=</varname> default to
- 90s. <varname>DefaultRestartSec=</varname> defaults to
+ 90s. <varname>DefaultTimeoutAbortSec=</varname> is not set by default
+ so that all units fall back to <varname>TimeoutStopSec=</varname>.
+ <varname>DefaultRestartSec=</varname> defaults to
100ms.</para></listitem>
</varlistentry>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index df1e1e8681..b69691b3c4 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -180,6 +180,13 @@
is used. In this case the source path refers to a path on the host file system, while the destination path
refers to a path below the root directory of the unit.</para>
+ <para>Note that the destination directory must exist or systemd must be able to create it. Thus, it
+ is not possible to use those options for mount points nested underneath paths specified in
+ <varname>InaccessiblePaths=</varname>, or under <filename>/home/</filename> and other protected
+ directories if <varname>ProtectHome=yes</varname> is
+ specified. <varname>TemporaryFileSystem=</varname> with <literal>:ro</literal> or
+ <varname>ProtectHome=tmpfs</varname> should be used instead.</para>
+
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
@@ -822,23 +829,25 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<term><varname>ProtectHome=</varname></term>
<listitem><para>Takes a boolean argument or the special values <literal>read-only</literal> or
- <literal>tmpfs</literal>. If true, the directories <filename>/home</filename>, <filename>/root</filename> and
- <filename>/run/user</filename> are made inaccessible and empty for processes invoked by this unit. If set to
- <literal>read-only</literal>, the three directories are made read-only instead. If set to <literal>tmpfs</literal>,
- temporary file systems are mounted on the three directories in read-only mode. The value <literal>tmpfs</literal>
- is useful to hide home directories not relevant to the processes invoked by the unit, while necessary directories
- are still visible by combining with <varname>BindPaths=</varname> or <varname>BindReadOnlyPaths=</varname>.</para>
+ <literal>tmpfs</literal>. If true, the directories <filename>/home</filename>,
+ <filename>/root</filename>, and <filename>/run/user</filename> are made inaccessible and empty for
+ processes invoked by this unit. If set to <literal>read-only</literal>, the three directories are
+ made read-only instead. If set to <literal>tmpfs</literal>, temporary file systems are mounted on the
+ three directories in read-only mode. The value <literal>tmpfs</literal> is useful to hide home
+ directories not relevant to the processes invoked by the unit, while still allowing necessary
+ directories to be made visible when listed in <varname>BindPaths=</varname> or
+ <varname>BindReadOnlyPaths=</varname>.</para>
<para>Setting this to <literal>yes</literal> is mostly equivalent to set the three directories in
<varname>InaccessiblePaths=</varname>. Similarly, <literal>read-only</literal> is mostly equivalent to
<varname>ReadOnlyPaths=</varname>, and <literal>tmpfs</literal> is mostly equivalent to
- <varname>TemporaryFileSystem=</varname>.</para>
+ <varname>TemporaryFileSystem=</varname> with <literal>:ro</literal>.</para>
- <para> It is recommended to enable this setting for all long-running services (in particular network-facing
- ones), to ensure they cannot get access to private user data, unless the services actually require access to
- the user's private data. This setting is implied if <varname>DynamicUser=</varname> is set. This setting cannot
- ensure protection in all cases. In general it has the same limitations as <varname>ReadOnlyPaths=</varname>,
- see below.</para>
+ <para>It is recommended to enable this setting for all long-running services (in particular
+ network-facing ones), to ensure they cannot get access to private user data, unless the services
+ actually require access to the user's private data. This setting is implied if
+ <varname>DynamicUser=</varname> is set. This setting cannot ensure protection in all cases. In
+ general it has the same limitations as <varname>ReadOnlyPaths=</varname>, see below.</para>
<xi:include href="system-only.xml" xpointer="singular"/></listitem>
</varlistentry>
@@ -1053,7 +1062,7 @@ StateDirectory=aaa/bbb ccc</programlisting>
<para>This is useful to hide files or directories not relevant to the processes invoked by the unit, while necessary
files or directories can be still accessed by combining with <varname>BindPaths=</varname> or
- <varname>BindReadOnlyPaths=</varname>. See the example below.</para>
+ <varname>BindReadOnlyPaths=</varname>:</para>
<para>Example: if a unit has the following,
<programlisting>TemporaryFileSystem=/var:ro
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
index af9799e8c0..ea744bd251 100644
--- a/man/systemd.link.xml
+++ b/man/systemd.link.xml
@@ -60,8 +60,13 @@
<refsect1>
<title>[Match] Section Options</title>
- <para>A link file is said to match a device if each of the entries in the [Match] section matches, or if
- the section is empty. The following keys are accepted:</para>
+ <para>A link file is said to match a device if all matches specified by the
+ <literal>[Match]</literal> section are satisfied. When a link file does not contain valid settings
+ in <literal>[Match]</literal> section, then the file will match all devices and
+ <command>systemd-udevd</command> warns about that. Hint: to avoid the warning and to make it clear
+ that all interfaces shall be matched, add the following:
+ <programlisting>OriginalName=*</programlisting>
+ The following keys are accepted:</para>
<variablelist class='network-directives'>
<varlistentry>
diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index 2d8eeee88f..be982cbb1a 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -77,9 +77,13 @@
is applied, all later files are ignored, even if they match as
well.</para>
- <para>A network file is said to match a device if each of the
- entries in the <literal>[Match]</literal> section matches, or if
- the section is empty. The following keys are accepted:</para>
+ <para>A network file is said to match a network interface if all matches specified by the
+ <literal>[Match]</literal> section are satisfied. When a network file does not contain valid
+ settings in <literal>[Match]</literal> section, then the file will match all interfaces and
+ <command>systemd-networkd</command> warns about that. Hint: to avoid the warning and to make it
+ clear that all interfaces shall be matched, add the following:
+ <programlisting>Name=*</programlisting>
+ The following keys are accepted:</para>
<variablelist class='network-directives'>
<varlistentry>
diff --git a/man/systemd.resource-control.xml b/man/systemd.resource-control.xml
index 4a8c57f45a..e7fb46873c 100644
--- a/man/systemd.resource-control.xml
+++ b/man/systemd.resource-control.xml
@@ -265,6 +265,10 @@
<para>This setting is supported only if the unified control group hierarchy is used and disables
<varname>MemoryLimit=</varname>.</para>
+
+ <para>Units may can have their children use a default <literal>memory.low</literal> value by specifying
+ <varname>DefaultMemoryLow=</varname>, which has the same usage as <varname>MemoryLow=</varname>. This setting
+ does not affect <literal>memory.low</literal> in the unit itself.</para>
</listitem>
</varlistentry>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 1f40c2ff37..c2b3e21076 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -574,6 +574,35 @@
</varlistentry>
<varlistentry>
+ <term><varname>TimeoutAbortSec=</varname></term>
+ <listitem><para>This option configures the time to wait for the service to terminate when it was aborted due to a
+ watchdog timeout (see <varname>WatchdogSec=</varname>). If the service has a short <varname>TimeoutStopSec=</varname>
+ this option can be used to give the system more time to write a core dump of the service. Upon expiration the service
+ will be forcibly terminated by <constant>SIGKILL</constant> (see <varname>KillMode=</varname> in
+ <citerefentry><refentrytitle>systemd.kill</refentrytitle><manvolnum>5</manvolnum></citerefentry>). The core file will
+ be truncated in this case. Use <varname>TimeoutAbortSec=</varname> to set a sensible timeout for the core dumping per
+ service that is large enough to write all expected data while also being short enough to handle the service failure
+ in due time.
+ </para>
+
+ <para>Takes a unit-less value in seconds, or a time span value such as "5min 20s". Pass an empty value to skip
+ the dedicated watchdog abort timeout handling and fall back <varname>TimeoutStopSec=</varname>. Pass
+ <literal>infinity</literal> to disable the timeout logic. Defaults to <varname>DefaultTimeoutAbortSec=</varname> from
+ the manager configuration file (see
+ <citerefentry><refentrytitle>systemd-system.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>).
+ </para>
+
+ <para>If a service of <varname>Type=notify</varname> handles <constant>SIGABRT</constant> itself (instead of relying
+ on the kernel to write a core dump) it can send <literal>EXTEND_TIMEOUT_USEC=…</literal> to
+ extended the abort time beyond <varname>TimeoutAbortSec=</varname>. The first receipt of this message
+ must occur before <varname>TimeoutAbortSec=</varname> is exceeded, and once the abort time has exended beyond
+ <varname>TimeoutAbortSec=</varname>, the service manager will allow the service to continue to abort, provided
+ the service repeats <literal>EXTEND_TIMEOUT_USEC=…</literal> within the interval specified, or terminates itself
+ (see <citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>).
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>TimeoutSec=</varname></term>
<listitem><para>A shorthand for configuring both
<varname>TimeoutStartSec=</varname> and
diff --git a/man/udev.xml b/man/udev.xml
index 5a78be3208..98d17bbb54 100644
--- a/man/udev.xml
+++ b/man/udev.xml
@@ -437,6 +437,8 @@
<para>Note that running programs that access the network or mount/unmount
filesystems is not allowed inside of udev rules, due to the default sandbox
that is enforced on <filename>systemd-udevd.service</filename>.</para>
+ <para>Please also note that <literal>:=</literal> and <literal>=</literal> are clearing
+ both, program and builtin commands.</para>
</listitem>
</varlistentry>
diff --git a/man/vtable-example.c b/man/vtable-example.c
new file mode 100644
index 0000000000..a2a6cd18d7
--- /dev/null
+++ b/man/vtable-example.c
@@ -0,0 +1,70 @@
+#include <errno.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <systemd/sd-bus.h>
+
+#define _cleanup_(f) __attribute__((cleanup(f)))
+
+typedef struct object {
+ char *name;
+ uint32_t number;
+} object;
+
+static int method(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ printf("Got called with userdata=%p\n", userdata);
+ return 1;
+}
+
+static const sd_bus_vtable vtable[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD(
+ "Method1", "s", "s", method, 0),
+ SD_BUS_METHOD_WITH_NAMES_OFFSET(
+ "Method2",
+ "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+ "s", SD_BUS_PARAM(returnstring),
+ method, offsetof(object, number),
+ SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_WRITABLE_PROPERTY(
+ "AutomaticStringProperty", "s", NULL, NULL,
+ offsetof(object, name),
+ SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_WRITABLE_PROPERTY(
+ "AutomaticIntegerProperty", "u", NULL, NULL,
+ offsetof(object, number),
+ SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_VTABLE_END
+};
+
+#define check(x) ({ \
+ int r = x; \
+ errno = r < 0 ? -r : 0; \
+ printf(#x ": %m\n"); \
+ if (r < 0) \
+ return EXIT_FAILURE; \
+ })
+
+int main(int argc, char **argv) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+
+ sd_bus_default(&bus);
+
+ object object = { .number = 666 };
+ check((object.name = strdup("name")) != NULL);
+
+ check(sd_bus_add_object_vtable(bus, NULL, "/object",
+ "org.freedesktop.systemd.VtableExample",
+ vtable,
+ &object));
+
+ while (true) {
+ check(sd_bus_wait(bus, UINT64_MAX));
+ check(sd_bus_process(bus, NULL));
+ }
+
+ free(object.name);
+
+ return 0;
+}
diff --git a/man/vtable-example.xml b/man/vtable-example.xml
new file mode 100644
index 0000000000..a3cdeae704
--- /dev/null
+++ b/man/vtable-example.xml
@@ -0,0 +1,54 @@
+<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
+<node>
+ <interface name="org.freedesktop.DBus.Peer">
+ <method name="Ping"/>
+ <method name="GetMachineId">
+ <arg type="s" name="machine_uuid" direction="out"/>
+ </method>
+ </interface>
+ <interface name="org.freedesktop.DBus.Introspectable">
+ <method name="Introspect">
+ <arg name="data" type="s" direction="out"/>
+ </method>
+ </interface>
+ <interface name="org.freedesktop.DBus.Properties">
+ <method name="Get">
+ <arg name="interface" direction="in" type="s"/>
+ <arg name="property" direction="in" type="s"/>
+ <arg name="value" direction="out" type="v"/>
+ </method>
+ <method name="GetAll">
+ <arg name="interface" direction="in" type="s"/>
+ <arg name="properties" direction="out" type="a{sv}"/>
+ </method>
+ <method name="Set">
+ <arg name="interface" direction="in" type="s"/>
+ <arg name="property" direction="in" type="s"/>
+ <arg name="value" direction="in" type="v"/>
+ </method>
+ <signal name="PropertiesChanged">
+ <arg type="s" name="interface"/>
+ <arg type="a{sv}" name="changed_properties"/>
+ <arg type="as" name="invalidated_properties"/>
+ </signal>
+ </interface>
+ <interface name="org.freedesktop.systemd.VtableExample">
+ <method name="Method1">
+ <arg type="s" direction="in"/>
+ <arg type="s" direction="out"/>
+ </method>
+ <method name="Method2">
+ <arg type="s" name="string" direction="in"/>
+ <arg type="o" name="path" direction="in"/>
+ <arg type="s" name="returnstring" direction="out"/>
+ <annotation name="org.freedesktop.DBus.Deprecated" value="true"/>
+ </method>
+ <property name="AutomaticStringProperty" type="s" access="readwrite">
+ </property>
+ <property name="AutomaticIntegerProperty" type="u" access="readwrite">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="invalidates"/>
+ </property>
+ </interface>
+</node>
+
diff --git a/network/99-default.link b/network/99-default.link
index 92fcbe83ea..347d4b72d2 100644
--- a/network/99-default.link
+++ b/network/99-default.link
@@ -7,6 +7,9 @@
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
+[Match]
+OriginalName=*
+
[Link]
NamePolicy=keep kernel database onboard slot path
MACAddressPolicy=persistent
diff --git a/rules/50-udev-default.rules.in b/rules/50-udev-default.rules.in
index 191f56f42e..580b8971a6 100644
--- a/rules/50-udev-default.rules.in
+++ b/rules/50-udev-default.rules.in
@@ -81,6 +81,8 @@ KERNEL=="fuse", MODE="0666", OPTIONS+="static_node=fuse"
# The static_node is required on s390x and ppc (they are using MODULE_ALIAS)
KERNEL=="kvm", GROUP="kvm", MODE="@DEV_KVM_MODE@", OPTIONS+="static_node=kvm"
+KERNEL=="udmabuf", GROUP="kvm"
+
SUBSYSTEM=="ptp", ATTR{clock_name}=="KVM virtual PTP", SYMLINK += "ptp_kvm"
LABEL="default_end"
diff --git a/semaphoreci/gcc-compilation.sh b/semaphoreci/gcc-compilation.sh
deleted file mode 100755
index ef499b8a35..0000000000
--- a/semaphoreci/gcc-compilation.sh
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/bin/bash
-set -ex
-
-# keep this in sync with setup.sh
-CONTAINER=${RELEASE:-buster}-${ARCH:-amd64}
-AUTOPKGTESTDIR=${SEMAPHORE_CACHE_DIR:-/tmp}/autopkgtest
-# semaphore cannot expose these, but useful for interactive/local runs
-ARTIFACTS_DIR=/tmp/artifacts
-
-# add current debian/ packaging
-git fetch --depth=1 https://salsa.debian.org/systemd-team/systemd.git master
-git checkout FETCH_HEAD debian
-
-# craft changelog
-UPSTREAM_VER=$(git describe | sed 's/^v//')
-cat << EOF > debian/changelog.new
-systemd (${UPSTREAM_VER}-0) UNRELEASED; urgency=low
-
- * Automatic build for upstream test
-
- -- systemd test <pkg-systemd-maintainers@lists.alioth.debian.org> $(date -R)
-
-EOF
-cat debian/changelog >> debian/changelog.new
-mv debian/changelog.new debian/changelog
-
-# clean out patches
-rm -rf debian/patches
-# disable autopkgtests which are not for upstream
-sed -i '/# NOUPSTREAM/ q' debian/tests/control
-# enable more unit tests
-sed -i '/^CONFFLAGS =/ s/=/= -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true /' debian/rules
-# no orig tarball
-echo '1.0' > debian/source/format
-
-# build source package
-dpkg-buildpackage -S -I -I$(basename "$SEMAPHORE_CACHE_DIR") -d -us -uc -nc
-
-# now build the package and run the tests
-rm -rf "$ARTIFACTS_DIR"
-# autopkgtest exits with 2 for "some tests skipped", accept that
-$AUTOPKGTESTDIR/runner/autopkgtest --apt-upgrade \
- --env DEB_BUILD_OPTIONS=noudeb \
- --env TEST_UPSTREAM=1 ../systemd_*.dsc \
- -o "$ARTIFACTS_DIR" \
- -- lxc -s $CONTAINER \
- || [ $? -eq 2 ]
diff --git a/semaphoreci/semaphore-runner.sh b/semaphoreci/semaphore-runner.sh
new file mode 100755
index 0000000000..5117bb4861
--- /dev/null
+++ b/semaphoreci/semaphore-runner.sh
@@ -0,0 +1,111 @@
+#!/bin/bash
+
+set -eux
+
+# default to Debian testing
+DISTRO=${DISTRO:-debian}
+RELEASE=${RELEASE:-buster}
+ARCH=${ARCH:-amd64}
+CONTAINER=${RELEASE}-${ARCH}
+MAX_CACHE_AGE=604800 # one week
+CACHE_DIR=${SEMAPHORE_CACHE_DIR:=/tmp}
+CACHE="${CACHE_DIR}/${CONTAINER}.img.tar.gz"
+AUTOPKGTEST_DIR="${CACHE_DIR}/autopkgtest"
+# semaphore cannot expose these, but useful for interactive/local runs
+ARTIFACTS_DIR=/tmp/artifacts
+PHASES=(${@:-SETUP RUN})
+
+create_container() {
+ # create autopkgtest LXC image; this sometimes fails with "Unable to fetch
+ # GPG key from keyserver", so retry a few times
+ for retry in $(seq 5); do
+ sudo lxc-create -n $CONTAINER -t download -- -d $DISTRO -r $RELEASE -a $ARCH && break
+ sleep $((retry*retry))
+ done
+
+ # unconfine the container, otherwise some tests fail
+ echo 'lxc.apparmor.profile = unconfined' | sudo tee -a /var/lib/lxc/$CONTAINER/config
+
+ sudo lxc-start -n $CONTAINER
+
+ # enable source repositories so that apt-get build-dep works
+ sudo lxc-attach -n $CONTAINER -- sh -ex <<EOF
+sed 's/^deb/deb-src/' /etc/apt/sources.list >> /etc/apt/sources.list.d/sources.list
+# wait until online
+while [ -z "\$(ip route list 0/0)" ]; do sleep 1; done
+apt-get -q update
+apt-get -y dist-upgrade
+apt-get install -y eatmydata
+EOF
+ sudo lxc-stop -n $CONTAINER
+
+ # cache it
+ sudo tar cpzf "$CACHE" /var/lib/lxc/$CONTAINER
+}
+
+for phase in "${PHASES[@]}"; do
+ case $phase in
+ SETUP)
+ # remove semaphore repos, some of them don't work and cause error messages
+ sudo rm -f /etc/apt/sources.list.d/*
+
+ # enable backports for latest LXC
+ echo 'deb http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse' | sudo tee -a /etc/apt/sources.list.d/backports.list
+ sudo apt-get -q update
+ sudo apt-get install -y -t xenial-backports lxc
+ sudo apt-get install -y python3-debian git dpkg-dev fakeroot
+
+ [ -d $AUTOPKGTEST_DIR ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTEST_DIR"
+
+ # use cached container image, unless older than a week
+ if [ -e "$CACHE" ] && [ $(( $(date +%s) - $(stat -c %Y "$CACHE") )) -le $MAX_CACHE_AGE ]; then
+ sudo tar -C / -xpzf "$CACHE"
+ else
+ create_container
+ fi
+ ;;
+ RUN)
+ # add current debian/ packaging
+ git fetch --depth=1 https://salsa.debian.org/systemd-team/systemd.git master
+ git checkout FETCH_HEAD debian
+
+ # craft changelog
+ UPSTREAM_VER=$(git describe | sed 's/^v//')
+ cat << EOF > debian/changelog.new
+systemd (${UPSTREAM_VER}-0) UNRELEASED; urgency=low
+
+ * Automatic build for upstream test
+
+ -- systemd test <pkg-systemd-maintainers@lists.alioth.debian.org> $(date -R)
+
+EOF
+ cat debian/changelog >> debian/changelog.new
+ mv debian/changelog.new debian/changelog
+
+ # clean out patches
+ rm -rf debian/patches
+ # disable autopkgtests which are not for upstream
+ sed -i '/# NOUPSTREAM/ q' debian/tests/control
+ # enable more unit tests
+ sed -i '/^CONFFLAGS =/ s/=/= -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true /' debian/rules
+ # no orig tarball
+ echo '1.0' > debian/source/format
+
+ # build source package
+ dpkg-buildpackage -S -I -I$(basename "$CACHE_DIR") -d -us -uc -nc
+
+ # now build the package and run the tests
+ rm -rf "$ARTIFACTS_DIR"
+ # autopkgtest exits with 2 for "some tests skipped", accept that
+ $AUTOPKGTEST_DIR/runner/autopkgtest --apt-upgrade \
+ --env DEB_BUILD_OPTIONS=noudeb \
+ --env TEST_UPSTREAM=1 ../systemd_*.dsc \
+ -o "$ARTIFACTS_DIR" \
+ -- lxc -s $CONTAINER \
+ || [ $? -eq 2 ]
+ ;;
+ *)
+ echo >&2 "Unknown phase '$phase'"
+ exit 1
+ esac
+done
diff --git a/semaphoreci/setup.sh b/semaphoreci/setup.sh
deleted file mode 100755
index c39238a4e9..0000000000
--- a/semaphoreci/setup.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-set -ex
-
-# default to Debian testing
-DISTRO=${DISTRO:-debian}
-RELEASE=${RELEASE:-buster}
-ARCH=${ARCH:-amd64}
-CONTAINER=${RELEASE}-${ARCH}
-MAX_CACHE_AGE=604800 # one week
-CACHE=${SEMAPHORE_CACHE_DIR:=/tmp}/${CONTAINER}.img.tar.gz
-
-create_container() {
- # create autopkgtest LXC image; this sometimes fails with "Unable to fetch
- # GPG key from keyserver", so retry a few times
- for retry in $(seq 5); do
- sudo lxc-create -n $CONTAINER -t download -- -d $DISTRO -r $RELEASE -a $ARCH && break
- sleep $((retry*retry))
- done
-
- # unconfine the container, otherwise some tests fail
- echo 'lxc.apparmor.profile = unconfined' | sudo tee -a /var/lib/lxc/$CONTAINER/config
-
- sudo lxc-start -n $CONTAINER
-
- # enable source repositories so that apt-get build-dep works
- sudo lxc-attach -n $CONTAINER -- sh -ex <<EOF
-sed 's/^deb/deb-src/' /etc/apt/sources.list >> /etc/apt/sources.list.d/sources.list
-# wait until online
-while [ -z "\$(ip route list 0/0)" ]; do sleep 1; done
-apt-get -q update
-apt-get -y dist-upgrade
-apt-get install -y eatmydata
-EOF
- sudo lxc-stop -n $CONTAINER
-
- # cache it
- sudo tar cpzf "$CACHE" /var/lib/lxc/$CONTAINER
-}
-
-# remove semaphore repos, some of them don't work and cause error messages
-sudo rm -f /etc/apt/sources.list.d/*
-
-# enable backports for latest LXC
-echo 'deb http://archive.ubuntu.com/ubuntu xenial-backports main restricted universe multiverse' | sudo tee -a /etc/apt/sources.list.d/backports.list
-sudo apt-get -q update
-sudo apt-get install -y -t xenial-backports lxc
-sudo apt-get install -y python3-debian git dpkg-dev fakeroot
-
-AUTOPKGTESTDIR=$SEMAPHORE_CACHE_DIR/autopkgtest
-[ -d $AUTOPKGTESTDIR ] || git clone --quiet --depth=1 https://salsa.debian.org/ci-team/autopkgtest.git "$AUTOPKGTESTDIR"
-
-# use cached container image, unless older than a week
-if [ -e "$CACHE" ] && [ $(( $(date +%s) - $(stat -c %Y "$CACHE") )) -le $MAX_CACHE_AGE ]; then
- sudo tar -C / -xpzf "$CACHE"
-else
- create_container
-fi
diff --git a/shell-completion/bash/journalctl b/shell-completion/bash/journalctl
index 52ed2e3bcb..53ffaacdb5 100644
--- a/shell-completion/bash/journalctl
+++ b/shell-completion/bash/journalctl
@@ -86,6 +86,7 @@ _journalctl() {
;;
--unit|-u)
comps=$(journalctl -F '_SYSTEMD_UNIT' 2>/dev/null)
+ compopt -o filenames
;;
--user-unit)
comps=$(journalctl -F '_SYSTEMD_USER_UNIT' 2>/dev/null)
@@ -100,7 +101,7 @@ _journalctl() {
return 0
;;
esac
- COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
+ COMPREPLY=( $(compgen -o filenames -W '$comps' -- "$cur") )
return 0
fi
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
index 8c86fed974..dfb2d4a4c9 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -114,11 +114,12 @@ __get_all_unit_files () { { __systemctl $1 list-unit-files "$2*"; } | { while re
__get_machines() {
local a b
{ machinectl list-images --no-legend --no-pager; machinectl list --no-legend --no-pager; } | \
- { while read a b; do echo " $a"; done; }
+ { while read a b; do echo " $a"; done; }
}
_systemctl () {
local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+ local cur_orig=$cur
local i verb comps mode
local -A OPTS=(
@@ -221,6 +222,13 @@ _systemctl () {
fi
done
+ # When trying to match a unit name with certain special characters in its name (i.e
+ # foo\x2dbar:01) they get escaped by bash along the way, thus causing any possible
+ # match to fail. Let's unescape such characters in the verb we're trying to
+ # autocomplete to avoid this, however, use the original verb (cur_orig)
+ # during the final match (COMPREPLY)
+ cur="$(echo $cur | xargs echo)"
+
if [[ -z $verb ]]; then
comps="${VERBS[*]}"
@@ -306,7 +314,7 @@ _systemctl () {
| { while read -r a b; do echo " $a"; done; } )
fi
- COMPREPLY=( $(compgen -o filenames -W '$comps' -- "$cur") )
+ COMPREPLY=( $(compgen -o filenames -W '$comps' -- "$cur_orig") )
return 0
}
diff --git a/src/activate/activate.c b/src/activate/activate.c
index 473366fb20..48aa617e78 100644
--- a/src/activate/activate.c
+++ b/src/activate/activate.c
@@ -24,11 +24,11 @@
#include "terminal-util.h"
#include "util.h"
-static char** arg_listen = NULL;
+static char **arg_listen = NULL;
static bool arg_accept = false;
static int arg_socket_type = SOCK_STREAM;
-static char** arg_args = NULL;
-static char** arg_setenv = NULL;
+static char **arg_args = NULL;
+static char **arg_setenv = NULL;
static char **arg_fdnames = NULL;
static bool arg_inetd = false;
@@ -86,7 +86,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
*/
STRV_FOREACH(address, arg_listen) {
- fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept*SOCK_CLOEXEC));
+ fd = make_socket_fd(LOG_DEBUG, *address, arg_socket_type, (arg_accept * SOCK_CLOEXEC));
if (fd < 0) {
log_open();
return log_error_errno(fd, "Failed to open '%s': %m", *address);
@@ -117,7 +117,7 @@ static int open_sockets(int *epoll_fd, bool accept) {
return count;
}
-static int exec_process(const char* name, char **argv, char **env, int start_fd, size_t n_fds) {
+static int exec_process(const char *name, char **argv, char **env, int start_fd, size_t n_fds) {
_cleanup_strv_free_ char **envp = NULL;
_cleanup_free_ char *joined = NULL;
@@ -199,10 +199,10 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
start_fd = SD_LISTEN_FDS_START;
}
- if (asprintf((char**)(envp + n_env++), "LISTEN_FDS=%zu", n_fds) < 0)
+ if (asprintf((char **) (envp + n_env++), "LISTEN_FDS=%zu", n_fds) < 0)
return log_oom();
- if (asprintf((char**)(envp + n_env++), "LISTEN_PID=" PID_FMT, getpid_cached()) < 0)
+ if (asprintf((char **) (envp + n_env++), "LISTEN_PID=" PID_FMT, getpid_cached()) < 0)
return log_oom();
if (arg_fdnames) {
@@ -244,7 +244,7 @@ static int exec_process(const char* name, char **argv, char **env, int start_fd,
return log_error_errno(errno, "Failed to execp %s (%s): %m", name, joined);
}
-static int fork_and_exec_process(const char* child, char** argv, char **env, int fd) {
+static int fork_and_exec_process(const char *child, char **argv, char **env, int fd) {
_cleanup_free_ char *joined = NULL;
pid_t child_pid;
int r;
@@ -253,7 +253,9 @@ static int fork_and_exec_process(const char* child, char** argv, char **env, int
if (!joined)
return log_oom();
- r = safe_fork("(activate)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_RLIMIT_NOFILE_SAFE|FORK_LOG, &child_pid);
+ r = safe_fork("(activate)",
+ FORK_RESET_SIGNALS | FORK_DEATHSIG | FORK_RLIMIT_NOFILE_SAFE | FORK_LOG,
+ &child_pid);
if (r < 0)
return r;
if (r == 0) {
@@ -266,7 +268,7 @@ static int fork_and_exec_process(const char* child, char** argv, char **env, int
return 0;
}
-static int do_accept(const char* name, char **argv, char **envp, int fd) {
+static int do_accept(const char *name, char **argv, char **envp, int fd) {
_cleanup_free_ char *local = NULL, *peer = NULL;
_cleanup_close_ int fd_accepted = -1;
@@ -294,7 +296,7 @@ static void sigchld_hdl(int sig) {
int r;
si.si_pid = 0;
- r = waitid(P_ALL, 0, &si, WEXITED|WNOHANG);
+ r = waitid(P_ALL, 0, &si, WEXITED | WNOHANG);
if (r < 0) {
if (errno != ECHILD)
log_error_errno(errno, "Failed to reap children: %m");
@@ -309,7 +311,7 @@ static void sigchld_hdl(int sig) {
static int install_chld_handler(void) {
static const struct sigaction act = {
- .sa_flags = SA_NOCLDSTOP|SA_RESTART,
+ .sa_flags = SA_NOCLDSTOP | SA_RESTART,
.sa_handler = sigchld_hdl,
};
@@ -376,7 +378,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argv);
while ((c = getopt_long(argc, argv, "+hl:aE:d", options, NULL)) >= 0)
- switch(c) {
+ switch (c) {
case 'h':
return help();
diff --git a/src/analyze/analyze-security.c b/src/analyze/analyze-security.c
index a9a93d0f07..0962950dd0 100644
--- a/src/analyze/analyze-security.c
+++ b/src/analyze/analyze-security.c
@@ -100,7 +100,12 @@ struct security_assessor {
const char *url;
uint64_t weight;
uint64_t range;
- int (*assess)(const struct security_assessor *a, const struct security_info *info, const void *data, uint64_t *ret_badness, char **ret_description);
+ int (*assess)(
+ const struct security_assessor *a,
+ const struct security_info *info,
+ const void *data,
+ uint64_t *ret_badness,
+ char **ret_description);
size_t offset;
uint64_t parameter;
bool default_dependencies_only;
@@ -1438,7 +1443,7 @@ static int assess(const struct security_info *info, Table *overview_table, Analy
uint64_t badness;
void *data;
- data = (uint8_t*) info + a->offset;
+ data = (uint8_t *) info + a->offset;
if (a->default_dependencies_only && !info->default_dependencies) {
badness = UINT64_MAX;
@@ -1916,14 +1921,15 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
if (!path)
return log_oom();
- r = bus_map_all_properties(bus,
- "org.freedesktop.systemd1",
- path,
- security_map,
- BUS_MAP_STRDUP|BUS_MAP_BOOLEAN_AS_BOOL,
- &error,
- NULL,
- info);
+ r = bus_map_all_properties(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ security_map,
+ BUS_MAP_STRDUP | BUS_MAP_BOOLEAN_AS_BOOL,
+ &error,
+ NULL,
+ info);
if (r < 0)
return log_error_errno(r, "Failed to get unit properties: %s", bus_error_message(&error, r));
@@ -1965,7 +1971,7 @@ static int acquire_security_info(sd_bus *bus, const char *name, struct security_
return 0;
}
-static int analyze_security_one(sd_bus *bus, const char *name, Table* overview_table, AnalyzeSecurityFlags flags) {
+static int analyze_security_one(sd_bus *bus, const char *name, Table *overview_table, AnalyzeSecurityFlags flags) {
_cleanup_(security_info_free) struct security_info info = {
.default_dependencies = true,
.capability_bounding_set = UINT64_MAX,
@@ -2015,7 +2021,8 @@ int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"ListUnits",
- &error, &reply,
+ &error,
+ &reply,
NULL);
if (r < 0)
return log_error_errno(r, "Failed to list units: %s", bus_error_message(&error, r));
@@ -2037,7 +2044,7 @@ int analyze_security(sd_bus *bus, char **units, AnalyzeSecurityFlags flags) {
if (!endswith(info.id, ".service"))
continue;
- if (!GREEDY_REALLOC(list, allocated, n+2))
+ if (!GREEDY_REALLOC(list, allocated, n + 2))
return log_oom();
copy = strdup(info.id);
diff --git a/src/analyze/analyze-verify.h b/src/analyze/analyze-verify.h
index f6b7f54961..3561d4302b 100644
--- a/src/analyze/analyze-verify.h
+++ b/src/analyze/analyze-verify.h
@@ -5,8 +5,4 @@
#include "path-lookup.h"
-int verify_units(
- char **filenames,
- UnitFileScope scope,
- bool check_man,
- bool run_generators);
+int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators);
diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c
index ac7cb0da63..97d94516c8 100644
--- a/src/analyze/analyze.c
+++ b/src/analyze/analyze.c
@@ -48,7 +48,7 @@
#include "util.h"
#include "verbs.h"
-#define SCALE_X (0.1 / 1000.0) /* pixels per us */
+#define SCALE_X (0.1 / 1000.0) /* pixels per us */
#define SCALE_Y (20.0)
#define svg(...) printf(__VA_ARGS__)
@@ -71,8 +71,8 @@ static enum dot {
DEP_ORDER,
DEP_REQUIRE
} arg_dot = DEP_ALL;
-static char** arg_dot_from_patterns = NULL;
-static char** arg_dot_to_patterns = NULL;
+static char **arg_dot_from_patterns = NULL;
+static char **arg_dot_to_patterns = NULL;
static usec_t arg_fuzz = 0;
static PagerFlags arg_pager_flags = 0;
static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
@@ -295,8 +295,8 @@ static int acquire_boot_times(sd_bus *bus, struct boot_times **bt) {
*/
times.reverse_offset = times.userspace_time;
- times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time = times.userspace_time =
- times.security_start_time = times.security_finish_time = 0;
+ times.firmware_time = times.loader_time = times.kernel_time = times.initrd_time =
+ times.userspace_time = times.security_start_time = times.security_finish_time = 0;
subtract_timestamp(&times.finish_time, times.reverse_offset);
@@ -328,7 +328,7 @@ static void free_host_info(struct host_info *hi) {
free(hi);
}
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info*, free_host_info);
+DEFINE_TRIVIAL_CLEANUP_FUNC(struct host_info *, free_host_info);
static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
static const struct bus_properties_map property_map[] = {
@@ -368,10 +368,10 @@ static int acquire_time_data(sd_bus *bus, struct unit_times **out) {
while ((r = bus_parse_unit_info(reply, &u)) > 0) {
struct unit_times *t;
- if (!GREEDY_REALLOC(unit_times, allocated, c+2))
+ if (!GREEDY_REALLOC(unit_times, allocated, c + 2))
return log_oom();
- unit_times[c+1].has_data = false;
+ unit_times[c + 1].has_data = false;
t = &unit_times[c];
t->name = NULL;
@@ -430,8 +430,8 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
};
static const struct bus_properties_map manager_map[] = {
- { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
- { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
+ { "Virtualization", "s", NULL, offsetof(struct host_info, virtualization) },
+ { "Architecture", "s", NULL, offsetof(struct host_info, architecture) },
{}
};
@@ -452,14 +452,15 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
}
}
- r = bus_map_all_properties(system_bus ?: bus,
- "org.freedesktop.hostname1",
- "/org/freedesktop/hostname1",
- hostname_map,
- BUS_MAP_STRDUP,
- &error,
- NULL,
- host);
+ r = bus_map_all_properties(
+ system_bus ?: bus,
+ "org.freedesktop.hostname1",
+ "/org/freedesktop/hostname1",
+ hostname_map,
+ BUS_MAP_STRDUP,
+ &error,
+ NULL,
+ host);
if (r < 0) {
log_debug_errno(r, "Failed to get host information from systemd-hostnamed, ignoring: %s",
bus_error_message(&error, r));
@@ -467,14 +468,15 @@ static int acquire_host_info(sd_bus *bus, struct host_info **hi) {
}
manager:
- r = bus_map_all_properties(bus,
- "org.freedesktop.systemd1",
- "/org/freedesktop/systemd1",
- manager_map,
- BUS_MAP_STRDUP,
- &error,
- NULL,
- host);
+ r = bus_map_all_properties(
+ bus,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ manager_map,
+ BUS_MAP_STRDUP,
+ &error,
+ NULL,
+ host);
if (r < 0)
return log_error_errno(r, "Failed to get host information from systemd: %s",
bus_error_message(&error, r));
@@ -491,7 +493,7 @@ static int pretty_boot_time(sd_bus *bus, char **_buf) {
char *ptr;
int r;
usec_t activated_time = USEC_INFINITY;
- _cleanup_free_ char* path = NULL, *unit_id = NULL;
+ _cleanup_free_ char *path = NULL, *unit_id = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
r = acquire_boot_times(bus, &t);
@@ -566,21 +568,34 @@ static void svg_graph_box(double height, double begin, double end) {
/* outside box, fill */
svg("<rect class=\"box\" x=\"0\" y=\"0\" width=\"%.03f\" height=\"%.03f\" />\n",
- SCALE_X * (end - begin), SCALE_Y * height);
+ SCALE_X * (end - begin),
+ SCALE_Y * height);
- for (i = ((long long) (begin / 100000)) * 100000; i <= end; i+=100000) {
+ for (i = ((long long) (begin / 100000)) * 100000; i <= end; i += 100000) {
/* lines for each second */
if (i % 5000000 == 0)
svg(" <line class=\"sec5\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
- SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
+ SCALE_X * i,
+ SCALE_X * i,
+ SCALE_Y * height,
+ SCALE_X * i,
+ -5.0,
+ 0.000001 * i);
else if (i % 1000000 == 0)
svg(" <line class=\"sec1\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n"
" <text class=\"sec\" x=\"%.03f\" y=\"%.03f\" >%.01fs</text>\n",
- SCALE_X * i, SCALE_X * i, SCALE_Y * height, SCALE_X * i, -5.0, 0.000001 * i);
+ SCALE_X * i,
+ SCALE_X * i,
+ SCALE_Y * height,
+ SCALE_X * i,
+ -5.0,
+ 0.000001 * i);
else
svg(" <line class=\"sec01\" x1=\"%.03f\" y1=\"0\" x2=\"%.03f\" y2=\"%.03f\" />\n",
- SCALE_X * i, SCALE_X * i, SCALE_Y * height);
+ SCALE_X * i,
+ SCALE_X * i,
+ SCALE_Y * height);
}
}
@@ -822,8 +837,14 @@ static int analyze_plot(int argc, char *argv[], void *userdata) {
return 0;
}
-static int list_dependencies_print(const char *name, unsigned level, unsigned branches,
- bool last, struct unit_times *times, struct boot_times *boot) {
+static int list_dependencies_print(
+ const char *name,
+ unsigned level,
+ unsigned branches,
+ bool last,
+ struct unit_times *times,
+ struct boot_times *boot) {
+
unsigned i;
char ts[FORMAT_TIMESPAN_MAX], ts2[FORMAT_TIMESPAN_MAX];
@@ -864,7 +885,7 @@ static int list_dependencies_get_dependencies(sd_bus *bus, const char *name, cha
static Hashmap *unit_times_hashmap;
-static int list_dependencies_compare(char * const *a, char * const *b) {
+static int list_dependencies_compare(char *const *a, char *const *b) {
usec_t usa = 0, usb = 0;
struct unit_times *times;
@@ -879,12 +900,10 @@ static int list_dependencies_compare(char * const *a, char * const *b) {
}
static bool times_in_range(const struct unit_times *times, const struct boot_times *boot) {
- return times &&
- times->activated > 0 && times->activated <= boot->finish_time;
+ return times && times->activated > 0 && times->activated <= boot->finish_time;
}
-static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units,
- unsigned branches) {
+static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level, char ***units, unsigned branches) {
_cleanup_strv_free_ char **deps = NULL;
char **c;
int r = 0;
@@ -908,8 +927,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level,
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times_in_range(times, boot) &&
- times->activated >= service_longest)
+ if (times_in_range(times, boot) && times->activated >= service_longest)
service_longest = times->activated;
}
@@ -918,8 +936,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level,
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (times_in_range(times, boot) &&
- service_longest - times->activated <= arg_fuzz)
+ if (times_in_range(times, boot) && service_longest - times->activated <= arg_fuzz)
to_print++;
}
@@ -928,8 +945,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level,
STRV_FOREACH(c, deps) {
times = hashmap_get(unit_times_hashmap, *c);
- if (!times_in_range(times, boot) ||
- service_longest - times->activated > arg_fuzz)
+ if (!times_in_range(times, boot) || service_longest - times->activated > arg_fuzz)
continue;
to_print--;
@@ -946,8 +962,7 @@ static int list_dependencies_one(sd_bus *bus, const char *name, unsigned level,
continue;
}
- r = list_dependencies_one(bus, *c, level + 1, units,
- (branches << 1) | (to_print ? 1 : 0));
+ r = list_dependencies_one(bus, *c, level + 1, units, (branches << 1) | (to_print ? 1 : 0));
if (r < 0)
return r;
@@ -1096,7 +1111,15 @@ static int analyze_time(int argc, char *argv[], void *userdata) {
return 0;
}
-static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop, const char *color, char* patterns[], char* from_patterns[], char* to_patterns[]) {
+static int graph_one_property(
+ sd_bus *bus,
+ const UnitInfo *u,
+ const char *prop,
+ const char *color,
+ char *patterns[],
+ char *from_patterns[],
+ char *to_patterns[]) {
+
_cleanup_strv_free_ char **units = NULL;
char **unit;
int r;
@@ -1108,10 +1131,8 @@ static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop,
match_patterns = strv_fnmatch(patterns, u->id, 0);
- if (!strv_isempty(from_patterns) &&
- !match_patterns &&
- !strv_fnmatch(from_patterns, u->id, 0))
- return 0;
+ if (!strv_isempty(from_patterns) && !match_patterns && !strv_fnmatch(from_patterns, u->id, 0))
+ return 0;
r = bus_get_unit_property_strv(bus, u->unit_path, prop, &units);
if (r < 0)
@@ -1122,9 +1143,7 @@ static int graph_one_property(sd_bus *bus, const UnitInfo *u, const char* prop,
match_patterns2 = strv_fnmatch(patterns, *unit, 0);
- if (!strv_isempty(to_patterns) &&
- !match_patterns2 &&
- !strv_fnmatch(to_patterns, *unit, 0))
+ if (!strv_isempty(to_patterns) && !match_patterns2 && !strv_fnmatch(to_patterns, *unit, 0))
continue;
if (!strv_isempty(patterns) && !match_patterns && !match_patterns2)
@@ -1516,8 +1535,8 @@ static int load_kernel_syscalls(Set **ret) {
_cleanup_fclose_ FILE *f = NULL;
int r;
- /* Let's read the available system calls from the list of available tracing events. Slightly dirty, but good
- * enough for analysis purposes. */
+ /* Let's read the available system calls from the list of available tracing events. Slightly dirty,
+ * but good enough for analysis purposes. */
f = fopen("/sys/kernel/tracing/available_events", "re");
if (!f) {
@@ -1543,7 +1562,8 @@ static int load_kernel_syscalls(Set **ret) {
if (!e)
continue;
- /* These are named differently inside the kernel than their external name for historical reasons. Let's hide them here. */
+ /* These are named differently inside the kernel than their external name for historical
+ * reasons. Let's hide them here. */
if (STR_IN_SET(e, "newuname", "newfstat", "newstat", "newlstat", "sysctl"))
continue;
@@ -1582,10 +1602,7 @@ static void dump_syscall_filter(const SyscallFilterSet *set) {
set->help);
NULSTR_FOREACH(syscall, set->value)
- printf(" %s%s%s\n",
- syscall[0] == '@' ? ansi_underline() : "",
- syscall,
- ansi_normal());
+ printf(" %s%s%s\n", syscall[0] == '@' ? ansi_underline() : "", syscall, ansi_normal());
}
static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
@@ -1652,8 +1669,7 @@ static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
#else
static int dump_syscall_filters(int argc, char *argv[], void *userdata) {
- return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
- "Not compiled with syscall filters, sorry.");
+ return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not compiled with syscall filters, sorry.");
}
#endif
@@ -1709,8 +1725,7 @@ static int test_calendar_one(usec_t n, const char *p) {
r = calendar_spec_next_usec(spec, n, &next);
if (r == -ENOENT) {
if (i == 0)
- printf(" Next elapse: %snever%s\n",
- ansi_highlight_yellow(), ansi_normal());
+ printf(" Next elapse: %snever%s\n", ansi_highlight_yellow(), ansi_normal());
return 0;
}
if (r < 0)
@@ -1718,9 +1733,11 @@ static int test_calendar_one(usec_t n, const char *p) {
if (i == 0)
printf(" Next elapse: %s%s%s\n",
- ansi_highlight_blue(), format_timestamp(buffer, sizeof(buffer), next), ansi_normal());
+ ansi_highlight_blue(),
+ format_timestamp(buffer, sizeof(buffer), next),
+ ansi_normal());
else {
- int k = DECIMAL_STR_WIDTH(i+1);
+ int k = DECIMAL_STR_WIDTH(i + 1);
if (k < 8)
k = 8 - k;
@@ -1755,7 +1772,7 @@ static int test_calendar(int argc, char *argv[], void *userdata) {
if (ret == 0 && r < 0)
ret = r;
- if (*(p+1))
+ if (*(p + 1))
putchar('\n');
}
@@ -1883,8 +1900,8 @@ static int help(int argc, char *argv[], void *userdata) {
, link
);
- /* When updating this list, including descriptions, apply changes to shell-completion/bash/systemd-analyze and
- * shell-completion/zsh/_systemd-analyze too. */
+ /* When updating this list, including descriptions, apply changes to
+ * shell-completion/bash/systemd-analyze and shell-completion/zsh/_systemd-analyze too. */
return 0;
}
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 2cec054610..16034fb9e8 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -359,6 +359,7 @@ int read_full_stream_full(
}
memcpy_safe(t, buf, n);
explicit_bzero_safe(buf, n);
+ buf = mfree(buf);
} else {
t = realloc(buf, n_next + 1);
if (!t)
diff --git a/src/basic/linux/if_ether.h b/src/basic/linux/if_ether.h
new file mode 100644
index 0000000000..3a45b4ad71
--- /dev/null
+++ b/src/basic/linux/if_ether.h
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version: @(#)if_ether.h 1.0.1a 02/08/94
+ *
+ * Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Donald Becker, <becker@super.org>
+ * Alan Cox, <alan@lxorguk.ukuu.org.uk>
+ * Steve Whitehouse, <gw7rrm@eeshack3.swan.ac.uk>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_IF_ETHER_H
+#define _UAPI_LINUX_IF_ETHER_H
+
+#include <linux/types.h>
+
+/*
+ * IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
+ * and FCS/CRC (frame check sequence).
+ */
+
+#define ETH_ALEN 6 /* Octets in one ethernet addr */
+#define ETH_TLEN 2 /* Octets in ethernet type field */
+#define ETH_HLEN 14 /* Total octets in header. */
+#define ETH_ZLEN 60 /* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN 1500 /* Max. octets in payload */
+#define ETH_FRAME_LEN 1514 /* Max. octets in frame sans FCS */
+#define ETH_FCS_LEN 4 /* Octets in the FCS */
+
+#define ETH_MIN_MTU 68 /* Min IPv4 MTU per RFC791 */
+#define ETH_MAX_MTU 0xFFFFU /* 65535, same as IP_MAX_MTU */
+
+/*
+ * These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */
+#define ETH_P_PUP 0x0200 /* Xerox PUP packet */
+#define ETH_P_PUPAT 0x0201 /* Xerox PUP Addr Trans packet */
+#define ETH_P_TSN 0x22F0 /* TSN (IEEE 1722) packet */
+#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */
+#define ETH_P_IP 0x0800 /* Internet Protocol packet */
+#define ETH_P_X25 0x0805 /* CCITT X.25 */
+#define ETH_P_ARP 0x0806 /* Address Resolution packet */
+#define ETH_P_BPQ 0x08FF /* G8BPQ AX.25 Ethernet Packet [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IEEEPUP 0x0a00 /* Xerox IEEE802.3 PUP packet */
+#define ETH_P_IEEEPUPAT 0x0a01 /* Xerox IEEE802.3 PUP Addr Trans packet */
+#define ETH_P_BATMAN 0x4305 /* B.A.T.M.A.N.-Advanced packet [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DEC 0x6000 /* DEC Assigned proto */
+#define ETH_P_DNA_DL 0x6001 /* DEC DNA Dump/Load */
+#define ETH_P_DNA_RC 0x6002 /* DEC DNA Remote Console */
+#define ETH_P_DNA_RT 0x6003 /* DEC DNA Routing */
+#define ETH_P_LAT 0x6004 /* DEC LAT */
+#define ETH_P_DIAG 0x6005 /* DEC Diagnostics */
+#define ETH_P_CUST 0x6006 /* DEC Customer use */
+#define ETH_P_SCA 0x6007 /* DEC Systems Comms Arch */
+#define ETH_P_TEB 0x6558 /* Trans Ether Bridging */
+#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */
+#define ETH_P_ATALK 0x809B /* Appletalk DDP */
+#define ETH_P_AARP 0x80F3 /* Appletalk AARP */
+#define ETH_P_8021Q 0x8100 /* 802.1Q VLAN Extended Header */
+#define ETH_P_ERSPAN 0x88BE /* ERSPAN type II */
+#define ETH_P_IPX 0x8137 /* IPX over DIX */
+#define ETH_P_IPV6 0x86DD /* IPv6 over bluebook */
+#define ETH_P_PAUSE 0x8808 /* IEEE Pause frames. See 802.3 31B */
+#define ETH_P_SLOW 0x8809 /* Slow Protocol. See 802.3ad 43B */
+#define ETH_P_WCCP 0x883E /* Web-cache coordination protocol
+ * defined in draft-wilson-wrec-wccp-v2-00.txt */
+#define ETH_P_MPLS_UC 0x8847 /* MPLS Unicast traffic */
+#define ETH_P_MPLS_MC 0x8848 /* MPLS Multicast traffic */
+#define ETH_P_ATMMPOA 0x884c /* MultiProtocol Over ATM */
+#define ETH_P_PPP_DISC 0x8863 /* PPPoE discovery messages */
+#define ETH_P_PPP_SES 0x8864 /* PPPoE session messages */
+#define ETH_P_LINK_CTL 0x886c /* HPNA, wlan link local tunnel */
+#define ETH_P_ATMFATE 0x8884 /* Frame-based ATM Transport
+ * over Ethernet
+ */
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#define ETH_P_AOE 0x88A2 /* ATA over Ethernet */
+#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
+#define ETH_P_802_EX1 0x88B5 /* 802.1 Local Experimental 1. */
+#define ETH_P_PREAUTH 0x88C7 /* 802.11 Preauthentication */
+#define ETH_P_TIPC 0x88CA /* TIPC */
+#define ETH_P_MACSEC 0x88E5 /* 802.1ae MACsec */
+#define ETH_P_8021AH 0x88E7 /* 802.1ah Backbone Service Tag */
+#define ETH_P_MVRP 0x88F5 /* 802.1Q MVRP */
+#define ETH_P_1588 0x88F7 /* IEEE 1588 Timesync */
+#define ETH_P_NCSI 0x88F8 /* NCSI protocol */
+#define ETH_P_PRP 0x88FB /* IEC 62439-3 PRP/HSRv0 */
+#define ETH_P_FCOE 0x8906 /* Fibre Channel over Ethernet */
+#define ETH_P_IBOE 0x8915 /* Infiniband over Ethernet */
+#define ETH_P_TDLS 0x890D /* TDLS */
+#define ETH_P_FIP 0x8914 /* FCoE Initialization Protocol */
+#define ETH_P_80221 0x8917 /* IEEE 802.21 Media Independent Handover Protocol */
+#define ETH_P_HSR 0x892F /* IEC 62439-3 HSRv1 */
+#define ETH_P_NSH 0x894F /* Network Service Header */
+#define ETH_P_LOOPBACK 0x9000 /* Ethernet loopback packet, per IEEE 802.3 */
+#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_EDSA 0xDADA /* Ethertype DSA [ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_IFE 0xED3E /* ForCES inter-FE LFB type */
+#define ETH_P_AF_IUCV 0xFBFB /* IBM af_iucv [ NOT AN OFFICIALLY REGISTERED ID ] */
+
+#define ETH_P_802_3_MIN 0x0600 /* If the value in the ethernet type is less than this value
+ * then the frame is Ethernet II. Else it is 802.3 */
+
+/*
+ * Non DIX types. Won't clash for 1500 types.
+ */
+
+#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
+#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */
+#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */
+#define ETH_P_802_2 0x0004 /* 802.2 frames */
+#define ETH_P_SNAP 0x0005 /* Internal only */
+#define ETH_P_DDCMP 0x0006 /* DEC DDCMP: Internal only */
+#define ETH_P_WAN_PPP 0x0007 /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP 0x0008 /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009 /* Localtalk pseudo type */
+#define ETH_P_CAN 0x000C /* CAN: Controller Area Network */
+#define ETH_P_CANFD 0x000D /* CANFD: CAN flexible data rate*/
+#define ETH_P_PPPTALK 0x0010 /* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2 0x0011 /* 802.2 frames */
+#define ETH_P_MOBITEX 0x0015 /* Mobitex (kaz@cafe.net) */
+#define ETH_P_CONTROL 0x0016 /* Card specific control frames */
+#define ETH_P_IRDA 0x0017 /* Linux-IrDA */
+#define ETH_P_ECONET 0x0018 /* Acorn Econet */
+#define ETH_P_HDLC 0x0019 /* HDLC frames */
+#define ETH_P_ARCNET 0x001A /* 1A for ArcNet :-) */
+#define ETH_P_DSA 0x001B /* Distributed Switch Arch. */
+#define ETH_P_TRAILER 0x001C /* Trailer switch tagging */
+#define ETH_P_PHONET 0x00F5 /* Nokia Phonet frames */
+#define ETH_P_IEEE802154 0x00F6 /* IEEE802.15.4 frame */
+#define ETH_P_CAIF 0x00F7 /* ST-Ericsson CAIF protocol */
+#define ETH_P_XDSA 0x00F8 /* Multiplexed DSA protocol */
+#define ETH_P_MAP 0x00F9 /* Qualcomm multiplexing and
+ * aggregation protocol
+ */
+
+/*
+ * This is an Ethernet frame header.
+ */
+
+/* allow libcs like musl to deactivate this, glibc does not implement this. */
+#ifndef __UAPI_DEF_ETHHDR
+#define __UAPI_DEF_ETHHDR 1
+#endif
+
+#if __UAPI_DEF_ETHHDR
+struct ethhdr {
+ unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
+ unsigned char h_source[ETH_ALEN]; /* source ether addr */
+ __be16 h_proto; /* packet type ID field */
+} __attribute__((packed));
+#endif
+
+
+#endif /* _UAPI_LINUX_IF_ETHER_H */
diff --git a/src/basic/linux/in.h b/src/basic/linux/in.h
new file mode 100644
index 0000000000..a55cb8b101
--- /dev/null
+++ b/src/basic/linux/in.h
@@ -0,0 +1,305 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * Definitions of the Internet Protocol.
+ *
+ * Version: @(#)in.h 1.0.1 04/21/93
+ *
+ * Authors: Original taken from the GNU Project <netinet/in.h> file.
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+#ifndef _UAPI_LINUX_IN_H
+#define _UAPI_LINUX_IN_H
+
+#include <linux/types.h>
+#include <linux/libc-compat.h>
+#include <linux/socket.h>
+
+#if __UAPI_DEF_IN_IPPROTO
+/* Standard well-defined IP protocols. */
+enum {
+ IPPROTO_IP = 0, /* Dummy protocol for TCP */
+#define IPPROTO_IP IPPROTO_IP
+ IPPROTO_ICMP = 1, /* Internet Control Message Protocol */
+#define IPPROTO_ICMP IPPROTO_ICMP
+ IPPROTO_IGMP = 2, /* Internet Group Management Protocol */
+#define IPPROTO_IGMP IPPROTO_IGMP
+ IPPROTO_IPIP = 4, /* IPIP tunnels (older KA9Q tunnels use 94) */
+#define IPPROTO_IPIP IPPROTO_IPIP
+ IPPROTO_TCP = 6, /* Transmission Control Protocol */
+#define IPPROTO_TCP IPPROTO_TCP
+ IPPROTO_EGP = 8, /* Exterior Gateway Protocol */
+#define IPPROTO_EGP IPPROTO_EGP
+ IPPROTO_PUP = 12, /* PUP protocol */
+#define IPPROTO_PUP IPPROTO_PUP
+ IPPROTO_UDP = 17, /* User Datagram Protocol */
+#define IPPROTO_UDP IPPROTO_UDP
+ IPPROTO_IDP = 22, /* XNS IDP protocol */
+#define IPPROTO_IDP IPPROTO_IDP
+ IPPROTO_TP = 29, /* SO Transport Protocol Class 4 */
+#define IPPROTO_TP IPPROTO_TP
+ IPPROTO_DCCP = 33, /* Datagram Congestion Control Protocol */
+#define IPPROTO_DCCP IPPROTO_DCCP
+ IPPROTO_IPV6 = 41, /* IPv6-in-IPv4 tunnelling */
+#define IPPROTO_IPV6 IPPROTO_IPV6
+ IPPROTO_RSVP = 46, /* RSVP Protocol */
+#define IPPROTO_RSVP IPPROTO_RSVP
+ IPPROTO_GRE = 47, /* Cisco GRE tunnels (rfc 1701,1702) */
+#define IPPROTO_GRE IPPROTO_GRE
+ IPPROTO_ESP = 50, /* Encapsulation Security Payload protocol */
+#define IPPROTO_ESP IPPROTO_ESP
+ IPPROTO_AH = 51, /* Authentication Header protocol */
+#define IPPROTO_AH IPPROTO_AH
+ IPPROTO_MTP = 92, /* Multicast Transport Protocol */
+#define IPPROTO_MTP IPPROTO_MTP
+ IPPROTO_BEETPH = 94, /* IP option pseudo header for BEET */
+#define IPPROTO_BEETPH IPPROTO_BEETPH
+ IPPROTO_ENCAP = 98, /* Encapsulation Header */
+#define IPPROTO_ENCAP IPPROTO_ENCAP
+ IPPROTO_PIM = 103, /* Protocol Independent Multicast */
+#define IPPROTO_PIM IPPROTO_PIM
+ IPPROTO_COMP = 108, /* Compression Header Protocol */
+#define IPPROTO_COMP IPPROTO_COMP
+ IPPROTO_SCTP = 132, /* Stream Control Transport Protocol */
+#define IPPROTO_SCTP IPPROTO_SCTP
+ IPPROTO_UDPLITE = 136, /* UDP-Lite (RFC 3828) */
+#define IPPROTO_UDPLITE IPPROTO_UDPLITE
+ IPPROTO_MPLS = 137, /* MPLS in IP (RFC 4023) */
+#define IPPROTO_MPLS IPPROTO_MPLS
+ IPPROTO_RAW = 255, /* Raw IP packets */
+#define IPPROTO_RAW IPPROTO_RAW
+ IPPROTO_MAX
+};
+#endif
+
+#if __UAPI_DEF_IN_ADDR
+/* Internet address. */
+struct in_addr {
+ __be32 s_addr;
+};
+#endif
+
+#define IP_TOS 1
+#define IP_TTL 2
+#define IP_HDRINCL 3
+#define IP_OPTIONS 4
+#define IP_ROUTER_ALERT 5
+#define IP_RECVOPTS 6
+#define IP_RETOPTS 7
+#define IP_PKTINFO 8
+#define IP_PKTOPTIONS 9
+#define IP_MTU_DISCOVER 10
+#define IP_RECVERR 11
+#define IP_RECVTTL 12
+#define IP_RECVTOS 13
+#define IP_MTU 14
+#define IP_FREEBIND 15
+#define IP_IPSEC_POLICY 16
+#define IP_XFRM_POLICY 17
+#define IP_PASSSEC 18
+#define IP_TRANSPARENT 19
+
+/* BSD compatibility */
+#define IP_RECVRETOPTS IP_RETOPTS
+
+/* TProxy original addresses */
+#define IP_ORIGDSTADDR 20
+#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR
+
+#define IP_MINTTL 21
+#define IP_NODEFRAG 22
+#define IP_CHECKSUM 23
+#define IP_BIND_ADDRESS_NO_PORT 24
+#define IP_RECVFRAGSIZE 25
+
+/* IP_MTU_DISCOVER values */
+#define IP_PMTUDISC_DONT 0 /* Never send DF frames */
+#define IP_PMTUDISC_WANT 1 /* Use per route hints */
+#define IP_PMTUDISC_DO 2 /* Always DF */
+#define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu */
+/* Always use interface mtu (ignores dst pmtu) but don't set DF flag.
+ * Also incoming ICMP frag_needed notifications will be ignored on
+ * this socket to prevent accepting spoofed ones.
+ */
+#define IP_PMTUDISC_INTERFACE 4
+/* weaker version of IP_PMTUDISC_INTERFACE, which allos packets to get
+ * fragmented if they exeed the interface mtu
+ */
+#define IP_PMTUDISC_OMIT 5
+
+#define IP_MULTICAST_IF 32
+#define IP_MULTICAST_TTL 33
+#define IP_MULTICAST_LOOP 34
+#define IP_ADD_MEMBERSHIP 35
+#define IP_DROP_MEMBERSHIP 36
+#define IP_UNBLOCK_SOURCE 37
+#define IP_BLOCK_SOURCE 38
+#define IP_ADD_SOURCE_MEMBERSHIP 39
+#define IP_DROP_SOURCE_MEMBERSHIP 40
+#define IP_MSFILTER 41
+#define MCAST_JOIN_GROUP 42
+#define MCAST_BLOCK_SOURCE 43
+#define MCAST_UNBLOCK_SOURCE 44
+#define MCAST_LEAVE_GROUP 45
+#define MCAST_JOIN_SOURCE_GROUP 46
+#define MCAST_LEAVE_SOURCE_GROUP 47
+#define MCAST_MSFILTER 48
+#define IP_MULTICAST_ALL 49
+#define IP_UNICAST_IF 50
+
+#define MCAST_EXCLUDE 0
+#define MCAST_INCLUDE 1
+
+/* These need to appear somewhere around here */
+#define IP_DEFAULT_MULTICAST_TTL 1
+#define IP_DEFAULT_MULTICAST_LOOP 1
+
+/* Request struct for multicast socket ops */
+
+#if __UAPI_DEF_IP_MREQ
+struct ip_mreq {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_interface; /* local IP address of interface */
+};
+
+struct ip_mreqn {
+ struct in_addr imr_multiaddr; /* IP multicast address of group */
+ struct in_addr imr_address; /* local IP address of interface */
+ int imr_ifindex; /* Interface index */
+};
+
+struct ip_mreq_source {
+ __be32 imr_multiaddr;
+ __be32 imr_interface;
+ __be32 imr_sourceaddr;
+};
+
+struct ip_msfilter {
+ __be32 imsf_multiaddr;
+ __be32 imsf_interface;
+ __u32 imsf_fmode;
+ __u32 imsf_numsrc;
+ __be32 imsf_slist[1];
+};
+
+#define IP_MSFILTER_SIZE(numsrc) \
+ (sizeof(struct ip_msfilter) - sizeof(__u32) \
+ + (numsrc) * sizeof(__u32))
+
+struct group_req {
+ __u32 gr_interface; /* interface index */
+ struct __kernel_sockaddr_storage gr_group; /* group address */
+};
+
+struct group_source_req {
+ __u32 gsr_interface; /* interface index */
+ struct __kernel_sockaddr_storage gsr_group; /* group address */
+ struct __kernel_sockaddr_storage gsr_source; /* source address */
+};
+
+struct group_filter {
+ __u32 gf_interface; /* interface index */
+ struct __kernel_sockaddr_storage gf_group; /* multicast address */
+ __u32 gf_fmode; /* filter mode */
+ __u32 gf_numsrc; /* number of sources */
+ struct __kernel_sockaddr_storage gf_slist[1]; /* interface index */
+};
+
+#define GROUP_FILTER_SIZE(numsrc) \
+ (sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
+ + (numsrc) * sizeof(struct __kernel_sockaddr_storage))
+#endif
+
+#if __UAPI_DEF_IN_PKTINFO
+struct in_pktinfo {
+ int ipi_ifindex;
+ struct in_addr ipi_spec_dst;
+ struct in_addr ipi_addr;
+};
+#endif
+
+/* Structure describing an Internet (IP) socket address. */
+#if __UAPI_DEF_SOCKADDR_IN
+#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
+struct sockaddr_in {
+ __kernel_sa_family_t sin_family; /* Address family */
+ __be16 sin_port; /* Port number */
+ struct in_addr sin_addr; /* Internet address */
+
+ /* Pad to size of `struct sockaddr'. */
+ unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) -
+ sizeof(unsigned short int) - sizeof(struct in_addr)];
+};
+#define sin_zero __pad /* for BSD UNIX comp. -FvK */
+#endif
+
+#if __UAPI_DEF_IN_CLASS
+/*
+ * Definitions of the bits in an Internet address integer.
+ * On subnets, host and network parts are found according
+ * to the subnet mask, not these masks.
+ */
+#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0)
+#define IN_CLASSA_NET 0xff000000
+#define IN_CLASSA_NSHIFT 24
+#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
+#define IN_CLASSA_MAX 128
+
+#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000)
+#define IN_CLASSB_NET 0xffff0000
+#define IN_CLASSB_NSHIFT 16
+#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
+#define IN_CLASSB_MAX 65536
+
+#define IN_CLASSC(a) ((((long int) (a)) & 0xe0000000) == 0xc0000000)
+#define IN_CLASSC_NET 0xffffff00
+#define IN_CLASSC_NSHIFT 8
+#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
+
+#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000)
+#define IN_MULTICAST(a) IN_CLASSD(a)
+#define IN_MULTICAST_NET 0xe0000000
+
+#define IN_BADCLASS(a) (((long int) (a) ) == (long int)0xffffffff)
+#define IN_EXPERIMENTAL(a) IN_BADCLASS((a))
+
+#define IN_CLASSE(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
+#define IN_CLASSE_NET 0xffffffff
+#define IN_CLASSE_NSHIFT 0
+
+/* Address to accept any incoming messages. */
+#define INADDR_ANY ((unsigned long int) 0x00000000)
+
+/* Address to send to all hosts. */
+#define INADDR_BROADCAST ((unsigned long int) 0xffffffff)
+
+/* Address indicating an error return. */
+#define INADDR_NONE ((unsigned long int) 0xffffffff)
+
+/* Network number for local host loopback. */
+#define IN_LOOPBACKNET 127
+
+/* Address to loopback in software to local host. */
+#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */
+#define IN_LOOPBACK(a) ((((long int) (a)) & 0xff000000) == 0x7f000000)
+
+/* Defines for Multicast INADDR */
+#define INADDR_UNSPEC_GROUP 0xe0000000U /* 224.0.0.0 */
+#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
+#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
+#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
+#endif
+
+/* <asm/byteorder.h> contains the htonl type stuff.. */
+#include <asm/byteorder.h>
+
+
+#endif /* _UAPI_LINUX_IN_H */
diff --git a/src/basic/linux/in6.h b/src/basic/linux/in6.h
new file mode 100644
index 0000000000..71d82fe15b
--- /dev/null
+++ b/src/basic/linux/in6.h
@@ -0,0 +1,299 @@
+/* SPDX-License-Identifier: GPL-2.0+ WITH Linux-syscall-note */
+/*
+ * Types and definitions for AF_INET6
+ * Linux INET6 implementation
+ *
+ * Authors:
+ * Pedro Roque <roque@di.fc.ul.pt>
+ *
+ * Sources:
+ * IPv6 Program Interfaces for BSD Systems
+ * <draft-ietf-ipngwg-bsd-api-05.txt>
+ *
+ * Advanced Sockets API for IPv6
+ * <draft-stevens-advanced-api-00.txt>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UAPI_LINUX_IN6_H
+#define _UAPI_LINUX_IN6_H
+
+#include <linux/types.h>
+#include <linux/libc-compat.h>
+
+/*
+ * IPv6 address structure
+ */
+
+#if __UAPI_DEF_IN6_ADDR
+struct in6_addr {
+ union {
+ __u8 u6_addr8[16];
+#if __UAPI_DEF_IN6_ADDR_ALT
+ __be16 u6_addr16[8];
+ __be32 u6_addr32[4];
+#endif
+ } in6_u;
+#define s6_addr in6_u.u6_addr8
+#if __UAPI_DEF_IN6_ADDR_ALT
+#define s6_addr16 in6_u.u6_addr16
+#define s6_addr32 in6_u.u6_addr32
+#endif
+};
+#endif /* __UAPI_DEF_IN6_ADDR */
+
+#if __UAPI_DEF_SOCKADDR_IN6
+struct sockaddr_in6 {
+ unsigned short int sin6_family; /* AF_INET6 */
+ __be16 sin6_port; /* Transport layer port # */
+ __be32 sin6_flowinfo; /* IPv6 flow information */
+ struct in6_addr sin6_addr; /* IPv6 address */
+ __u32 sin6_scope_id; /* scope id (new in RFC2553) */
+};
+#endif /* __UAPI_DEF_SOCKADDR_IN6 */
+
+#if __UAPI_DEF_IPV6_MREQ
+struct ipv6_mreq {
+ /* IPv6 multicast address of group */
+ struct in6_addr ipv6mr_multiaddr;
+
+ /* local IPv6 address of interface */
+ int ipv6mr_ifindex;
+};
+#endif /* __UAPI_DEF_IVP6_MREQ */
+
+#define ipv6mr_acaddr ipv6mr_multiaddr
+
+struct in6_flowlabel_req {
+ struct in6_addr flr_dst;
+ __be32 flr_label;
+ __u8 flr_action;
+ __u8 flr_share;
+ __u16 flr_flags;
+ __u16 flr_expires;
+ __u16 flr_linger;
+ __u32 __flr_pad;
+ /* Options in format of IPV6_PKTOPTIONS */
+};
+
+#define IPV6_FL_A_GET 0
+#define IPV6_FL_A_PUT 1
+#define IPV6_FL_A_RENEW 2
+
+#define IPV6_FL_F_CREATE 1
+#define IPV6_FL_F_EXCL 2
+#define IPV6_FL_F_REFLECT 4
+#define IPV6_FL_F_REMOTE 8
+
+#define IPV6_FL_S_NONE 0
+#define IPV6_FL_S_EXCL 1
+#define IPV6_FL_S_PROCESS 2
+#define IPV6_FL_S_USER 3
+#define IPV6_FL_S_ANY 255
+
+
+/*
+ * Bitmask constant declarations to help applications select out the
+ * flow label and priority fields.
+ *
+ * Note that this are in host byte order while the flowinfo field of
+ * sockaddr_in6 is in network byte order.
+ */
+
+#define IPV6_FLOWINFO_FLOWLABEL 0x000fffff
+#define IPV6_FLOWINFO_PRIORITY 0x0ff00000
+
+/* These definitions are obsolete */
+#define IPV6_PRIORITY_UNCHARACTERIZED 0x0000
+#define IPV6_PRIORITY_FILLER 0x0100
+#define IPV6_PRIORITY_UNATTENDED 0x0200
+#define IPV6_PRIORITY_RESERVED1 0x0300
+#define IPV6_PRIORITY_BULK 0x0400
+#define IPV6_PRIORITY_RESERVED2 0x0500
+#define IPV6_PRIORITY_INTERACTIVE 0x0600
+#define IPV6_PRIORITY_CONTROL 0x0700
+#define IPV6_PRIORITY_8 0x0800
+#define IPV6_PRIORITY_9 0x0900
+#define IPV6_PRIORITY_10 0x0a00
+#define IPV6_PRIORITY_11 0x0b00
+#define IPV6_PRIORITY_12 0x0c00
+#define IPV6_PRIORITY_13 0x0d00
+#define IPV6_PRIORITY_14 0x0e00
+#define IPV6_PRIORITY_15 0x0f00
+
+/*
+ * IPV6 extension headers
+ */
+#if __UAPI_DEF_IPPROTO_V6
+#define IPPROTO_HOPOPTS 0 /* IPv6 hop-by-hop options */
+#define IPPROTO_ROUTING 43 /* IPv6 routing header */
+#define IPPROTO_FRAGMENT 44 /* IPv6 fragmentation header */
+#define IPPROTO_ICMPV6 58 /* ICMPv6 */
+#define IPPROTO_NONE 59 /* IPv6 no next header */
+#define IPPROTO_DSTOPTS 60 /* IPv6 destination options */
+#define IPPROTO_MH 135 /* IPv6 mobility header */
+#endif /* __UAPI_DEF_IPPROTO_V6 */
+
+/*
+ * IPv6 TLV options.
+ */
+#define IPV6_TLV_PAD1 0
+#define IPV6_TLV_PADN 1
+#define IPV6_TLV_ROUTERALERT 5
+#define IPV6_TLV_CALIPSO 7 /* RFC 5570 */
+#define IPV6_TLV_JUMBO 194
+#define IPV6_TLV_HAO 201 /* home address option */
+
+/*
+ * IPV6 socket options
+ */
+#if __UAPI_DEF_IPV6_OPTIONS
+#define IPV6_ADDRFORM 1
+#define IPV6_2292PKTINFO 2
+#define IPV6_2292HOPOPTS 3
+#define IPV6_2292DSTOPTS 4
+#define IPV6_2292RTHDR 5
+#define IPV6_2292PKTOPTIONS 6
+#define IPV6_CHECKSUM 7
+#define IPV6_2292HOPLIMIT 8
+#define IPV6_NEXTHOP 9
+#define IPV6_AUTHHDR 10 /* obsolete */
+#define IPV6_FLOWINFO 11
+
+#define IPV6_UNICAST_HOPS 16
+#define IPV6_MULTICAST_IF 17
+#define IPV6_MULTICAST_HOPS 18
+#define IPV6_MULTICAST_LOOP 19
+#define IPV6_ADD_MEMBERSHIP 20
+#define IPV6_DROP_MEMBERSHIP 21
+#define IPV6_ROUTER_ALERT 22
+#define IPV6_MTU_DISCOVER 23
+#define IPV6_MTU 24
+#define IPV6_RECVERR 25
+#define IPV6_V6ONLY 26
+#define IPV6_JOIN_ANYCAST 27
+#define IPV6_LEAVE_ANYCAST 28
+#define IPV6_MULTICAST_ALL 29
+
+/* IPV6_MTU_DISCOVER values */
+#define IPV6_PMTUDISC_DONT 0
+#define IPV6_PMTUDISC_WANT 1
+#define IPV6_PMTUDISC_DO 2
+#define IPV6_PMTUDISC_PROBE 3
+/* same as IPV6_PMTUDISC_PROBE, provided for symetry with IPv4
+ * also see comments on IP_PMTUDISC_INTERFACE
+ */
+#define IPV6_PMTUDISC_INTERFACE 4
+/* weaker version of IPV6_PMTUDISC_INTERFACE, which allows packets to
+ * get fragmented if they exceed the interface mtu
+ */
+#define IPV6_PMTUDISC_OMIT 5
+
+/* Flowlabel */
+#define IPV6_FLOWLABEL_MGR 32
+#define IPV6_FLOWINFO_SEND 33
+
+#define IPV6_IPSEC_POLICY 34
+#define IPV6_XFRM_POLICY 35
+#define IPV6_HDRINCL 36
+#endif
+
+/*
+ * Multicast:
+ * Following socket options are shared between IPv4 and IPv6.
+ *
+ * MCAST_JOIN_GROUP 42
+ * MCAST_BLOCK_SOURCE 43
+ * MCAST_UNBLOCK_SOURCE 44
+ * MCAST_LEAVE_GROUP 45
+ * MCAST_JOIN_SOURCE_GROUP 46
+ * MCAST_LEAVE_SOURCE_GROUP 47
+ * MCAST_MSFILTER 48
+ */
+
+/*
+ * Advanced API (RFC3542) (1)
+ *
+ * Note: IPV6_RECVRTHDRDSTOPTS does not exist. see net/ipv6/datagram.c.
+ */
+
+#define IPV6_RECVPKTINFO 49
+#define IPV6_PKTINFO 50
+#define IPV6_RECVHOPLIMIT 51
+#define IPV6_HOPLIMIT 52
+#define IPV6_RECVHOPOPTS 53
+#define IPV6_HOPOPTS 54
+#define IPV6_RTHDRDSTOPTS 55
+#define IPV6_RECVRTHDR 56
+#define IPV6_RTHDR 57
+#define IPV6_RECVDSTOPTS 58
+#define IPV6_DSTOPTS 59
+#define IPV6_RECVPATHMTU 60
+#define IPV6_PATHMTU 61
+#define IPV6_DONTFRAG 62
+#if 0 /* not yet */
+#define IPV6_USE_MIN_MTU 63
+#endif
+
+/*
+ * Netfilter (1)
+ *
+ * Following socket options are used in ip6_tables;
+ * see include/linux/netfilter_ipv6/ip6_tables.h.
+ *
+ * IP6T_SO_SET_REPLACE / IP6T_SO_GET_INFO 64
+ * IP6T_SO_SET_ADD_COUNTERS / IP6T_SO_GET_ENTRIES 65
+ */
+
+/*
+ * Advanced API (RFC3542) (2)
+ */
+#define IPV6_RECVTCLASS 66
+#define IPV6_TCLASS 67
+
+/*
+ * Netfilter (2)
+ *
+ * Following socket options are used in ip6_tables;
+ * see include/linux/netfilter_ipv6/ip6_tables.h.
+ *
+ * IP6T_SO_GET_REVISION_MATCH 68
+ * IP6T_SO_GET_REVISION_TARGET 69
+ * IP6T_SO_ORIGINAL_DST 80
+ */
+
+#define IPV6_AUTOFLOWLABEL 70
+/* RFC5014: Source address selection */
+#define IPV6_ADDR_PREFERENCES 72
+
+#define IPV6_PREFER_SRC_TMP 0x0001
+#define IPV6_PREFER_SRC_PUBLIC 0x0002
+#define IPV6_PREFER_SRC_PUBTMP_DEFAULT 0x0100
+#define IPV6_PREFER_SRC_COA 0x0004
+#define IPV6_PREFER_SRC_HOME 0x0400
+#define IPV6_PREFER_SRC_CGA 0x0008
+#define IPV6_PREFER_SRC_NONCGA 0x0800
+
+/* RFC5082: Generalized Ttl Security Mechanism */
+#define IPV6_MINHOPCOUNT 73
+
+#define IPV6_ORIGDSTADDR 74
+#define IPV6_RECVORIGDSTADDR IPV6_ORIGDSTADDR
+#define IPV6_TRANSPARENT 75
+#define IPV6_UNICAST_IF 76
+#define IPV6_RECVFRAGSIZE 77
+#define IPV6_FREEBIND 78
+
+/*
+ * Multicast Routing:
+ * see include/uapi/linux/mroute6.h.
+ *
+ * MRT6_BASE 200
+ * ...
+ * MRT6_MAX
+ */
+#endif /* _UAPI_LINUX_IN6_H */
diff --git a/src/basic/linux/l2tp.h b/src/basic/linux/l2tp.h
new file mode 100644
index 0000000000..61158f5a1a
--- /dev/null
+++ b/src/basic/linux/l2tp.h
@@ -0,0 +1,201 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/*
+ * L2TP-over-IP socket for L2TPv3.
+ *
+ * Author: James Chapman <jchapman@katalix.com>
+ */
+
+#ifndef _UAPI_LINUX_L2TP_H_
+#define _UAPI_LINUX_L2TP_H_
+
+#include <linux/types.h>
+#include <linux/socket.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+
+#define IPPROTO_L2TP 115
+
+/**
+ * struct sockaddr_l2tpip - the sockaddr structure for L2TP-over-IP sockets
+ * @l2tp_family: address family number AF_L2TPIP.
+ * @l2tp_addr: protocol specific address information
+ * @l2tp_conn_id: connection id of tunnel
+ */
+#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
+struct sockaddr_l2tpip {
+ /* The first fields must match struct sockaddr_in */
+ __kernel_sa_family_t l2tp_family; /* AF_INET */
+ __be16 l2tp_unused; /* INET port number (unused) */
+ struct in_addr l2tp_addr; /* Internet address */
+
+ __u32 l2tp_conn_id; /* Connection ID of tunnel */
+
+ /* Pad to size of `struct sockaddr'. */
+ unsigned char __pad[__SOCK_SIZE__ -
+ sizeof(__kernel_sa_family_t) -
+ sizeof(__be16) - sizeof(struct in_addr) -
+ sizeof(__u32)];
+};
+
+/**
+ * struct sockaddr_l2tpip6 - the sockaddr structure for L2TP-over-IPv6 sockets
+ * @l2tp_family: address family number AF_L2TPIP.
+ * @l2tp_addr: protocol specific address information
+ * @l2tp_conn_id: connection id of tunnel
+ */
+struct sockaddr_l2tpip6 {
+ /* The first fields must match struct sockaddr_in6 */
+ __kernel_sa_family_t l2tp_family; /* AF_INET6 */
+ __be16 l2tp_unused; /* INET port number (unused) */
+ __be32 l2tp_flowinfo; /* IPv6 flow information */
+ struct in6_addr l2tp_addr; /* IPv6 address */
+ __u32 l2tp_scope_id; /* scope id (new in RFC2553) */
+ __u32 l2tp_conn_id; /* Connection ID of tunnel */
+};
+
+/*****************************************************************************
+ * NETLINK_GENERIC netlink family.
+ *****************************************************************************/
+
+/*
+ * Commands.
+ * Valid TLVs of each command are:-
+ * TUNNEL_CREATE - CONN_ID, pw_type, netns, ifname, ipinfo, udpinfo, udpcsum
+ * TUNNEL_DELETE - CONN_ID
+ * TUNNEL_MODIFY - CONN_ID, udpcsum
+ * TUNNEL_GETSTATS - CONN_ID, (stats)
+ * TUNNEL_GET - CONN_ID, (...)
+ * SESSION_CREATE - SESSION_ID, PW_TYPE, cookie, peer_cookie, l2spec
+ * SESSION_DELETE - SESSION_ID
+ * SESSION_MODIFY - SESSION_ID
+ * SESSION_GET - SESSION_ID, (...)
+ * SESSION_GETSTATS - SESSION_ID, (stats)
+ *
+ */
+enum {
+ L2TP_CMD_NOOP,
+ L2TP_CMD_TUNNEL_CREATE,
+ L2TP_CMD_TUNNEL_DELETE,
+ L2TP_CMD_TUNNEL_MODIFY,
+ L2TP_CMD_TUNNEL_GET,
+ L2TP_CMD_SESSION_CREATE,
+ L2TP_CMD_SESSION_DELETE,
+ L2TP_CMD_SESSION_MODIFY,
+ L2TP_CMD_SESSION_GET,
+ __L2TP_CMD_MAX,
+};
+
+#define L2TP_CMD_MAX (__L2TP_CMD_MAX - 1)
+
+/*
+ * ATTR types defined for L2TP
+ */
+enum {
+ L2TP_ATTR_NONE, /* no data */
+ L2TP_ATTR_PW_TYPE, /* u16, enum l2tp_pwtype */
+ L2TP_ATTR_ENCAP_TYPE, /* u16, enum l2tp_encap_type */
+ L2TP_ATTR_OFFSET, /* u16 (not used) */
+ L2TP_ATTR_DATA_SEQ, /* u16 (not used) */
+ L2TP_ATTR_L2SPEC_TYPE, /* u8, enum l2tp_l2spec_type */
+ L2TP_ATTR_L2SPEC_LEN, /* u8 (not used) */
+ L2TP_ATTR_PROTO_VERSION, /* u8 */
+ L2TP_ATTR_IFNAME, /* string */
+ L2TP_ATTR_CONN_ID, /* u32 */
+ L2TP_ATTR_PEER_CONN_ID, /* u32 */
+ L2TP_ATTR_SESSION_ID, /* u32 */
+ L2TP_ATTR_PEER_SESSION_ID, /* u32 */
+ L2TP_ATTR_UDP_CSUM, /* u8 */
+ L2TP_ATTR_VLAN_ID, /* u16 (not used) */
+ L2TP_ATTR_COOKIE, /* 0, 4 or 8 bytes */
+ L2TP_ATTR_PEER_COOKIE, /* 0, 4 or 8 bytes */
+ L2TP_ATTR_DEBUG, /* u32, enum l2tp_debug_flags */
+ L2TP_ATTR_RECV_SEQ, /* u8 */
+ L2TP_ATTR_SEND_SEQ, /* u8 */
+ L2TP_ATTR_LNS_MODE, /* u8 */
+ L2TP_ATTR_USING_IPSEC, /* u8 */
+ L2TP_ATTR_RECV_TIMEOUT, /* msec */
+ L2TP_ATTR_FD, /* int */
+ L2TP_ATTR_IP_SADDR, /* u32 */
+ L2TP_ATTR_IP_DADDR, /* u32 */
+ L2TP_ATTR_UDP_SPORT, /* u16 */
+ L2TP_ATTR_UDP_DPORT, /* u16 */
+ L2TP_ATTR_MTU, /* u16 (not used) */
+ L2TP_ATTR_MRU, /* u16 (not used) */
+ L2TP_ATTR_STATS, /* nested */
+ L2TP_ATTR_IP6_SADDR, /* struct in6_addr */
+ L2TP_ATTR_IP6_DADDR, /* struct in6_addr */
+ L2TP_ATTR_UDP_ZERO_CSUM6_TX, /* flag */
+ L2TP_ATTR_UDP_ZERO_CSUM6_RX, /* flag */
+ L2TP_ATTR_PAD,
+ __L2TP_ATTR_MAX,
+};
+
+#define L2TP_ATTR_MAX (__L2TP_ATTR_MAX - 1)
+
+/* Nested in L2TP_ATTR_STATS */
+enum {
+ L2TP_ATTR_STATS_NONE, /* no data */
+ L2TP_ATTR_TX_PACKETS, /* u64 */
+ L2TP_ATTR_TX_BYTES, /* u64 */
+ L2TP_ATTR_TX_ERRORS, /* u64 */
+ L2TP_ATTR_RX_PACKETS, /* u64 */
+ L2TP_ATTR_RX_BYTES, /* u64 */
+ L2TP_ATTR_RX_SEQ_DISCARDS, /* u64 */
+ L2TP_ATTR_RX_OOS_PACKETS, /* u64 */
+ L2TP_ATTR_RX_ERRORS, /* u64 */
+ L2TP_ATTR_STATS_PAD,
+ __L2TP_ATTR_STATS_MAX,
+};
+
+#define L2TP_ATTR_STATS_MAX (__L2TP_ATTR_STATS_MAX - 1)
+
+enum l2tp_pwtype {
+ L2TP_PWTYPE_NONE = 0x0000,
+ L2TP_PWTYPE_ETH_VLAN = 0x0004,
+ L2TP_PWTYPE_ETH = 0x0005,
+ L2TP_PWTYPE_PPP = 0x0007,
+ L2TP_PWTYPE_PPP_AC = 0x0008,
+ L2TP_PWTYPE_IP = 0x000b,
+ __L2TP_PWTYPE_MAX
+};
+
+enum l2tp_l2spec_type {
+ L2TP_L2SPECTYPE_NONE,
+ L2TP_L2SPECTYPE_DEFAULT,
+};
+
+enum l2tp_encap_type {
+ L2TP_ENCAPTYPE_UDP,
+ L2TP_ENCAPTYPE_IP,
+};
+
+/* For L2TP_ATTR_DATA_SEQ. Unused. */
+enum l2tp_seqmode {
+ L2TP_SEQ_NONE = 0,
+ L2TP_SEQ_IP = 1,
+ L2TP_SEQ_ALL = 2,
+};
+
+/**
+ * enum l2tp_debug_flags - debug message categories for L2TP tunnels/sessions
+ *
+ * @L2TP_MSG_DEBUG: verbose debug (if compiled in)
+ * @L2TP_MSG_CONTROL: userspace - kernel interface
+ * @L2TP_MSG_SEQ: sequence numbers
+ * @L2TP_MSG_DATA: data packets
+ */
+enum l2tp_debug_flags {
+ L2TP_MSG_DEBUG = (1 << 0),
+ L2TP_MSG_CONTROL = (1 << 1),
+ L2TP_MSG_SEQ = (1 << 2),
+ L2TP_MSG_DATA = (1 << 3),
+};
+
+/*
+ * NETLINK_GENERIC related info
+ */
+#define L2TP_GENL_NAME "l2tp"
+#define L2TP_GENL_VERSION 0x1
+#define L2TP_GENL_MCGROUP "l2tp"
+
+#endif /* _UAPI_LINUX_L2TP_H_ */
diff --git a/src/shared/linux/netdevice.h b/src/basic/linux/netdevice.h
index f3770c5b0f..f3770c5b0f 100644
--- a/src/shared/linux/netdevice.h
+++ b/src/basic/linux/netdevice.h
diff --git a/src/basic/meson.build b/src/basic/meson.build
index 524f3785dc..7d281c8841 100644
--- a/src/basic/meson.build
+++ b/src/basic/meson.build
@@ -94,11 +94,16 @@ basic_sources = files('''
linux/if_arp.h
linux/if_bonding.h
linux/if_bridge.h
+ linux/if_ether.h
linux/if_link.h
linux/if_macsec.h
linux/if_tun.h
linux/if_tunnel.h
+ linux/in.h
+ linux/in6.h
+ linux/l2tp.h
linux/libc-compat.h
+ linux/netdevice.h
linux/netlink.h
linux/rtnetlink.h
linux/wireguard.h
diff --git a/src/basic/ordered-set.h b/src/basic/ordered-set.h
index 61107eb148..ba43451e27 100644
--- a/src/basic/ordered-set.h
+++ b/src/basic/ordered-set.h
@@ -34,6 +34,10 @@ static inline int ordered_set_put(OrderedSet *s, void *p) {
return ordered_hashmap_put((OrderedHashmap*) s, p, p);
}
+static inline unsigned ordered_set_size(OrderedSet *s) {
+ return ordered_hashmap_size((OrderedHashmap*) s);
+}
+
static inline bool ordered_set_isempty(OrderedSet *s) {
return ordered_hashmap_isempty((OrderedHashmap*) s);
}
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 904bafb76f..32a0d9c5d0 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -1219,17 +1219,34 @@ fallback:
return (ssize_t) k;
}
+/* Put a limit on how many times will attempt to call accept4(). We loop
+ * only on "transient" errors, but let's make sure we don't loop forever. */
+#define MAX_FLUSH_ITERATIONS 1024
+
int flush_accept(int fd) {
struct pollfd pollfd = {
.fd = fd,
.events = POLLIN,
};
- int r;
+ int r, b;
+ socklen_t l = sizeof(b);
- /* Similar to flush_fd() but flushes all incoming connection by accepting them and immediately closing them. */
+ /* Similar to flush_fd() but flushes all incoming connections by accepting and immediately closing
+ * them. */
- for (;;) {
+ if (getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0)
+ return -errno;
+
+ assert(l == sizeof(b));
+ if (!b) /* Let's check if this socket accepts connections before calling accept(). accept4() can
+ * return EOPNOTSUPP if the fd is not a listening socket, which we should treat as a fatal
+ * error, or in case the incoming TCP connection triggered a network issue, which we want to
+ * treat as a transient error. Thus, let's rule out the first reason for EOPNOTSUPP early, so
+ * we can loop safely on transient errors below. */
+ return -ENOTTY;
+
+ for (unsigned iteration = 0;; iteration++) {
int cfd;
r = poll(&pollfd, 1, 0);
@@ -1242,6 +1259,10 @@ int flush_accept(int fd) {
if (r == 0)
return 0;
+ if (iteration >= MAX_FLUSH_ITERATIONS)
+ return log_debug_errno(SYNTHETIC_ERRNO(EBUSY),
+ "Failed to flush connections within " STRINGIFY(MAX_FLUSH_ITERATIONS) " iterations.");
+
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
if (cfd < 0) {
if (errno == EAGAIN)
diff --git a/src/busctl/busctl.c b/src/busctl/busctl.c
index 02f12dc701..86efc02bd8 100644
--- a/src/busctl/busctl.c
+++ b/src/busctl/busctl.c
@@ -50,6 +50,7 @@ static size_t arg_snaplen = 4096;
static bool arg_list = false;
static bool arg_quiet = false;
static bool arg_verbose = false;
+static bool arg_xml_interface = false;
static bool arg_expect_reply = true;
static bool arg_auto_start = true;
static bool arg_allow_interactive_authorization = true;
@@ -948,6 +949,12 @@ static int introspect(int argc, char **argv, void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
+ if (arg_xml_interface) {
+ /* Just dump the received XML and finish */
+ puts(xml);
+ return 0;
+ }
+
/* First, get list of all properties */
r = parse_xml_introspect(argv[2], xml, &ops, members);
if (r < 0)
@@ -2255,6 +2262,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_SIZE,
ARG_LIST,
ARG_VERBOSE,
+ ARG_XML_INTERFACE,
ARG_EXPECT_REPLY,
ARG_AUTO_START,
ARG_ALLOW_INTERACTIVE_AUTHORIZATION,
@@ -2284,6 +2292,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "list", no_argument, NULL, ARG_LIST },
{ "quiet", no_argument, NULL, 'q' },
{ "verbose", no_argument, NULL, ARG_VERBOSE },
+ { "xml-interface", no_argument, NULL, ARG_XML_INTERFACE },
{ "expect-reply", required_argument, NULL, ARG_EXPECT_REPLY },
{ "auto-start", required_argument, NULL, ARG_AUTO_START },
{ "allow-interactive-authorization", required_argument, NULL, ARG_ALLOW_INTERACTIVE_AUTHORIZATION },
@@ -2388,6 +2397,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_verbose = true;
break;
+ case ARG_XML_INTERFACE:
+ arg_xml_interface = true;
+ break;
+
case ARG_EXPECT_REPLY:
r = parse_boolean(optarg);
if (r < 0)
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 2bfa8df0cb..e4e0965bfb 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -202,6 +202,7 @@ void cgroup_context_done(CGroupContext *c) {
}
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
+ _cleanup_free_ char *disable_controllers_str = NULL;
CGroupIODeviceLimit *il;
CGroupIODeviceWeight *iw;
CGroupIODeviceLatency *l;
@@ -217,6 +218,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix = strempty(prefix);
+ (void) cg_mask_to_string(c->disable_controllers, &disable_controllers_str);
+
fprintf(f,
"%sCPUAccounting=%s\n"
"%sIOAccounting=%s\n"
@@ -234,6 +237,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sStartupIOWeight=%" PRIu64 "\n"
"%sBlockIOWeight=%" PRIu64 "\n"
"%sStartupBlockIOWeight=%" PRIu64 "\n"
+ "%sDefaultMemoryMin=%" PRIu64 "\n"
+ "%sDefaultMemoryLow=%" PRIu64 "\n"
"%sMemoryMin=%" PRIu64 "\n"
"%sMemoryLow=%" PRIu64 "\n"
"%sMemoryHigh=%" PRIu64 "\n"
@@ -242,6 +247,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sMemoryLimit=%" PRIu64 "\n"
"%sTasksMax=%" PRIu64 "\n"
"%sDevicePolicy=%s\n"
+ "%sDisableControllers=%s\n"
"%sDelegate=%s\n",
prefix, yes_no(c->cpu_accounting),
prefix, yes_no(c->io_accounting),
@@ -259,6 +265,8 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, c->startup_io_weight,
prefix, c->blockio_weight,
prefix, c->startup_blockio_weight,
+ prefix, c->default_memory_min,
+ prefix, c->default_memory_low,
prefix, c->memory_min,
prefix, c->memory_low,
prefix, c->memory_high,
@@ -267,6 +275,7 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, c->memory_limit,
prefix, c->tasks_max,
prefix, cgroup_device_policy_to_string(c->device_policy),
+ prefix, strnull(disable_controllers_str),
prefix, yes_no(c->delegate));
if (c->delegate) {
@@ -382,6 +391,38 @@ int cgroup_add_device_allow(CGroupContext *c, const char *dev, const char *mode)
return 0;
}
+#define UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(entry) \
+ uint64_t unit_get_ancestor_##entry(Unit *u) { \
+ CGroupContext *c; \
+ \
+ /* 1. Is entry set in this unit? If so, use that. \
+ * 2. Is the default for this entry set in any \
+ * ancestor? If so, use that. \
+ * 3. Otherwise, return CGROUP_LIMIT_MIN. */ \
+ \
+ assert(u); \
+ \
+ c = unit_get_cgroup_context(u); \
+ \
+ if (c->entry##_set) \
+ return c->entry; \
+ \
+ while (UNIT_ISSET(u->slice)) { \
+ u = UNIT_DEREF(u->slice); \
+ c = unit_get_cgroup_context(u); \
+ \
+ if (c->default_##entry##_set) \
+ return c->default_##entry; \
+ } \
+ \
+ /* We've reached the root, but nobody had default for \
+ * this entry set, so set it to the kernel default. */ \
+ return CGROUP_LIMIT_MIN; \
+}
+
+UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_low);
+UNIT_DEFINE_ANCESTOR_MEMORY_LOOKUP(memory_min);
+
static void cgroup_xattr_apply(Unit *u) {
char ids[SD_ID128_STRING_MAX];
int r;
@@ -877,8 +918,17 @@ static void cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint6
(void) set_attribute_and_warn(u, "blkio", "blkio.throttle.write_bps_device", buf);
}
-static bool cgroup_context_has_unified_memory_config(CGroupContext *c) {
- return c->memory_min > 0 || c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX || c->memory_swap_max != CGROUP_LIMIT_MAX;
+static bool unit_has_unified_memory_config(Unit *u) {
+ CGroupContext *c;
+
+ assert(u);
+
+ c = unit_get_cgroup_context(u);
+ assert(c);
+
+ return c->memory_min > 0 || unit_get_ancestor_memory_low(u) > 0 ||
+ c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX ||
+ c->memory_swap_max != CGROUP_LIMIT_MAX;
}
static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) {
@@ -1127,7 +1177,7 @@ static void cgroup_context_apply(
if (cg_all_unified() > 0) {
uint64_t max, swap_max = CGROUP_LIMIT_MAX;
- if (cgroup_context_has_unified_memory_config(c)) {
+ if (unit_has_unified_memory_config(u)) {
max = c->memory_max;
swap_max = c->memory_swap_max;
} else {
@@ -1138,7 +1188,7 @@ static void cgroup_context_apply(
}
cgroup_apply_unified_memory_limit(u, "memory.min", c->memory_min);
- cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low);
+ cgroup_apply_unified_memory_limit(u, "memory.low", unit_get_ancestor_memory_low(u));
cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high);
cgroup_apply_unified_memory_limit(u, "memory.max", max);
cgroup_apply_unified_memory_limit(u, "memory.swap.max", swap_max);
@@ -1149,7 +1199,7 @@ static void cgroup_context_apply(
char buf[DECIMAL_STR_MAX(uint64_t) + 1];
uint64_t val;
- if (cgroup_context_has_unified_memory_config(c)) {
+ if (unit_has_unified_memory_config(u)) {
val = c->memory_max;
log_cgroup_compat(u, "Applying MemoryMax=%" PRIi64 " as MemoryLimit=", val);
} else
@@ -1323,8 +1373,13 @@ static bool unit_get_needs_bpf_firewall(Unit *u) {
return false;
}
-static CGroupMask cgroup_context_get_mask(CGroupContext *c) {
+static CGroupMask unit_get_cgroup_mask(Unit *u) {
CGroupMask mask = 0;
+ CGroupContext *c;
+
+ assert(u);
+
+ c = unit_get_cgroup_context(u);
/* Figure out which controllers we need, based on the cgroup context object */
@@ -1341,7 +1396,7 @@ static CGroupMask cgroup_context_get_mask(CGroupContext *c) {
if (c->memory_accounting ||
c->memory_limit != CGROUP_LIMIT_MAX ||
- cgroup_context_has_unified_memory_config(c))
+ unit_has_unified_memory_config(u))
mask |= CGROUP_MASK_MEMORY;
if (c->device_allow ||
@@ -1380,7 +1435,7 @@ CGroupMask unit_get_own_mask(Unit *u) {
if (!c)
return 0;
- return (cgroup_context_get_mask(c) | unit_get_bpf_mask(u) | unit_get_delegate_mask(u)) & ~unit_get_ancestor_disable_mask(u);
+ return (unit_get_cgroup_mask(u) | unit_get_bpf_mask(u) | unit_get_delegate_mask(u)) & ~unit_get_ancestor_disable_mask(u);
}
CGroupMask unit_get_delegate_mask(Unit *u) {
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index ad04be30e9..8fb5481fc0 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -98,12 +98,19 @@ struct CGroupContext {
LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
LIST_HEAD(CGroupIODeviceLatency, io_device_latencies);
+ uint64_t default_memory_min;
+ uint64_t default_memory_low;
uint64_t memory_min;
uint64_t memory_low;
uint64_t memory_high;
uint64_t memory_max;
uint64_t memory_swap_max;
+ bool default_memory_min_set;
+ bool default_memory_low_set;
+ bool memory_min_set;
+ bool memory_low_set;
+
LIST_HEAD(IPAddressAccessItem, ip_address_allow);
LIST_HEAD(IPAddressAccessItem, ip_address_deny);
@@ -202,6 +209,9 @@ Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup);
Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid);
Unit* manager_get_unit_by_pid(Manager *m, pid_t pid);
+uint64_t unit_get_ancestor_memory_min(Unit *u);
+uint64_t unit_get_ancestor_memory_low(Unit *u);
+
int unit_search_main_pid(Unit *u, pid_t *ret);
int unit_watch_all_pids(Unit *u);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index 7a5e440e9c..c427c3cafe 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -347,6 +347,7 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
+ SD_BUS_PROPERTY("DefaultMemoryLow", "t", NULL, offsetof(CGroupContext, default_memory_low), 0),
SD_BUS_PROPERTY("MemoryMin", "t", NULL, offsetof(CGroupContext, memory_min), 0),
SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
@@ -400,10 +401,10 @@ static int bus_cgroup_set_transient_property(
return 1;
- } else if (streq(name, "DelegateControllers")) {
+ } else if (STR_IN_SET(name, "DelegateControllers", "DisableControllers")) {
CGroupMask mask = 0;
- if (!UNIT_VTABLE(u)->can_delegate)
+ if (streq(name, "DelegateControllers") && !UNIT_VTABLE(u)->can_delegate)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Delegation not available for unit type");
r = sd_bus_message_enter_container(message, 'a', "s");
@@ -438,13 +439,25 @@ static int bus_cgroup_set_transient_property(
if (r < 0)
return r;
- c->delegate = true;
- if (mask == 0)
- c->delegate_controllers = 0;
- else
- c->delegate_controllers |= mask;
+ if (streq(name, "DelegateControllers")) {
+
+ c->delegate = true;
+ if (mask == 0)
+ c->delegate_controllers = 0;
+ else
+ c->delegate_controllers |= mask;
- unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
+ unit_write_settingf(u, flags, name, "Delegate=%s", strempty(t));
+
+ } else if (streq(name, "DisableControllers")) {
+
+ if (mask == 0)
+ c->disable_controllers = 0;
+ else
+ c->disable_controllers |= mask;
+
+ unit_write_settingf(u, flags, name, "%s=%s", name, strempty(t));
+ }
}
return 1;
@@ -663,6 +676,12 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryLow"))
return bus_cgroup_set_memory(u, name, &c->memory_low, message, flags, error);
+ if (streq(name, "DefaultMemoryMin"))
+ return bus_cgroup_set_memory(u, name, &c->default_memory_min, message, flags, error);
+
+ if (streq(name, "DefaultMemoryLow"))
+ return bus_cgroup_set_memory(u, name, &c->default_memory_low, message, flags, error);
+
if (streq(name, "MemoryHigh"))
return bus_cgroup_set_memory(u, name, &c->memory_high, message, flags, error);
@@ -681,6 +700,12 @@ int bus_cgroup_set_property(
if (streq(name, "MemoryLowScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_low, message, flags, error);
+ if (streq(name, "DefaultMemoryMinScale"))
+ return bus_cgroup_set_memory_scale(u, name, &c->default_memory_min, message, flags, error);
+
+ if (streq(name, "DefaultMemoryLowScale"))
+ return bus_cgroup_set_memory_scale(u, name, &c->default_memory_low, message, flags, error);
+
if (streq(name, "MemoryHighScale"))
return bus_cgroup_set_memory_scale(u, name, &c->memory_high, message, flags, error);
@@ -1419,7 +1444,7 @@ int bus_cgroup_set_property(
return 1;
}
- if (u->transient && u->load_state == UNIT_STUB)
+ if (streq(name, "DisableControllers") || (u->transient && u->load_state == UNIT_STUB))
return bus_cgroup_set_transient_property(u, c, name, message, flags, error);
return 0;
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 9c0b994cc3..c113140e8f 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -53,6 +53,7 @@ static BUS_DEFINE_PROPERTY_GET2(property_get_system_state, "s", Manager, manager
static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_timer_slack_nsec, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
static BUS_DEFINE_PROPERTY_GET_REF(property_get_hashmap_size, "u", Hashmap *, hashmap_size);
static BUS_DEFINE_PROPERTY_GET_REF(property_get_set_size, "u", Set *, set_size);
+static BUS_DEFINE_PROPERTY_GET(property_get_default_timeout_abort_usec, "t", Manager, manager_default_timeout_abort_usec);
static int property_get_virtualization(
sd_bus *bus,
@@ -2410,6 +2411,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutAbortUSec", "t", property_get_default_timeout_abort_usec, 0, 0),
SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("DefaultStartLimitIntervalUSec", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
/* The following two items are obsolete alias */
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 4e6709c42e..824955b944 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -28,6 +28,7 @@ static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, Service
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction);
+static BUS_DEFINE_PROPERTY_GET(property_get_timeout_abort_usec, "t", Service, service_timeout_abort_usec);
static int property_get_exit_status_set(
sd_bus *bus,
@@ -103,6 +104,7 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TimeoutAbortUSec", "t", property_get_timeout_abort_usec, 0, 0),
SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 9cbce4f11f..13e9bbbfb1 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -172,6 +172,7 @@ $1.CPUQuota, config_parse_cpu_quota, 0,
$1.CPUQuotaPeriodSec, config_parse_sec_def_infinity, 0, offsetof($1, cgroup_context.cpu_quota_period_usec)
$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
$1.MemoryMin, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
+$1.DefaultMemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.MemoryMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
@@ -307,6 +308,7 @@ Service.RestartSec, config_parse_sec, 0,
Service.TimeoutSec, config_parse_service_timeout, 0, 0
Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
Service.TimeoutStopSec, config_parse_sec_fix_0, 0, offsetof(Service, timeout_stop_usec)
+Service.TimeoutAbortSec, config_parse_service_timeout_abort, 0, 0
Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
m4_dnl The following five only exist for compatibility, they moved into Unit, see above
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 66e5c6d231..bb302fb46b 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -1894,6 +1894,42 @@ int config_parse_service_timeout(
return 0;
}
+int config_parse_service_timeout_abort(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Service *s = userdata;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(s);
+
+ rvalue += strspn(rvalue, WHITESPACE);
+ if (isempty(rvalue)) {
+ s->timeout_abort_set = false;
+ return 0;
+ }
+
+ r = parse_sec(rvalue, &s->timeout_abort_usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse TimeoutAbortSec= setting, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ s->timeout_abort_set = true;
+ return 0;
+}
+
int config_parse_sec_fix_0(
const char *unit,
const char *filename,
@@ -3107,11 +3143,25 @@ int config_parse_memory_limit(
}
}
- if (streq(lvalue, "MemoryMin"))
+ if (streq(lvalue, "DefaultMemoryLow")) {
+ c->default_memory_low_set = true;
+ if (isempty(rvalue))
+ c->default_memory_low = CGROUP_LIMIT_MIN;
+ else
+ c->default_memory_low = bytes;
+ } else if (streq(lvalue, "DefaultMemoryMin")) {
+ c->default_memory_min_set = true;
+ if (isempty(rvalue))
+ c->default_memory_min = CGROUP_LIMIT_MIN;
+ else
+ c->default_memory_min = bytes;
+ } else if (streq(lvalue, "MemoryMin")) {
c->memory_min = bytes;
- else if (streq(lvalue, "MemoryLow"))
+ c->memory_min_set = true;
+ } else if (streq(lvalue, "MemoryLow")) {
c->memory_low = bytes;
- else if (streq(lvalue, "MemoryHigh"))
+ c->memory_low_set = true;
+ } else if (streq(lvalue, "MemoryHigh"))
c->memory_high = bytes;
else if (streq(lvalue, "MemoryMax"))
c->memory_max = bytes;
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 95d06320c0..0891f36760 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -24,6 +24,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_exec_nice);
CONFIG_PARSER_PROTOTYPE(config_parse_exec_oom_score_adjust);
CONFIG_PARSER_PROTOTYPE(config_parse_exec);
CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout);
+CONFIG_PARSER_PROTOTYPE(config_parse_service_timeout_abort);
CONFIG_PARSER_PROTOTYPE(config_parse_service_type);
CONFIG_PARSER_PROTOTYPE(config_parse_service_restart);
CONFIG_PARSER_PROTOTYPE(config_parse_socket_bindtodevice);
diff --git a/src/core/main.c b/src/core/main.c
index 3c4b5202df..f80f32183d 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -112,6 +112,8 @@ static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
static usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC;
static usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
static usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
+static usec_t arg_default_timeout_abort_usec = DEFAULT_TIMEOUT_USEC;
+static bool arg_default_timeout_abort_set = false;
static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
static usec_t arg_runtime_watchdog = 0;
@@ -668,6 +670,40 @@ static int config_parse_crash_chvt(
return 0;
}
+static int config_parse_timeout_abort(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+
+ rvalue += strspn(rvalue, WHITESPACE);
+ if (isempty(rvalue)) {
+ arg_default_timeout_abort_set = false;
+ return 0;
+ }
+
+ r = parse_sec(rvalue, &arg_default_timeout_abort_usec);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DefaultTimeoutAbortSec= setting, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ arg_default_timeout_abort_set = true;
+ return 0;
+}
+
static int parse_config_file(void) {
const ConfigTableItem items[] = {
@@ -697,6 +733,7 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStandardError", config_parse_output_restricted,0, &arg_default_std_error },
{ "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
{ "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
+ { "Manager", "DefaultTimeoutAbortSec", config_parse_timeout_abort, 0, NULL },
{ "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval }, /* obsolete alias */
{ "Manager", "DefaultStartLimitIntervalSec",config_parse_sec, 0, &arg_default_start_limit_interval },
@@ -765,6 +802,8 @@ static void set_manager_defaults(Manager *m) {
m->default_std_error = arg_default_std_error;
m->default_timeout_start_usec = arg_default_timeout_start_usec;
m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
+ m->default_timeout_abort_usec = arg_default_timeout_abort_usec;
+ m->default_timeout_abort_set = arg_default_timeout_abort_set;
m->default_restart_usec = arg_default_restart_usec;
m->default_start_limit_interval = arg_default_start_limit_interval;
m->default_start_limit_burst = arg_default_start_limit_burst;
diff --git a/src/core/manager.h b/src/core/manager.h
index b5def59ed0..92bfd48997 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -330,6 +330,8 @@ struct Manager {
ExecOutput default_std_output, default_std_error;
usec_t default_restart_usec, default_timeout_start_usec, default_timeout_stop_usec;
+ usec_t default_timeout_abort_usec;
+ bool default_timeout_abort_set;
usec_t default_start_limit_interval;
unsigned default_start_limit_burst;
@@ -417,6 +419,11 @@ struct Manager {
bool honor_device_enumeration;
};
+static inline usec_t manager_default_timeout_abort_usec(Manager *m) {
+ assert(m);
+ return m->default_timeout_abort_set ? m->default_timeout_abort_usec : m->default_timeout_stop_usec;
+}
+
#define MANAGER_IS_SYSTEM(m) ((m)->unit_file_scope == UNIT_FILE_SYSTEM)
#define MANAGER_IS_USER(m) ((m)->unit_file_scope != UNIT_FILE_SYSTEM)
diff --git a/src/core/service.c b/src/core/service.c
index 53cead772a..56667f03e8 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -99,6 +99,8 @@ static void service_init(Unit *u) {
s->timeout_start_usec = u->manager->default_timeout_start_usec;
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
+ s->timeout_abort_usec = u->manager->default_timeout_abort_usec;
+ s->timeout_abort_set = u->manager->default_timeout_abort_set;
s->restart_usec = u->manager->default_restart_usec;
s->runtime_max_usec = USEC_INFINITY;
s->type = _SERVICE_TYPE_INVALID;
@@ -789,7 +791,7 @@ static int service_load(Unit *u) {
static void service_dump(Unit *u, FILE *f, const char *prefix) {
char buf_restart[FORMAT_TIMESPAN_MAX], buf_start[FORMAT_TIMESPAN_MAX], buf_stop[FORMAT_TIMESPAN_MAX];
- char buf_runtime[FORMAT_TIMESPAN_MAX], buf_watchdog[FORMAT_TIMESPAN_MAX];
+ char buf_runtime[FORMAT_TIMESPAN_MAX], buf_watchdog[FORMAT_TIMESPAN_MAX], buf_abort[FORMAT_TIMESPAN_MAX];
ServiceExecCommand c;
Service *s = SERVICE(u);
const char *prefix2;
@@ -859,12 +861,19 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
fprintf(f,
"%sRestartSec: %s\n"
"%sTimeoutStartSec: %s\n"
- "%sTimeoutStopSec: %s\n"
- "%sRuntimeMaxSec: %s\n"
- "%sWatchdogSec: %s\n",
+ "%sTimeoutStopSec: %s\n",
prefix, format_timespan(buf_restart, sizeof(buf_restart), s->restart_usec, USEC_PER_SEC),
prefix, format_timespan(buf_start, sizeof(buf_start), s->timeout_start_usec, USEC_PER_SEC),
- prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC),
+ prefix, format_timespan(buf_stop, sizeof(buf_stop), s->timeout_stop_usec, USEC_PER_SEC));
+
+ if (s->timeout_abort_set)
+ fprintf(f,
+ "%sTimeoutAbortSec: %s\n",
+ prefix, format_timespan(buf_abort, sizeof(buf_abort), s->timeout_abort_usec, USEC_PER_SEC));
+
+ fprintf(f,
+ "%sRuntimeMaxSec: %s\n"
+ "%sWatchdogSec: %s\n",
prefix, format_timespan(buf_runtime, sizeof(buf_runtime), s->runtime_max_usec, USEC_PER_SEC),
prefix, format_timespan(buf_watchdog, sizeof(buf_watchdog), s->watchdog_usec, USEC_PER_SEC));
@@ -1132,7 +1141,6 @@ static usec_t service_coldplug_timeout(Service *s) {
return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
case SERVICE_STOP:
- case SERVICE_STOP_WATCHDOG:
case SERVICE_STOP_SIGTERM:
case SERVICE_STOP_SIGKILL:
case SERVICE_STOP_POST:
@@ -1140,6 +1148,9 @@ static usec_t service_coldplug_timeout(Service *s) {
case SERVICE_FINAL_SIGKILL:
return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
+ case SERVICE_STOP_WATCHDOG:
+ return usec_add(UNIT(s)->state_change_timestamp.monotonic, service_timeout_abort_usec(s));
+
case SERVICE_AUTO_RESTART:
return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, s->restart_usec);
@@ -1857,7 +1868,8 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
goto fail;
if (r > 0) {
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
+ r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC),
+ state == SERVICE_STOP_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec));
if (r < 0)
goto fail;
@@ -2428,7 +2440,7 @@ static int service_stop(Unit *u) {
/* Already on it */
if (IN_SET(s->state,
- SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
return 0;
@@ -2440,7 +2452,7 @@ static int service_stop(Unit *u) {
/* If there's already something running we go directly into
* kill mode. */
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD)) {
+ if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD, SERVICE_STOP_WATCHDOG)) {
service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
return 0;
}
@@ -3730,6 +3742,16 @@ static bool service_notify_message_authorized(Service *s, pid_t pid, char **tags
return true;
}
+static void service_force_watchdog(Service *s) {
+ if (!UNIT(s)->manager->service_watchdogs)
+ return;
+
+ log_unit_error(UNIT(s), "Watchdog request (last status: %s)!",
+ s->status_text ? s->status_text : "<unset>");
+
+ service_enter_signal(s, SERVICE_STOP_WATCHDOG, SERVICE_FAILURE_WATCHDOG);
+}
+
static void service_notify_message(
Unit *u,
const struct ucred *ucred,
@@ -3876,8 +3898,15 @@ static void service_notify_message(
}
/* Interpret WATCHDOG= */
- if (strv_find(tags, "WATCHDOG=1"))
- service_reset_watchdog(s);
+ e = strv_find_startswith(tags, "WATCHDOG=");
+ if (e) {
+ if (streq(e, "1"))
+ service_reset_watchdog(s);
+ else if (streq(e, "trigger"))
+ service_force_watchdog(s);
+ else
+ log_unit_warning(u, "Passed WATCHDOG= field is invalid, ignoring.");
+ }
e = strv_find_startswith(tags, "WATCHDOG_USEC=");
if (e) {
diff --git a/src/core/service.h b/src/core/service.h
index 5cc946acaf..2aebc5f09d 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -97,6 +97,8 @@ struct Service {
usec_t restart_usec;
usec_t timeout_start_usec;
usec_t timeout_stop_usec;
+ usec_t timeout_abort_usec;
+ bool timeout_abort_set;
usec_t runtime_max_usec;
dual_timestamp watchdog_timestamp;
@@ -189,6 +191,11 @@ struct Service {
OOMPolicy oom_policy;
};
+static inline usec_t service_timeout_abort_usec(Service *s) {
+ assert(s);
+ return s->timeout_abort_set ? s->timeout_abort_usec : s->timeout_stop_usec;
+}
+
extern const UnitVTable service_vtable;
int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
diff --git a/src/core/system.conf.in b/src/core/system.conf.in
index 0a58737b82..548e6dfb8c 100644
--- a/src/core/system.conf.in
+++ b/src/core/system.conf.in
@@ -35,6 +35,7 @@
#DefaultStandardError=inherit
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
+#DefaultTimeoutAbortSec=
#DefaultRestartSec=100ms
#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
diff --git a/src/core/user.conf b/src/core/user.conf
index b427f1ef6d..0b52f733ef 100644
--- a/src/core/user.conf
+++ b/src/core/user.conf
@@ -22,6 +22,7 @@
#DefaultStandardError=inherit
#DefaultTimeoutStartSec=90s
#DefaultTimeoutStopSec=90s
+#DefaultTimeoutAbortSec=
#DefaultRestartSec=100ms
#DefaultStartLimitIntervalSec=10s
#DefaultStartLimitBurst=5
diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c
index 2a960ebb3e..ee6c25541c 100644
--- a/src/journal/journald-server.c
+++ b/src/journal/journald-server.c
@@ -1421,14 +1421,13 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
- /* Let's process SIGTERM late, so that we flush all queued
- * messages to disk before we exit */
+ /* Let's process SIGTERM late, so that we flush all queued messages to disk before we exit */
r = sd_event_source_set_priority(s->sigterm_event_source, SD_EVENT_PRIORITY_NORMAL+20);
if (r < 0)
return r;
- /* When journald is invoked on the terminal (when debugging),
- * it's useful if C-c is handled equivalent to SIGTERM. */
+ /* When journald is invoked on the terminal (when debugging), it's useful if C-c is handled
+ * equivalent to SIGTERM. */
r = sd_event_add_signal(s->event, &s->sigint_event_source, SIGINT, dispatch_sigterm, s);
if (r < 0)
return r;
@@ -1437,11 +1436,9 @@ static int setup_signals(Server *s) {
if (r < 0)
return r;
- /* SIGRTMIN+1 causes an immediate sync. We process this very
- * late, so that everything else queued at this point is
- * really written to disk. Clients can watch
- * /run/systemd/journal/synced with inotify until its mtime
- * changes to see when a sync happened. */
+ /* SIGRTMIN+1 causes an immediate sync. We process this very late, so that everything else queued at
+ * this point is really written to disk. Clients can watch /run/systemd/journal/synced with inotify
+ * until its mtime changes to see when a sync happened. */
r = sd_event_add_signal(s->event, &s->sigrtmin1_event_source, SIGRTMIN+1, dispatch_sigrtmin1, s);
if (r < 0)
return r;
@@ -1759,23 +1756,17 @@ static int server_connect_notify(Server *s) {
assert(!s->notify_event_source);
/*
- So here's the problem: we'd like to send notification
- messages to PID 1, but we cannot do that via sd_notify(),
- since that's synchronous, and we might end up blocking on
- it. Specifically: given that PID 1 might block on
- dbus-daemon during IPC, and dbus-daemon is logging to us,
- and might hence block on us, we might end up in a deadlock
- if we block on sending PID 1 notification messages — by
- generating a full blocking circle. To avoid this, let's
- create a non-blocking socket, and connect it to the
- notification socket, and then wait for POLLOUT before we
- send anything. This should efficiently avoid any deadlocks,
- as we'll never block on PID 1, hence PID 1 can safely block
- on dbus-daemon which can safely block on us again.
-
- Don't think that this issue is real? It is, see:
- https://github.com/systemd/systemd/issues/1505
- */
+ * So here's the problem: we'd like to send notification messages to PID 1, but we cannot do that via
+ * sd_notify(), since that's synchronous, and we might end up blocking on it. Specifically: given
+ * that PID 1 might block on dbus-daemon during IPC, and dbus-daemon is logging to us, and might
+ * hence block on us, we might end up in a deadlock if we block on sending PID 1 notification
+ * messages — by generating a full blocking circle. To avoid this, let's create a non-blocking
+ * socket, and connect it to the notification socket, and then wait for POLLOUT before we send
+ * anything. This should efficiently avoid any deadlocks, as we'll never block on PID 1, hence PID 1
+ * can safely block on dbus-daemon which can safely block on us again.
+ *
+ * Don't think that this issue is real? It is, see: https://github.com/systemd/systemd/issues/1505
+ */
e = getenv("NOTIFY_SOCKET");
if (!e)
@@ -1807,8 +1798,7 @@ static int server_connect_notify(Server *s) {
return log_error_errno(r, "Failed to add watchdog time event: %m");
}
- /* This should fire pretty soon, which we'll use to send the
- * READY=1 event. */
+ /* This should fire pretty soon, which we'll use to send the READY=1 event. */
return 0;
}
@@ -1820,32 +1810,43 @@ int server_init(Server *s) {
assert(s);
- zero(*s);
- s->syslog_fd = s->native_fd = s->stdout_fd = s->dev_kmsg_fd = s->audit_fd = s->hostname_fd = s->notify_fd = -1;
- s->compress.enabled = true;
- s->compress.threshold_bytes = (uint64_t) -1;
- s->seal = true;
- s->read_kmsg = true;
+ *s = (Server) {
+ .syslog_fd = -1,
+ .native_fd = -1,
+ .stdout_fd = -1,
+ .dev_kmsg_fd = -1,
+ .audit_fd = -1,
+ .hostname_fd = -1,
+ .notify_fd = -1,
- s->watchdog_usec = USEC_INFINITY;
+ .compress.enabled = true,
+ .compress.threshold_bytes = (uint64_t) -1,
+ .seal = true,
+ .read_kmsg = true,
- s->sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC;
- s->sync_scheduled = false;
+ .watchdog_usec = USEC_INFINITY,
- s->rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL;
- s->rate_limit_burst = DEFAULT_RATE_LIMIT_BURST;
+ .sync_interval_usec = DEFAULT_SYNC_INTERVAL_USEC,
+ .sync_scheduled = false,
- s->forward_to_wall = true;
+ .rate_limit_interval = DEFAULT_RATE_LIMIT_INTERVAL,
+ .rate_limit_burst = DEFAULT_RATE_LIMIT_BURST,
- s->max_file_usec = DEFAULT_MAX_FILE_USEC;
+ .forward_to_wall = true,
- s->max_level_store = LOG_DEBUG;
- s->max_level_syslog = LOG_DEBUG;
- s->max_level_kmsg = LOG_NOTICE;
- s->max_level_console = LOG_INFO;
- s->max_level_wall = LOG_EMERG;
+ .max_file_usec = DEFAULT_MAX_FILE_USEC,
- s->line_max = DEFAULT_LINE_MAX;
+ .max_level_store = LOG_DEBUG,
+ .max_level_syslog = LOG_DEBUG,
+ .max_level_kmsg = LOG_NOTICE,
+ .max_level_console = LOG_INFO,
+ .max_level_wall = LOG_EMERG,
+
+ .line_max = DEFAULT_LINE_MAX,
+
+ .runtime_storage.name = "Runtime Journal",
+ .system_storage.name = "System Journal",
+ };
journal_reset_metrics(&s->system_storage.metrics);
journal_reset_metrics(&s->runtime_storage.metrics);
@@ -1996,9 +1997,6 @@ int server_init(Server *s) {
server_cache_boot_id(s);
server_cache_machine_id(s);
- s->runtime_storage.name = "Runtime journal";
- s->system_storage.name = "System journal";
-
s->runtime_storage.path = strjoin("/run/log/journal/", SERVER_MACHINE_ID(s));
s->system_storage.path = strjoin("/var/log/journal/", SERVER_MACHINE_ID(s));
if (!s->runtime_storage.path || !s->system_storage.path)
@@ -2082,8 +2080,7 @@ void server_done(Server *s) {
free(s->runtime_storage.path);
free(s->system_storage.path);
- if (s->mmap)
- mmap_cache_unref(s->mmap);
+ mmap_cache_unref(s->mmap);
}
static const char* const storage_table[_STORAGE_MAX] = {
@@ -2157,20 +2154,25 @@ int config_parse_line_max(
return 0;
}
-int config_parse_compress(const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_compress(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
JournalCompressOptions* compress = data;
int r;
- if (streq(rvalue, "1")) {
+ if (isempty(rvalue)) {
+ compress->enabled = true;
+ compress->threshold_bytes = (uint64_t) -1;
+ } else if (streq(rvalue, "1")) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Compress= ambiguously specified as 1, enabling compression with default threshold");
compress->enabled = true;
@@ -2178,15 +2180,18 @@ int config_parse_compress(const char* unit,
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Compress= ambiguously specified as 0, disabling compression");
compress->enabled = false;
- } else if ((r = parse_boolean(rvalue)) >= 0)
- compress->enabled = r;
- else if (parse_size(rvalue, 1024, &compress->threshold_bytes) == 0)
- compress->enabled = true;
- else if (isempty(rvalue)) {
- compress->enabled = true;
- compress->threshold_bytes = (uint64_t) -1;
- } else
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Compress= value, ignoring: %s", rvalue);
+ } else {
+ r = parse_boolean(rvalue);
+ if (r < 0) {
+ r = parse_size(rvalue, 1024, &compress->threshold_bytes);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse Compress= value, ignoring: %s", rvalue);
+ else
+ compress->enabled = true;
+ } else
+ compress->enabled = r;
+ }
return 0;
}
diff --git a/src/libsystemd-network/arp-util.h b/src/libsystemd-network/arp-util.h
index 10c684864b..9a4427e831 100644
--- a/src/libsystemd-network/arp-util.h
+++ b/src/libsystemd-network/arp-util.h
@@ -5,7 +5,7 @@
Copyright © 2014 Axis Communications AB. All rights reserved.
***/
-#include <netinet/if_ether.h>
+#include <net/ethernet.h>
#include "socket-util.h"
#include "sparse-endian.h"
diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym
index a6748ceb20..a9ab0605ce 100644
--- a/src/libsystemd/libsystemd.sym
+++ b/src/libsystemd/libsystemd.sym
@@ -676,3 +676,8 @@ LIBSYSTEMD_241 {
global:
sd_bus_close_unref;
} LIBSYSTEMD_240;
+
+LIBSYSTEMD_243 {
+global:
+ sd_bus_object_vtable_format;
+} LIBSYSTEMD_241;
diff --git a/src/libsystemd/sd-bus/bus-introspect.c b/src/libsystemd/sd-bus/bus-introspect.c
index 022eddb10f..beab80687d 100644
--- a/src/libsystemd/sd-bus/bus-introspect.c
+++ b/src/libsystemd/sd-bus/bus-introspect.c
@@ -172,13 +172,10 @@ int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v) {
return 0;
}
-int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply) {
- sd_bus_message *q;
+int introspect_finish(struct introspect *i, char **ret) {
int r;
assert(i);
- assert(m);
- assert(reply);
fputs("</node>\n", i->f);
@@ -186,25 +183,17 @@ int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_b
if (r < 0)
return r;
- r = sd_bus_message_new_method_return(m, &q);
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(q, "s", i->introspection);
- if (r < 0) {
- sd_bus_message_unref(q);
- return r;
- }
+ i->f = safe_fclose(i->f);
+ *ret = TAKE_PTR(i->introspection);
- *reply = q;
return 0;
}
void introspect_free(struct introspect *i) {
assert(i);
- safe_fclose(i->f);
+ /* Normally introspect_finish() does all the work, this is just a backup for error paths */
+ safe_fclose(i->f);
free(i->introspection);
- zero(*i);
}
diff --git a/src/libsystemd/sd-bus/bus-introspect.h b/src/libsystemd/sd-bus/bus-introspect.h
index bb2dd7ef7b..ccbb543d0c 100644
--- a/src/libsystemd/sd-bus/bus-introspect.h
+++ b/src/libsystemd/sd-bus/bus-introspect.h
@@ -18,5 +18,5 @@ int introspect_begin(struct introspect *i, bool trusted);
int introspect_write_default_interfaces(struct introspect *i, bool object_manager);
int introspect_write_child_nodes(struct introspect *i, Set *s, const char *prefix);
int introspect_write_interface(struct introspect *i, const sd_bus_vtable *v);
-int introspect_finish(struct introspect *i, sd_bus *bus, sd_bus_message *m, sd_bus_message **reply);
+int introspect_finish(struct introspect *i, char **ret);
void introspect_free(struct introspect *i);
diff --git a/src/libsystemd/sd-bus/bus-objects.c b/src/libsystemd/sd-bus/bus-objects.c
index d9fc25605a..fe3b9feea6 100644
--- a/src/libsystemd/sd-bus/bus-objects.c
+++ b/src/libsystemd/sd-bus/bus-objects.c
@@ -22,7 +22,7 @@ static int node_vtable_get_userdata(
sd_bus_error *error) {
sd_bus_slot *s;
- void *u, *found_u;
+ void *u, *found_u = NULL;
int r;
assert(bus);
@@ -883,31 +883,33 @@ static int bus_node_exists(
return 0;
}
-static int process_introspect(
+int introspect_path(
sd_bus *bus,
- sd_bus_message *m,
+ const char *path,
struct node *n,
bool require_fallback,
- bool *found_object) {
+ bool ignore_nodes_modified,
+ bool *found_object,
+ char **ret,
+ sd_bus_error *error) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_set_free_free_ Set *s = NULL;
const char *previous_interface = NULL;
- struct introspect intro;
+ _cleanup_(introspect_free) struct introspect intro = {};
struct node_vtable *c;
bool empty;
int r;
- assert(bus);
- assert(m);
- assert(n);
- assert(found_object);
+ if (!n) {
+ n = hashmap_get(bus->nodes, path);
+ if (!n)
+ return -ENOENT;
+ }
- r = get_child_nodes(bus, m->path, n, 0, &s, &error);
+ r = get_child_nodes(bus, path, n, 0, &s, error);
if (r < 0)
- return bus_maybe_reply_error(m, r, &error);
- if (bus->nodes_modified)
+ return r;
+ if (bus->nodes_modified && !ignore_nodes_modified)
return 0;
r = introspect_begin(&intro, bus->trusted);
@@ -924,15 +926,11 @@ static int process_introspect(
if (require_fallback && !c->is_fallback)
continue;
- r = node_vtable_get_userdata(bus, m->path, c, NULL, &error);
- if (r < 0) {
- r = bus_maybe_reply_error(m, r, &error);
- goto finish;
- }
- if (bus->nodes_modified) {
- r = 0;
- goto finish;
- }
+ r = node_vtable_get_userdata(bus, path, c, NULL, error);
+ if (r < 0)
+ return r;
+ if (bus->nodes_modified && !ignore_nodes_modified)
+ return 0;
if (r == 0)
continue;
@@ -942,7 +940,6 @@ static int process_introspect(
continue;
if (!streq_ptr(previous_interface, c->interface)) {
-
if (previous_interface)
fputs(" </interface>\n", intro.f);
@@ -951,7 +948,7 @@ static int process_introspect(
r = introspect_write_interface(&intro, c->vtable);
if (r < 0)
- goto finish;
+ return r;
previous_interface = c->interface;
}
@@ -962,36 +959,64 @@ static int process_introspect(
if (empty) {
/* Nothing?, let's see if we exist at all, and if not
* refuse to do anything */
- r = bus_node_exists(bus, n, m->path, require_fallback);
- if (r <= 0) {
- r = bus_maybe_reply_error(m, r, &error);
- goto finish;
- }
- if (bus->nodes_modified) {
- r = 0;
- goto finish;
- }
+ r = bus_node_exists(bus, n, path, require_fallback);
+ if (r <= 0)
+ return r;
+ if (bus->nodes_modified && !ignore_nodes_modified)
+ return 0;
}
- *found_object = true;
+ if (found_object)
+ *found_object = true;
- r = introspect_write_child_nodes(&intro, s, m->path);
+ r = introspect_write_child_nodes(&intro, s, path);
if (r < 0)
- goto finish;
+ return r;
- r = introspect_finish(&intro, bus, m, &reply);
+ r = introspect_finish(&intro, ret);
if (r < 0)
- goto finish;
+ return r;
- r = sd_bus_send(bus, reply, NULL);
+ return 1;
+}
+
+static int process_introspect(
+ sd_bus *bus,
+ sd_bus_message *m,
+ struct node *n,
+ bool require_fallback,
+ bool *found_object) {
+
+ _cleanup_free_ char *s = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ int r;
+
+ assert(bus);
+ assert(m);
+ assert(n);
+ assert(found_object);
+
+ r = introspect_path(bus, m->path, n, require_fallback, false, found_object, &s, &error);
if (r < 0)
- goto finish;
+ return bus_maybe_reply_error(m, r, &error);
+ if (r == 0)
+ /* nodes_modified == true */
+ return 0;
- r = 1;
+ r = sd_bus_message_new_method_return(m, &reply);
+ if (r < 0)
+ return r;
-finish:
- introspect_free(&intro);
- return r;
+ r = sd_bus_message_append(reply, "s", s);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_send(bus, reply, NULL);
+ if (r < 0)
+ return r;
+
+ return 1;
}
static int object_manager_serialize_path(
@@ -1668,7 +1693,7 @@ static bool names_are_valid(const char *signature, const char **names, names_fla
/* the current version of this struct is defined in sd-bus-vtable.h, but we need to list here the historical versions
to make sure the calling code is compatible with one of these */
-struct sd_bus_vtable_original {
+struct sd_bus_vtable_221 {
uint8_t type:8;
uint64_t flags:56;
union {
@@ -1696,12 +1721,16 @@ struct sd_bus_vtable_original {
} x;
};
/* Structure size up to v241 */
-#define VTABLE_ELEMENT_SIZE_ORIGINAL sizeof(struct sd_bus_vtable_original)
-/* Current structure size */
-#define VTABLE_ELEMENT_SIZE sizeof(struct sd_bus_vtable)
+#define VTABLE_ELEMENT_SIZE_221 sizeof(struct sd_bus_vtable_221)
+
+/* Size of the structure when "features" field was added. If the structure definition is augmented, a copy of
+ * the structure definition will need to be made (similarly to the sd_bus_vtable_221 above), and this
+ * definition updated to refer to it. */
+#define VTABLE_ELEMENT_SIZE_242 sizeof(struct sd_bus_vtable)
static int vtable_features(const sd_bus_vtable *vtable) {
- if (vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL)
+ if (vtable[0].x.start.element_size < VTABLE_ELEMENT_SIZE_242 ||
+ !vtable[0].x.start.vtable_format_reference)
return 0;
return vtable[0].x.start.features;
}
@@ -1711,13 +1740,7 @@ bool bus_vtable_has_names(const sd_bus_vtable *vtable) {
}
const sd_bus_vtable* bus_vtable_next(const sd_bus_vtable *vtable, const sd_bus_vtable *v) {
- if (vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL) {
- const struct sd_bus_vtable_original *v2 = (const struct sd_bus_vtable_original *)v;
- v2++;
- v = (const sd_bus_vtable*)v2;
- } else /* current version */
- v++;
- return v;
+ return (const sd_bus_vtable*) ((char*) v + vtable[0].x.start.element_size);
}
static int add_object_vtable_internal(
@@ -1744,8 +1767,8 @@ static int add_object_vtable_internal(
assert_return(interface_name_is_valid(interface), -EINVAL);
assert_return(vtable, -EINVAL);
assert_return(vtable[0].type == _SD_BUS_VTABLE_START, -EINVAL);
- assert_return(vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_ORIGINAL ||
- vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE,
+ assert_return(vtable[0].x.start.element_size == VTABLE_ELEMENT_SIZE_221 ||
+ vtable[0].x.start.element_size >= VTABLE_ELEMENT_SIZE_242,
-EINVAL);
assert_return(!bus_pid_changed(bus), -ECHILD);
assert_return(!streq(interface, "org.freedesktop.DBus.Properties") &&
@@ -1928,6 +1951,9 @@ fail:
return r;
}
+/* This symbol exists solely to tell the linker that the "new" vtable format is used. */
+_public_ const unsigned sd_bus_object_vtable_format = 242;
+
_public_ int sd_bus_add_object_vtable(
sd_bus *bus,
sd_bus_slot **slot,
diff --git a/src/libsystemd/sd-bus/bus-objects.h b/src/libsystemd/sd-bus/bus-objects.h
index b45fe6323e..f650196a54 100644
--- a/src/libsystemd/sd-bus/bus-objects.h
+++ b/src/libsystemd/sd-bus/bus-objects.h
@@ -2,8 +2,19 @@
#pragma once
#include "bus-internal.h"
+#include "bus-introspect.h"
const sd_bus_vtable* bus_vtable_next(const sd_bus_vtable *vtable, const sd_bus_vtable *v);
bool bus_vtable_has_names(const sd_bus_vtable *vtable);
int bus_process_object(sd_bus *bus, sd_bus_message *m);
void bus_node_gc(sd_bus *b, struct node *n);
+
+int introspect_path(
+ sd_bus *bus,
+ const char *path,
+ struct node *n,
+ bool require_fallback,
+ bool ignore_nodes_modified,
+ bool *found_object,
+ char **ret,
+ sd_bus_error *error);
diff --git a/src/libsystemd/sd-bus/test-bus-introspect.c b/src/libsystemd/sd-bus/test-bus-introspect.c
index 9c8e93e897..9c8d1434b1 100644
--- a/src/libsystemd/sd-bus/test-bus-introspect.c
+++ b/src/libsystemd/sd-bus/test-bus-introspect.c
@@ -4,33 +4,13 @@
#include "log.h"
#include "tests.h"
-static int prop_get(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return -EINVAL;
-}
-
-static int prop_set(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return -EINVAL;
-}
+#include "test-vtable-data.h"
-static const sd_bus_vtable vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0),
- SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED),
- SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY),
- SD_BUS_SIGNAL("Wowza", "sss", 0),
- SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
- SD_BUS_WRITABLE_PROPERTY("AProperty", "s", prop_get, prop_set, 0, 0),
- SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", prop_get, 0, SD_BUS_VTABLE_DEPRECATED),
- SD_BUS_PROPERTY("ChangingProperty", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Invalidating", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_PROPERTY("Constant", "t", prop_get, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EXPLICIT),
- SD_BUS_VTABLE_END
-};
-
-int main(int argc, char *argv[]) {
- struct introspect intro;
+static void test_manual_introspection(const sd_bus_vtable vtable[]) {
+ struct introspect intro = {};
+ _cleanup_free_ char *s = NULL;
- test_setup_logging(LOG_DEBUG);
+ log_info("/* %s */", __func__);
assert_se(introspect_begin(&intro, false) >= 0);
@@ -38,10 +18,18 @@ int main(int argc, char *argv[]) {
assert_se(introspect_write_interface(&intro, vtable) >= 0);
fputs(" </interface>\n", intro.f);
- fflush(intro.f);
- fputs(intro.introspection, stdout);
+ assert_se(introspect_finish(&intro, &s) == 0);
+ fputs(s, stdout);
+ fputs("\n", stdout);
+}
+
+int main(int argc, char *argv[]) {
+ test_setup_logging(LOG_DEBUG);
- introspect_free(&intro);
+ test_manual_introspection(test_vtable_1);
+ test_manual_introspection(test_vtable_2);
+ test_manual_introspection(test_vtable_deprecated);
+ test_manual_introspection((const sd_bus_vtable *) vtable_format_221);
return 0;
}
diff --git a/src/libsystemd/sd-bus/test-bus-vtable.c b/src/libsystemd/sd-bus/test-bus-vtable.c
index b278094fad..d69ca6ac97 100644
--- a/src/libsystemd/sd-bus/test-bus-vtable.c
+++ b/src/libsystemd/sd-bus/test-bus-vtable.c
@@ -1,3 +1,5 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
#include <stdbool.h>
#include <stddef.h>
@@ -5,119 +7,17 @@
#undef NDEBUG
#include <assert.h>
#include <errno.h>
+#include <stdio.h>
#include "sd-bus-vtable.h"
-#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
-
-struct context {
- bool quit;
- char *something;
- char *automatic_string_property;
- uint32_t automatic_integer_property;
-};
-
-static int handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- return 1;
-}
-
-static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return 1;
-}
+#ifndef __cplusplus
+# include "bus-objects.h"
+#endif
-static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
- return 1;
-}
+#include "test-vtable-data.h"
-static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
- return 1;
-}
-
-static const sd_bus_vtable vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("AlterSomething", "s", "s", handler, 0),
- SD_BUS_METHOD("Exit", "", "", handler, 0),
- SD_BUS_METHOD_WITH_OFFSET("AlterSomething2", "s", "s", handler, 200, 0),
- SD_BUS_METHOD_WITH_OFFSET("Exit2", "", "", handler, 200, 0),
- SD_BUS_METHOD_WITH_NAMES_OFFSET("AlterSomething3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
- "s", SD_BUS_PARAM(returnstring), handler, 200, 0),
- SD_BUS_METHOD_WITH_NAMES("Exit3", "bx", SD_BUS_PARAM(with_confirmation) SD_BUS_PARAM(after_msec),
- "bb", SD_BUS_PARAM(accepted) SD_BUS_PARAM(scheduled), handler, 0),
- SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
- SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL, offsetof(struct context, something),
- SD_BUS_VTABLE_PROPERTY_EXPLICIT|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
- SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL,
- offsetof(struct context, automatic_string_property), 0),
- SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL,
- offsetof(struct context, automatic_integer_property), 0),
- SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
- SD_BUS_SIGNAL("DummySignal", "b", 0),
- SD_BUS_SIGNAL("DummySignal2", "so", 0),
- SD_BUS_SIGNAL_WITH_NAMES("DummySignal3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path), 0),
- SD_BUS_VTABLE_END
-};
-
-struct sd_bus_vtable_original {
- uint8_t type:8;
- uint64_t flags:56;
- union {
- struct {
- size_t element_size;
- } start;
- struct {
- const char *member;
- const char *signature;
- const char *result;
- sd_bus_message_handler_t handler;
- size_t offset;
- } method;
- struct {
- const char *member;
- const char *signature;
- } signal;
- struct {
- const char *member;
- const char *signature;
- sd_bus_property_get_t get;
- sd_bus_property_set_t set;
- size_t offset;
- } property;
- } x;
-};
-
-static const struct sd_bus_vtable_original vtable_format_original[] = {
- {
- .type = _SD_BUS_VTABLE_START,
- .flags = 0,
- .x = {
- .start = {
- .element_size = sizeof(struct sd_bus_vtable_original)
- },
- },
- },
- {
- .type = _SD_BUS_VTABLE_METHOD,
- .flags = 0,
- .x = {
- .method = {
- .member = "Exit",
- .signature = "",
- .result = "",
- .handler = handler,
- .offset = 0,
- },
- },
- },
- {
- .type = _SD_BUS_VTABLE_END,
- .flags = 0,
- .x = { { 0 } },
- }
-};
+#define DEFAULT_BUS_PATH "unix:path=/run/dbus/system_bus_socket"
static void test_vtable(void) {
sd_bus *bus = NULL;
@@ -126,16 +26,24 @@ static void test_vtable(void) {
assert(sd_bus_new(&bus) >= 0);
- assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable", vtable, &c) >= 0);
- assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable2", vtable, &c) >= 0);
+ assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable", test_vtable_2, &c) >= 0);
+ assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable2", test_vtable_2, &c) >= 0);
/* the cast on the line below is needed to test with the old version of the table */
- assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtableOriginal", (const sd_bus_vtable *)vtable_format_original, &c) >= 0);
+ assert(sd_bus_add_object_vtable(bus, NULL, "/foo", "org.freedesktop.systemd.testVtable221",
+ (const sd_bus_vtable *)vtable_format_221, &c) >= 0);
assert(sd_bus_set_address(bus, DEFAULT_BUS_PATH) >= 0);
r = sd_bus_start(bus);
assert(r == 0 || /* success */
r == -ENOENT /* dbus is inactive */ );
+#ifndef __cplusplus
+ _cleanup_free_ char *s = NULL;
+
+ assert_se(introspect_path(bus, "/foo", NULL, false, true, NULL, &s, NULL) == 1);
+ fputs(s, stdout);
+#endif
+
sd_bus_unref(bus);
}
diff --git a/src/libsystemd/sd-bus/test-vtable-data.h b/src/libsystemd/sd-bus/test-vtable-data.h
new file mode 100644
index 0000000000..333dbd5b12
--- /dev/null
+++ b/src/libsystemd/sd-bus/test-vtable-data.h
@@ -0,0 +1,132 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+/* This is meant to be included in other files, hence no headers */
+
+struct context {
+ bool quit;
+ char *something;
+ char *automatic_string_property;
+ uint32_t automatic_integer_property;
+};
+
+static int handler(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static int value_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static int get_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static int set_handler(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *value, void *userdata, sd_bus_error *error) {
+ return 1;
+}
+
+static const sd_bus_vtable test_vtable_1[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("Hello", "ssas", "a(uu)", NULL, 0),
+ SD_BUS_METHOD("DeprecatedHello", "", "", NULL, SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_METHOD("DeprecatedHelloNoReply", "", "", NULL, SD_BUS_VTABLE_DEPRECATED|SD_BUS_VTABLE_METHOD_NO_REPLY),
+ SD_BUS_SIGNAL("Wowza", "sss", 0),
+ SD_BUS_SIGNAL("DeprecatedWowza", "ut", SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_WRITABLE_PROPERTY("AProperty", "s", get_handler, set_handler, 0, 0),
+ SD_BUS_PROPERTY("AReadOnlyDeprecatedProperty", "(ut)", get_handler, 0, SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_PROPERTY("ChangingProperty", "t", get_handler, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Invalidating", "t", get_handler, 0, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_PROPERTY("Constant", "t", get_handler, 0, SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_PROPERTY_EXPLICIT),
+ SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable test_vtable_2[] = {
+ SD_BUS_VTABLE_START(0),
+ SD_BUS_METHOD("AlterSomething", "s", "s", handler, 0),
+ SD_BUS_METHOD("Exit", "", "", handler, 0),
+ SD_BUS_METHOD_WITH_OFFSET("AlterSomething2", "s", "s", handler, 200, 0),
+ SD_BUS_METHOD_WITH_OFFSET("Exit2", "", "", handler, 200, 0),
+ SD_BUS_METHOD_WITH_NAMES_OFFSET("AlterSomething3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path),
+ "s", SD_BUS_PARAM(returnstring), handler, 200, 0),
+ SD_BUS_METHOD_WITH_NAMES("Exit3", "bx", SD_BUS_PARAM(with_confirmation) SD_BUS_PARAM(after_msec),
+ "bb", SD_BUS_PARAM(accepted) SD_BUS_PARAM(scheduled), handler, 0),
+ SD_BUS_PROPERTY("Value", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
+ SD_BUS_PROPERTY("Value2", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_PROPERTY("Value3", "s", value_handler, 10, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("Value4", "s", value_handler, 10, 0),
+ SD_BUS_PROPERTY("AnExplicitProperty", "s", NULL, offsetof(struct context, something),
+ SD_BUS_VTABLE_PROPERTY_EXPLICIT|SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
+ SD_BUS_WRITABLE_PROPERTY("Something", "s", get_handler, set_handler, 0, 0),
+ SD_BUS_WRITABLE_PROPERTY("AutomaticStringProperty", "s", NULL, NULL,
+ offsetof(struct context, automatic_string_property), 0),
+ SD_BUS_WRITABLE_PROPERTY("AutomaticIntegerProperty", "u", NULL, NULL,
+ offsetof(struct context, automatic_integer_property), 0),
+ SD_BUS_METHOD("NoOperation", NULL, NULL, NULL, 0),
+ SD_BUS_SIGNAL("DummySignal", "b", 0),
+ SD_BUS_SIGNAL("DummySignal2", "so", 0),
+ SD_BUS_SIGNAL_WITH_NAMES("DummySignal3", "so", SD_BUS_PARAM(string) SD_BUS_PARAM(path), 0),
+ SD_BUS_VTABLE_END
+};
+
+static const sd_bus_vtable test_vtable_deprecated[] = {
+ SD_BUS_VTABLE_START(SD_BUS_VTABLE_DEPRECATED),
+ SD_BUS_VTABLE_END
+};
+
+struct sd_bus_vtable_221 {
+ uint8_t type:8;
+ uint64_t flags:56;
+ union {
+ struct {
+ size_t element_size;
+ } start;
+ struct {
+ const char *member;
+ const char *signature;
+ const char *result;
+ sd_bus_message_handler_t handler;
+ size_t offset;
+ } method;
+ struct {
+ const char *member;
+ const char *signature;
+ } signal;
+ struct {
+ const char *member;
+ const char *signature;
+ sd_bus_property_get_t get;
+ sd_bus_property_set_t set;
+ size_t offset;
+ } property;
+ } x;
+};
+
+static const struct sd_bus_vtable_221 vtable_format_221[] = {
+ {
+ .type = _SD_BUS_VTABLE_START,
+ .flags = 0,
+ .x = {
+ .start = {
+ .element_size = sizeof(struct sd_bus_vtable_221)
+ },
+ },
+ },
+ {
+ .type = _SD_BUS_VTABLE_METHOD,
+ .flags = 0,
+ .x = {
+ .method = {
+ .member = "Exit",
+ .signature = "",
+ .result = "",
+ .handler = handler,
+ .offset = 0,
+ },
+ },
+ },
+ {
+ .type = _SD_BUS_VTABLE_END,
+ .flags = 0,
+ .x = { { 0 } },
+ }
+};
diff --git a/src/libsystemd/sd-netlink/generic-netlink.c b/src/libsystemd/sd-netlink/generic-netlink.c
index 473d8670a9..5467f62ffa 100644
--- a/src/libsystemd/sd-netlink/generic-netlink.c
+++ b/src/libsystemd/sd-netlink/generic-netlink.c
@@ -10,11 +10,11 @@ typedef struct {
} genl_family;
static const genl_family genl_families[] = {
- [SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
+ [SD_GENL_ID_CTRL] = { .name = "", .version = 1 },
[SD_GENL_WIREGUARD] = { .name = "wireguard", .version = 1 },
- [SD_GENL_FOU] = { .name = "fou", .version = 1 },
- [SD_GENL_L2TP] = { .name = "l2tp", .version = 1},
- [SD_GENL_MACSEC] = { .name = "macsec", .version = 1},
+ [SD_GENL_FOU] = { .name = "fou", .version = 1 },
+ [SD_GENL_L2TP] = { .name = "l2tp", .version = 1 },
+ [SD_GENL_MACSEC] = { .name = "macsec", .version = 1 },
};
int sd_genl_socket_open(sd_netlink **ret) {
diff --git a/src/network/netdev/bond.c b/src/network/netdev/bond.c
index 7d912ae5a7..166aa37139 100644
--- a/src/network/netdev/bond.c
+++ b/src/network/netdev/bond.c
@@ -1,16 +1,12 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-#include <netinet/ether.h>
-#include <linux/if_bonding.h>
-
#include "sd-netlink.h"
#include "alloc-util.h"
+#include "bond.h"
#include "conf-parser.h"
#include "ether-addr-util.h"
#include "extract-word.h"
-#include "missing.h"
-#include "netdev/bond.h"
#include "string-table.h"
#include "string-util.h"
@@ -125,48 +121,9 @@ static const char *const bond_primary_reselect_table[_NETDEV_BOND_PRIMARY_RESELE
DEFINE_STRING_TABLE_LOOKUP(bond_primary_reselect, BondPrimaryReselect);
DEFINE_CONFIG_PARSE_ENUM(config_parse_bond_primary_reselect, bond_primary_reselect, BondPrimaryReselect, "Failed to parse bond primary reselect");
-static uint8_t bond_mode_to_kernel(BondMode mode) {
- switch (mode) {
- case NETDEV_BOND_MODE_BALANCE_RR:
- return BOND_MODE_ROUNDROBIN;
- case NETDEV_BOND_MODE_ACTIVE_BACKUP:
- return BOND_MODE_ACTIVEBACKUP;
- case NETDEV_BOND_MODE_BALANCE_XOR:
- return BOND_MODE_XOR;
- case NETDEV_BOND_MODE_BROADCAST:
- return BOND_MODE_BROADCAST;
- case NETDEV_BOND_MODE_802_3AD:
- return BOND_MODE_8023AD;
- case NETDEV_BOND_MODE_BALANCE_TLB:
- return BOND_MODE_TLB;
- case NETDEV_BOND_MODE_BALANCE_ALB:
- return BOND_MODE_ALB;
- default:
- return (uint8_t) -1;
- }
-}
-
-static uint8_t bond_xmit_hash_policy_to_kernel(BondXmitHashPolicy policy) {
- switch (policy) {
- case NETDEV_BOND_XMIT_HASH_POLICY_LAYER2:
- return BOND_XMIT_POLICY_LAYER2;
- case NETDEV_BOND_XMIT_HASH_POLICY_LAYER34:
- return BOND_XMIT_POLICY_LAYER34;
- case NETDEV_BOND_XMIT_HASH_POLICY_LAYER23:
- return BOND_XMIT_POLICY_LAYER23;
- case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23:
- return BOND_XMIT_POLICY_ENCAP23;
- case NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34:
- return BOND_XMIT_POLICY_ENCAP34;
- default:
- return (uint8_t) -1;
- }
-}
-
static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
Bond *b;
- ArpIpTarget *target = NULL;
- int r, i = 0;
+ int r;
assert(netdev);
assert(!link);
@@ -177,14 +134,13 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
assert(b);
if (b->mode != _NETDEV_BOND_MODE_INVALID) {
- r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, bond_mode_to_kernel(b->mode));
+ r = sd_netlink_message_append_u8(m, IFLA_BOND_MODE, b->mode);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_MODE attribute: %m");
}
if (b->xmit_hash_policy != _NETDEV_BOND_XMIT_HASH_POLICY_INVALID) {
- r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY,
- bond_xmit_hash_policy_to_kernel(b->xmit_hash_policy));
+ r = sd_netlink_message_append_u8(m, IFLA_BOND_XMIT_HASH_POLICY, b->xmit_hash_policy);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_XMIT_HASH_POLICY attribute: %m");
}
@@ -296,8 +252,8 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_USER_PORT_KEY attribute: %m");
}
- if (b->ad_actor_system) {
- r = sd_netlink_message_append_ether_addr(m, IFLA_BOND_AD_ACTOR_SYSTEM, b->ad_actor_system);
+ if (!ether_addr_is_null(&b->ad_actor_system)) {
+ r = sd_netlink_message_append_ether_addr(m, IFLA_BOND_AD_ACTOR_SYSTEM, &b->ad_actor_system);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_AD_ACTOR_SYSTEM attribute: %m");
}
@@ -312,13 +268,17 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_TLB_DYNAMIC_LB attribute: %m");
}
- if (b->arp_interval > 0 && b->n_arp_ip_targets > 0) {
+ if (b->arp_interval > 0 && !ordered_set_isempty(b->arp_ip_targets)) {
+ Iterator i;
+ void *val;
+ int n = 0;
+
r = sd_netlink_message_open_container(m, IFLA_BOND_ARP_IP_TARGET);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not open contaniner IFLA_BOND_ARP_IP_TARGET : %m");
- LIST_FOREACH(arp_ip_target, target, b->arp_ip_targets) {
- r = sd_netlink_message_append_u32(m, i++, target->ip.in.s_addr);
+ ORDERED_SET_FOREACH(val, b->arp_ip_targets, i) {
+ r = sd_netlink_message_append_u32(m, n++, PTR_TO_UINT32(val));
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BOND_ARP_ALL_TARGETS attribute: %m");
}
@@ -331,16 +291,18 @@ static int netdev_bond_fill_message_create(NetDev *netdev, Link *link, sd_netlin
return 0;
}
-int config_parse_arp_ip_target_address(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_arp_ip_target_address(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
Bond *b = userdata;
int r;
@@ -349,57 +311,64 @@ int config_parse_arp_ip_target_address(const char *unit,
assert(rvalue);
assert(data);
+ if (isempty(rvalue)) {
+ b->arp_ip_targets = ordered_set_free(b->arp_ip_targets);
+ return 0;
+ }
+
for (;;) {
- _cleanup_free_ ArpIpTarget *buffer = NULL;
_cleanup_free_ char *n = NULL;
- int f;
+ union in_addr_union ip;
r = extract_first_word(&rvalue, &n, NULL, 0);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse Bond ARP ip target address, ignoring assignment: %s", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse Bond ARP ip target address, ignoring assignment: %s",
+ rvalue);
return 0;
}
-
if (r == 0)
- break;
-
- buffer = new0(ArpIpTarget, 1);
- if (!buffer)
- return -ENOMEM;
+ return 0;
- r = in_addr_from_string_auto(n, &f, &buffer->ip);
+ r = in_addr_from_string(AF_INET, n, &ip);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
- return 0;
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
+ continue;
}
- if (f != AF_INET) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Bond ARP ip target address is invalid, ignoring assignment: %s", n);
- return 0;
+ r = ordered_set_ensure_allocated(&b->arp_ip_targets, NULL);
+ if (r < 0)
+ return log_oom();
+
+ if (ordered_set_size(b->arp_ip_targets) >= NETDEV_BOND_ARP_TARGETS_MAX) {
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Too many ARP ip targets are specified. The maximum number is %d. Ignoring assignment: %s",
+ NETDEV_BOND_ARP_TARGETS_MAX, n);
+ continue;
}
- LIST_PREPEND(arp_ip_target, b->arp_ip_targets, TAKE_PTR(buffer));
- b->n_arp_ip_targets++;
+ r = ordered_set_put(b->arp_ip_targets, UINT32_TO_PTR(ip.in.s_addr));
+ if (r == -EEXIST)
+ log_syntax(unit, LOG_WARNING, filename, line, r,
+ "Bond ARP ip target address is duplicated, ignoring assignment: %s", n);
+ if (r < 0)
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to store bond ARP ip target address '%s', ignoring assignment: %m", n);
}
-
- if (b->n_arp_ip_targets > NETDEV_BOND_ARP_TARGETS_MAX)
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "More than the maximum number of kernel-supported ARP ip targets specified: %d > %d",
- b->n_arp_ip_targets, NETDEV_BOND_ARP_TARGETS_MAX);
-
- return 0;
}
-int config_parse_ad_actor_sys_prio(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_ad_actor_sys_prio(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Bond *b = userdata;
uint16_t v;
int r;
@@ -411,12 +380,15 @@ int config_parse_ad_actor_sys_prio(const char *unit,
r = safe_atou16(rvalue, &v);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse actor system priority '%s', ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse actor system priority '%s', ignoring: %m", rvalue);
return 0;
}
if (v == 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse actor system priority '%s'. Range is [1,65535], ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse actor system priority '%s'. Range is [1,65535], ignoring.",
+ rvalue);
return 0;
}
@@ -425,16 +397,17 @@ int config_parse_ad_actor_sys_prio(const char *unit,
return 0;
}
-int config_parse_ad_user_port_key(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_ad_user_port_key(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Bond *b = userdata;
uint16_t v;
int r;
@@ -446,12 +419,14 @@ int config_parse_ad_user_port_key(const char *unit,
r = safe_atou16(rvalue, &v);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse user port key '%s', ignoring: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Failed to parse user port key '%s', ignoring: %m", rvalue);
return 0;
}
if (v > 1023) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse user port key '%s'. Range is [0,1023], ignoring.", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Failed to parse user port key '%s'. Range is [0…1023], ignoring.", rvalue);
return 0;
}
@@ -460,18 +435,19 @@ int config_parse_ad_user_port_key(const char *unit,
return 0;
}
-int config_parse_ad_actor_system(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_ad_actor_system(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
Bond *b = userdata;
- _cleanup_free_ struct ether_addr *n = NULL;
+ struct ether_addr n;
int r;
assert(filename);
@@ -479,42 +455,33 @@ int config_parse_ad_actor_system(const char *unit,
assert(rvalue);
assert(data);
- n = new0(struct ether_addr, 1);
- if (!n)
- return log_oom();
-
- r = ether_addr_from_string(rvalue, n);
+ r = ether_addr_from_string(rvalue, &n);
if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Not a valid MAC address %s. Ignoring assignment: %m", rvalue);
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Not a valid MAC address %s. Ignoring assignment: %m",
+ rvalue);
return 0;
}
-
- if (ether_addr_is_null(n) || (n->ether_addr_octet[0] & 0x01)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not a valid MAC address %s, can not be null or multicast. Ignoring assignment.", rvalue);
+ if (ether_addr_is_null(&n) || (n.ether_addr_octet[0] & 0x01)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0,
+ "Not a valid MAC address %s, can not be null or multicast. Ignoring assignment.",
+ rvalue);
return 0;
}
- free_and_replace(b->ad_actor_system, n);
+ b->ad_actor_system = n;
return 0;
}
static void bond_done(NetDev *netdev) {
- ArpIpTarget *t = NULL, *n = NULL;
Bond *b;
assert(netdev);
-
b = BOND(netdev);
-
assert(b);
- free(b->ad_actor_system);
-
- LIST_FOREACH_SAFE(arp_ip_target, t, n, b->arp_ip_targets)
- free(t);
-
- b->arp_ip_targets = NULL;
+ ordered_set_free(b->arp_ip_targets);
}
static void bond_init(NetDev *netdev) {
@@ -542,9 +509,6 @@ static void bond_init(NetDev *netdev) {
b->packets_per_slave = PACKETS_PER_SLAVE_DEFAULT;
b->num_grat_arp = GRATUITOUS_ARP_DEFAULT;
b->lp_interval = LEARNING_PACKETS_INTERVAL_MIN_SEC;
-
- LIST_HEAD_INIT(b->arp_ip_targets);
- b->n_arp_ip_targets = 0;
}
const NetDevVTable bond_vtable = {
diff --git a/src/network/netdev/bond.h b/src/network/netdev/bond.h
index 31b922b032..12f59cd946 100644
--- a/src/network/netdev/bond.h
+++ b/src/network/netdev/bond.h
@@ -1,10 +1,11 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include "in-addr-util.h"
-#include "list.h"
+#include <linux/if_bonding.h>
-#include "netdev/netdev.h"
+#include "in-addr-util.h"
+#include "netdev.h"
+#include "ordered-set.h"
/*
* Maximum number of targets supported by the kernel for a single
@@ -13,23 +14,23 @@
#define NETDEV_BOND_ARP_TARGETS_MAX 16
typedef enum BondMode {
- NETDEV_BOND_MODE_BALANCE_RR,
- NETDEV_BOND_MODE_ACTIVE_BACKUP,
- NETDEV_BOND_MODE_BALANCE_XOR,
- NETDEV_BOND_MODE_BROADCAST,
- NETDEV_BOND_MODE_802_3AD,
- NETDEV_BOND_MODE_BALANCE_TLB,
- NETDEV_BOND_MODE_BALANCE_ALB,
+ NETDEV_BOND_MODE_BALANCE_RR = BOND_MODE_ROUNDROBIN,
+ NETDEV_BOND_MODE_ACTIVE_BACKUP = BOND_MODE_ACTIVEBACKUP,
+ NETDEV_BOND_MODE_BALANCE_XOR = BOND_MODE_XOR,
+ NETDEV_BOND_MODE_BROADCAST = BOND_MODE_BROADCAST,
+ NETDEV_BOND_MODE_802_3AD = BOND_MODE_8023AD,
+ NETDEV_BOND_MODE_BALANCE_TLB = BOND_MODE_TLB,
+ NETDEV_BOND_MODE_BALANCE_ALB = BOND_MODE_ALB,
_NETDEV_BOND_MODE_MAX,
- _NETDEV_BOND_MODE_INVALID = -1
+ _NETDEV_BOND_MODE_INVALID = -1
} BondMode;
typedef enum BondXmitHashPolicy {
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER2,
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER34,
- NETDEV_BOND_XMIT_HASH_POLICY_LAYER23,
- NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23,
- NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER2 = BOND_XMIT_POLICY_LAYER2,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER34 = BOND_XMIT_POLICY_LAYER34,
+ NETDEV_BOND_XMIT_HASH_POLICY_LAYER23 = BOND_XMIT_POLICY_LAYER23,
+ NETDEV_BOND_XMIT_HASH_POLICY_ENCAP23 = BOND_XMIT_POLICY_ENCAP23,
+ NETDEV_BOND_XMIT_HASH_POLICY_ENCAP34 = BOND_XMIT_POLICY_ENCAP34,
_NETDEV_BOND_XMIT_HASH_POLICY_MAX,
_NETDEV_BOND_XMIT_HASH_POLICY_INVALID = -1
} BondXmitHashPolicy;
@@ -81,12 +82,6 @@ typedef enum BondPrimaryReselect {
_NETDEV_BOND_PRIMARY_RESELECT_INVALID = -1,
} BondPrimaryReselect;
-typedef struct ArpIpTarget {
- union in_addr_union ip;
-
- LIST_FIELDS(struct ArpIpTarget, arp_ip_target);
-} ArpIpTarget;
-
typedef struct Bond {
NetDev meta;
@@ -110,7 +105,7 @@ typedef struct Bond {
uint16_t ad_actor_sys_prio;
uint16_t ad_user_port_key;
- struct ether_addr *ad_actor_system;
+ struct ether_addr ad_actor_system;
usec_t miimon;
usec_t updelay;
@@ -118,8 +113,7 @@ typedef struct Bond {
usec_t arp_interval;
usec_t lp_interval;
- int n_arp_ip_targets;
- ArpIpTarget *arp_ip_targets;
+ OrderedSet *arp_ip_targets;
} Bond;
DEFINE_NETDEV_CAST(BOND, Bond);
diff --git a/src/network/netdev/macsec.c b/src/network/netdev/macsec.c
index 15b5378f30..ccc37cded4 100644
--- a/src/network/netdev/macsec.c
+++ b/src/network/netdev/macsec.c
@@ -563,7 +563,7 @@ int config_parse_macsec_port(
_cleanup_(macsec_receive_channel_free_or_set_invalidp) ReceiveChannel *c = NULL;
MACsec *s = userdata;
uint16_t port;
- be16_t *dest;
+ void *dest;
int r;
assert(filename);
@@ -600,7 +600,7 @@ int config_parse_macsec_port(
return 0;
}
- *dest = htobe16(port);
+ unaligned_write_be16(dest, port);
TAKE_PTR(b);
TAKE_PTR(c);
diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c
index e138393514..d8b8bca7e8 100644
--- a/src/network/netdev/netdev.c
+++ b/src/network/netdev/netdev.c
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#include <net/if.h>
+#include <netinet/in.h>
#include "alloc-util.h"
#include "conf-files.h"
diff --git a/src/network/netdev/wireguard.c b/src/network/netdev/wireguard.c
index f3084c0773..5ebc5dfed8 100644
--- a/src/network/netdev/wireguard.c
+++ b/src/network/netdev/wireguard.c
@@ -452,22 +452,23 @@ int config_parse_wireguard_listen_port(
void *userdata) {
uint16_t *s = data;
- uint16_t port = 0;
int r;
assert(rvalue);
assert(data);
- if (!streq(rvalue, "auto")) {
- r = parse_ip_port(rvalue, s);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Invalid port specification, ignoring assignment: %s", rvalue);
- return 0;
- }
+ if (isempty(rvalue) || streq(rvalue, "auto")) {
+ *s = 0;
+ return 0;
+ }
+
+ r = parse_ip_port(rvalue, s);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Invalid port specification, ignoring assignment: %s", rvalue);
+ return 0;
}
- *s = port;
return 0;
}
diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c
index 4846b13a8b..d3928e2862 100644
--- a/src/network/networkd-link.c
+++ b/src/network/networkd-link.c
@@ -409,7 +409,7 @@ void link_update_operstate(Link *link, bool also_update_master) {
if (operstate >= LINK_OPERSTATE_CARRIER) {
Link *slave;
- HASHMAP_FOREACH(slave, link->slaves, i) {
+ SET_FOREACH(slave, link->slaves, i) {
link_update_operstate(slave, false);
if (slave->operstate < LINK_OPERSTATE_CARRIER)
@@ -605,17 +605,8 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
return 0;
}
-static void link_detach_from_manager(Link *link) {
- if (!link || !link->manager)
- return;
-
- hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
- set_remove(link->manager->links_requesting_uuid, link);
- link_clean(link);
-}
-
static Link *link_free(Link *link) {
- Link *carrier, *master;
+ Link *carrier;
Address *address;
Route *route;
Iterator i;
@@ -663,10 +654,7 @@ static Link *link_free(Link *link) {
sd_ndisc_unref(link->ndisc);
sd_radv_unref(link->radv);
- link_detach_from_manager(link);
-
free(link->ifname);
-
free(link->kind);
(void) unlink(link->state_file);
@@ -682,17 +670,7 @@ static Link *link_free(Link *link) {
hashmap_remove(link->bound_by_links, INT_TO_PTR(carrier->ifindex));
hashmap_free(link->bound_by_links);
- hashmap_free(link->slaves);
-
- if (link->network) {
- if (link->network->bond &&
- link_get(link->manager, link->network->bond->ifindex, &master) >= 0)
- (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex));
-
- if (link->network->bridge &&
- link_get(link->manager, link->network->bridge->ifindex, &master) >= 0)
- (void) hashmap_remove(master->slaves, INT_TO_PTR(link->ifindex));
- }
+ set_free_with_destructor(link->slaves, link_unref);
return mfree(link);
}
@@ -721,6 +699,10 @@ static void link_set_state(Link *link, LinkState state) {
if (link->state == state)
return;
+ log_link_debug(link, "State changed: %s -> %s",
+ link_state_to_string(link->state),
+ link_state_to_string(state));
+
link->state = state;
link_send_changed(link, "AdministrativeState", NULL);
@@ -1451,7 +1433,7 @@ static int set_mtu_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
log_link_debug(link, "Setting MTU done.");
- if (link->state == LINK_STATE_PENDING)
+ if (link->state == LINK_STATE_INITIALIZED)
(void) link_configure_after_setting_mtu(link);
return 1;
@@ -1747,28 +1729,6 @@ static int link_set_bond(Link *link) {
return r;
}
-static int link_append_to_master(Link *link, NetDev *netdev) {
- Link *master;
- int r;
-
- assert(link);
- assert(netdev);
-
- r = link_get(link->manager, netdev->ifindex, &master);
- if (r < 0)
- return r;
-
- r = hashmap_ensure_allocated(&master->slaves, NULL);
- if (r < 0)
- return r;
-
- r = hashmap_put(master->slaves, INT_TO_PTR(link->ifindex), link);
- if (r < 0)
- return r;
-
- return 0;
-}
-
static int link_lldp_save(Link *link) {
_cleanup_free_ char *temp_path = NULL;
_cleanup_fclose_ FILE *f = NULL;
@@ -2531,6 +2491,55 @@ static void link_free_carrier_maps(Link *link) {
return;
}
+static int link_append_to_master(Link *link, NetDev *netdev) {
+ Link *master;
+ int r;
+
+ assert(link);
+ assert(netdev);
+
+ r = link_get(link->manager, netdev->ifindex, &master);
+ if (r < 0)
+ return r;
+
+ r = set_ensure_allocated(&master->slaves, NULL);
+ if (r < 0)
+ return r;
+
+ r = set_put(master->slaves, link);
+ if (r < 0)
+ return r;
+
+ link_ref(link);
+ return 0;
+}
+
+static void link_drop_from_master(Link *link, NetDev *netdev) {
+ Link *master;
+
+ assert(link);
+
+ if (!link->manager || !netdev)
+ return;
+
+ if (link_get(link->manager, netdev->ifindex, &master) < 0)
+ return;
+
+ link_unref(set_remove(master->slaves, link));
+}
+
+static void link_detach_from_manager(Link *link) {
+ if (!link || !link->manager)
+ return;
+
+ link_unref(set_remove(link->manager->links_requesting_uuid, link));
+ link_clean(link);
+
+ /* The following must be called at last. */
+ assert_se(hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex)) == link);
+ link_unref(link);
+}
+
void link_drop(Link *link) {
if (!link || link->state == LINK_STATE_LINGER)
return;
@@ -2539,15 +2548,15 @@ void link_drop(Link *link) {
link_free_carrier_maps(link);
+ if (link->network) {
+ link_drop_from_master(link, link->network->bridge);
+ link_drop_from_master(link, link->network->bond);
+ }
+
log_link_debug(link, "Link removed");
(void) unlink(link->state_file);
-
link_detach_from_manager(link);
-
- link_unref(link);
-
- return;
}
static int link_joined(Link *link) {
@@ -2640,7 +2649,7 @@ static int link_enter_join_netdev(Link *link) {
assert(link);
assert(link->network);
- assert(link->state == LINK_STATE_PENDING);
+ assert(link->state == LINK_STATE_INITIALIZED);
link_set_state(link, LINK_STATE_CONFIGURING);
@@ -3053,7 +3062,7 @@ static int link_configure(Link *link) {
assert(link);
assert(link->network);
- assert(link->state == LINK_STATE_PENDING);
+ assert(link->state == LINK_STATE_INITIALIZED);
if (STRPTR_IN_SET(link->kind, "can", "vcan"))
return link_configure_can(link);
@@ -3202,7 +3211,7 @@ static int link_configure_after_setting_mtu(Link *link) {
assert(link);
assert(link->network);
- assert(link->state == LINK_STATE_PENDING);
+ assert(link->state == LINK_STATE_INITIALIZED);
if (link->setting_mtu)
return 0;
@@ -3353,10 +3362,13 @@ static int link_initialized_and_synced(Link *link) {
assert(link->ifname);
assert(link->manager);
- if (link->state != LINK_STATE_PENDING)
+ /* We may get called either from the asynchronous netlink callback,
+ * or directly for link_add() if running in a container. See link_add(). */
+ if (!IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED))
return 1;
log_link_debug(link, "Link state is up-to-date");
+ link_set_state(link, LINK_STATE_INITIALIZED);
r = link_new_bound_by_list(link);
if (r < 0)
@@ -3432,6 +3444,7 @@ int link_initialized(Link *link, sd_device *device) {
return 0;
log_link_debug(link, "udev initialized link");
+ link_set_state(link, LINK_STATE_INITIALIZED);
link->sd_device = sd_device_ref(device);
@@ -4349,6 +4362,7 @@ void link_clean(Link *link) {
static const char* const link_state_table[_LINK_STATE_MAX] = {
[LINK_STATE_PENDING] = "pending",
+ [LINK_STATE_INITIALIZED] = "initialized",
[LINK_STATE_CONFIGURING] = "configuring",
[LINK_STATE_CONFIGURED] = "configured",
[LINK_STATE_UNMANAGED] = "unmanaged",
diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h
index e65246c87d..e5497379d7 100644
--- a/src/network/networkd-link.h
+++ b/src/network/networkd-link.h
@@ -20,12 +20,13 @@
#include "set.h"
typedef enum LinkState {
- LINK_STATE_PENDING,
- LINK_STATE_CONFIGURING,
- LINK_STATE_CONFIGURED,
- LINK_STATE_UNMANAGED,
- LINK_STATE_FAILED,
- LINK_STATE_LINGER,
+ LINK_STATE_PENDING, /* udev has not initialized the link */
+ LINK_STATE_INITIALIZED, /* udev has initialized the link */
+ LINK_STATE_CONFIGURING, /* configuring addresses, routes, etc. */
+ LINK_STATE_CONFIGURED, /* everything is configured */
+ LINK_STATE_UNMANAGED, /* Unmanaged=yes is set */
+ LINK_STATE_FAILED, /* at least one configuration process failed */
+ LINK_STATE_LINGER, /* RTM_DELLINK for the link has been received */
_LINK_STATE_MAX,
_LINK_STATE_INVALID = -1
} LinkState;
@@ -121,7 +122,7 @@ typedef struct Link {
Hashmap *bound_by_links;
Hashmap *bound_to_links;
- Hashmap *slaves;
+ Set *slaves;
} Link;
typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c
index 677f66a478..c9579370cb 100644
--- a/src/network/networkd-manager.c
+++ b/src/network/networkd-manager.c
@@ -1450,13 +1450,12 @@ void manager_free(Manager *m) {
}
m->dirty_links = set_free_with_destructor(m->dirty_links, link_unref);
- m->links = hashmap_free(m->links);
- m->links_requesting_uuid = set_free(m->links_requesting_uuid);
- set_free(m->duids_requesting_uuid);
+ m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref);
+ m->links = hashmap_free_with_destructor(m->links, link_unref);
+ m->duids_requesting_uuid = set_free(m->duids_requesting_uuid);
while ((network = m->networks))
network_free(network);
-
hashmap_free(m->networks_by_name);
m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref);
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 52cfc4bec1..b5bf0366f1 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -172,6 +172,14 @@ int network_verify(Network *network) {
assert(network);
assert(network->filename);
+ if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
+ strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
+ strv_isempty(network->match_name) && !network->conditions)
+ log_warning("%s: No valid settings found in the [Match] section. "
+ "The file will match all interfaces. "
+ "If that is intended, please add Name=* in the [Match] section.",
+ network->filename);
+
/* skip out early if configuration does not match the environment */
if (!condition_test_list(network->conditions, NULL, NULL, NULL))
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL),
diff --git a/src/network/test-networkd-conf.c b/src/network/test-networkd-conf.c
index 6408719d15..05fc01d048 100644
--- a/src/network/test-networkd-conf.c
+++ b/src/network/test-networkd-conf.c
@@ -173,6 +173,7 @@ static void test_config_parse_address_one(const char *rvalue, int family, unsign
assert_se(network = new0(Network, 1));
assert_se(network->filename = strdup("hogehoge.network"));
+ assert_se(config_parse_ifnames("network", "filename", 1, "section", 1, "Name", 0, "*", &network->match_name, network) == 0);
assert_se(config_parse_address("network", "filename", 1, "section", 1, "Address", 0, rvalue, network, network) == 0);
assert_se(network->n_static_addresses == 1);
assert_se(network_verify(network) >= 0);
diff --git a/src/nspawn/nspawn-oci.c b/src/nspawn/nspawn-oci.c
index db8e4d3b78..6040243899 100644
--- a/src/nspawn/nspawn-oci.c
+++ b/src/nspawn/nspawn-oci.c
@@ -1621,26 +1621,26 @@ static bool sysctl_key_valid(const char *s) {
static int oci_sysctl(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
Settings *s = userdata;
- JsonVariant *k, *w;
+ JsonVariant *w;
+ const char *k;
int r;
assert(s);
JSON_VARIANT_OBJECT_FOREACH(k, w, v) {
- const char *n, *m;
+ const char *m;
if (!json_variant_is_string(w))
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
"sysctl parameter is not a string, refusing.");
- assert_se(n = json_variant_string(k));
assert_se(m = json_variant_string(w));
- if (sysctl_key_valid(n))
+ if (sysctl_key_valid(k))
return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
- "sysctl key invalid, refusing: %s", n);
+ "sysctl key invalid, refusing: %s", k);
- r = strv_extend_strv(&s->sysctl, STRV_MAKE(n, m), false);
+ r = strv_extend_strv(&s->sysctl, STRV_MAKE(k, m), false);
if (r < 0)
return log_oom();
}
@@ -2171,22 +2171,20 @@ static int oci_hooks(const char *name, JsonVariant *v, JsonDispatchFlags flags,
}
static int oci_annotations(const char *name, JsonVariant *v, JsonDispatchFlags flags, void *userdata) {
- JsonVariant *k, *w;
+ JsonVariant *w;
+ const char *k;
JSON_VARIANT_OBJECT_FOREACH(k, w, v) {
- const char *n;
-
- assert_se(n = json_variant_string(k));
- if (isempty(n))
- return json_log(k, flags, SYNTHETIC_ERRNO(EINVAL),
+ if (isempty(k))
+ return json_log(v, flags, SYNTHETIC_ERRNO(EINVAL),
"Annotation with empty key, refusing.");
if (!json_variant_is_string(w))
return json_log(w, flags, SYNTHETIC_ERRNO(EINVAL),
"Annotation has non-string value, refusing.");
- json_log(k, flags|JSON_DEBUG, 0, "Ignoring annotation '%s' with value '%s'.", n, json_variant_string(w));
+ json_log(w, flags|JSON_DEBUG, 0, "Ignoring annotation '%s' with value '%s'.", k, json_variant_string(w));
}
return 0;
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index e05fa3dbf2..0f64aa68f3 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -3262,7 +3262,7 @@ static int outer_child(
arg_userns_mode != USER_NAMESPACE_NO,
arg_uid_shift,
arg_uid_range,
- arg_selinux_context);
+ arg_selinux_apifs_context);
if (r < 0)
return r;
diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c
index 66dd2b1b5a..f072966767 100644
--- a/src/resolve/resolved-dns-scope.c
+++ b/src/resolve/resolved-dns-scope.c
@@ -67,7 +67,7 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int
dns_scope_llmnr_membership(s, true);
dns_scope_mdns_membership(s, true);
- log_debug("New scope on link %s, protocol %s, family %s", l ? l->name : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
+ log_debug("New scope on link %s, protocol %s, family %s", l ? l->ifname : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family));
/* Enforce ratelimiting for the multicast protocols */
RATELIMIT_INIT(s->ratelimit, MULTICAST_RATELIMIT_INTERVAL_USEC, MULTICAST_RATELIMIT_BURST);
@@ -98,7 +98,7 @@ DnsScope* dns_scope_free(DnsScope *s) {
if (!s)
return NULL;
- log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
+ log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->ifname : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));
dns_scope_llmnr_membership(s, false);
dns_scope_mdns_membership(s, false);
@@ -1137,7 +1137,7 @@ void dns_scope_dump(DnsScope *s, FILE *f) {
if (s->link) {
fputs(" interface=", f);
- fputs(s->link->name, f);
+ fputs(s->link->ifname, f);
}
if (s->family != AF_UNSPEC) {
diff --git a/src/resolve/resolved-dns-server.c b/src/resolve/resolved-dns-server.c
index b85eb75273..95162845fc 100644
--- a/src/resolve/resolved-dns-server.c
+++ b/src/resolve/resolved-dns-server.c
@@ -836,7 +836,7 @@ void dns_server_dump(DnsServer *s, FILE *f) {
assert(s->link);
fputs(" interface=", f);
- fputs(s->link->name, f);
+ fputs(s->link->ifname, f);
}
fputs("]\n", f);
diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c
index 9cac91f536..df42115edc 100644
--- a/src/resolve/resolved-dns-transaction.c
+++ b/src/resolve/resolved-dns-transaction.c
@@ -268,7 +268,7 @@ static void dns_transaction_tentative(DnsTransaction *t, DnsPacket *p) {
t->id,
dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
- t->scope->link ? t->scope->link->name : "*",
+ t->scope->link ? t->scope->link->ifname : "*",
af_to_name_short(t->scope->family),
strnull(pretty));
@@ -333,7 +333,7 @@ void dns_transaction_complete(DnsTransaction *t, DnsTransactionState state) {
t->id,
dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
- t->scope->link ? t->scope->link->name : "*",
+ t->scope->link ? t->scope->link->ifname : "*",
af_to_name_short(t->scope->family),
st,
t->answer_source < 0 ? "none" : dns_transaction_source_to_string(t->answer_source),
@@ -1648,7 +1648,7 @@ int dns_transaction_go(DnsTransaction *t) {
t->id,
dns_resource_key_to_string(t->key, key_str, sizeof key_str),
dns_protocol_to_string(t->scope->protocol),
- t->scope->link ? t->scope->link->name : "*",
+ t->scope->link ? t->scope->link->ifname : "*",
af_to_name_short(t->scope->family));
if (!t->initial_jitter_scheduled &&
diff --git a/src/resolve/resolved-link-bus.c b/src/resolve/resolved-link-bus.c
index 96093fff53..81ef5ffaa4 100644
--- a/src/resolve/resolved-link-bus.c
+++ b/src/resolve/resolved-link-bus.c
@@ -1,5 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
+#include <net/if.h>
+
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-util.h"
@@ -190,9 +192,9 @@ static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
assert(l);
if (l->flags & IFF_LOOPBACK)
- return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
+ return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
if (l->is_managed)
- return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
+ return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->ifname);
return 0;
}
diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c
index f65ce64d17..7c8d23d2f8 100644
--- a/src/resolve/resolved-link.c
+++ b/src/resolve/resolved-link.c
@@ -1,6 +1,5 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
-#include <net/if.h>
#include <linux/if.h>
#include <unistd.h>
@@ -10,6 +9,7 @@
#include "env-file.h"
#include "fd-util.h"
#include "fileio.h"
+#include "log-link.h"
#include "mkdir.h"
#include "parse-util.h"
#include "resolved-link.h"
@@ -98,6 +98,7 @@ Link *link_free(Link *l) {
dns_scope_free(l->mdns_ipv6_scope);
free(l->state_file);
+ free(l->ifname);
return mfree(l);
}
@@ -239,8 +240,9 @@ int link_process_rtnl(Link *l, sd_netlink_message *m) {
(void) sd_netlink_message_read_u8(m, IFLA_OPERSTATE, &l->operstate);
if (sd_netlink_message_read_string(m, IFLA_IFNAME, &n) >= 0) {
- strncpy(l->name, n, sizeof(l->name)-1);
- char_array_0(l->name);
+ r = free_and_strdup(&l->ifname, n);
+ if (r < 0)
+ return r;
}
link_allocate_scopes(l);
@@ -596,7 +598,7 @@ static void link_read_settings(Link *l) {
r = link_is_managed(l);
if (r < 0) {
- log_warning_errno(r, "Failed to determine whether interface %s is managed: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to determine whether the interface is managed: %m");
return;
}
if (r == 0) {
@@ -613,35 +615,35 @@ static void link_read_settings(Link *l) {
r = link_update_dns_servers(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNS servers for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNS servers for the interface, ignoring: %m");
r = link_update_llmnr_support(l);
if (r < 0)
- log_warning_errno(r, "Failed to read LLMNR support for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read LLMNR support for the interface, ignoring: %m");
r = link_update_mdns_support(l);
if (r < 0)
- log_warning_errno(r, "Failed to read mDNS support for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read mDNS support for the interface, ignoring: %m");
r = link_update_dns_over_tls_mode(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNS-over-TLS mode for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNS-over-TLS mode for the interface, ignoring: %m");
r = link_update_dnssec_mode(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNSSEC mode for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNSSEC mode for the interface, ignoring: %m");
r = link_update_dnssec_negative_trust_anchors(l);
if (r < 0)
- log_warning_errno(r, "Failed to read DNSSEC negative trust anchors for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read DNSSEC negative trust anchors for the interface, ignoring: %m");
r = link_update_search_domains(l);
if (r < 0)
- log_warning_errno(r, "Failed to read search domains for interface %s, ignoring: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read search domains for the interface, ignoring: %m");
r = link_update_default_route(l);
if (r < 0)
- log_warning_errno(r, "Failed to read default route setting for interface %s, proceeding anyway: %m", l->name);
+ log_link_warning_errno(l, r, "Failed to read default route setting for the interface, proceeding anyway: %m");
}
int link_update(Link *l) {
@@ -728,7 +730,7 @@ DnsServer* link_set_dns_server(Link *l, DnsServer *s) {
return s;
if (s)
- log_debug("Switching to DNS server %s for interface %s.", dns_server_string(s), l->name);
+ log_debug("Switching to DNS server %s for interface %s.", dns_server_string(s), l->ifname);
dns_server_unref(l->current_dns_server);
l->current_dns_server = dns_server_ref(s);
diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h
index f95ea37a4f..4b545a5536 100644
--- a/src/resolve/resolved-link.h
+++ b/src/resolve/resolved-link.h
@@ -1,8 +1,6 @@
/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
-#include <net/if.h>
-
#include "in-addr-util.h"
#include "ratelimit.h"
#include "resolve-util.h"
@@ -67,7 +65,7 @@ struct Link {
bool is_managed;
- char name[IF_NAMESIZE];
+ char *ifname;
uint32_t mtu;
uint8_t operstate;
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 24a752e3bb..5f63a21e01 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -82,14 +82,14 @@ static int manager_process_link(sd_netlink *rtnl, sd_netlink_message *mm, void *
goto fail;
if (is_new)
- log_debug("Found new link %i/%s", ifindex, l->name);
+ log_debug("Found new link %i/%s", ifindex, l->ifname);
break;
}
case RTM_DELLINK:
if (l) {
- log_debug("Removing link %i/%s", l->ifindex, l->name);
+ log_debug("Removing link %i/%s", l->ifindex, l->ifname);
link_remove_user(l);
link_free(l);
}
diff --git a/src/run/run.c b/src/run/run.c
index 18b46f2a40..6a0b0d78b9 100644
--- a/src/run/run.c
+++ b/src/run/run.c
@@ -380,13 +380,31 @@ static int parse_argv(int argc, char *argv[]) {
arg_with_timer = true;
break;
- case ARG_ON_CALENDAR:
+ case ARG_ON_CALENDAR: {
+ _cleanup_(calendar_spec_freep) CalendarSpec *cs = NULL;
+ usec_t next, curr;
+
+ /* Let's make sure the given calendar event is not in the past */
+ curr = now(CLOCK_REALTIME);
+ r = calendar_spec_from_string(optarg, &cs);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse calendar event specification");
+ r = calendar_spec_next_usec(cs, curr, &next);
+ if (r < 0) {
+ /* The calendar event is in the past - in such case
+ * don't add an OnCalendar property and execute
+ * the command immediately instead */
+ log_warning("Specified calendar event is in the past, executing immediately");
+ break;
+ }
+
r = add_timer_property("OnCalendar", optarg);
if (r < 0)
return r;
arg_with_timer = true;
break;
+ }
case ARG_ON_TIMEZONE_CHANGE:
r = add_timer_property("OnTimezoneChange", "yes");
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
index b2f8936038..5c823a3d84 100644
--- a/src/shared/bootspec.c
+++ b/src/shared/bootspec.c
@@ -725,8 +725,8 @@ int boot_entries_load_config_auto(
return boot_entries_load_config(esp_where, xbootldr_where, config);
}
+#if ENABLE_EFI
int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
-
static const char * const title_table[] = {
/* Pretty names for a few well-known automatically discovered entries. */
"auto-osx", "macOS",
@@ -793,6 +793,7 @@ int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
return 0;
}
+#endif
/********************************************************************************/
diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h
index b35eaf1110..c18d89494a 100644
--- a/src/shared/bootspec.h
+++ b/src/shared/bootspec.h
@@ -71,7 +71,13 @@ static inline BootEntry* boot_config_default_entry(BootConfig *config) {
void boot_config_free(BootConfig *config);
int boot_entries_load_config(const char *esp_path, const char *xbootldr_path, BootConfig *config);
int boot_entries_load_config_auto(const char *override_esp_path, const char *override_xbootldr_path, BootConfig *config);
+#if ENABLE_EFI
int boot_entries_augment_from_loader(BootConfig *config, bool only_auto);
+#else
+static inline int boot_entries_augment_from_loader(BootConfig *config, bool only_auto) {
+ return -EOPNOTSUPP;
+}
+#endif
static inline const char* boot_entry_title(const BootEntry *entry) {
return entry->show_title ?: entry->title ?: entry->id;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index 8d99955ca7..c6cbc9828c 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -396,6 +396,10 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return bus_append_cg_blkio_weight_parse(m, field, eq);
+ if (streq(field, "DisableControllers"))
+
+ return bus_append_strv(m, "DisableControllers", eq, EXTRACT_QUOTES);
+
if (streq(field, "Delegate")) {
r = parse_boolean(eq);
@@ -409,7 +413,7 @@ static int bus_append_cgroup_property(sd_bus_message *m, const char *field, cons
return 1;
}
- if (STR_IN_SET(field, "MemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
+ if (STR_IN_SET(field, "MemoryMin", "DefaultMemoryLow", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
if (isempty(eq) || streq(eq, "infinity")) {
r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index e31fcfbd5a..9c3ce2f712 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -794,7 +794,7 @@ static int bus_print_property(const char *name, const char *expected_value, sd_b
bus_print_property_value(name, expected_value, value, "[not set]");
- else if ((STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
+ else if ((STR_IN_SET(name, "DefaultMemoryLow", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit") && u == CGROUP_LIMIT_MAX) ||
(STR_IN_SET(name, "TasksMax", "DefaultTasksMax") && u == (uint64_t) -1) ||
(startswith(name, "Limit") && u == (uint64_t) -1) ||
(startswith(name, "DefaultLimit") && u == (uint64_t) -1))
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index 17b4bdf1a2..04c68b18d8 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -128,6 +128,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_path);
CONFIG_PARSER_PROTOTYPE(config_parse_strv);
CONFIG_PARSER_PROTOTYPE(config_parse_sec);
CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_infinity);
+CONFIG_PARSER_PROTOTYPE(config_parse_sec_def_unset);
CONFIG_PARSER_PROTOTYPE(config_parse_nsec);
CONFIG_PARSER_PROTOTYPE(config_parse_mode);
CONFIG_PARSER_PROTOTYPE(config_parse_warn_compat);
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index 49d1b338fb..1346da9323 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -79,6 +79,10 @@ static inline int efi_set_reboot_to_firmware(bool value) {
return -EOPNOTSUPP;
}
+static inline char* efi_variable_path(sd_id128_t vendor, const char *name) {
+ return NULL;
+}
+
static inline int efi_get_variable(sd_id128_t vendor, const char *name, uint32_t *attribute, void **value, size_t *size) {
return -EOPNOTSUPP;
}
diff --git a/src/shared/json.h b/src/shared/json.h
index e5532c506e..70dfe70dfd 100644
--- a/src/shared/json.h
+++ b/src/shared/json.h
@@ -135,15 +135,17 @@ struct json_variant_foreach_state {
#define JSON_VARIANT_ARRAY_FOREACH(i, v) \
for (struct json_variant_foreach_state _state = { (v), 0 }; \
- _state.idx < json_variant_elements(_state.variant) && \
+ json_variant_is_array(_state.variant) && \
+ _state.idx < json_variant_elements(_state.variant) && \
({ i = json_variant_by_index(_state.variant, _state.idx); \
true; }); \
_state.idx++)
#define JSON_VARIANT_OBJECT_FOREACH(k, e, v) \
for (struct json_variant_foreach_state _state = { (v), 0 }; \
- _state.idx < json_variant_elements(_state.variant) && \
- ({ k = json_variant_by_index(_state.variant, _state.idx); \
+ json_variant_is_object(_state.variant) && \
+ _state.idx < json_variant_elements(_state.variant) && \
+ ({ k = json_variant_string(json_variant_by_index(_state.variant, _state.idx)); \
e = json_variant_by_index(_state.variant, _state.idx + 1); \
true; }); \
_state.idx += 2)
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 15466bcaf1..c80a67cdde 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -102,7 +102,6 @@ shared_sources = files('''
linux/bpf_insn.h
linux/dm-ioctl.h
linux/ethtool.h
- linux/netdevice.h
lockfile-util.c
lockfile-util.h
log-link.h
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index cfcc4f6874..dd48533899 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -4130,6 +4130,9 @@ typedef struct UnitStatusInfo {
uint64_t io_read_bytes;
uint64_t io_write_bytes;
+ uint64_t default_memory_min;
+ uint64_t default_memory_low;
+
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
@@ -5488,6 +5491,8 @@ static int show_one(
{ "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
{ "What", "s", NULL, offsetof(UnitStatusInfo, what) },
{ "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
+ { "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
+ { "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
{ "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
{ "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
{ "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
diff --git a/src/systemd/sd-bus-vtable.h b/src/systemd/sd-bus-vtable.h
index 8a73ef0503..e3804e203c 100644
--- a/src/systemd/sd-bus-vtable.h
+++ b/src/systemd/sd-bus-vtable.h
@@ -52,6 +52,15 @@ enum {
_SD_BUS_VTABLE_PARAM_NAMES = 1 << 0,
};
+extern const unsigned sd_bus_object_vtable_format;
+
+/* Note: unused areas in the sd_bus_vtable[] array must be initalized to 0. The stucture contains an embedded
+ * union, and the compiler is NOT required to initalize the unused areas of the union when the rest of the
+ * structure is initalized. Normally the array is defined as read-only data, in which case the linker places
+ * it in the BSS section, which is always fully initalized, so this is not a concern. But if the array is
+ * created on the stack or on the heap, care must be taken to initalize the unused areas, for examply by
+ * first memsetting the whole region to zero before filling the data in. */
+
struct sd_bus_vtable {
/* Please do not initialize this structure directly, use the
* macros below instead */
@@ -62,6 +71,7 @@ struct sd_bus_vtable {
struct {
size_t element_size;
uint64_t features;
+ const unsigned *vtable_format_reference;
} start;
struct {
const char *member;
@@ -93,7 +103,8 @@ struct sd_bus_vtable {
.x = { \
.start = { \
.element_size = sizeof(sd_bus_vtable), \
- .features = _SD_BUS_VTABLE_PARAM_NAMES \
+ .features = _SD_BUS_VTABLE_PARAM_NAMES, \
+ .vtable_format_reference = &sd_bus_object_vtable_format, \
}, \
}, \
}
diff --git a/src/test/generate-sym-test.py b/src/test/generate-sym-test.py
index 357cce8e44..4d358b8e34 100755
--- a/src/test/generate-sym-test.py
+++ b/src/test/generate-sym-test.py
@@ -6,18 +6,22 @@ for header in sys.argv[2:]:
print('#include "{}"'.format(header.split('/')[-1]))
print('''
-void* functions[] = {''')
+const void* symbols[] = {''')
for line in open(sys.argv[1]):
match = re.search('^ +([a-zA-Z0-9_]+);', line)
if match:
- print(' {},'.format(match.group(1)))
+ s = match.group(1)
+ if s == 'sd_bus_object_vtable_format':
+ print(' &{},'.format(s))
+ else:
+ print(' {},'.format(s))
print('''};
int main(void) {
unsigned i;
- for (i = 0; i < sizeof(functions)/sizeof(void*); i++)
- printf("%p\\n", functions[i]);
+ for (i = 0; i < sizeof(symbols)/sizeof(void*); i++)
+ printf("%p\\n", symbols[i]);
return 0;
}''')
diff --git a/src/test/meson.build b/src/test/meson.build
index ae970cf8a0..e58e1cc73d 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -574,6 +574,12 @@ tests += [
libshared],
[]],
+ [['src/test/test-cgroup-unit-default.c',
+ 'src/test/test-helper.c'],
+ [libcore,
+ libshared],
+ []],
+
[['src/test/test-cgroup-mask.c',
'src/test/test-helper.c'],
[libcore,
@@ -905,7 +911,8 @@ tests += [
[],
[threads]],
- [['src/libsystemd/sd-bus/test-bus-vtable.c'],
+ [['src/libsystemd/sd-bus/test-bus-vtable.c',
+ 'src/libsystemd/sd-bus/test-vtable-data.h'],
[],
[]],
@@ -928,7 +935,8 @@ tests += [
[threads],
'', 'manual'],
- [['src/libsystemd/sd-bus/test-bus-introspect.c'],
+ [['src/libsystemd/sd-bus/test-bus-introspect.c',
+ 'src/libsystemd/sd-bus/test-vtable-data.h'],
[],
[]],
diff --git a/src/test/test-cgroup-unit-default.c b/src/test/test-cgroup-unit-default.c
new file mode 100644
index 0000000000..7372f97a1c
--- /dev/null
+++ b/src/test/test-cgroup-unit-default.c
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+
+#include <stdio.h>
+
+#include "cgroup.h"
+#include "manager.h"
+#include "rm-rf.h"
+#include "test-helper.h"
+#include "tests.h"
+#include "unit.h"
+
+static int test_default_memory_low(void) {
+ _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
+ _cleanup_(manager_freep) Manager *m = NULL;
+ Unit *root, *dml,
+ *dml_passthrough, *dml_passthrough_empty, *dml_passthrough_set_dml, *dml_passthrough_set_ml,
+ *dml_override, *dml_override_empty,
+ *dml_discard, *dml_discard_empty, *dml_discard_set_ml;
+ uint64_t dml_tree_default;
+ int r;
+
+ r = enter_cgroup_subroot();
+ if (r == -ENOMEDIUM)
+ return log_tests_skipped("cgroupfs not available");
+
+ assert_se(set_unit_path(get_testdata_dir()) >= 0);
+ assert_se(runtime_dir = setup_fake_runtime_dir());
+ r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &m);
+ if (IN_SET(r, -EPERM, -EACCES)) {
+ log_error_errno(r, "manager_new: %m");
+ return log_tests_skipped("cannot create manager");
+ }
+
+ assert_se(r >= 0);
+ assert_se(manager_startup(m, NULL, NULL) >= 0);
+
+ /* dml.slice has DefaultMemoryLow=50. Beyond that, individual subhierarchies look like this:
+ *
+ * 1. dml-passthrough.slice sets MemoryLow=100. This should not affect its children, as only
+ * DefaultMemoryLow is propagated, not MemoryLow. As such, all leaf services should end up with
+ * memory.low as 50, inherited from dml.slice, *except* for dml-passthrough-set-ml.service, which
+ * should have the value of 25, as it has MemoryLow explicitly set.
+ *
+ * ┌───────────┐
+ * │ dml.slice │
+ * └─────┬─────┘
+ * MemoryLow=100
+ * ┌───────────┴───────────┐
+ * │ dml-passthrough.slice │
+ * └───────────┬───────────┘
+ * ┌───────────────────────────────────┼───────────────────────────────────┐
+ * no new settings DefaultMemoryLow=15 MemoryLow=25
+ * ┌───────────────┴───────────────┐ ┌────────────────┴────────────────┐ ┌───────────────┴────────────────┐
+ * │ dml-passthrough-empty.service │ │ dml-passthrough-set-dml.service │ │ dml-passthrough-set-ml.service │
+ * └───────────────────────────────┘ └─────────────────────────────────┘ └────────────────────────────────┘
+ *
+ * 2. dml-override.slice sets DefaultMemoryLow=10. As such, dml-override-empty.service should also
+ * end up with a memory.low of 10. dml-override.slice should still have a memory.low of 50.
+ *
+ * ┌───────────┐
+ * │ dml.slice │
+ * └─────┬─────┘
+ * DefaultMemoryLow=10
+ * ┌─────────┴──────────┐
+ * │ dml-override.slice │
+ * └─────────┬──────────┘
+ * no new settings
+ * ┌─────────────┴──────────────┐
+ * │ dml-override-empty.service │
+ * └────────────────────────────┘
+ *
+ * 3. dml-discard.slice sets DefaultMemoryLow= with no rvalue. As such,
+ * dml-discard-empty.service should end up with a value of 0.
+ * dml-discard-explicit-ml.service sets MemoryLow=70, and as such should have that override the
+ * reset DefaultMemoryLow value. dml-discard.slice should still have an eventual memory.low of 50.
+ *
+ * ┌───────────┐
+ * │ dml.slice │
+ * └─────┬─────┘
+ * DefaultMemoryLow=
+ * ┌─────────┴─────────┐
+ * │ dml-discard.slice │
+ * └─────────┬─────────┘
+ * ┌──────────────┴───────────────┐
+ * no new settings MemoryLow=15
+ * ┌─────────────┴─────────────┐ ┌─────────────┴──────────────┐
+ * │ dml-discard-empty.service │ │ dml-discard-set-ml.service │
+ * └───────────────────────────┘ └────────────────────────────┘
+ */
+ assert_se(manager_load_startable_unit_or_warn(m, "dml.slice", NULL, &dml) >= 0);
+
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough.slice", NULL, &dml_passthrough) >= 0);
+ assert_se(UNIT_DEREF(dml_passthrough->slice) == dml);
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-empty.service", NULL, &dml_passthrough_empty) >= 0);
+ assert_se(UNIT_DEREF(dml_passthrough_empty->slice) == dml_passthrough);
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-dml.service", NULL, &dml_passthrough_set_dml) >= 0);
+ assert_se(UNIT_DEREF(dml_passthrough_set_dml->slice) == dml_passthrough);
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-passthrough-set-ml.service", NULL, &dml_passthrough_set_ml) >= 0);
+ assert_se(UNIT_DEREF(dml_passthrough_set_ml->slice) == dml_passthrough);
+
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-override.slice", NULL, &dml_override) >= 0);
+ assert_se(UNIT_DEREF(dml_override->slice) == dml);
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-override-empty.service", NULL, &dml_override_empty) >= 0);
+ assert_se(UNIT_DEREF(dml_override_empty->slice) == dml_override);
+
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-discard.slice", NULL, &dml_discard) >= 0);
+ assert_se(UNIT_DEREF(dml_discard->slice) == dml);
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-discard-empty.service", NULL, &dml_discard_empty) >= 0);
+ assert_se(UNIT_DEREF(dml_discard_empty->slice) == dml_discard);
+ assert_se(manager_load_startable_unit_or_warn(m, "dml-discard-set-ml.service", NULL, &dml_discard_set_ml) >= 0);
+ assert_se(UNIT_DEREF(dml_discard_set_ml->slice) == dml_discard);
+
+ root = UNIT_DEREF(dml->slice);
+ assert_se(!UNIT_ISSET(root->slice));
+
+ assert_se(unit_get_ancestor_memory_low(root) == CGROUP_LIMIT_MIN);
+
+ assert_se(unit_get_ancestor_memory_low(dml) == CGROUP_LIMIT_MIN);
+ dml_tree_default = unit_get_cgroup_context(dml)->default_memory_low;
+ assert_se(dml_tree_default == 50);
+
+ assert_se(unit_get_ancestor_memory_low(dml_passthrough) == 100);
+ assert_se(unit_get_ancestor_memory_low(dml_passthrough_empty) == dml_tree_default);
+ assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_dml) == 50);
+ assert_se(unit_get_ancestor_memory_low(dml_passthrough_set_ml) == 25);
+
+ assert_se(unit_get_ancestor_memory_low(dml_override) == dml_tree_default);
+ assert_se(unit_get_ancestor_memory_low(dml_override_empty) == 10);
+
+ assert_se(unit_get_ancestor_memory_low(dml_discard) == dml_tree_default);
+ assert_se(unit_get_ancestor_memory_low(dml_discard_empty) == CGROUP_LIMIT_MIN);
+ assert_se(unit_get_ancestor_memory_low(dml_discard_set_ml) == 15);
+
+ return 0;
+}
+
+int main(int argc, char* argv[]) {
+ int rc = EXIT_SUCCESS;
+
+ test_setup_logging(LOG_DEBUG);
+
+ TEST_REQ_RUNNING_SYSTEMD(rc = test_default_memory_low());
+
+ return rc;
+}
diff --git a/src/test/test-socket-util.c b/src/test/test-socket-util.c
index 057840d76f..4e9a0bddf4 100644
--- a/src/test/test-socket-util.c
+++ b/src/test/test-socket-util.c
@@ -810,6 +810,67 @@ static void test_send_emptydata(void) {
assert_se(fd == -999);
}
+static void test_flush_accept(void) {
+ _cleanup_close_ int listen_stream = -1, listen_dgram = -1, listen_seqpacket = 1, connect_stream = -1, connect_dgram = -1, connect_seqpacket = -1;
+ static const union sockaddr_union sa = { .un.sun_family = AF_UNIX };
+ union sockaddr_union lsa;
+ socklen_t l;
+
+ listen_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(listen_stream >= 0);
+
+ listen_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(listen_dgram >= 0);
+
+ listen_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(listen_seqpacket >= 0);
+
+ assert_se(flush_accept(listen_stream) < 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) < 0);
+
+ assert_se(bind(listen_stream, &sa.sa, sizeof(sa_family_t)) >= 0);
+ assert_se(bind(listen_dgram, &sa.sa, sizeof(sa_family_t)) >= 0);
+ assert_se(bind(listen_seqpacket, &sa.sa, sizeof(sa_family_t)) >= 0);
+
+ assert_se(flush_accept(listen_stream) < 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) < 0);
+
+ assert_se(listen(listen_stream, SOMAXCONN) >= 0);
+ assert_se(listen(listen_dgram, SOMAXCONN) < 0);
+ assert_se(listen(listen_seqpacket, SOMAXCONN) >= 0);
+
+ assert_se(flush_accept(listen_stream) >= 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) >= 0);
+
+ connect_stream = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(connect_stream >= 0);
+
+ connect_dgram = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(connect_dgram >= 0);
+
+ connect_seqpacket = socket(AF_UNIX, SOCK_SEQPACKET|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ assert_se(connect_seqpacket >= 0);
+
+ l = sizeof(lsa);
+ assert_se(getsockname(listen_stream, &lsa.sa, &l) >= 0);
+ assert_se(connect(connect_stream, &lsa.sa, l) >= 0);
+
+ l = sizeof(lsa);
+ assert_se(getsockname(listen_dgram, &lsa.sa, &l) >= 0);
+ assert_se(connect(connect_dgram, &lsa.sa, l) >= 0);
+
+ l = sizeof(lsa);
+ assert_se(getsockname(listen_seqpacket, &lsa.sa, &l) >= 0);
+ assert_se(connect(connect_seqpacket, &lsa.sa, l) >= 0);
+
+ assert_se(flush_accept(listen_stream) >= 0);
+ assert_se(flush_accept(listen_dgram) < 0);
+ assert_se(flush_accept(listen_seqpacket) >= 0);
+}
+
int main(int argc, char *argv[]) {
test_setup_logging(LOG_DEBUG);
@@ -843,6 +904,7 @@ int main(int argc, char *argv[]) {
test_receive_nopassfd();
test_send_nodata_nofd();
test_send_emptydata();
+ test_flush_accept();
return 0;
}
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index a26c4cefa8..7754959cdf 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -159,6 +159,14 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
if (link->speed > UINT_MAX)
return -ERANGE;
+ if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
+ strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
+ strv_isempty(link->match_name) && !link->conditions)
+ log_warning("%s: No valid settings found in the [Match] section. "
+ "The file will match all interfaces. "
+ "If that is intended, please add OriginalName=* in the [Match] section.",
+ filename);
+
if (!condition_test_list(link->conditions, NULL, NULL, NULL)) {
log_debug("%s: Conditions do not match the system environment, skipping.", filename);
return 0;
diff --git a/src/udev/net/naming-scheme.c b/src/udev/net/naming-scheme.c
index 27cede5e2e..8223f9cda1 100644
--- a/src/udev/net/naming-scheme.c
+++ b/src/udev/net/naming-scheme.c
@@ -8,6 +8,7 @@ static const NamingScheme naming_schemes[] = {
{ "v238", NAMING_V238 },
{ "v239", NAMING_V239 },
{ "v240", NAMING_V240 },
+ { "v243", NAMING_V243 },
/* … add more schemes here, as the logic to name devices is updated … */
};
diff --git a/src/udev/net/naming-scheme.h b/src/udev/net/naming-scheme.h
index 0b3d9bff1d..1f7cb0ccb9 100644
--- a/src/udev/net/naming-scheme.h
+++ b/src/udev/net/naming-scheme.h
@@ -27,11 +27,13 @@ typedef enum NamingSchemeFlags {
NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */
NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */
NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */
+ NAMING_NETDEVSIM = 1 << 5, /* Allow re-renaming of netdevsim devices */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
NAMING_V239 = NAMING_V238 | NAMING_SR_IOV_V | NAMING_NPAR_ARI,
NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES,
+ NAMING_V243 = NAMING_V240 | NAMING_NETDEVSIM,
_NAMING_SCHEME_FLAGS_INVALID = -1,
} NamingSchemeFlags;
diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
index 03b281a771..2c7dcf7d2a 100644
--- a/src/udev/udev-builtin-net_id.c
+++ b/src/udev/udev-builtin-net_id.c
@@ -31,6 +31,7 @@
* — USB port number chain
* v<slot> - VIO slot number (IBM PowerVM)
* a<vendor><model>i<instance> — Platform bus ACPI instance id
+ * i<addr>n<phys_port_name> — Netdevsim bus address and port name
*
* All multi-function PCI devices will carry the [f<function>] number in the
* device name, including the function 0 device.
@@ -126,6 +127,7 @@ enum netname_type{
NET_CCW,
NET_VIO,
NET_PLATFORM,
+ NET_NETDEVSIM,
};
struct netnames {
@@ -145,6 +147,7 @@ struct netnames {
char ccw_busid[IFNAMSIZ];
char vio_slot[IFNAMSIZ];
char platform_path[IFNAMSIZ];
+ char netdevsim_path[IFNAMSIZ];
};
struct virtfn_info {
@@ -794,6 +797,43 @@ static int names_mac(sd_device *dev, struct netnames *names) {
return 0;
}
+static int names_netdevsim(sd_device *dev, struct netnames *names) {
+ sd_device *netdevsimdev;
+ const char *sysname;
+ unsigned addr;
+ const char *port_name = NULL;
+ int r;
+ bool ok;
+
+ if (!naming_scheme_has(NAMING_NETDEVSIM))
+ return 0;
+
+ assert(dev);
+ assert(names);
+
+ r = sd_device_get_parent_with_subsystem_devtype(dev, "netdevsim", NULL, &netdevsimdev);
+ if (r < 0)
+ return r;
+ r = sd_device_get_sysname(netdevsimdev, &sysname);
+ if (r < 0)
+ return r;
+
+ if (sscanf(sysname, "netdevsim%u", &addr) != 1)
+ return -EINVAL;
+
+ r = sd_device_get_sysattr_value(dev, "phys_port_name", &port_name);
+ if (r < 0)
+ return r;
+
+ ok = snprintf_ok(names->netdevsim_path, sizeof(names->netdevsim_path), "i%un%s", addr, port_name);
+ if (!ok)
+ return -ENOBUFS;
+
+ names->type = NET_NETDEVSIM;
+
+ return 0;
+}
+
/* IEEE Organizationally Unique Identifier vendor string */
static int ieee_oui(sd_device *dev, struct netnames *names, bool test) {
char str[32];
@@ -897,6 +937,16 @@ static int builtin_net_id(sd_device *dev, int argc, char *argv[], bool test) {
return 0;
}
+ /* get netdevsim path names */
+ if (names_netdevsim(dev, &names) >= 0 && names.type == NET_NETDEVSIM) {
+ char str[IFNAMSIZ];
+
+ if (snprintf_ok(str, sizeof str, "%s%s", prefix, names.netdevsim_path))
+ udev_builtin_add_property(dev, test, "ID_NET_NAME_PATH", str);
+
+ return 0;
+ }
+
/* get PCI based path names, we compose only PCI based paths */
if (names_pci(dev, &names) < 0)
return 0;
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index ee87d7c65c..96840b272c 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -2443,6 +2443,11 @@ int udev_rules_apply_to_event(
case TK_A_RUN_PROGRAM: {
_cleanup_free_ char *cmd = NULL;
+ if (event->run_final)
+ break;
+ if (cur->key.op == OP_ASSIGN_FINAL)
+ event->run_final = true;
+
if (IN_SET(cur->key.op, OP_ASSIGN, OP_ASSIGN_FINAL))
ordered_hashmap_clear_free_key(event->run_list);
diff --git a/test/TEST-16-EXTEND-TIMEOUT/testsuite.service b/test/TEST-16-EXTEND-TIMEOUT/testsuite.service
index e1cd5caeea..7512ba9e12 100644
--- a/test/TEST-16-EXTEND-TIMEOUT/testsuite.service
+++ b/test/TEST-16-EXTEND-TIMEOUT/testsuite.service
@@ -12,7 +12,7 @@ Wants=testsuite-fail-runtime.service
StopWhenUnneeded=yes
[Service]
-
Type=simple
+TimeoutStartSec=infinity
ExecStartPre=/assess.sh
ExecStart=/bin/true
diff --git a/test/dml-discard-empty.service b/test/dml-discard-empty.service
new file mode 100644
index 0000000000..75228f6470
--- /dev/null
+++ b/test/dml-discard-empty.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=DML discard empty service
+
+[Service]
+Slice=dml-discard.slice
+Type=oneshot
+ExecStart=/bin/true
diff --git a/test/dml-discard-set-ml.service b/test/dml-discard-set-ml.service
new file mode 100644
index 0000000000..591c99270c
--- /dev/null
+++ b/test/dml-discard-set-ml.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=DML discard set ml service
+
+[Service]
+Slice=dml-discard.slice
+Type=oneshot
+ExecStart=/bin/true
+MemoryLow=15
diff --git a/test/dml-discard.slice b/test/dml-discard.slice
new file mode 100644
index 0000000000..e26d86846c
--- /dev/null
+++ b/test/dml-discard.slice
@@ -0,0 +1,5 @@
+[Unit]
+Description=DML discard slice
+
+[Slice]
+DefaultMemoryLow=
diff --git a/test/dml-override-empty.service b/test/dml-override-empty.service
new file mode 100644
index 0000000000..142c98720c
--- /dev/null
+++ b/test/dml-override-empty.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=DML override empty service
+
+[Service]
+Slice=dml-override.slice
+Type=oneshot
+ExecStart=/bin/true
diff --git a/test/dml-override.slice b/test/dml-override.slice
new file mode 100644
index 0000000000..feb6773e39
--- /dev/null
+++ b/test/dml-override.slice
@@ -0,0 +1,5 @@
+[Unit]
+Description=DML override slice
+
+[Slice]
+DefaultMemoryLow=10
diff --git a/test/dml-passthrough-empty.service b/test/dml-passthrough-empty.service
new file mode 100644
index 0000000000..34832de491
--- /dev/null
+++ b/test/dml-passthrough-empty.service
@@ -0,0 +1,7 @@
+[Unit]
+Description=DML passthrough empty service
+
+[Service]
+Slice=dml-passthrough.slice
+Type=oneshot
+ExecStart=/bin/true
diff --git a/test/dml-passthrough-set-dml.service b/test/dml-passthrough-set-dml.service
new file mode 100644
index 0000000000..5bdf4ed4b7
--- /dev/null
+++ b/test/dml-passthrough-set-dml.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=DML passthrough set DML service
+
+[Service]
+Slice=dml-passthrough.slice
+Type=oneshot
+ExecStart=/bin/true
+DefaultMemoryLow=15
diff --git a/test/dml-passthrough-set-ml.service b/test/dml-passthrough-set-ml.service
new file mode 100644
index 0000000000..2abd591389
--- /dev/null
+++ b/test/dml-passthrough-set-ml.service
@@ -0,0 +1,8 @@
+[Unit]
+Description=DML passthrough set ML service
+
+[Service]
+Slice=dml-passthrough.slice
+Type=oneshot
+ExecStart=/bin/true
+MemoryLow=25
diff --git a/test/dml-passthrough.slice b/test/dml-passthrough.slice
new file mode 100644
index 0000000000..1b1a848edb
--- /dev/null
+++ b/test/dml-passthrough.slice
@@ -0,0 +1,5 @@
+[Unit]
+Description=DML passthrough slice
+
+[Slice]
+MemoryLow=100
diff --git a/test/dml.slice b/test/dml.slice
new file mode 100644
index 0000000000..84e333ef04
--- /dev/null
+++ b/test/dml.slice
@@ -0,0 +1,5 @@
+[Unit]
+Description=DML slice
+
+[Slice]
+DefaultMemoryLow=50
diff --git a/test/fuzz/fuzz-unit-file/directives.service b/test/fuzz/fuzz-unit-file/directives.service
index 86e59184d7..fe6b1be302 100644
--- a/test/fuzz/fuzz-unit-file/directives.service
+++ b/test/fuzz/fuzz-unit-file/directives.service
@@ -227,6 +227,7 @@ TimeoutIdleSec=
TimeoutSec=
TimeoutStartSec=
TimeoutStopSec=
+TimeoutAbortSec=
Transparent=
TriggerLimitBurst=
TriggerLimitIntervalSec=
@@ -686,6 +687,7 @@ DefaultTasksAccounting=
DefaultTasksMax=
DefaultTimeoutStartSec=
DefaultTimeoutStopSec=
+DefaultTimeoutAbortSec=
DefaultTimerAccuracySec=
DumpCore=
HibernateMode=
diff --git a/test/meson.build b/test/meson.build
index 7255c79dcb..17d0f3cddd 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -7,6 +7,16 @@ test_data_files = '''
c.service
d.service
daughter.service
+ dml.slice
+ dml-passthrough.slice
+ dml-passthrough-empty.service
+ dml-passthrough-set-dml.service
+ dml-passthrough-set-ml.service
+ dml-override.slice
+ dml-override-empty.service
+ dml-discard.slice
+ dml-discard-empty.service
+ dml-discard-set-ml.service
e.service
end.service
f.service
diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py
index d9db9c1657..843125ee65 100755
--- a/test/test-network/systemd-networkd-tests.py
+++ b/test/test-network/systemd-networkd-tests.py
@@ -443,16 +443,16 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
print(output)
- self.assertTrue(output, ' mtu 2004 ')
+ self.assertRegex(output, ' mtu 2004 ')
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'vlan99']).rstrip().decode('utf-8')
print(output)
- self.assertTrue(output, ' mtu 2000 ')
- self.assertTrue(output, 'REORDER_HDR')
- self.assertTrue(output, 'LOOSE_BINDING')
- self.assertTrue(output, 'GVRP')
- self.assertTrue(output, 'MVRP')
- self.assertTrue(output, ' id 99 ')
+ self.assertRegex(output, ' mtu 2000 ')
+ self.assertRegex(output, 'REORDER_HDR')
+ self.assertRegex(output, 'LOOSE_BINDING')
+ self.assertRegex(output, 'GVRP')
+ self.assertRegex(output, 'MVRP')
+ self.assertRegex(output, ' id 99 ')
output = subprocess.check_output(['ip', '-4', 'address', 'show', 'dev', 'test1']).rstrip().decode('utf-8')
print(output)
@@ -478,11 +478,11 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'test1']).rstrip().decode('utf-8')
print(output)
- self.assertTrue(output, ' mtu 2000 ')
+ self.assertRegex(output, ' mtu 2000 ')
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'macvlan99']).rstrip().decode('utf-8')
print(output)
- self.assertTrue(output, ' mtu 2000 ')
+ self.assertRegex(output, ' mtu 2000 ')
@expectedFailureIfModuleIsNotAvailable('ipvlan')
def test_ipvlan(self):
@@ -544,24 +544,24 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
subprocess.call('wg')
output = subprocess.check_output(['wg', 'show', 'wg99', 'listen-port']).rstrip().decode('utf-8')
- self.assertTrue(output, '51820')
+ self.assertRegex(output, '51820')
output = subprocess.check_output(['wg', 'show', 'wg99', 'fwmark']).rstrip().decode('utf-8')
- self.assertTrue(output, '0x4d2')
+ self.assertRegex(output, '0x4d2')
output = subprocess.check_output(['wg', 'show', 'wg99', 'allowed-ips']).rstrip().decode('utf-8')
- self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
- self.assertTrue(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
+ self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.26.0/24 fd31:bf08:57cb::/48')
+ self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc=\tfdbc:bae2:7871:e1fe:793:8636::/96 fdbc:bae2:7871:500:e1fe:793:8636:dad1/128')
output = subprocess.check_output(['wg', 'show', 'wg99', 'persistent-keepalive']).rstrip().decode('utf-8')
- self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t20')
+ self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t20')
output = subprocess.check_output(['wg', 'show', 'wg99', 'endpoints']).rstrip().decode('utf-8')
- self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA=\t192.168.27.3:51820')
+ self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA=\t192.168.27.3:51820')
output = subprocess.check_output(['wg', 'show', 'wg99', 'private-key']).rstrip().decode('utf-8')
- self.assertTrue(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS+UENyPncC4bF46ong=')
+ self.assertRegex(output, 'EEGlnEPYJV//kbvvIqxKkQwOiS\+UENyPncC4bF46ong=')
output = subprocess.check_output(['wg', 'show', 'wg99', 'preshared-keys']).rstrip().decode('utf-8')
- self.assertTrue(output, 'RDf+LSpeEre7YEIKaxg+wbpsNV7du+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
- self.assertTrue(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
+ self.assertRegex(output, 'RDf\+LSpeEre7YEIKaxg\+wbpsNV7du\+ktR99uBEtIiCA= IIWIV17wutHv7t4cR6pOT91z6NSz/T8Arh0yaywhw3M=')
+ self.assertRegex(output, 'lsDtM3AbjxNlauRKzHEPfgS1Zp7cp/VX5Use/P4PQSc= cPLOy1YUrEI0EMMIycPJmOo0aTu3RZnw8bL5meVD6m0=')
output = subprocess.check_output(['wg', 'show', 'wg98', 'private-key']).rstrip().decode('utf-8')
- self.assertTrue(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr+WHtZLZ90FU=')
+ self.assertRegex(output, 'CJQUtcS9emY2fLYqDlpSZiE/QJyHkPWr\+WHtZLZ90FU=')
def test_geneve(self):
self.copy_unit_to_networkd_unit_path('25-geneve.netdev')
@@ -571,10 +571,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
output = subprocess.check_output(['ip', '-d', 'link', 'show', 'geneve99']).rstrip().decode('utf-8')
print(output)
- self.assertTrue(output, '192.168.22.1')
- self.assertTrue(output, '6082')
- self.assertTrue(output, 'udpcsum')
- self.assertTrue(output, 'udp6zerocsumrx')
+ self.assertRegex(output, '192.168.22.1')
+ self.assertRegex(output, '6082')
+ self.assertRegex(output, 'udpcsum')
+ self.assertRegex(output, 'udp6zerocsumrx')
def test_ipip_tunnel(self):
self.copy_unit_to_networkd_unit_path('12-dummy.netdev', '25-ipip-tunnel.netdev', 'ipip.network',
diff --git a/tmpfiles.d/meson.build b/tmpfiles.d/meson.build
index 35eea2be5c..b94a9d0f47 100644
--- a/tmpfiles.d/meson.build
+++ b/tmpfiles.d/meson.build
@@ -6,6 +6,7 @@ tmpfiles = [['home.conf', ''],
['journal-nocow.conf', ''],
['systemd-nologin.conf', ''],
['systemd-nspawn.conf', 'ENABLE_MACHINED'],
+ ['systemd-tmp.conf', ''],
['portables.conf', 'ENABLE_PORTABLED'],
['tmp.conf', ''],
['x11.conf', ''],
diff --git a/tmpfiles.d/systemd-tmp.conf b/tmpfiles.d/systemd-tmp.conf
new file mode 100644
index 0000000000..beb77dd0e0
--- /dev/null
+++ b/tmpfiles.d/systemd-tmp.conf
@@ -0,0 +1,18 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+
+# See tmpfiles.d(5) for details
+
+# Exclude namespace mountpoints created with PrivateTmp=yes
+x /tmp/systemd-private-%b-*
+X /tmp/systemd-private-%b-*/tmp
+x /var/tmp/systemd-private-%b-*
+X /var/tmp/systemd-private-%b-*/tmp
+
+# Remove top-level private temporary directories on each boot
+R! /tmp/systemd-private-*
+R! /var/tmp/systemd-private-*
diff --git a/tmpfiles.d/tmp.conf b/tmpfiles.d/tmp.conf
index 22555a0076..fe5225d751 100644
--- a/tmpfiles.d/tmp.conf
+++ b/tmpfiles.d/tmp.conf
@@ -10,13 +10,3 @@
# Clear tmp directories separately, to make them easier to override
q /tmp 1777 root root 10d
q /var/tmp 1777 root root 30d
-
-# Exclude namespace mountpoints created with PrivateTmp=yes
-x /tmp/systemd-private-%b-*
-X /tmp/systemd-private-%b-*/tmp
-x /var/tmp/systemd-private-%b-*
-X /var/tmp/systemd-private-%b-*/tmp
-
-# Remove top-level private temporary directories on each boot
-R! /tmp/systemd-private-*
-R! /var/tmp/systemd-private-*