chiark / gitweb /
tree-wide: drop redundant if checks before safe_close()
[elogind.git] / CODING_STYLE
index d93ccd8a9813a5d4c595403e53b3b767b04526eb..f13f9becbc0839d246ebffa44c34bcfee6963f72 100644 (file)
+- 8ch indent, no tabs, except for files in man/ which are 2ch indent,
+  and still no tabs
 
-- 8ch indent, no tabs
+- We prefer /* comments */ over // comments, please. This is not C++, after
+  all. (Yes we know that C99 supports both kinds of comments, but still,
+  please!)
 
-- structs in MixedCase, variables, functions in lower_case
+- 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.
 
-- the destructors always unregister the object from the next bigger
+- 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
+- To minimize strict aliasing violations, we prefer unions over casting
 
-- for robustness reasons destructors should be able to destruct
+- 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
-  are some exceptions: for constructors its is OK to return NULL on
-  OOM. For lookup functions NULL is fine too for "not found"
+- 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 the main daemon as this might trigger deadlocks when
-  those lookups involve synchronously talking to services that we
-  would need to start up
+  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!
+
+- 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.
+
+- Please do not allocate variables on the stack in the middle of code,
+  even if C99 allows it. Wrong:
+
+  {
+          a = 5;
+          int b;
+          b = a;
+  }
+
+  Right:
+
+  {
+          int 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".
+
+- 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. 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 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 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
+
+- 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. Everytime 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 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.
 
-- Do not access any directories outside of /etc, /dev, /lib from the
-  init daemon to avoid deadlocks with the automounter
+- 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.
 
-- Don't synchronously talk to any other service, due to risk of
-  deadlocks
+- 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 (;;)".