SYSTEMD....GENERATOR(7)

๐ŸŒธ NAME ๐ŸŒธ

systemd.environment-generator โ€” bestie, these are the systemd environment file generators ๐Ÿ’–

It's manual section 7, so you know it's a ~concepts~ page, not a command you run. Sit with me, this one's cute actually.


โœจ SYNOPSIS โœจ

/usr/lib/systemd/system-environment-generators/some-generator

/usr/lib/systemd/user-environment-generators/some-generator

    /run/systemd/system-environment-generators/*
    /etc/systemd/system-environment-generators/*
    /usr/local/lib/systemd/system-environment-generators/*
    /usr/lib/systemd/system-environment-generators/*

    /run/systemd/user-environment-generators/*
    /etc/systemd/user-environment-generators/*
    /usr/local/lib/systemd/user-environment-generators/*
    /usr/lib/systemd/user-environment-generators/*

Like. That's it. That's the whole synopsis. A bunch of directories and the lil executables that live inside them ๐Ÿซถ


๐Ÿฆ‹ DESCRIPTION ๐Ÿฆ‹

OK so generators are these small executables that live in /usr/lib/systemd/system-environment-generators/ and all those other directories we just listed up there. And systemd(1) runs them very early at the startup of every manager, and again whenever the configuration gets reloaded โ€” and listen, this happens before it runs the generators described in systemd.generator(7), and before it starts any units at all. Early early. First-thing energy. โฐ

And what do they do? Environment generators get to override the environment that the manager exports to services and other processes. They literally rewrite the vibe of your environment. Iconic behavior honestly ๐Ÿ’…

Generators get loaded from a set of paths that was decided during compilation โ€” that's the list up in the synopsis. System and user environment generators come from directories whose names end in system-environment-generators/ and user-environment-generators/, respectively. And here's the rule: a generator found in a directory listed earlier overrides one with the same name sitting in a directory lower down the list [1].

You can also mask a generator so it never runs โ€” either drop a symlink pointing at /dev/null there, or an empty file. Boom, silenced. ๐Ÿ”‡

โš ๏ธ Heads up though: the order of the two directories with the highest priority is reversed compared to the unit load path. So generators in /run/ overwrite those in /etc/. Not the other way around. Don't get got.

After you install new generators or update the configuration, you can run systemctl daemon-reload. That re-runs all the generators and updates the environment configuration. It'll be used for any services started after that. Slay โœจ

Environment file generators run pretty much the same way as the unit file generators in systemd.generator(7), except for these two differences:

  • Generators are executed sequentially in the alphanumerical order of the final component of their name. And the output of each generator is immediately parsed and used to update the environment for the generators that run after it. So yes bestie โ€” later generators can use and/or modify the output of earlier ones. It's a whole pipeline ๐Ÿงš
  • Generators are run by every manager instance, and their output can be different for each user. Personal. Bespoke. Main character energy.
๐Ÿ’ก Pro tip (well, the page's tip): use numerical prefixes on your generator names. It makes the ordering situation so much simpler. Trust. ๐Ÿ”ข

๐ŸŽ€ EXAMPLES ๐ŸŽ€

Example 1. A simple generator that extends an environment variable if a directory exists in the file system

# 50-xdg-data-dirs.sh

#!/bin/sh
# SPDX-License-Identifier: MIT-0

# set the default value
XDG_DATA_DIRS="${XDG_DATA_DIRS:-/usr/local/share/:/usr/share}"

# add a directory if it exists
if [ -d /opt/foo/share ]; then
    XDG_DATA_DIRS="/opt/foo/share:${XDG_DATA_DIRS}"
fi

# write our output
echo "XDG_DATA_DIRS=${XDG_DATA_DIRS}"

Look at her. Six lines of logic and she's already changing your whole environment. Ate. ๐Ÿ’–

Example 2. A more complicated generator which reads existing configuration and mutates one variable

# 90-rearrange-path.py

#!/usr/bin/python
# SPDX-License-Identifier: MIT-0

"""

Proof-of-concept systemd environment generator that makes sure that bin dirs
are always after matching sbin dirs in the path.
(Changes /sbin:/bin:/foo/bar to /bin:/sbin:/foo/bar.)

This generator shows how to override the configuration possibly created by
earlier generators. It would be easier to write in bash, but let's have it
in Python just to prove that we can, and to serve as a template for more
interesting generators.

"""

import os
import pathlib

def rearrange_bin_sbin(path):
    """Make sure any pair of .../bin, .../sbin directories is in this order

    >>> rearrange_bin_sbin('/bin:/sbin:/usr/sbin:/usr/bin')
    '/bin:/sbin:/usr/bin:/usr/sbin'
    """
    items = [pathlib.Path(p) for p in path.split(':')]
    for i in range(len(items)):
        if 'sbin' in items[i].parts:
            ind = items[i].parts.index('sbin')
            bin = pathlib.Path(*items[i].parts[:ind], 'bin', *items[i].parts[ind + 1 :])
            if bin in items[i + 1 :]:
                j = i + 1 + items[i + 1 :].index(bin)
                items[i], items[j] = items[j], items[i]
    return ':'.join(p.as_posix() for p in items)

if __name__ == '__main__':
    # This should be always set. If it is not, we will just crash, which is OK too.
    path = os.environ['PATH']
    new = rearrange_bin_sbin(path)
    if new != path:
        print(f'PATH={new}')

The way this one literally rearranges your PATH to keep bin dirs after matching sbin dirsโ€ฆ she's doing the most and I respect it ๐Ÿ’…

Example 3. Debugging a generator

SYSTEMD_LOG_LEVEL=debug VAR_A=something VAR_B="something else" \
/usr/lib/systemd/system-environment-generators/path-to-generator

When your generator is acting up, hit it with SYSTEMD_LOG_LEVEL=debug and feed it some vars by hand. Very demure, very mindful debugging. ๐Ÿ”


๐Ÿ‘‘ SEE ALSO ๐Ÿ‘‘

Go read those if you want the full lore. They're all connected, iykyk ๐Ÿ”—


๐Ÿ’€ NOTES ๐Ÿ’€

  1. ๐Ÿ’ฃ๐Ÿ’ฅ๐Ÿงจ๐Ÿ’ฅ๐Ÿ’ฅ๐Ÿ’ฃ Please note that those configuration files must be available at all times. If /usr/local/ is a separate partition, it may not be available during early boot, and must not be used for configuration. Like, genuinely do not do it. This is the one where the manpage itself brought out the explosives. Respect the explosives. ๐Ÿ™ˆ

and that's the whole page, bestie ๐Ÿซถ This was systemd 262.1, page SYSTEMD....GENERATOR(7). Thanks for reading, you're officially a generator girlie now ๐Ÿ’–โœจ๐ŸŽ€

๐Ÿ“ฆ where this page comes from
  • arch rolling: systemd 262.1-1 ยท LGPL-2.1-or-later AND CC0-1.0 AND GPL-2.0-or-later AND MIT-0
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms