+- 8ch indent, no tabs, except for files in man/ which are 2ch indent,
+ and still no tabs
-- 8ch indent, no tabs
+- 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, ~140ch should be enough really.
- Variables and functions *must* be static, unless they have a
prototype, and are supposed to be exported.
- For robustness reasons, destructors should be able to destruct
half-initialized objects, too
-- Error codes are returned as negative Exxx. i.e. return -EINVAL. There
+- 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".
more than one cause, it *really* should have "int" as return value
for the error code.
-- Don't bother with error checking whether writing to stdout/stderr
+- 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's OK to log with DEBUG level
+ 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's no excuse. In program code, you can use
+- 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 involve synchronously talking to services that we would need
to start up
-- Don't synchronously talk to any other service from PID 1, due to
+- Do not synchronously talk to any other service from PID 1, due to
risk of deadlocks
-- Avoid fixed sized string buffers, unless you really know the maximum
+- 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. Often it is nicer
- to use dynamic memory, alloca() or VLAs. If you do allocate fixed
- size strings on the stack, then it's probably only OK if you either
+ 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!)
doing something wrong!
- Stay uniform. For example, always use "usec_t" for time
- values. Don't usec mix msec, and usec and whatnot.
+ 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!
{
}
- But it's OK if you don't.
+ But it is OK if you do not.
-- Don't write "foo ()", write "foo()".
+- 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.
- 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 upgraded
+ no speed benefit, and on calls like printf() "float"s get promoted
to "double"s anyway, so there is no point.
-- Don't invoke functions when you allocate variables on the stack. Wrong:
+- Do not invoke functions when you allocate variables on the stack. Wrong:
{
int a = foobar();
backwards!
- Think about the types you use. If a value cannot sensibly be
- negative, don't use "int", but use "unsigned".
+ negative, do not use "int", but use "unsigned".
-- Don't use types like "short". They *never* make sense. Use ints,
+- Do not use types like "short". They *never* make sense. Use ints,
longs, long longs, all in unsigned+signed fashion, and the fixed
size types uint32_t and so on, as well as size_t, but nothing else.
users then 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 shouldn't expect these checks to fail,
+ 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.
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". Everytime a
+ 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
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
+
+- We never use the XDG version of basename(). glibc defines it in
+ libgen.h. The only reason to include that file is because dirname()
+ is needed. Everytime you need that please immediately undefine
+ basename(), and add a comment about it, so that no code ever ends up
+ using the XDG 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 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.