Add support for user units
With ‘systemd.user.units’ and ‘systemd.user.services’, you can specify units used by per-user systemd instances. For example, systemd.user.services.foo = { description = "foo"; wantedBy = [ "default.target" ]; serviceConfig.ExecStart = "${pkgs.foo}/bin/foo"; }; declares a unit ‘foo.service’ that gets started automatically when the user systemd instance starts, and is stopped when the user systemd instance stops. Note that there is at most one systemd instance per user: it's created when a user logs in and there is no systemd instance for that user yet, and it's removed when the user fully logs out (i.e. has no sessions anymore). So if you're simultaneously logged in via X11 and a virtual console, you get only one copy of foo.
This commit is contained in:
parent
073351a5cf
commit
e34a1589fe
@ -24,7 +24,7 @@ let
|
|||||||
ln -s /dev/null $out/${name}
|
ln -s /dev/null $out/${name}
|
||||||
'';
|
'';
|
||||||
|
|
||||||
upstreamUnits =
|
upstreamSystemUnits =
|
||||||
[ # Targets.
|
[ # Targets.
|
||||||
"basic.target"
|
"basic.target"
|
||||||
"sysinit.target"
|
"sysinit.target"
|
||||||
@ -165,7 +165,7 @@ let
|
|||||||
"emergency.service"
|
"emergency.service"
|
||||||
];
|
];
|
||||||
|
|
||||||
upstreamWants =
|
upstreamSystemWants =
|
||||||
[ #"basic.target.wants"
|
[ #"basic.target.wants"
|
||||||
"sysinit.target.wants"
|
"sysinit.target.wants"
|
||||||
"sockets.target.wants"
|
"sockets.target.wants"
|
||||||
@ -174,6 +174,17 @@ let
|
|||||||
"timers.target.wants"
|
"timers.target.wants"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
upstreamUserUnits =
|
||||||
|
[ "basic.target"
|
||||||
|
"default.target"
|
||||||
|
"exit.target"
|
||||||
|
"paths.target"
|
||||||
|
"shutdown.target"
|
||||||
|
"sockets.target"
|
||||||
|
"systemd-exit.service"
|
||||||
|
"timers.target"
|
||||||
|
];
|
||||||
|
|
||||||
makeJobScript = name: text:
|
makeJobScript = name: text:
|
||||||
let x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${name}"; inherit text; };
|
let x = pkgs.writeTextFile { name = "unit-script"; executable = true; destination = "/bin/${name}"; inherit text; };
|
||||||
in "${x}/bin/${name}";
|
in "${x}/bin/${name}";
|
||||||
@ -359,13 +370,13 @@ let
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
units = pkgs.runCommand "units" { preferLocalBuild = true; }
|
generateUnits = type: units: upstreamUnits: upstreamWants:
|
||||||
''
|
pkgs.runCommand "${type}-units" { preferLocalBuild = true; } ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
|
|
||||||
# Copy the upstream systemd units we're interested in.
|
# Copy the upstream systemd units we're interested in.
|
||||||
for i in ${toString upstreamUnits}; do
|
for i in ${toString upstreamUnits}; do
|
||||||
fn=${systemd}/example/systemd/system/$i
|
fn=${systemd}/example/systemd/${type}/$i
|
||||||
if ! [ -e $fn ]; then echo "missing $fn"; false; fi
|
if ! [ -e $fn ]; then echo "missing $fn"; false; fi
|
||||||
if [ -L $fn ]; then
|
if [ -L $fn ]; then
|
||||||
cp -pd $fn $out/
|
cp -pd $fn $out/
|
||||||
@ -377,7 +388,7 @@ let
|
|||||||
# Copy .wants links, but only those that point to units that
|
# Copy .wants links, but only those that point to units that
|
||||||
# we're interested in.
|
# we're interested in.
|
||||||
for i in ${toString upstreamWants}; do
|
for i in ${toString upstreamWants}; do
|
||||||
fn=${systemd}/example/systemd/system/$i
|
fn=${systemd}/example/systemd/${type}/$i
|
||||||
if ! [ -e $fn ]; then echo "missing $fn"; false; fi
|
if ! [ -e $fn ]; then echo "missing $fn"; false; fi
|
||||||
x=$out/$(basename $fn)
|
x=$out/$(basename $fn)
|
||||||
mkdir $x
|
mkdir $x
|
||||||
@ -390,14 +401,16 @@ let
|
|||||||
|
|
||||||
# Symlink all units provided listed in systemd.packages.
|
# Symlink all units provided listed in systemd.packages.
|
||||||
for i in ${toString cfg.packages}; do
|
for i in ${toString cfg.packages}; do
|
||||||
ln -s $i/etc/systemd/system/* $i/lib/systemd/system/* $out/
|
if [ -n "$(echo $i/etc/systemd/${type}/*)" ]; then
|
||||||
|
ln -s $i/etc/systemd/${type}/* $i/lib/systemd/${type}/* $out/
|
||||||
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
# Symlink all units defined by systemd.units. If these are also
|
# Symlink all units defined by systemd.units. If these are also
|
||||||
# provided by systemd or systemd.packages, then add them as
|
# provided by systemd or systemd.packages, then add them as
|
||||||
# <unit-name>.d/overrides.conf, which makes them extend the
|
# <unit-name>.d/overrides.conf, which makes them extend the
|
||||||
# upstream unit.
|
# upstream unit.
|
||||||
for i in ${toString (mapAttrsToList (n: v: v.unit) cfg.units)}; do
|
for i in ${toString (mapAttrsToList (n: v: v.unit) units)}; do
|
||||||
fn=$(basename $i/*)
|
fn=$(basename $i/*)
|
||||||
if [ -e $out/$fn ]; then
|
if [ -e $out/$fn ]; then
|
||||||
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
|
if [ "$(readlink -f $i/$fn)" = /dev/null ]; then
|
||||||
@ -417,14 +430,15 @@ let
|
|||||||
concatMapStrings (name2: ''
|
concatMapStrings (name2: ''
|
||||||
mkdir -p $out/'${name2}.wants'
|
mkdir -p $out/'${name2}.wants'
|
||||||
ln -sfn '../${name}' $out/'${name2}.wants'/
|
ln -sfn '../${name}' $out/'${name2}.wants'/
|
||||||
'') unit.wantedBy) cfg.units)}
|
'') unit.wantedBy) units)}
|
||||||
|
|
||||||
${concatStrings (mapAttrsToList (name: unit:
|
${concatStrings (mapAttrsToList (name: unit:
|
||||||
concatMapStrings (name2: ''
|
concatMapStrings (name2: ''
|
||||||
mkdir -p $out/'${name2}.requires'
|
mkdir -p $out/'${name2}.requires'
|
||||||
ln -sfn '../${name}' $out/'${name2}.requires'/
|
ln -sfn '../${name}' $out/'${name2}.requires'/
|
||||||
'') unit.requiredBy) cfg.units)}
|
'') unit.requiredBy) units)}
|
||||||
|
|
||||||
|
${optionalString (type == "system") ''
|
||||||
# Stupid misc. symlinks.
|
# Stupid misc. symlinks.
|
||||||
ln -s ${cfg.defaultUnit} $out/default.target
|
ln -s ${cfg.defaultUnit} $out/default.target
|
||||||
|
|
||||||
@ -435,6 +449,7 @@ let
|
|||||||
|
|
||||||
ln -s ../local-fs.target ../remote-fs.target ../network.target ../nss-lookup.target \
|
ln -s ../local-fs.target ../remote-fs.target ../network.target ../nss-lookup.target \
|
||||||
../nss-user-lookup.target ../swap.target $out/multi-user.target.wants/
|
../nss-user-lookup.target ../swap.target $out/multi-user.target.wants/
|
||||||
|
''}
|
||||||
''; # */
|
''; # */
|
||||||
|
|
||||||
in
|
in
|
||||||
@ -638,6 +653,25 @@ in
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
systemd.user.units = mkOption {
|
||||||
|
description = "Definition of systemd per-user units.";
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf types.optionSet;
|
||||||
|
options = { name, config, ... }:
|
||||||
|
{ options = concreteUnitOptions;
|
||||||
|
config = {
|
||||||
|
unit = mkDefault (makeUnit name config);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.user.services = mkOption {
|
||||||
|
default = {};
|
||||||
|
type = types.attrsOf types.optionSet;
|
||||||
|
options = [ serviceOptions unitConfig serviceConfig ];
|
||||||
|
description = "Definition of systemd per-user service units.";
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -651,11 +685,15 @@ in
|
|||||||
message = "${name}: Type=oneshot services must have Restart=no";
|
message = "${name}: Type=oneshot services must have Restart=no";
|
||||||
}) cfg.services;
|
}) cfg.services;
|
||||||
|
|
||||||
system.build.units = units;
|
system.build.units = cfg.units;
|
||||||
|
|
||||||
environment.systemPackages = [ systemd ];
|
environment.systemPackages = [ systemd ];
|
||||||
|
|
||||||
environment.etc."systemd/system".source = units;
|
environment.etc."systemd/system".source =
|
||||||
|
generateUnits "system" cfg.units upstreamSystemUnits upstreamSystemWants;
|
||||||
|
|
||||||
|
environment.etc."systemd/user".source =
|
||||||
|
generateUnits "user" cfg.user.units upstreamUserUnits [];
|
||||||
|
|
||||||
environment.etc."systemd/system.conf".text =
|
environment.etc."systemd/system.conf".text =
|
||||||
''
|
''
|
||||||
@ -719,6 +757,9 @@ in
|
|||||||
(v: let n = escapeSystemdPath v.where;
|
(v: let n = escapeSystemdPath v.where;
|
||||||
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
|
in nameValuePair "${n}.automount" (automountToUnit n v)) cfg.automounts);
|
||||||
|
|
||||||
|
systemd.user.units =
|
||||||
|
mapAttrs' (n: v: nameValuePair "${n}.service" (serviceToUnit n v)) cfg.user.services;
|
||||||
|
|
||||||
system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
|
system.requiredKernelConfig = map config.lib.kernelConfig.isEnabled [
|
||||||
"CGROUPS" "AUTOFS4_FS" "DEVTMPFS"
|
"CGROUPS" "AUTOFS4_FS" "DEVTMPFS"
|
||||||
];
|
];
|
||||||
@ -753,10 +794,6 @@ in
|
|||||||
startSession = true;
|
startSession = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
# Provide systemd user units. FIXME: Should make this definable,
|
|
||||||
# just like the system units.
|
|
||||||
environment.etc."systemd/user".source = "${systemd}/example/systemd/user";
|
|
||||||
|
|
||||||
environment.etc."tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
|
environment.etc."tmpfiles.d/x11.conf".source = "${systemd}/example/tmpfiles.d/x11.conf";
|
||||||
|
|
||||||
environment.etc."tmpfiles.d/nixos.conf".text =
|
environment.etc."tmpfiles.d/nixos.conf".text =
|
||||||
|
Loading…
Reference in New Issue
Block a user