docs: use collections to structure the data

This commit is contained in:
hulkoba
2024-02-22 10:11:54 +01:00
parent 4049d92fda
commit 5e8ff010a1
83 changed files with 144 additions and 107 deletions
+225
View File
@@ -0,0 +1,225 @@
---
title: systemd Repository Architecture
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# The systemd Repository Architecture
## Code Map
This document provides a high-level overview of the various components of the
systemd repository.
## Source Code
Directories in `src/` provide the implementation of all daemons, libraries and
command-line tools shipped by the project. There are many, and more are
constantly added, so we will not enumerate them all here — the directory
names are self-explanatory.
### Shared Code
The code that is shared between components is split into a few directories,
each with a different purpose:
- `src/basic/` and `src/fundamental/` — those directories contain code
primitives that are used by all other code. `src/fundamental/` is stricter,
because it used for EFI and user-space code, while `src/basic/` is only used
for user-space code. The code in `src/fundamental/` cannot depend on any
other code in the tree, and `src/basic/` can depend only on itself and
`src/fundamental/`. For user-space, a static library is built from this code
and linked statically in various places.
- `src/libsystemd/` implements the `libsystemd.so` shared library (also
available as static `libsystemd.a`). This code may use anything in
`src/basic/` or `src/fundamental/`.
- `src/shared/` provides various utilities and code shared between other
components that is exposed as the `libsystemd-shared-<nnn>.so` shared library.
The other subdirectories implement individual components. They may depend only
on `src/fundamental/` + `src/basic/`, or also on `src/libsystemd/`, or also on
`src/shared/`.
You might wonder what kind of code belongs where. In general, the rule is that
code should be linked as few times as possible, ideally only once. Thus code that
is used by "higher-level" components (e.g. our binaries which are linked to
`libsystemd-shared-<nnn>.so`), would go to a subdirectory specific to that
component if it is only used there. If the code is to be shared between
components, it'd go to `src/shared/`. Shared code that is used by multiple
components that do not link to `libsystemd-shared-<nnn>.so` may live either in
`src/libsystemd/`, `src/basic/`, or `src/fundamental/`. Any code that is used
only for EFI goes under `src/boot/efi/`, and `src/fundamental/` if is shared
with non-EFI compoenents.
To summarize:
`src/fundamental/`
- may be used by all code in the tree
- may not use any code outside of `src/fundamental/`
`src/basic/`
- may be used by all code in the tree
- may not use any code outside of `src/fundamental/` and `src/basic/`
`src/libsystemd/`
- may be used by all code in the tree that links to `libsystem.so`
- may not use any code outside of `src/fundamental/`, `src/basic/`, and
`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/fundamental/`, `src/basic/`,
`src/libsystemd/`, `src/shared/`
### PID 1
Code located in `src/core/` implements the main logic of the systemd system (and user)
service manager.
BPF helpers written in C and used by PID 1 can be found under `src/core/bpf/`.
#### Implementing Unit Settings
The system and session manager supports a large number of unit settings. These can generally
be configured in three ways:
1. Via textual, INI-style configuration files called *unit* *files*
2. Via D-Bus messages to the manager
3. Via the `systemd-run` and `systemctl set-property` commands
From a user's perspective, the third is a wrapper for the second. To implement a new unit
setting, it is necessary to support all three input methods:
1. *unit* *files* are parsed in `src/core/load-fragment.c`, with many simple and fixed-type
unit settings being parsed by common helpers, with the definition in the generator file
`src/core/load-fragment-gperf.gperf.in`
2. D-Bus messages are defined and parsed in `src/core/dbus-*.c`
3. `systemd-run` and `systemctl set-property` do client-side parsing and translation into
D-Bus messages in `src/shared/bus-unit-util.c`
So that they are exercised by the fuzzing CI, new unit settings should also be listed in the
text files under `test/fuzz/fuzz-unit-file/`.
### systemd-udev
Sources for the udev daemon and command-line tool (single binary) can be found under
`src/udev/`.
### Unit Tests
Source files found under `src/test/` implement unit-level testing, mostly for
modules found in `src/basic/` and `src/shared/`, but not exclusively. Each test
file is compiled in a standalone binary that can be run to exercise the
corresponding module. While most of the tests can be run by any user, some
require privileges, and will attempt to clearly log about what they need
(mostly in the form of effective capabilities). These tests are self-contained,
and generally safe to run on the host without side effects.
Ideally, every module in `src/basic/` and `src/shared/` should have a
corresponding unit test under `src/test/`, exercising every helper function.
### Fuzzing
Fuzzers are a type of unit tests that execute code on an externally-supplied
input sample. Fuzzers are called `fuzz-*`. Fuzzers for `src/basic/` and
`src/shared` live under `src/fuzz/`, and those for other parts of the codebase
should be located next to the code they test.
Files under `test/fuzz/` contain input data for fuzzers, one subdirectory for
each fuzzer. Some of the files are "seed corpora", i.e. files that contain
lists of settings and input values intended to generate initial coverage, and
other files are samples saved by the fuzzing engines when they find an issue.
When adding new input samples under `test/fuzz/*/`, please use some
short-but-meaningful names. Names of meson tests include the input file name
and output looks awkward if they are too long.
Fuzzers are invoked primarily in three ways: firstly, each fuzzer is compiled
as a normal executable and executed for each of the input samples under
`test/fuzz/` as part of the test suite. Secondly, fuzzers may be instrumented
with sanitizers and invoked as part of the test suite (if `-Dfuzz-tests=true`
is configured). Thirdly, fuzzers are executed through fuzzing engines that try
to find new "interesting" inputs through coverage feedback and massive
parallelization; see the links for oss-fuzz in [Code quality](CODE_QUALITY).
For testing and debugging, fuzzers can be executed as any other program,
including under `valgrind` or `gdb`.
## Integration Tests
Sources in `test/TEST-*` implement system-level testing for executables,
libraries and daemons that are shipped by the project. They require privileges
to run, and are not safe to execute directly on a host. By default they will
build an image and run the test under it via `qemu` or `systemd-nspawn`.
Most of those tests should be able to run via `systemd-nspawn`, which is
orders-of-magnitude faster than `qemu`, but some tests require privileged
operations like using `dm-crypt` or `loopdev`. They are clearly marked if that
is the case.
See `test/README.testsuite` for more specific details.
## hwdb
Rules built in the static hardware database shipped by the project can be found
under `hwdb.d/`. Some of these files are updated automatically, some are filled
by contributors.
## Documentation
### systemd.io
Markdown files found under `docs/` are automatically published on the
[systemd.io](https://systemd.io) website using Github Pages. A minimal unit test
to ensure the formatting doesn't have errors is included in the
`meson test -C build/ github-pages` run as part of the CI.
### Man pages
Manpages for binaries and libraries, and the DBUS interfaces, can be found under
`man/` and should ideally be kept in sync with changes to the corresponding
binaries and libraries.
### Translations
Translations files for binaries and daemons, provided by volunteers, can be found
under `po/` in the usual format. They are kept up to date by contributors and by
automated tools.
## System Configuration files and presets
Presets (or templates from which they are generated) for various daemons and tools
can be found under various directories such as `factory/`, `modprobe.d/`, `network/`,
`presets/`, `rules.d/`, `shell-completion/`, `sysctl.d/`, `sysusers.d/`, `tmpfiles.d/`.
## Utilities for Developers
`tools/`, `coccinelle/`, `.github/`, `.semaphore/`, `.mkosi/` host various
utilities and scripts that are used by maintainers and developers. They are not
shipped or installed.
# Service Manager Overview
The Service Manager takes configuration in the form of unit files, credentials,
kernel command line options and D-Bus commands, and based on those manages the
system and spawns other processes. It runs in system mode as PID1, and in user
mode with one instance per user session.
When starting a unit requires forking a new process, configuration for the new
process will be serialized and passed over to the new process, created via a
posix_spawn() call. This is done in order to avoid excessive processing after
a fork() but before an exec(), which is against glibc's best practices and can
also result in a copy-on-write trap. The new process will start as the
`systemd-executor` binary, which will deserialize the configuration and apply
all the options (sandboxing, namespacing, cgroup, etc.) before exec'ing the
configured executable.
```
┌──────┐posix_spawn() ┌───────────┐execve() ┌────────┐
│ PID1 ├─────────────►│sd-executor├────────►│program │
└──────┘ (memfd) └───────────┘ └────────┘
```
+21
View File
@@ -0,0 +1,21 @@
---
title: systemd Community Conduct Guidelines
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# The systemd Community Conduct Guidelines
This document provides community guidelines for a safe, respectful, productive, and collaborative place for any person who is willing to contribute to systemd. It applies to all “collaborative spaces”, which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.).
- Participants will be tolerant of opposing views.
- Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
- When interpreting the words and actions of others, participants should always assume good intentions.
- Behaviour which can be reasonably considered harassment will not be tolerated.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at systemd-conduct@googlegroups.com. This team currently consists of David Strauss <<systemd-conduct@davidstrauss.net>>, Ekaterina Gerasimova (Kat) <<Kittykat3756@gmail.com>>, and Zbigniew Jędrzejewski-Szmek <<zbyszek@in.waw.pl>>. In the unfortunate event that you wish to make a complaint against one of the members, you may instead contact any of the other members individually.
All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident.
+85
View File
@@ -0,0 +1,85 @@
---
title: Code Quality Tools
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Code Quality Tools
The systemd project has a number of code quality tools set up in the source
tree and on the github infrastructure. Here's an incomprehensive list of the
available functionality:
1. Use `meson test -C build` to run the unit tests. Some tests are skipped if
no privileges are available, hence consider also running them with `sudo
meson test -C build`. A couple of unit tests are considered "unsafe" (as
they change system state); to run those too, build with `meson setup
-Dtests=unsafe`. Finally, some unit tests are considered to be very slow,
build them too with `meson setup -Dslow-tests=true`. (Note that there are a
couple of manual tests in addition to these unit tests.) (Also note: you can
change these flags for an already set up build tree, too, with "meson
configure -C build -D…".)
2. Use `./test/run-integration-tests.sh` to run the full integration test
suite. This will build OS images with a number of integration tests and run
them using `systemd-nspawn` and `qemu`. Requires root.
3. Use `./coccinelle/run-coccinelle.sh` to run all
[Coccinelle](http://coccinelle.lip6.fr/) semantic patch scripts we ship. The
output will show false positives, hence take it with a pinch of salt.
4. Use `./tools/find-double-newline.sh recdiff` to find double newlines. Use
`./tools/find-double-newline.sh recpatch` to fix them. Take this with a grain
of salt, in particular as we generally leave foreign header files we include in
our tree unmodified, if possible.
5. Similar use `./tools/find-tabs.sh recdiff` to find TABs, and
`./tools/find-tabs.sh recpatch` to fix them. (Again, grain of salt, foreign
headers should usually be left unmodified.)
6. Use `ninja -C build check-api-docs` to compare the list of exported symbols
of `libsystemd.so` and `libudev.so` with the list of man pages. Symbols
lacking documentation are highlighted.
7. Use `ninja -C build update-hwdb` and `ninja -C build update-hwdb-autosuspend`
to automatically download and import the PCI, USB, and OUI databases and the
autosuspend quirks into the hwdb.
8. Use `ninja -C build update-man-rules` to update the meson rules for building
man pages automatically from the docbook XML files included in `man/`.
9. There are multiple CI systems in use that run on every github pull request
submission or update.
10. [Coverity](https://scan.coverity.com/) is analyzing systemd `main` branch
in regular intervals. The reports are available
[online](https://scan.coverity.com/projects/systemd).
11. [OSS-Fuzz](https://github.com/google/oss-fuzz) is continuously fuzzing the
codebase. Reports are available
[online](https://oss-fuzz.com/testcases?project=systemd&open=yes).
It also builds
[coverage reports](https://oss-fuzz.com/coverage-report/job/libfuzzer_asan_systemd/latest)
daily.
12. Our tree includes `.editorconfig`, `.dir-locals.el` and `.vimrc` files, to
ensure that editors follow the right indentiation styles automatically.
13. When building systemd from a git checkout the build scripts will
automatically enable a git commit hook that ensures whitespace cleanliness.
14. [CodeQL](https://codeql.github.com/) analyzes each PR and every commit
pushed to `main`. The list of active alerts can be found
[here](https://github.com/systemd/systemd/security/code-scanning).
15. Each PR is automatically tested with [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
and [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).
See [Testing systemd using sanitizers](TESTING_WITH_SANITIZERS)
for more information.
16. Fossies provides [source code misspelling reports](https://fossies.org/features.html#codespell).
The systemd report can be found [here](https://fossies.org/linux/misc/systemd/codespell.html).
Access to Coverity and oss-fuzz reports is limited. Please reach out to the
maintainers if you need access.
+782
View File
@@ -0,0 +1,782 @@
---
title: Coding Style
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# 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).
- 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
overdo it, ~109ch should be enough really. The `.editorconfig`, `.vimrc` and
`.dir-locals.el` files contained in the repository will set this limit up for
you automatically, if you let them (as well as a few other things). Please
note that emacs loads `.dir-locals.el` automatically, but vim needs to be
configured to load `.vimrc`, see that file for instructions.
- If you break a function declaration over multiple lines, do it like this:
```c
void some_function(
int foo,
bool bar,
char baz) {
int a, b, c;
```
(i.e. use double indentation — 16 spaces — for the parameter list.)
- Try to write this:
```c
void foo() {
}
```
instead of this:
```c
void foo()
{
}
```
- Single-line `if` blocks should not be enclosed in `{}`. Write this:
```c
if (foobar)
waldo();
```
instead of this:
```c
if (foobar) {
waldo();
}
```
- Do not write `foo ()`, write `foo()`.
- `else` blocks should generally start on the same line as the closing `}`:
```c
if (foobar) {
find();
waldo();
} else
dont_find_waldo();
```
- Please define flags types like this:
```c
typedef enum FoobarFlags {
FOOBAR_QUUX = 1 << 0,
FOOBAR_WALDO = 1 << 1,
FOOBAR_XOXO = 1 << 2,
…
} FoobarFlags;
```
i.e. use an enum for it, if possible. Indicate bit values via `1 <<`
expressions, and align them vertically. Define both an enum and a type for
it.
- If you define (non-flags) enums, follow this template:
```c
typedef enum FoobarMode {
FOOBAR_AAA,
FOOBAR_BBB,
FOOBAR_CCC,
…
_FOOBAR_MAX,
_FOOBAR_INVALID = -EINVAL,
} FoobarMode;
```
i.e. define a `_MAX` enum for the largest defined enum value, plus one. Since
this is not a regular enum value, prefix it with `_`. Also, define a special
"invalid" enum value, and set it to `-EINVAL`. That way the enum type can
safely be used to propagate conversion errors.
- If you define an enum in a public API, be extra careful, as the size of the
enum might change when new values are added, which would break ABI
compatibility. Since we typically want to allow adding new enum values to an
existing enum type with later API versions, please use the
`_SD_ENUM_FORCE_S64()` macro in the enum definition, which forces the size of
the enum to be signed 64-bit wide.
- Empty lines to separate code blocks are a good thing, please add them
abundantly. However, please stick to one at a time, i.e. multiple empty lines
immediately following each other are not OK. Also, we try to keep function
calls and their immediate error handling together. Hence:
```c
/* → empty line here is good */
r = some_function(…);
/* → empty line here would be bad */
if (r < 0)
return log_error_errno(r, "Some function failed: %m");
/* → empty line here is good */
```
- In shell scripts, do not use whitespace after the redirection operator
(`>some/file` instead of `> some/file`, `<<EOF` instead of `<< EOF`).
## Code Organization and Semantics
- For our codebase we intend to use ISO C11 *with* GNU extensions (aka
"gnu11"). Public APIs (i.e. those we expose via `libsystemd.so`
i.e. `systemd/sd-*.h`) should only use ISO C89 however (with a very limited
set of conservative and common extensions, such as fixed size integer types
from `<inttypes.h>`), so that we don't force consuming programs into C11
mode. (This discrepancy in particular means one thing: internally we use C99
`bool` booleans, externally C89-compatible `int` booleans which generally
have different size in memory and slightly different semantics, also see
below.) Both for internal and external code it's OK to use even newer
features and GCC extension than "gnu11", as long as there's reasonable
fallback #ifdeffery in place to ensure compatibility is retained with older
compilers.
- 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 rule is: never clobber return parameters on
failure, always initialize return parameters on success.
- Typically, function parameters fit into three categories: input parameters,
mutable objects, and call-by-reference return parameters. Input parameters
should always carry suitable "const" declarators if they are pointers, to
indicate they are input-only and not changed by the function. Return
parameters are best prefixed with "ret_", to clarify they are return
parameters. (Conversely, please do not prefix parameters that aren't
output-only with "ret_", in particular not mutable parameters that are both
input as well as output). Example:
```c
static int foobar_frobnicate(
Foobar* object, /* the associated mutable object */
const char *input, /* immutable input parameter */
char **ret_frobnicated) { /* return parameter */
…
return 0;
}
```
- 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.
- 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
- Allocate local variables where it makes sense: at the top of the block, or at
the point where they can be initialized. Avoid huge variable declaration
lists at the top of the function.
As an exception, `int r` is typically used for a local state variable, but
should almost always be declared as the last variable at the top of the
function.
```c
{
uint64_t a;
int r;
r = frobnicate(&a);
if (r < 0)
…
uint64_t b = a + 1, c;
r = foobarify(a, b, &c);
if (r < 0)
…
const char *pretty = prettify(a, b, c);
…
}
```
- Do not mix multiple variable definitions with function invocations or
complicated expressions:
```c
{
uint64_t x = 7;
int a;
a = foobar();
}
```
instead of:
```c
{
int a = foobar();
uint64_t x = 7;
}
```
- 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!
- To minimize strict aliasing violations, we prefer unions over casting.
- 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:
```c
struct foobar t = {
.foo = 7,
.bar = "bazz",
};
```
instead of:
```c
struct foobar t;
zero(t);
t.foo = 7;
t.bar = "bazz";
```
- 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.
- Please use C's downgrade-to-bool feature only for expressions that are
actually booleans (or "boolean-like"), and not for variables that are really
numeric. Specifically, if you have an `int b` and it's only used in a boolean
sense, by all means check its state with `if (b) …` — but if `b` can actually
have more than two semantic values, and you want to compare for non-zero,
then please write that explicitly with `if (b != 0) …`. This helps readability
as the value range and semantical behaviour is directly clear from the
condition check. As a special addition: when dealing with pointers which you
want to check for non-NULL-ness, you may also use downgrade-to-bool feature.
- Please do not use yoda comparisons, i.e. please prefer the more readable `if
(a == 7)` over the less readable `if (7 == a)`.
## 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
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.
## Common Function Naming
- Name destructor functions that destroy an object in full freeing all its
memory and associated resources (and thus invalidating the pointer to it)
`xyz_free()`. Example: `strv_free()`.
- Name destructor functions that destroy only the referenced content of an
object but leave the object itself allocated `xyz_done()`. If it resets all
fields so that the object can be reused later call it `xyz_clear()`.
- Functions that decrease the reference counter of an object by one should be
called `xyz_unref()`. Example: `json_variant_unref()`. Functions that
increase the reference counter by one should be called `xyz_ref()`. Example:
`json_variant_ref()`
## Error Handling
- 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.
- libc system calls typically return -1 on error (with the error code in
`errno`), and >= 0 on success. Use the RET_NERRNO() helper if you are looking
for a simple way to convert this libc style error returning into systemd
style error returning. e.g.
```c
…
r = RET_NERRNO(unlink(t));
…
```
or
```c
…
r = RET_NERRNO(open("/some/file", O_RDONLY|O_CLOEXEC));
…
```
- 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).
- 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 it 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");
```
instead of just this:
```c
unlink("/foo/bar/baz");
```
When returning from a `void` function, you may also want to shorten the error
path boilerplate by returning a function invocation cast to `(void)` like so:
```c
if (condition_not_met)
return (void) log_tests_skipped("Cannot run ...");
```
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.
- When returning a return code from `main()`, please preferably use
`EXIT_FAILURE` and `EXIT_SUCCESS` as defined by libc.
## Logging
- For every function you add, think about whether it is a "logging" function or
a "non-logging" function. "Logging" functions do (non-debug) logging on their
own, "non-logging" functions never log on their own (except at debug level)
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. (Note that debug level logging — at syslog level
`LOG_DEBUG` — is not considered logging in this context, debug logging is
generally always fine and welcome.)
- If possible, do a combined log & return operation:
```c
r = operation(...);
if (r < 0)
return log_(error|warning|notice|...)_errno(r, "Failed to ...: %m");
```
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
n = read(..., s, sizeof s);
if (n != sizeof s)
return log_error_errno(SYNTHETIC_ERRNO(EIO), "Failed to read ...");
```
## Memory Allocation
- 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.
- Avoid fixed-size string buffers, unless you really know the maximum size and
that maximum size is small. It is often nicer to use dynamic memory,
`alloca_safe()` 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!
- Make use of `_cleanup_free_` and friends. It makes your code much nicer to
read (and shorter)!
- Do not use `alloca()`, `strdupa()` or `strndupa()` directly. Use
`alloca_safe()`, `strdupa_safe()` or `strndupa_safe()` instead. (The
difference is that the latter include an assertion that the specified size is
below a safety threshold, so that the program rather aborts than runs into
possible stack overruns.)
- Use `alloca_safe()`, but never forget that it is not OK to invoke
`alloca_safe()` within a loop or within function call
parameters. `alloca_safe()` 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_safe()` 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).
## Runtime Behaviour
- 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.
- 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 first, 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 allocate.
## Types
- Think about the types you use. If a value cannot sensibly be negative, do not
use `int`, but use `unsigned`. We prefer `unsigned` form to `unsigned int`.
- 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.
- 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.
- 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 extensions;
also see above).
## Deadlocks
- Do not issue NSS requests (that includes user name and hostname 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.
## File Descriptors
- 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:
- `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
were 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.
- These days we generally prefer `openat()`-style file APIs, i.e. APIs that
accept a combination of file descriptor and path string, and where the path
(if not absolute) is considered relative to the specified file
descriptor. When implementing library calls in similar style, please make
sure to imply `AT_EMPTY_PATH` if an empty or `NULL` path argument is
specified (and convert that latter to an empty string). This differs from the
underlying kernel semantics, where `AT_EMPTY_PATH` must always be specified
explicitly, and `NULL` is not accepted as path.
## 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
setting.
- When referring to a command line option in the documentation and such, please
always prefix with `--` or `-` (as appropriate), to indicate that it is a
command line option.
- When referring to a file system path that is a directory, please always
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.
- Use `typesafe_inet_ntop()`, `typesafe_inet_ntop4()`, and
`typesafe_inet_ntop6()` instead of `inet_ntop()`. But better yet, use the
`IN_ADDR_TO_STRING()`, `IN4_ADDR_TO_STRING()`, and `IN6_ADDR_TO_STRING()`
macros which allocate an anonymous buffer internally.
- Please never use `dup()`. Use `fcntl(fd, F_DUPFD_CLOEXEC, 3)` instead. For
two reasons: 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 more nicely.
- 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.
- Do not use `basename()` or `dirname()`. The semantics in corner cases are
full of pitfalls, and the fact that there are two quite different versions of
`basename()` (one POSIX and one GNU, of which the latter is much more useful)
doesn't make it better either. Use path_extract_filename() and
path_extract_directory() instead.
- Never use `FILENAME_MAX`. Use `PATH_MAX` instead (for checking maximum size
of paths) and `NAME_MAX` (for checking maximum size of filenames).
`FILENAME_MAX` is not POSIX, and is a confusingly named alias for `PATH_MAX`
on Linux. Note that `NAME_MAX` does not include space for a trailing `NUL`,
but `PATH_MAX` does. UNIX FTW!
## 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.
## Commenting
- The best place for code comments and explanations is in the code itself. Only
the second best is in git commit messages. The worst place is in the GitHub
PR cover letter. Hence, whenever you type a commit message consider for a
moment if what you are typing there wouldn't be a better fit for an in-code
comment. And if you type the cover letter of a PR, think hard if this
wouldn't be better as a commit message or even code comment. Comments are
supposed to be useful for somebody who reviews the code, and hence hiding
comments in git commits or PR cover letters makes reviews unnecessarily
hard. Moreover, while we rely heavily on GitHub's project management
infrastructure we'd like to keep everything that can reasonably be kept in
the git repository itself in the git repository, so that we can theoretically
move things elsewhere with the least effort possible.
- It's OK to reference GitHub PRs, GitHub issues and git commits from code
comments. Cross-referencing code, issues, and documentation is a good thing.
- Reasonable use of non-ASCII Unicode UTF-8 characters in code comments is
welcome. If your code comment contains an emoji or two this will certainly
brighten the day of the occasional reviewer of your code. Really! 😊
## Threading
- We generally avoid using threads, to the level this is possible. In
particular in the service manager/PID 1 threads are not OK to use. This is
because you cannot mix memory allocation in threads with use of glibc's
`clone()` call, or manual `clone()`/`clone3()` system call wrappers. Only
glibc's own `fork()` call will properly synchronize the memory allocation
locks around the process clone operation. This means that if a process is
cloned via `clone()`/`clone3()` and another thread currently has the
`malloc()` lock taken, it will be cloned in locked state to the child, and
thus can never be acquired in the child, leading to deadlocks. Hence, when
using `clone()`/`clone3()` there are only two ways out: never use threads in the
parent, or never do memory allocation in the child. For our uses we need
`clone()`/`clone3()` and hence decided to avoid threads. Of course, sometimes the
concurrency threads allow is beneficial, however we suggest forking off
worker *processes* rather than worker *threads* for this purpose, ideally
even with an `execve()` to remove the CoW trap situation `fork()` easily
triggers.
- A corollary of the above is: never use `clone()` where a `fork()` would do
too. Also consider using `posix_spawn()` which combines `clone()` +
`execve()` into one and has nice properties since it avoids becoming a CoW
trap by using `CLONE_VORK` and `CLONE_VM` together.
- While we avoid forking off threads on our own, writing thread-safe code is a
good idea where it might end up running inside of libsystemd.so or
similar. Hence, use TLS (i.e. `thread_local`) where appropriate, and maybe
the occasional `pthread_once()`.
+112
View File
@@ -0,0 +1,112 @@
---
title: Contributing
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Contributing
We welcome contributions from everyone. However, please follow the following guidelines when posting a GitHub Pull Request or filing a GitHub Issue on the systemd project:
## Filing Issues
* We use [GitHub Issues](https://github.com/systemd/systemd/issues) **exclusively** for tracking **bugs** and **feature** **requests** (RFEs) of systemd. If you are looking for help, please try the forums of your distribution first, or [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) for general questions about systemd.
* We only track bugs in the **two** **most** **recently** **released** (non-rc) **versions** of systemd in the GitHub Issue tracker. If you are using an older version of systemd, please contact your distribution's bug tracker instead (see below). See [GitHub Release Page](https://github.com/systemd/systemd/releases) for the list of most recent releases.
* When filing a feature request issue (RFE), please always check first if the newest upstream version of systemd already implements the feature, and whether there's already an issue filed for your feature by someone else.
* When filing an issue, specify the **systemd** **version** you are experiencing the issue with. Also, indicate which **distribution** you are using.
* Please include an explanation how to reproduce the issue you are pointing out.
Following these guidelines makes it easier for us to process your issue, and ensures we won't close your issue right-away for being misfiled.
### Older downstream versions
For older versions that are still supported by your distribution please use respective downstream tracker:
* **Fedora** - [bugzilla](https://bugzilla.redhat.com/enter_bug.cgi?product=Fedora&component=systemd)
* **RHEL/CentOS stream** - [Jira](https://issues.redhat.com/secure/CreateIssueDetails!init.jspa?pid=12332745&issuetype=1&components=12380515&priority=10300) or [contribute to systemd-rhel @GitHub](https://github.com/redhat-plumbers#systemd)
* **Debian** - [bugs.debian.org](https://bugs.debian.org/cgi-bin/pkgreport.cgi?pkg=systemd)
## Security vulnerability reports
See [reporting of security vulnerabilities](SECURITY).
## Posting Pull Requests
* Make sure to post PRs only relative to a recent tip of the `main` branch.
* Follow our [Coding Style](CODING_STYLE) when contributing code. This is a requirement for all code we merge.
* Please make sure to test your change before submitting the PR. See the [Hacking guide](HACKING) for details on how to do this.
* Make sure to run the test suite locally, before posting your PR. We use a CI system, meaning we don't even look at your PR if the build and tests don't pass.
* If you need to update the code in an existing PR, force-push into the same branch, overriding old commits with new versions.
* After you have pushed a new version, add a comment explaining the latest changes. If you are a member of the systemd project on GitHub, remove the `reviewed/needs-rework`/`ci-fails/needs-rework`/`needs-rebase` labels.
* If you are copying existing code from another source (eg: a compat header), please make sure the license is compatible with `LGPL-2.1-or-later`. If the license is not `LGPL-2.1-or-later`, please add a note to [`LICENSES/README.md`](https://github.com/systemd/systemd/blob/main/LICENSES/README.md).
* If the pull request stalls without review, post a ping in a comment after some time has passed. We are always short on reviewer time, and pull requests which haven't seen any recent activity can be easily forgotten.
* Github will automatically add the `please-review` label when a pull request is opened or updated. If you need
more information after a review, you can comment `/please-review` on the pull request to have Github add the
`please-review` label to the pull request.
## Reviewing Pull Requests
* See [filtered list of pull requests](https://github.com/systemd/systemd/pulls?q=is%3Aopen+is%3Apr+-label%3A%22reviewed%2Fneeds-rework+%F0%9F%94%A8%22+-label%3Aneeds-rebase+-label%3Agood-to-merge%2Fwith-minor-suggestions+-label%3A%22good-to-merge%2Fwaiting-for-ci+%F0%9F%91%8D%22+-label%3Apostponed+-label%3A%22needs-reporter-feedback+%E2%9D%93%22+-label%3A%22dont-merge+%F0%9F%92%A3%22+-label%3A%22ci-fails%2Fneeds-rework+%F0%9F%94%A5%22+sort%3Aupdated-desc) for requests that are ready for review.
* After performing a review, set
* `reviewed/needs-rework` if the pull request needs significant changes
* `ci-fails/needs-rework` if the automatic tests fail and the failure is relevant to the pull request
* `ci-failure-appears-unrelated` if the test failures seem irrelevant
* `needs-rebase` if the pull request needs a rebase because of conflicts
* `good-to-merge/waiting-for-ci` if the pull request should be merged without further review
* `good-to-merge/with-minor-suggestions` if the pull request should be merged after an update without going through another round of reviews
Unfortunately only members of the `systemd` organization on github can change labels.
If your pull request is mislabeled, make a comment in the pull request and somebody will fix it.
Reviews from non-members are still welcome.
## Final Words
We'd like to apologize in advance if we are not able to process and reply to your issue or PR right-away. We have a lot of work to do, but we are trying our best!
Thank you very much for your contributions!
# Backward Compatibility And External Dependencies
We strive to keep backward compatibility where possible and reasonable. The following are general guidelines, not hard
rules, and case-by-case exceptions might be applied at the discretion of the maintainers. The current set of build-time
and runtime dependencies are documented in the [README](https://github.com/systemd/systemd/blob/main/README).
## New features
It is fine for new features/functionality/tools/daemons to require bleeding edge external dependencies, provided there
are runtime and build-time graceful fallbacks (e.g.: a daemon will not be built, runtime functionality will be skipped with a clear log message).
In case a new feature is added to both `systemd` and one of its dependencies, we expect the corresponding feature code to
be merged upstream in the dependency before accepting our side of the implementation.
Making use of new kernel syscalls can be achieved through compat wrappers in our tree (see: `src/basic/missing_syscall_def.h`),
and does not need to wait for glibc support.
## External Build/Runtime Dependencies
It is often tempting to bump external dependencies' minimum versions to cut cruft, and in general it's an essential part
of the maintenance process. But as a general rule, existing dependencies should not be bumped without strong
reasons. When possible, we try to keep compatibility with the most recent LTS releases of each mainstream distribution
for optional components, and with all currently maintained (i.e.: not EOL) LTS releases for core components. When in
doubt, ask before committing time to work on contributions if it's not clear that cutting support would be obviously
acceptable.
## Kernel Requirements
Same principles as with other dependencies should be applied. It is fine to require newer kernel versions for additional
functionality or optional features, but very strong reasons should be required for breaking compatibility for existing
functionality, especially for core components. It is not uncommon, for example, for embedded systems to be stuck on older
kernel versions due to hardware requirements, so do not assume everybody is running with latest and greatest at all times.
In general, [currently maintained LTS branches](https://www.kernel.org/category/releases.html) should keep being supported
for existing functionality.
## `libsystemd.so`
`libsystemd.so` is a shared public library, so breaking ABI/API compatibility would create lot of work for everyone, and is not allowed. Instead, always add a new interface instead of modifying
the signature of an existing function. It is fine to mark an interface as deprecated to gently nudge users toward a newer one,
but support for the old one must be maintained.
Symbol versioning and the compiler's deprecated attribute should be used when managing the lifetime of a public interface.
## `libudev.so`
`libudev.so` is a shared public library, and is still maintained, but should not gain new symbols at this point.
+356
View File
@@ -0,0 +1,356 @@
---
title: Hacking on systemd
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Hacking on systemd
We welcome all contributions to systemd. If you notice a bug or a missing
feature, please feel invited to fix it, and submit your work as a
[GitHub Pull Request (PR)](https://github.com/systemd/systemd/pull/new).
Please make sure to follow our [Coding Style](CODING_STYLE) when submitting
patches. Also have a look at our [Contribution Guidelines](CONTRIBUTING).
When adding new functionality, tests should be added. For shared functionality
(in `src/basic/` and `src/shared/`) unit tests should be sufficient. The general
policy is to keep tests in matching files underneath `src/test/`,
e.g. `src/test/test-path-util.c` contains tests for any functions in
`src/basic/path-util.c`. If adding a new source file, consider adding a matching
test executable. For features at a higher level, tests in `src/test/` are very
strongly recommended. If that is not possible, integration tests in `test/` are
encouraged.
Please also have a look at our list of [code quality tools](CODE_QUALITY) we
have setup for systemd, to ensure our codebase stays in good shape.
Please always test your work before submitting a PR. For many of the components
of systemd testing is straightforward as you can simply compile systemd and
run the relevant tool from the build directory.
For some components (most importantly, systemd/PID 1 itself) this is not
possible, however. In order to simplify testing for cases like this we provide
a set of `mkosi` build files directly in the source tree.
[mkosi](https://github.com/systemd/mkosi) is a tool for building clean OS images
from an upstream distribution in combination with a fresh build of the project
in the local working directory. To make use of this, please install `mkosi` v19
or newer using your distribution's package manager or from the
[GitHub repository](https://github.com/systemd/mkosi). `mkosi` will build an
image for the host distro by default. First, run `mkosi genkey` to generate a key
and certificate to be used for secure boot and verity signing. After that is done,
it is sufficient to type `mkosi` in the systemd project directory to generate a disk
image you can boot either in `systemd-nspawn` or in a UEFI-capable VM:
```sh
$ sudo mkosi boot # nspawn still needs sudo for now
```
or:
```sh
$ mkosi qemu
```
Every time you rerun the `mkosi` command a fresh image is built, incorporating
all current changes you made to the project tree.
By default a directory image is built. This requires `virtiofsd` to be installed
on the host. To build a disk image instead which does not require `virtiofsd`,
add the following to `mkosi.local.conf`:
```conf
[Output]
Format=disk
```
To boot in UEFI mode instead of using QEMU's direct kernel boot, add the following
to `mkosi.local.conf`:
```conf
[Host]
QemuFirmware=uefi
```
Putting this all together, here's a series of commands for preparing a patch
for systemd:
```sh
$ git clone https://github.com/systemd/mkosi.git # If mkosi v19 or newer is not packaged by your distribution
$ ln -s $PWD/mkosi/bin/mkosi /usr/local/bin/mkosi # If mkosi v19 or newer is not packaged by your distribution
$ git clone https://github.com/systemd/systemd.git
$ cd systemd
$ git checkout -b <BRANCH> # where BRANCH is the name of the branch
$ vim src/core/main.c # or wherever you'd like to make your changes
$ mkosi -f qemu # (re-)build and boot up the test image in qemu
$ git add -p # interactively put together your patch
$ git commit # commit it
$ git push -u <REMOTE> # where REMOTE is your "fork" on GitHub
```
And after that, head over to your repo on GitHub and click "Compare & pull request"
If you want to do a local build without mkosi, most distributions also provide
very simple and convenient ways to install most development packages necessary
to build systemd:
```sh
# Fedora
$ sudo dnf builddep systemd
# Debian/Ubuntu
$ sudo apt-get build-dep systemd
# Arch
$ sudo pacman -S devtools
$ pkgctl repo clone --protocol=https systemd
$ cd systemd
$ makepkg -seoc
```
After installing the development packages, systemd can be built from source as follows:
```sh
$ meson setup build <options>
$ ninja -C build
$ meson test -C build
```
Happy hacking!
## Templating engines in .in files
Some source files are generated during build. We use two templating engines:
* meson's `configure_file()` directive uses syntax with `@VARIABLE@`.
See the
[Meson docs for `configure_file()`](https://mesonbuild.com/Reference-manual.html#configure_file)
for details.
{% raw %}
* most files are rendered using jinja2, with `{{VARIABLE}}` and `{% if … %}`,
`{% elif … %}`, `{% else … %}`, `{% endif … %}` blocks. `{# … #}` is a
jinja2 comment, i.e. that block will not be visible in the rendered
output. `{% raw %} … `{% endraw %}`{{ '{' }}{{ '% endraw %' }}}` creates a block
where jinja2 syntax is not interpreted.
See the
[Jinja Template Designer Documentation](https://jinja2docs.readthedocs.io/en/stable/templates.html#synopsis)
for details.
Please note that files for both template engines use the `.in` extension.
## Developer and release modes
In the default meson configuration (`-Dmode=developer`), certain checks are
enabled that are suitable when hacking on systemd (such as internal
documentation consistency checks). Those are not useful when compiling for
distribution and can be disabled by setting `-Dmode=release`.
## Sanitizers in mkosi
See [Testing systemd using sanitizers](TESTING_WITH_SANITIZERS) for more information
on how to build with sanitizers enabled in mkosi.
## Fuzzers
systemd includes fuzzers in `src/fuzz/` that use libFuzzer and are automatically
run by [OSS-Fuzz](https://github.com/google/oss-fuzz) with sanitizers.
To add a fuzz target, create a new `src/fuzz/fuzz-foo.c` file with a `LLVMFuzzerTestOneInput`
function and add it to the list in `src/fuzz/meson.build`.
Whenever possible, a seed corpus and a dictionary should also be added with new
fuzz targets. The dictionary should be named `src/fuzz/fuzz-foo.dict` and the seed
corpus should be built and exported as `$OUT/fuzz-foo_seed_corpus.zip` in
`tools/oss-fuzz.sh`.
The fuzzers can be built locally if you have libFuzzer installed by running
`tools/oss-fuzz.sh`, or by running:
```
CC=clang CXX=clang++ \
meson setup build-libfuzz -Dllvm-fuzz=true -Db_sanitize=address,undefined -Db_lundef=false \
-Dc_args='-fno-omit-frame-pointer -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION'
ninja -C build-libfuzz fuzzers
```
Each fuzzer then can be then run manually together with a directory containing
the initial corpus:
```
export UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
build-libfuzz/fuzz-varlink-idl test/fuzz/fuzz-varlink-idl/
```
Note: the `halt_on_error=1` UBSan option is especially important, otherwise
the fuzzer won't crash when undefined behavior is triggered.
You should also confirm that the fuzzers can be built and run using
[the OSS-Fuzz toolchain](https://google.github.io/oss-fuzz/advanced-topics/reproducing/#building-using-docker):
```
path_to_systemd=...
git clone --depth=1 https://github.com/google/oss-fuzz
cd oss-fuzz
for sanitizer in address undefined memory; do
for engine in libfuzzer afl honggfuzz; do
./infra/helper.py build_fuzzers --sanitizer "$sanitizer" --engine "$engine" \
--clean systemd "$path_to_systemd"
./infra/helper.py check_build --sanitizer "$sanitizer" --engine "$engine" \
-e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd
done
done
./infra/helper.py build_fuzzers --clean --architecture i386 systemd "$path_to_systemd"
./infra/helper.py check_build --architecture i386 -e ALLOWED_BROKEN_TARGETS_PERCENTAGE=0 systemd
./infra/helper.py build_fuzzers --clean --sanitizer coverage systemd "$path_to_systemd"
./infra/helper.py coverage --no-corpus-download systemd
```
If you find a bug that impacts the security of systemd, please follow the
guidance in [CONTRIBUTING.md](CONTRIBUTING) on how to report a security vulnerability.
For more details on building fuzzers and integrating with OSS-Fuzz, visit:
- [Setting up a new project - OSS-Fuzz](https://google.github.io/oss-fuzz/getting-started/new-project-guide/)
- [Tutorials - OSS-Fuzz](https://google.github.io/oss-fuzz/reference/useful-links/#tutorials)
## Debugging binaries that need to run as root in vscode
When trying to debug binaries that need to run as root, we need to do some custom configuration in vscode to
have it try to run the applications as root and to ask the user for the root password when trying to start
the binary. To achieve this, we'll use a custom debugger path which points to a script that starts `gdb` as
root using `pkexec`. pkexec will prompt the user for their root password via a graphical interface. This
guide assumes the C/C++ extension is used for debugging.
First, create a file `sgdb` in the root of the systemd repository with the following contents and make it
executable:
```
#!/bin/sh
exec pkexec gdb "$@"
```
Then, open launch.json in vscode, and set `miDebuggerPath` to `${workspaceFolder}/sgdb` for the corresponding
debug configuration. Now, whenever you try to debug the application, vscode will try to start gdb as root via
pkexec which will prompt you for your password via a graphical interface. After entering your password,
vscode should be able to start debugging the application.
For more information on how to set up a debug configuration for C binaries, please refer to the official
vscode documentation [here](https://code.visualstudio.com/docs/cpp/launch-json-reference)
## Debugging systemd with mkosi + vscode
To simplify debugging systemd when testing changes using mkosi, we're going to show how to attach
[VSCode](https://code.visualstudio.com/)'s debugger to an instance of systemd running in a mkosi image using
QEMU.
To allow VSCode's debugger to attach to systemd running in a mkosi image, we have to make sure it can access
the virtual machine spawned by mkosi where systemd is running. mkosi makes this possible via a handy SSH
option that makes the generated image accessible via SSH when booted. Thus you must build the image with
`mkosi --ssh`. The easiest way to set the option is to create a file `mkosi.local.conf` in the root of the
repository and add the following contents:
```
[Host]
Ssh=yes
RuntimeTrees=.
```
Also make sure that the SSH agent is running on your system and that you've added your SSH key to it with
`ssh-add`. Also make sure that `virtiofsd` is installed.
After rebuilding the image and booting it with `mkosi qemu`, you should now be able to connect to it by
running `mkosi ssh` from the same directory in another terminal window.
Now we need to configure VSCode. First, make sure the C/C++ extension is installed. If you're already using
a different extension for code completion and other IDE features for C in VSCode, make sure to disable the
corresponding parts of the C/C++ extension in your VSCode user settings by adding the following entries:
```json
"C_Cpp.formatting": "Disabled",
"C_Cpp.intelliSenseEngine": "Disabled",
"C_Cpp.enhancedColorization": "Disabled",
"C_Cpp.suggestSnippets": false,
```
With the extension set up, we can create the launch.json file in the .vscode/ directory to tell the VSCode
debugger how to attach to the systemd instance running in our mkosi container/VM. Create the file, and possibly
the directory, and add the following contents:
```json
{
"version": "0.2.0",
"configurations": [
{
"type": "cppdbg",
"program": "/usr/lib/systemd/systemd",
"processId": "${command:pickRemoteProcess}",
"request": "attach",
"name": "systemd",
"pipeTransport": {
"pipeProgram": "mkosi",
"pipeArgs": [
"-C",
"/path/to/systemd/repo/directory/on/host/system/",
"ssh"
],
"debuggerPath": "/usr/bin/gdb"
},
"MIMode": "gdb",
"sourceFileMap": {
"/root/src/systemd": {
"editorPath": "${workspaceFolder}",
"useForBreakpoints": false
},
}
}
]
}
```
Now that the debugger knows how to connect to our process in the container/VM and we've set up the necessary
source mappings, go to the "Run and Debug" window and run the "systemd" debug configuration. If everything
goes well, the debugger should now be attached to the systemd instance running in the container/VM. You can
attach breakpoints from the editor and enjoy all the other features of VSCode's debugger.
To debug systemd components other than PID 1, set "program" to the full path of the component you want to
debug and set "processId" to "${command:pickProcess}". Now, when starting the debugger, VSCode will ask you
the PID of the process you want to debug. Run `systemctl show --property MainPID --value <component>` in the
container to figure out the PID and enter it when asked and VSCode will attach to that process instead.
## Debugging systemd-boot
During boot, systemd-boot and the stub loader will output messages like
`systemd-boot@0x0A` and `systemd-stub@0x0B`, providing the base of the loaded
code. This location can then be used to attach to a QEMU session (provided it
was run with `-s`). See `debug-sd-boot.sh` script in the tools folder which
automates this processes.
If the debugger is too slow to attach to examine an early boot code passage,
the call to `DEFINE_EFI_MAIN_FUNCTION()` can be modified to enable waiting. As
soon as the debugger has control, we can then run `set variable wait = 0` or
`return` to continue. Once the debugger has attached, setting breakpoints will
work like usual.
To debug systemd-boot in an IDE such as VSCode we can use a launch configuration like this:
```json
{
"name": "systemd-boot",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/src/boot/efi/systemd-bootx64.efi",
"cwd": "${workspaceFolder}",
"MIMode": "gdb",
"miDebuggerServerAddress": ":1234",
"setupCommands": [
{ "text": "shell mkfifo /tmp/sdboot.{in,out}" },
{ "text": "shell qemu-system-x86_64 [...] -s -serial pipe:/tmp/sdboot" },
{ "text": "shell ${workspaceFolder}/tools/debug-sd-boot.sh ${workspaceFolder}/build/src/boot/efi/systemd-bootx64.efi /tmp/sdboot.out systemd-boot.gdb" },
{ "text": "source /tmp/systemd-boot.gdb" },
]
}
```
@@ -0,0 +1,58 @@
---
title: Porting to New Architectures
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Porting systemd to New Architectures
Here's a brief checklist of things to implement when porting systemd to a new
architecture.
1. Patch
[src/basic/architecture.h](https://github.com/systemd/systemd/blob/main/src/basic/architecture.h)
and
[src/basic/architecture.c](https://github.com/systemd/systemd/blob/main/src/basic/architecture.c)
to make your architecture known to systemd. Besides an `ARCHITECTURE_XYZ`
enumeration entry you need to provide an implementation of
`native_architecture()` and `uname_architecture()`.
2. Patch
[src/shared/gpt.h](https://github.com/systemd/systemd/blob/main/src/shared/gpt.h)
and
[src/shared/gpt.c](https://github.com/systemd/systemd/blob/main/src/shared/gpt.c)
and define a new set of GPT partition type UUIDs for the root file system,
`/usr/` file system, and the matching Verity and Verity signature
partitions. Use `systemd-id128 new -p` to generate new suitable UUIDs you
can use for this. Make sure to register your new types in the various
functions in `gpt.c`. Also make sure to update the tables in
[Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification)
and `man/systemd-gpt-auto-generator.xml` accordingly.
3. If your architecture supports UEFI, make sure to update the `efi_arch`
variable logic in `meson.build` to be set to the right architecture string
as defined by the UEFI specification. (This ensures that `systemd-boot` will
be built as the appropriately named `BOOT<arch>.EFI` binary.) Also, if your
architecture uses a special boot protocol for the Linux kernel, make sure to
implement it in `src/boot/efi/linux*.c`, so that the `systemd-stub` EFI stub
can work.
4. Make sure to register the right system call numbers for your architecture in
`src/basic/missing_syscall_def.h`. systemd uses various system calls the
Linux kernel provides that are currently not wrapped by glibc (or are only
in very new glibc), and we need to know the right numbers for them. It might
also be necessary to tweak `src/basic/raw-clone.h`.
5. Make sure the code in `src/shared/seccomp-util.c` properly understands the
local architecture and its system call quirks.
6. If your architecture uses a `/lib64/` library directory, then make sure that
the `BaseFilesystem` table in `src/shared/base-filesystem.c` has an entry
for it so that it can be set up automatically if missing. This is useful to
support booting into OS trees that have an empty root directory with only
`/usr/` mounted in.
7. If your architecture supports VM virtualization and provides CPU opcodes
similar to x86' CPUID, consider adding native support for detecting VMs this
way to `src/basic/virt.c`.
+30
View File
@@ -0,0 +1,30 @@
---
title: Steps to a Successful Release
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Steps to a Successful Release
1. Add all items to NEWS
2. Update the contributors list in NEWS (`ninja -C build git-contrib`)
3. Update the time and place in NEWS
4. Update hwdb (`ninja -C build update-hwdb`, `ninja -C build update-hwdb-autosuspend`, commit separately).
5. Update syscall numbers (`ninja -C build update-syscall-tables update-syscall-header`).
6. [RC1] Update library numbers in `meson.build`
7. Update version number in `meson.version` (e.g. from `v256~devel` to `v256~rc1` or from `v256~rc3` to `v256`)
8. Check dbus docs with `ninja -C build update-dbus-docs`
9. Update translation strings (`cd build`, `meson compile systemd-pot`, `meson compile systemd-update-po`) - drop the header comments from `systemd.pot` + re-add SPDX before committing. If the only change in a file is the 'POT-Creation-Date' field, then ignore that file.
10. Tag the release: `version=vXXX~rcY && git tag -s "${version}" -m "systemd ${version}"`. Note that this uses a tilde (\~) instead of a hyphen (-) because tildes sort lower in version comparisons according to the [version format specification](https://uapi-group.org/specifications/specs/version_format_specification/), and we want `v255~rc1` to sort lower than `v255`.
11. Do `ninja -C build`
12. Make sure that the version string and package string match: `build/systemctl --version`
13. [FINAL] Close the github milestone and open a new one (https://github.com/systemd/systemd/milestones)
14. "Draft" a new release on github (https://github.com/systemd/systemd/releases/new), mark "This is a pre-release" if appropriate.
15. Check that announcement to systemd-devel, with a copy&paste from NEWS, was sent. This should happen automatically.
16. Update IRC topic (`/msg chanserv TOPIC #systemd Version NNN released | Online resources https://systemd.io/`)
17. [FINAL] Push commits to stable, create an empty -stable branch: `git push systemd-stable --atomic origin/main:main origin/main:refs/heads/${version}-stable`.
18. [FINAL] Build and upload the documentation (on the -stable branch): `ninja -C build doc-sync`
19. [FINAL] Change the default branch to latest release (https://github.com/systemd/systemd-stable/settings/branches).
20. [FINAL] Change the Github Pages branch in the stable repository to the newly created branch (https://github.com/systemd/systemd-stable/settings/pages) and set the 'Custom domain' to 'systemd.io'
21. [FINAL] Update version number in `meson.version` to the devel version of the next release (e.g. from `v256` to `v257~devel`)
+14
View File
@@ -0,0 +1,14 @@
---
title: Reporting of Security Vulnerabilities
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Reporting of Security Vulnerabilities
If you discover a security vulnerability, we'd appreciate a non-public disclosure. systemd developers can be contacted privately on the **[systemd-security@redhat.com](mailto:systemd-security@redhat.com) mailing list**. The disclosure will be coordinated with distributions.
(The [issue tracker](https://github.com/systemd/systemd/issues) and [systemd-devel mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) are fully public.)
Subscription to the systemd-security mailing list is open to **regular systemd contributors and people working in the security teams of various distributions**. Those conditions should be backed by publicly accessible information (ideally, a track of posts and commits from the mail address in question). If you fall into one of those categories and wish to be subscribed, submit a **[subscription request](https://www.redhat.com/mailman/listinfo/systemd-security)**.
@@ -0,0 +1,106 @@
---
title: Testing systemd Using Sanitizers
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Testing systemd Using Sanitizers
To catch the *nastier* kind of bugs, you can run your code with [Address Sanitizer](https://clang.llvm.org/docs/AddressSanitizer.html)
and [Undefined Behavior Sanitizer](https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html).
This is mostly done automagically by various CI systems for each PR, but you may
want to do it locally as well. The process slightly varies depending on the
compiler you want to use and which part of the test suite you want to run.
## mkosi
To build with sanitizers in mkosi, create a file `mkosi.local.conf` and add the following contents:
```
[Content]
Environment=SANITIZERS=address,undefined
```
The value of `SANITIZERS` is passed directly to meson's `b_sanitize` option, See
https://mesonbuild.com/Builtin-options.html#base-options for the format expected by the option. Currently,
only the sanitizers supported by gcc can be used, which are `address` and `undefined`.
Note that this will only work with a recent version of mkosi (>= 14 or by running mkosi directly from source).
## gcc
gcc compiles in sanitizer libraries dynamically by default, so you need to get
the shared libraries first - on Fedora these are shipped as separate packages
(`libasan` for Address Sanitizer and `libubsan` for Undefined Behavior Sanitizer).
The compilation itself is then a matter of simply adding `-Db_sanitize=address,undefined`
to `meson`. That's it - following executions of `meson test` and integration tests
under `test/` subdirectory will run with sanitizers enabled. However, to get
truly useful results, you should tweak the runtime configuration of respective
sanitizers; e.g. in systemd we set the following environment variables:
```bash
ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
```
## clang
In case of clang things are somewhat different - the sanitizer libraries are
compiled in statically by default. This is not an issue if you plan to run
only the unit tests, but for integration tests you'll need to convince clang
to use the dynamic versions of sanitizer libraries.
First of all, pass `-shared-libsan` to both `clang` and `clang++`:
```bash
CFLAGS=-shared-libasan
CXXFLAGS=-shared-libasan
```
The `CXXFLAGS` are necessary for `src/libsystemd/sd-bus/test-bus-vtable-cc.c`. Compilation
is then the same as in case of gcc, simply add `-Db_sanitize=address,undefined`
to the `meson` call and use the same environment variables for runtime configuration.
```bash
ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1
UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1
```
After this, you'll probably notice that all compiled binaries complain about
missing `libclang_rt.asan*` library. To fix this, you have to install clang's
runtime libraries, usually shipped in the `compiler-rt` package. As these libraries
are installed in a non-standard location (non-standard for `ldconfig`), you'll
need to manually direct binaries to the respective runtime libraries.
```
# Optionally locate the respective runtime DSO
$ ldd build/systemd | grep libclang_rt.asan
libclang_rt.asan-x86_64.so => not found
libclang_rt.asan-x86_64.so => not found
$ find /usr/lib* /usr/local/lib* -type f -name libclang_rt.asan-x86_64.so 2>/dev/null
/usr/lib64/clang/7.0.1/lib/libclang_rt.asan-x86_64.so
# Set the LD_LIBRARY_PATH accordingly
export LD_LIBRARY_PATH=/usr/lib64/clang/7.0.1/lib/
# If the path is correct, the "not found" message should change to an actual path
$ ldd build/systemd | grep libclang_rt.asan
libclang_rt.asan-x86_64.so => /usr/lib64/clang/7.0.1/lib/libclang_rt.asan-x86_64.so (0x00007fa9752fc000)
```
This should help binaries to correctly find necessary sanitizer DSOs.
Also, to make the reports useful, `llvm-symbolizer` tool is required (usually
part of the `llvm` package).
## Background notes
The reason why you need to force dynamic linking in case of `clang` is that some
applications make use of `libsystemd`, which is compiled with sanitizers as well.
However, if a *standard* (uninstrumented) application loads an instrumented library,
it will immediately fail due to unresolved symbols. To fix/workaround this, you
need to pre-load the ASan DSO using `LD_PRELOAD=/path/to/asan/dso`, which will
make things work as expected in most cases. This will, obviously, not work with
statically linked sanitizer libraries.
These shenanigans are performed automatically when running the integration test
suite (i.e. `test/TEST-??-*`) and are located in `test/test-functions` (mainly,
but not only, in the `create_asan_wrapper` function).
+81
View File
@@ -0,0 +1,81 @@
---
title: Notes for Translators
category: Contributing
layout: default
SPDX-License-Identifier: LGPL-2.1-or-later
---
# Notes for Translators
systemd depends on the `gettext` package for multilingual support.
You'll find the i18n files in the `po/` directory.
The build system (meson/ninja) can be used to generate a template (`*.pot`),
which can be used to create new translations.
It can also merge the template into the existing translations (`*.po`), to pick
up new strings in need of translation.
Finally, it is able to compile the translations (to `*.gmo` files), so that
they can be used by systemd software. (This step is also useful to confirm the
syntax of the `*.po` files is correct.)
## Creating a New Translation
To create a translation to a language not yet available, start by creating the
initial template:
```
$ ninja -C build/ systemd-pot
```
This will generate file `po/systemd.pot` in the source tree.
Then simply copy it to a new `${lang_code}.po` file, where
`${lang_code}` is the two-letter code for a language
(possibly followed by a two-letter uppercase country code), according to the
ISO 639 standard.
In short:
```
$ cp po/systemd.pot po/${lang_code}.po
```
Then edit the new `po/${lang_code}.po` file (for example,
using the `poedit` GUI editor.)
## Updating an Existing Translation
Start by updating the `*.po` files from the latest template:
```
$ ninja -C build/ systemd-update-po
```
This will touch all the `*.po` files, so you'll want to pay attention when
creating a git commit from this change, to only include the one translation
you're actually updating.
Edit the `*.po` file, looking for empty translations and translations marked as
"fuzzy" (which means the merger found a similar message that needs to be
reviewed as it's expected not to match exactly.)
You can use any text editor to update the `*.po` files, but a good choice is
the `poedit` editor, a graphical application specifically designed for this
purpose.
Once you're done, create a git commit for the update of the `po/*.po` file you
touched. Remember to undo the changes to the other `*.po` files (for instance,
using `git checkout -- po/` after you commit the changes you do want to keep.)
## Recompiling Translations
You can recompile the `*.po` files using the following command:
```
$ ninja -C build/ systemd-gmo
```
The resulting files will be saved in the `build/po/` directory.