Skip to content

env

Publish per-session environment variables to every service of a scandir.

Interface

env [ -h ] import|set|unset|list [<subcommand options>] variable...

A scandir is started long before a session exists — a user one at the first login, the system one at boot. Its environment is frozen at that point and cannot be reloaded. Variables that only a session knows — DISPLAY, WAYLAND_DISPLAY, XAUTHORITY, or anything else a session wants to hand over — therefore never reach the services it supervises.

env is the way in. It writes to the runtime environment directory of the scandir owner, /run/66/environment/<uid>/, one file per variable, named after it. Every service picks up what is published there the next time it starts, without declaring anything in its frontend.

The directory is created along with the scandir and destroyed with it, so nothing published survives a scandir remove. env never creates it: if it is missing, the command says so instead of publishing into a store no service reads.

Subcommands

  • import variable...: publish each variable with the value it has in the environment of the caller. This is pure transport — the value is copied as it is found. A variable that is not set, or set to an empty value, is skipped with a warning; nothing is computed, guessed or checked for reachability.

  • set variable=value...: publish each pair with the given value.

  • unset variable...: withdraw each variable. A variable that is not published is reported with a warning and the command carries on.

  • list: print the published variables, one variable=value pair per line.

Options

  • -h, --help: prints this help.

Precedence

66-execute rebuilds the environment of a service every time it starts. The runtime environment is merged last, so a published variable wins over every other source:

    environment inherited from the scandir
 <  the [Environment] section of the frontend
 <  the service configuration file (66 configure)
 <  the ImportFile files
 <  /run/66/environment/<uid>/                    <- 66 env

The whole stack is then expanded once, when every source has been merged. A published value is therefore a first-class part of the environment rather than a late patch on it: a ${...} it contains is resolved like any other, and the variable it defines can itself be referenced by a ${...} written in the Execute field of a frontend — see Substitution in Execute.

Two consequences worth keeping in mind:

  • A ${HOME} typed into a published value is not kept literal; it resolves against the environment the service ends up with. env list and the stored file still show it as it was typed — the expansion happens when a service starts, not when the value is published.
  • A publication replaces the whole declaration of a key, its ! marker included. A key that a frontend keeps out of the environment with ! is exported again, with the published value, as soon as it is published here — the last source merged wins, as everywhere else. env set still refuses a value starting with an exclamation mark, so a publication can never introduce an unexported key itself.

Events

Publishing and withdrawing raise two distinct events on the event daemon of the scandir:

Raised by Event Means
import, set env.<variable> variable is now published with a usable value
unset unenv.<variable> variable is no longer published

Two names rather than one, because a reactor is woken by a name and nothing else: a single env.DISPLAY for both facts would start a service on the very disappearance it was waiting to avoid. A service subscribes to the one it needs:

# frontend: myterm
[Main]
Type = classic
Description = "a terminal that needs a display"
[Start]
Execute = ( xterm )
[Event]
EventType = user
On = ( env.DISPLAY )
Do = start

Reacting to both directions takes two services, since a reactor declares one Do: the one above starts on env.DISPLAY, a second one subscribes to unenv.DISPLAY with Do = stop.

Like the other names 66 raises itself, both carry a dot, which sets them apart from the bare names raised with emit. See the event system for how sources and reactors fit together.

If the event daemon cannot be reached, the variable is still published — the command warns and returns success, since the publication it announces has already taken place. Services will pick the value up at their next start.

Limits

A variable name must match [A-Za-z_][A-Za-z0-9_]*: it is both the name of the file holding the variable and the tail of the event raised for it.

An environment directory cannot hold more than 20 files, so at most 20 variables can be published at a time. env refuses the twenty-first with an explicit error rather than letting the limit break the next service start. See Environment for the syntax and the other limits of an environment directory.

Exit codes

  • 0 success
  • 100 wrong usage
  • 111 system call failed

Usage examples

Hand the display over to the user services from an Xorg startup hook, the same way /etc/X11/xinit/xinitrc.d/ scripts do it for other service managers:

66 env import DISPLAY XAUTHORITY

Publish a value directly:

66 env set EDITOR=nvim

See what a session has published:

66 env list

Withdraw the display when the session ends:

66 env unset DISPLAY XAUTHORITY

See also

  • scandir: the scandir owning the runtime environment directory.
  • configure: the persistent, per-service environment.
  • the event system: reacting to a variable appearing or disappearing.