summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2018-10-31 15:15:41 +0100
committerGitHub <noreply@github.com>2018-10-31 15:15:41 +0100
commitfc03c536538cd5fb29f42eb4a6920f13a9a98e54 (patch)
tree8a2ba5f1dbf53faa404fb4915165f268909212a5
parent9e97a15b5d66797c6d3f523ea40ac00c7e816e93 (diff)
parenteea984028f30bfd8f80180fce56d10f478c1b472 (diff)
downloadsystemd-fc03c536538cd5fb29f42eb4a6920f13a9a98e54.tar.gz
Merge pull request #10573 from faheel/master
Convert remaining docs to Markdown
-rw-r--r--README.md10
-rw-r--r--docs/CODING_STYLE464
-rw-r--r--docs/CODING_STYLE.md495
-rw-r--r--docs/CONTRIBUTING.md4
-rw-r--r--docs/HACKING122
-rw-r--r--docs/HACKING.md123
-rw-r--r--meson.build4
-rw-r--r--src/basic/verbs.c2
8 files changed, 628 insertions, 596 deletions
diff --git a/README.md b/README.md
index b0b0a86538..7d6e0d99a8 100644
--- a/README.md
+++ b/README.md
@@ -12,15 +12,15 @@
General information about systemd can be found in the [systemd Wiki](https://www.freedesktop.org/wiki/Software/systemd).
-Information about build requirements are provided in the [README file](../master/README).
+Information about build requirements is provided in the [README file](README).
-Consult our [NEWS file](../master/NEWS) for information about what's new in the most recent systemd versions.
+Consult our [NEWS file](NEWS) for information about what's new in the most recent systemd versions.
-Please see the [HACKING file](../master/docs/HACKING) for information how to hack on systemd and test your modifications.
+Please see the [Hacking guide](docs/HACKING.md) for information on how to hack on systemd and test your modifications.
-Please see our [Contribution Guidelines](../master/docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
+Please see our [Contribution Guidelines](docs/CONTRIBUTING.md) for more information about filing GitHub Issues and posting GitHub Pull Requests.
-When preparing patches for systemd, please follow our [Coding Style Guidelines](../master/docs/CODING_STYLE).
+When preparing patches for systemd, please follow our [Coding Style Guidelines](docs/CODING_STYLE.md).
If you are looking for support, please contact our [mailing list](https://lists.freedesktop.org/mailman/listinfo/systemd-devel) or join our [IRC channel](irc://irc.freenode.org/%23systemd).
diff --git a/docs/CODING_STYLE b/docs/CODING_STYLE
deleted file mode 100644
index ca6e1cb693..0000000000
--- a/docs/CODING_STYLE
+++ /dev/null
@@ -1,464 +0,0 @@
-- 8ch indent, no tabs, except for files in man/ which are 2ch indent,
- and still no tabs
-
-- 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 discernable 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, ~119ch 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).
-
-- Variables and functions *must* be static, unless they have a
- prototype, and are supposed to be exported.
-
-- structs in MixedCase (with exceptions, such as public API structs),
- variables + functions in lower_case.
-
-- The destructors always unregister 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 "int" as 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 on de_DE as 5000.).
-
-- Try to use this:
-
- void foo() {
- }
-
- instead of this:
-
- void foo()
- {
- }
-
- But it is OK if you do not.
-
-- Single-line "if" blocks should not be enclosed in {}. Use this:
-
- if (foobar)
- waldo();
-
- instead of this:
-
- if (foobar) {
- waldo();
- }
-
-- 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).
-
-- Preferably allocate stack variables on the top of the block:
-
- {
- int a, b;
-
- a = 5;
- b = a;
- }
-
-- Unless you allocate an array, "double" is always the better choice
- than "float". Processors speak "double" natively anyway, so this 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:
-
- {
- int a = foobar();
- uint64_t x = 7;
- }
-
- Right:
-
- {
- int a;
- uint64_t x = 7;
-
- a = foobar();
- }
-
-- 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 ints, longs, long longs, all in
- unsigned+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.
-
-- 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.
-
-- 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.
-
-- 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.
-
-- 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.
-
-- 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.
-
-- 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:
-
- a) open() must get O_CLOEXEC passed
- b) socket() and socketpair() must get SOCK_CLOEXEC passed
- c) recvmsg() must get MSG_CMSG_CLOEXEC set
- d) F_DUPFD_CLOEXEC should be used instead of F_DUPFD, and so on
- f) invocations of fopen() should take "e"
-
-- 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!
-
-- 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).
-
-- 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:
-
- (void) unlink("/foo/bar/baz");
-
- instead of just this:
-
- unlink("/foo/bar/baz");
-
- 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 fds be closed. Given the
- special semantics of those fds, it's probably a good idea to avoid
- them. F_DUPFD_CLOEXEC with "3" as parameter avoids them.
-
-- 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:
-
- 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.
-
-- 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
- behaviour 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.
-
-- Use memzero() or even better zero() instead of memset(..., 0, ...)
-
-- 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:
-
- struct foobar t = {
- .foo = 7,
- .bar = "bazz",
- };
-
- instead of:
-
- struct foobar t;
- zero(t);
- t.foo = 7;
- t.bar = "bazz";
-
-- 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.
-
-- 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 64bit and we
- don't support it any other way, but it could in theory also be
- 32bit. 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.
-
-- Do not use "Signed-Off-By:" in your commit messages. That's a kernel
- thing we don't do in the systemd project.
-
-- 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.
-
-- To determine the length of a constant string "foo", don't bother
- with sizeof("foo")-1, please use STRLEN() instead.
-
-- If you want to concatenate two or more strings, consider using
- strjoin() rather than asprintf(), as the latter is a lot
- slower. This matters particularly in inner loops.
-
-- 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.
-
-- 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.
-
-- 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.
-
-- 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 longs and
- shorts 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.
-
-- 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 uses public APIs
- we expose (i.e. any of the sd-bus, sd-login, sd-id128, ... APIs) must be
- located in src/shared/. All stuff that only uses external libraries from
- other projects (such as glibc's APIs), or APIs from src/basic/ itself should
- be placed in src/basic/. Conversely, src/libsystemd/ may only use symbols
- from src/basic, but not from 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/
- → 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.
-
-- 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.
-
-- 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.
-
-- 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).
-
-- 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.
diff --git a/docs/CODING_STYLE.md b/docs/CODING_STYLE.md
new file mode 100644
index 0000000000..64f7a8cddf
--- /dev/null
+++ b/docs/CODING_STYLE.md
@@ -0,0 +1,495 @@
+# Coding style
+
+- 8ch indent, no tabs, except for files in `man/` which are 2ch indent,
+ and still no tabs.
+
+- 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 discernable 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, ~119ch 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).
+
+- 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:
+
+ ```c
+ void foo() {
+ }
+ ```
+
+ instead of this:
+
+ ```c
+ void foo()
+ {
+ }
+ ```
+
+ But it is OK if you do not.
+
+- Single-line `if` blocks should not be enclosed in `{}`. Use this:
+
+ ```c
+ if (foobar)
+ waldo();
+ ```
+
+ instead of this:
+
+ ```c
+ if (foobar) {
+ waldo();
+ }
+ ```
+
+- 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).
+
+- Preferably allocate stack variables on the top of the block:
+
+ ```c
+ {
+ int a, b;
+
+ a = 5;
+ b = a;
+ }
+ ```
+
+- Unless you allocate an array, `double` is always the better choice
+ than `float`. Processors speak `double` natively anyway, so this 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:
+
+ ```c
+ {
+ int a = foobar();
+ uint64_t x = 7;
+ }
+ ```
+
+ Right:
+
+ ```c
+ {
+ int a;
+ uint64_t x = 7;
+
+ a = foobar();
+ }
+ ```
+
+- 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.
+
+- 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.
+
+- 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.
+
+- 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.
+
+- 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.
+
+- 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.
+
+- 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`.
+
+- 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!
+
+- 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).
+
+- 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");
+ ```
+
+ 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.
+
+- 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.
+
+- 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.
+
+- Use `memzero()` or even better `zero()` instead of `memset(..., 0, ...)`
+
+- 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";
+ ```
+
+- 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.
+
+- 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.
+
+- Do not use "Signed-Off-By:" in your commit messages. That's a kernel
+ thing we don't do in the systemd project.
+
+- 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.
+
+- To determine the length of a constant string `"foo"`, don't bother
+ with `sizeof("foo")-1`, please use `STRLEN()` instead.
+
+- If you want to concatenate two or more strings, consider using
+ `strjoin()` rather than `asprintf()`, as the latter is a lot
+ slower. This matters particularly in inner loops.
+
+- 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.
+
+- 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.
+
+- 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.
+
+- 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.
+
+- 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 uses public APIs
+ we expose (i.e. any of the sd-bus, sd-login, sd-id128, ... APIs) must be
+ located in `src/shared/`. All stuff that only uses external libraries from
+ other projects (such as glibc's APIs), or APIs from `src/basic/` itself should
+ be placed in `src/basic/`. Conversely, `src/libsystemd/` may only use symbols
+ from `src/basic`, but not from `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/`
+ - 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.
+
+- 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.
+
+- 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.
+
+- 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).
+
+- 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.
diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md
index ea15325fe9..6cfdd6f179 100644
--- a/docs/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -24,8 +24,8 @@ If you discover a security vulnerability, we'd appreciate a non-public disclosur
## Posting Pull Requests
* Make sure to post PRs only relative to a very recent git master.
-* Follow our [Coding Style](https://raw.githubusercontent.com/systemd/systemd/master/docs/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 [HACKING](https://raw.githubusercontent.com/systemd/systemd/master/docs/HACKING) for details how to do this.
+* Follow our [Coding Style](CODING_STYLE.md) 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.md) 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 about the new version (no notification is sent just for the commits, so it's easy to miss the update without an explicit comment). If you are a member of the systemd project on GitHub, remove the `reviewed/needs-rework` label.
diff --git a/docs/HACKING b/docs/HACKING
deleted file mode 100644
index c975ca183e..0000000000
--- a/docs/HACKING
+++ /dev/null
@@ -1,122 +0,0 @@
-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 when submitting patches. See
-docs/CODING_STYLE for details. Also have a look at our Contribution Guidelines:
-
- https://github.com/systemd/systemd/blob/master/docs/CONTRIBUTING.md
-
-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 no possible, integration tests in test/ are
-encouraged.
-
-Please also have a look at our list of code quality tools we have setup for systemd,
-to ensure our codebase stays in good shape:
-
- https://github.com/systemd/systemd/blob/master/docs/CODE_QUALITY.md
-
-Please always test your work before submitting a PR. For many of the components
-of systemd testing is straight-forward as you can simply compile systemd and
-run the relevant tool from the build directory.
-
-For some components (most importantly, systemd/PID1 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" 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 acquire "mkosi" from https://github.com/systemd/mkosi first, unless your
-distribution has packaged it already and you can get it from there. After the
-tool is installed it is sufficient to type "mkosi" in the systemd project
-directory to generate a disk image "image.raw" you can boot either in
-systemd-nspawn or in an UEFI-capable VM:
-
- # systemd-nspawn -bi image.raw
-
-or:
-
- # qemu-system-x86_64 -enable-kvm -m 512 -smp 2 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd -hda image.raw
-
-Every time you rerun the "mkosi" command a fresh image is built, incorporating
-all current changes you made to the project tree.
-
-Alternatively, you may install the systemd version from your git check-out
-directly on top of your host system's directory tree. This mostly works fine,
-but of course you should know what you are doing as you might make your system
-unbootable in case of a bug in your changes. Also, you might step into your
-package manager's territory with this. Be careful!
-
-And never forget: most distributions provide very simple and convenient ways to
-install all development packages necessary to build systemd. For example, on
-Fedora the following command line should be sufficient to install all of
-systemd's build dependencies:
-
- # dnf builddep systemd
-
-Putting this all together, here's a series of commands for preparing a patch
-for systemd (this example is for Fedora):
-
- $ sudo dnf builddep systemd # install build dependencies
- $ sudo dnf install mkosi # install tool to quickly build images
- $ git clone https://github.com/systemd/systemd.git
- $ cd systemd
- $ vim src/core/main.c # or wherever you'd like to make your changes
- $ meson build # configure the build
- $ ninja -C build # build it locally, see if everything compiles fine
- $ ninja -C build test # run some simple regression tests
- $ (umask 077; echo 123 > mkosi.rootpw) # set root password used by mkosi
- $ sudo mkosi # build a test image
- $ sudo systemd-nspawn -bi image.raw # boot up the test image
- $ git add -p # interactively put together your patch
- $ git commit # commit it
- $ git push REMOTE HEAD:refs/heads/BRANCH
- # where REMOTE is your "fork" on github
- # and BRANCH is a branch name.
-
-And after that, head over to your repo on github and click "Compare & pull request"
-
-Happy hacking!
-
-
-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. You should also confirm that the fuzzer runs in the
-OSS-Fuzz environment by checking out the OSS-Fuzz repo, and then running
-commands like this:
-
- python infra/helper.py build_image systemd
- python infra/helper.py build_fuzzers --sanitizer memory systemd ../systemd
- python infra/helper.py run_fuzzer systemd fuzz-foo
-
-If you find a bug that impacts the security of systemd, please follow the
-guidance in CONTRIBUTING.md on how to report a security vulnerability.
-
-For more details on building fuzzers and integrating with OSS-Fuzz, visit:
-
- https://github.com/google/oss-fuzz/blob/master/docs/new_project_guide.md
-
- https://llvm.org/docs/LibFuzzer.html
-
- https://github.com/google/fuzzer-test-suite/blob/master/tutorial/libFuzzerTutorial.md
-
- https://chromium.googlesource.com/chromium/src/testing/libfuzzer/+/HEAD/efficient_fuzzer.md
diff --git a/docs/HACKING.md b/docs/HACKING.md
new file mode 100644
index 0000000000..4a7d568087
--- /dev/null
+++ b/docs/HACKING.md
@@ -0,0 +1,123 @@
+# 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) at https://github.com/systemd/systemd/pull/new.
+
+Please make sure to follow our [Coding Style](CODING_STYLE.md) when submitting patches.
+Also have a look at our [Contribution Guidelines](CONTRIBUTING.md).
+
+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 no possible, integration tests in `test/` are
+encouraged.
+
+Please also have a look at our list of [code quality tools](CODE_QUALITY.md) 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 straight-forward as you can simply compile systemd and
+run the relevant tool from the build directory.
+
+For some components (most importantly, systemd/PID1 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` 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 acquire `mkosi` from https://github.com/systemd/mkosi first, unless your
+distribution has packaged it already and you can get it from there. After the
+tool is installed it is sufficient to type `mkosi` in the systemd project
+directory to generate a disk image `image.raw` you can boot either in
+`systemd-nspawn` or in an UEFI-capable VM:
+
+```
+# systemd-nspawn -bi image.raw
+```
+
+or:
+
+```
+# qemu-system-x86_64 -enable-kvm -m 512 -smp 2 -bios /usr/share/edk2/ovmf/OVMF_CODE.fd -hda image.raw
+```
+
+Every time you rerun the `mkosi` command a fresh image is built, incorporating
+all current changes you made to the project tree.
+
+Alternatively, you may install the systemd version from your git check-out
+directly on top of your host system's directory tree. This mostly works fine,
+but of course you should know what you are doing as you might make your system
+unbootable in case of a bug in your changes. Also, you might step into your
+package manager's territory with this. Be careful!
+
+And never forget: most distributions provide very simple and convenient ways to
+install all development packages necessary to build systemd. For example, on
+Fedora the following command line should be sufficient to install all of
+systemd's build dependencies:
+
+```
+# dnf builddep systemd
+```
+
+Putting this all together, here's a series of commands for preparing a patch
+for systemd (this example is for Fedora):
+
+```sh
+$ sudo dnf builddep systemd # install build dependencies
+$ sudo dnf install mkosi # install tool to quickly build images
+$ git clone https://github.com/systemd/systemd.git
+$ cd systemd
+$ vim src/core/main.c # or wherever you'd like to make your changes
+$ meson build # configure the build
+$ ninja -C build # build it locally, see if everything compiles fine
+$ ninja -C build test # run some simple regression tests
+$ (umask 077; echo 123 > mkosi.rootpw) # set root password used by mkosi
+$ sudo mkosi # build a test image
+$ sudo systemd-nspawn -bi image.raw # boot up the test image
+$ git add -p # interactively put together your patch
+$ git commit # commit it
+$ git push REMOTE HEAD:refs/heads/BRANCH
+ # where REMOTE is your "fork" on GitHub
+ # and BRANCH is a branch name.
+```
+
+And after that, head over to your repo on GitHub and click "Compare & pull request"
+
+Happy hacking!
+
+
+## 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`. You should also confirm that the fuzzer runs in the
+OSS-Fuzz environment by checking out the OSS-Fuzz repo, and then running
+commands like this:
+
+```
+python infra/helper.py build_image systemd
+python infra/helper.py build_fuzzers --sanitizer memory systemd ../systemd
+python infra/helper.py run_fuzzer systemd fuzz-foo
+```
+
+If you find a bug that impacts the security of systemd, please follow the
+guidance in [CONTRIBUTING.md](CONTRIBUTING.md) on how to report a security vulnerability.
+
+For more details on building fuzzers and integrating with OSS-Fuzz, visit:
+
+- https://github.com/google/oss-fuzz/blob/master/docs/new_project_guide.md
+- https://llvm.org/docs/LibFuzzer.html
+- https://github.com/google/fuzzer-test-suite/blob/master/tutorial/libFuzzerTutorial.md
+- https://chromium.googlesource.com/chromium/src/testing/libfuzzer/+/HEAD/efficient_fuzzer.md
diff --git a/meson.build b/meson.build
index a0e0305e02..fcbb22b540 100644
--- a/meson.build
+++ b/meson.build
@@ -2828,10 +2828,10 @@ install_data('LICENSE.GPL2',
'LICENSE.LGPL2.1',
'NEWS',
'README',
- 'docs/CODING_STYLE',
+ 'docs/CODING_STYLE.md',
'docs/DISTRO_PORTING.md',
'docs/ENVIRONMENT.md',
- 'docs/HACKING',
+ 'docs/HACKING.md',
'docs/TRANSIENT-SETTINGS.md',
'docs/TRANSLATORS.md',
'docs/UIDS-GIDS.md',
diff --git a/src/basic/verbs.c b/src/basic/verbs.c
index 34c7708080..f68c2bae08 100644
--- a/src/basic/verbs.c
+++ b/src/basic/verbs.c
@@ -23,7 +23,7 @@ bool running_in_chroot_or_offline(void) {
/* Added to support use cases like rpm-ostree, where from %post scripts we only want to execute "preset", but
* not "start"/"restart" for example.
*
- * See doc/ENVIRONMENT.md for docs.
+ * See docs/ENVIRONMENT.md for docs.
*/
r = getenv_bool("SYSTEMD_OFFLINE");
if (r < 0 && r != -ENXIO)