diff options
123 files changed, 3766 insertions, 1269 deletions
@@ -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 <systemd/sd-bus-vtable.h></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(×.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-* |