Skip to content

Commit 2af1ee5

Browse files
Merge pull request #259196 from liff/mod/systemd-lock-handler
nixos/systemd-lock-handler: init with corresponding package at 2.4.2
2 parents 0e03f6a + e103c5c commit 2af1ee5

File tree

7 files changed

+185
-0
lines changed

7 files changed

+185
-0
lines changed

nixos/doc/manual/release-notes/rl-2405.section.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m
6767

6868
- [RustDesk](https://rustdesk.com), a full-featured open source remote control alternative for self-hosting and security with minimal configuration. Alternative to TeamViewer.
6969

70+
- [systemd-lock-handler](https://git.sr.ht/~whynothugo/systemd-lock-handler/), a bridge between logind D-Bus events and systemd targets. Available as [services.systemd-lock-handler.enable](#opt-services.systemd-lock-handler.enable).
71+
7072
## Backward Incompatibilities {#sec-release-24.05-incompatibilities}
7173

7274
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

nixos/modules/module-list.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,7 @@
12361236
./services/system/saslauthd.nix
12371237
./services/system/self-deploy.nix
12381238
./services/system/systembus-notify.nix
1239+
./services/system/systemd-lock-handler.nix
12391240
./services/system/uptimed.nix
12401241
./services/system/zram-generator.nix
12411242
./services/torrent/deluge.nix
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# systemd-lock-handler {#module-services-systemd-lock-handler}
2+
3+
The `systemd-lock-handler` module provides a service that bridges
4+
D-Bus events from `logind` to user-level systemd targets:
5+
6+
- `lock.target` started by `loginctl lock-session`,
7+
- `unlock.target` started by `loginctl unlock-session` and
8+
- `sleep.target` started by `systemctl suspend`.
9+
10+
You can create a user service that starts with any of these targets.
11+
12+
For example, to create a service for `swaylock`:
13+
14+
```nix
15+
{
16+
services.systemd-lock-handler.enable = true;
17+
18+
systemd.user.services.swaylock = {
19+
description = "Screen locker for Wayland";
20+
documentation = ["man:swaylock(1)"];
21+
22+
# If swaylock exits cleanly, unlock the session:
23+
onSuccess = ["unlock.target"];
24+
25+
# When lock.target is stopped, stops this too:
26+
partOf = ["lock.target"];
27+
28+
# Delay lock.target until this service is ready:
29+
before = ["lock.target"];
30+
wantedBy = ["lock.target"];
31+
32+
serviceConfig = {
33+
# systemd will consider this service started when swaylock forks...
34+
Type = "forking";
35+
36+
# ... and swaylock will fork only after it has locked the screen.
37+
ExecStart = "${lib.getExe pkgs.swaylock} -f";
38+
39+
# If swaylock crashes, always restart it immediately:
40+
Restart = "on-failure";
41+
RestartSec = 0;
42+
};
43+
};
44+
}
45+
```
46+
47+
See [upstream documentation](https://sr.ht/~whynothugo/systemd-lock-handler) for more information.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{ config
2+
, pkgs
3+
, lib
4+
, ...
5+
}:
6+
let
7+
cfg = config.services.systemd-lock-handler;
8+
inherit (lib) mkIf mkEnableOption mkPackageOption;
9+
in
10+
{
11+
options.services.systemd-lock-handler = {
12+
enable = mkEnableOption (lib.mdDoc "systemd-lock-handler");
13+
package = mkPackageOption pkgs "systemd-lock-handler" { };
14+
};
15+
16+
config = mkIf cfg.enable {
17+
systemd.packages = [ cfg.package ];
18+
19+
# https://github.com/NixOS/nixpkgs/issues/81138
20+
systemd.user.services.systemd-lock-handler.wantedBy = [ "default.target" ];
21+
};
22+
23+
meta = {
24+
maintainers = with lib.maintainers; [ liff ];
25+
doc = ./systemd-lock-handler.md;
26+
};
27+
}

nixos/tests/all-tests.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,7 @@ in {
856856
systemd-journal = handleTest ./systemd-journal.nix {};
857857
systemd-journal-gateway = handleTest ./systemd-journal-gateway.nix {};
858858
systemd-journal-upload = handleTest ./systemd-journal-upload.nix {};
859+
systemd-lock-handler = runTestOn ["aarch64-linux" "x86_64-linux"] ./systemd-lock-handler.nix;
859860
systemd-machinectl = handleTest ./systemd-machinectl.nix {};
860861
systemd-networkd = handleTest ./systemd-networkd.nix {};
861862
systemd-networkd-dhcpserver = handleTest ./systemd-networkd-dhcpserver.nix {};
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{ lib, ... }: {
2+
name = "systemd-lock-handler";
3+
4+
meta.maintainers = with lib.maintainers; [ liff ];
5+
6+
enableOCR = true;
7+
8+
nodes.machine = { config, pkgs, lib, ... }:
9+
let
10+
touch = "${lib.getBin pkgs.coreutils}/bin/touch";
11+
in
12+
{
13+
imports = [ common/wayland-cage.nix ];
14+
15+
services.systemd-lock-handler.enable = true;
16+
17+
systemd.user.services = {
18+
test-lock = {
19+
partOf = [ "lock.target" ];
20+
onSuccess = [ "unlock.target" ];
21+
before = [ "lock.target" ];
22+
wantedBy = [ "lock.target" ];
23+
serviceConfig.ExecStart = "${touch} /tmp/lock.target.activated";
24+
};
25+
test-unlock = {
26+
partOf = [ "unlock.target" ];
27+
after = [ "unlock.target" ];
28+
wantedBy = [ "unlock.target" ];
29+
serviceConfig.ExecStart = "${touch} /tmp/unlock.target.activated";
30+
};
31+
test-sleep = {
32+
partOf = [ "sleep.target" ];
33+
before = [ "sleep.target" ];
34+
wantedBy = [ "sleep.target" ];
35+
serviceConfig.ExecStart = "${touch} /tmp/sleep.target.activated";
36+
};
37+
};
38+
};
39+
40+
testScript = ''
41+
machine.wait_for_unit('graphical.target')
42+
machine.wait_for_text('alice@machine')
43+
44+
machine.send_chars('loginctl lock-session\n')
45+
machine.wait_for_file('/tmp/lock.target.activated')
46+
machine.wait_for_file('/tmp/unlock.target.activated')
47+
48+
machine.send_chars('systemctl suspend\n')
49+
# wait_for_file won’t complete before the machine is asleep,
50+
# so we’ll watch the log instead.
51+
machine.wait_for_console_text('Started test-sleep.service.')
52+
53+
# The VM is asleep, regular shutdown won’t work.
54+
machine.crash()
55+
'';
56+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{ lib
2+
, fetchFromSourcehut
3+
, buildGoModule
4+
, nix-update-script
5+
, nixosTests
6+
}:
7+
8+
buildGoModule rec {
9+
pname = "systemd-lock-handler";
10+
version = "2.4.2";
11+
12+
src = fetchFromSourcehut {
13+
owner = "~whynothugo";
14+
repo = "systemd-lock-handler";
15+
rev = "v${version}";
16+
hash = "sha256-sTVAabwWtyvHuDp/+8FKNbfej1x/egoa9z1jLIMJuBg=";
17+
};
18+
19+
vendorHash = "sha256-dWzojV3tDA5lLdpAQNC9NaADGyvV7dNOS3x8mfgNNtA=";
20+
21+
passthru = {
22+
updateScript = nix-update-script { };
23+
tests = nixosTests.systemd-lock-handler;
24+
};
25+
26+
# The Makefile expects to find the binary in the source root. Make
27+
# the one built by `buildGoModule` available so that `make install`
28+
# doesn’t try to build it again.
29+
postBuild = ''
30+
cp -a $GOPATH/bin/* .
31+
'';
32+
33+
installPhase = ''
34+
runHook preInstall
35+
36+
substituteInPlace systemd-lock-handler.service \
37+
--replace /usr/lib/ $out/lib/
38+
39+
make install DESTDIR= PREFIX=$out
40+
41+
runHook postInstall
42+
'';
43+
44+
meta = with lib; {
45+
homepage = "https://git.sr.ht/~whynothugo/systemd-lock-handler";
46+
description = "Translates systemd-system lock/sleep signals into systemd-user target activations";
47+
license = licenses.isc;
48+
maintainers = with maintainers; [ liff ];
49+
platforms = platforms.linux;
50+
};
51+
}

0 commit comments

Comments
 (0)