Back to systemd

Generators

This describes generators as implemented in systemd 183 and newer. Generators have been available before but with slightly less powerful semantics.

Generators are small binaries that live in /lib/systemd/system-generators. systemd will execute those binaries very early at bootup and at configuration reload time -- before the unit files are loaded. The generators can dynamically generate/symlink unit files into special runtime directories (i.e. into the tmpfs that is /run), and extend or override existing definitions freely. Their main purpose is to convert configuration files that are not native unit files dynamically into native unit files.

Generators are not a magic wand. Not all problems are best solved with generators. However they are a valuable tool to dynamically extend the dependency tree of systemd.

Generators are invoked with three arguments, all of them paths to runtime directories where generator tools can place their generated unit files or symlinks.

  1. Normal: argv[1] may be used to override unit files in /usr, but not those in /etc. This means that unit files placed in this directory take precedence over vendor unit configuration but not over native user/administrator unit configuration.
  2. Early: argv[2] may be used to override unit files in /usr and in /etc. This means that unit files placed in this directory take precedence over all configuration, regardless if vendor or user/administrator.
  3. Late: argv[3] may be used to extend the unit file tree but not override any other unit files. Any native configuration files regardless if supplied by the vendor or user/administrator take precedence over the generated ones placed in this directory.

Examples:

  1. systemd-fstab-generator converts /etc/fstab into native mount units. It uses argv[1] as location to place the generated unit files in order to allow the user to override fstab with his own native unit files, but also to ensure that /etc/fstab overrides any vendor default from /usr.
  2. Similar, systemd-cryptsetup-generator converts /etc/crypttab to native service units. It also uses argv[1].
  3. systemd-system-update-generator temporarily redirects default.target to system-update.target if a system update is scheduled. Since this needs to override the default user configuration for default.target it uses argv[2]. (For details about this logic, see Implementing Offline System Updates).

Regarding overriding semantics: there are two rules we try to follow when thinking about the overriding semantics:

  1. User configuration should override vendor configuration. This (mostly) means that stuff from /etc should override stuff from /usr.
  2. Native configuration should override non-native configuration. This (mostly) means that stuff you generate should never override native unit files for the same purpose.

Of these two rules the first rule is probably the more important one and breaks the second one sometimes. Hence, when deciding whether to user argv[1], argv[2], or argv[3] your default choice should probably be argv[1].

A couple of notes:

  1. All generators are executed in parallel. That means all executables in /lib/systemd/system-generators are run at the very same time and need to be able to cope with this parallelism.
  2. Since generators are run very early at boot they cannot rely on any external services. They may not talk to any other process. That includes simple things such as logging to syslog, or systemd itself (this means: no systemctl!). However, they can rely on the most basic kernel functionality to be available, including mounted /sys, /proc, /dev.
  3. Units written by generators are removed when configuration is reloaded. That means the lifetime of the generated units is closely bound to the reload cycles of systemd itself.
  4. Generators should only be used to generate unit files, not any other kind of configuration. Due to the lifecycle logic mentioned above generators are not really the best fit to generate dynamic configuration for other services. If you need to generate dynamic configuration for other services do so in normal services you order before the service in question.
  5. Since syslog is not available (see above) write log messages to /dev/kmsg instead.
  6. It is a good idea to use the SourcePath= directive in generated unit files to specify the source configuration file you are generating the unit from. This makes things more easily understood by the user and also has the benefit that systemd can warn the user about configuration files that changed on disk but have not been read yet by systemd.
  7. Generators may write out dynamic unit files or just hook unit files into other units with the usual .wants/ or .requires/ symlinks. Often it is nicer to simply instantiate a template unit file from /usr with a generator instead of writing out entirely dynamic unit files. Of course this works only if a single parameter is to be used.
  8. If you are careful you can implement generators in shell scripts. We do recommend C code however, since generators delay are executed synchronously and hence delay the entire boot if they are slow.
  9. Instead of heading off now and writing all kind of generators for legacy configuration file formats, please think twice! It's often a better idea to just deprecate old stuff instead of keeping it artificially alive.

Or in short: Don't do IPC from generators. Don't use syslog. Don't use the bus. Don't use systemctl. Use /dev/kmsg for logging. Use SourcePath=. Don't write out non-unit configuration files from generators. Thank you!