mirror of
https://codeberg.org/privacy1st/nix-git
synced 2024-11-21 22:03:19 +01:00
WIP: service preventing systemd suspend
This commit is contained in:
parent
cfd2abe482
commit
b25be12e83
12
examples/signal-handling/sleeping.sh
Executable file
12
examples/signal-handling/sleeping.sh
Executable file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
printf '%s%s%s\n' 'START. Can be terminated with "kill -TERM ' "$$" '"'
|
||||||
|
while :; do
|
||||||
|
printf '%s\n' 'sleeping 10s'
|
||||||
|
sleep 10s
|
||||||
|
printf '%s\n' 'awoke from sleep'
|
||||||
|
done
|
||||||
|
printf '%s\n' 'END'
|
||||||
|
|
||||||
|
# When executing `kill -TERM $PID` in another terminal,
|
||||||
|
# this script terminates instantly.
|
21
examples/signal-handling/sleeping2.sh
Executable file
21
examples/signal-handling/sleeping2.sh
Executable file
@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu -o pipefail
|
||||||
|
|
||||||
|
function handle_sigterm(){
|
||||||
|
printf '%s\n' 'Ignored SIGTERM' >&2
|
||||||
|
}
|
||||||
|
|
||||||
|
# Handle SIGTERM
|
||||||
|
trap 'handle_sigterm' TERM
|
||||||
|
|
||||||
|
printf '%s%s%s\n' 'START. Can be terminated with "kill -TERM ' "$$" '"'
|
||||||
|
while :; do
|
||||||
|
printf '%s\n' 'sleeping 10s'
|
||||||
|
sleep 10s
|
||||||
|
printf '%s\n' 'awoke from sleep'
|
||||||
|
done
|
||||||
|
printf '%s\n' 'END'
|
||||||
|
|
||||||
|
# When executing `kill -TERM $PID` in another terminal,
|
||||||
|
# the command `sleep 10s` continues.
|
||||||
|
# After it has finished, `Ignored SIGTERM` is printed and the endless loop continues.
|
90
examples/suspend-impossible.nix
Normal file
90
examples/suspend-impossible.nix
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
{ config, pkgs, lib, ... }:
|
||||||
|
|
||||||
|
# Relevant references:
|
||||||
|
# How to prevent systemd suspend from stopping any service with a dont-sleep.service. https://askubuntu.com/q/830442/1002706
|
||||||
|
|
||||||
|
# systemctl show test-block-suspend.service -p TimeoutStopUSec
|
||||||
|
#=> TimeoutStopUSec=infinity
|
||||||
|
|
||||||
|
# systemctl cat test-block-suspend.service
|
||||||
|
|
||||||
|
# systemctl list-dependencies --before test-block-suspend.service
|
||||||
|
#=> test-block-suspend.service
|
||||||
|
#=> ├─shutdown.target
|
||||||
|
#=> ├─sleep.target
|
||||||
|
#=> │ ├─systemd-hibernate.service
|
||||||
|
#=> │ ├─systemd-hybrid-sleep.service
|
||||||
|
#=> │ ├─systemd-suspend-then-hibernate.service
|
||||||
|
#=> │ └─systemd-suspend.service
|
||||||
|
#=> └─suspend.target
|
||||||
|
#=> └─post-resume.service
|
||||||
|
|
||||||
|
{
|
||||||
|
# Alternative approach to adding `conflicts`, `before` and `ExecStop`.
|
||||||
|
#
|
||||||
|
# Immediately before entering system suspend, all executables in /usr/lib/systemd/system-sleep/ are run.
|
||||||
|
# Execution of the sleep action is not continued until all have finished.
|
||||||
|
# TODO: This happens after my screen got blank, wifi disabled, screen locker activated, etc.
|
||||||
|
# environment.etc."systemd/system-sleep/test-block-suspend".source =
|
||||||
|
# pkgs.writeShellScript "test-block-suspend" ''
|
||||||
|
# set -eu -o pipefail
|
||||||
|
# if [ "$1" == "pre" ]; then
|
||||||
|
# while :; do
|
||||||
|
# systemctl is-active --quiet test-block-suspend.service || exit 0
|
||||||
|
# ${pkgs.coreutils}/bin/echo 'Waiting until service has finished ...'
|
||||||
|
# ${pkgs.coreutils}/bin/sleep 1s
|
||||||
|
# done
|
||||||
|
# fi
|
||||||
|
# '';
|
||||||
|
|
||||||
|
systemd.services."test-block-suspend" = {
|
||||||
|
description = "Inhibit suspend";
|
||||||
|
|
||||||
|
# If suspend is initiated, this service is stopped.
|
||||||
|
conflicts = [ "sleep.target" ];
|
||||||
|
# Start-up of `sleep.target`
|
||||||
|
# is delayed until this service has finished starting up.
|
||||||
|
before = [ "sleep.target" ];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
# `simple`:
|
||||||
|
# As soon as the main process (defined in the `ExecStart`) is started (forked),
|
||||||
|
# start-up is considered as finished.
|
||||||
|
# `notify`:
|
||||||
|
# The service sends a "READY=1" notification message via `sd_notify` when it has finished starting up.
|
||||||
|
# Requires `NotifyAccess`.
|
||||||
|
# See https://www.freedesktop.org/software/systemd/man/latest/systemd-notify.html
|
||||||
|
Type = "notify";
|
||||||
|
NotifyAccess = "main";
|
||||||
|
|
||||||
|
# To stop this service `ExecStop` is run instead of sending SIGTERM to the main process of the service.
|
||||||
|
# The command specified by `ExecStop` does never end,
|
||||||
|
# thus stopping this service takes forever.
|
||||||
|
# TODO: However, the sleep action continues while `ExecStop` is running. As a reslut, the system suspends.
|
||||||
|
ExecStop = "${pkgs.coreutils}/bin/sleep infinity";
|
||||||
|
TimeoutStopSec = "infinity";
|
||||||
|
|
||||||
|
# This service executes a shell script as main process.
|
||||||
|
ExecStart = pkgs.writeShellScript "test-block-suspend-execstart" ''
|
||||||
|
set -eu -o pipefail
|
||||||
|
|
||||||
|
#handle_sigterm(){
|
||||||
|
# #while :; do
|
||||||
|
# printf '%s\n' 'Ignoring SIGTERM ...' >&2
|
||||||
|
# # ${pkgs.coreutils}/bin/sleep 5s
|
||||||
|
# #done
|
||||||
|
#}
|
||||||
|
#trap 'handle_sigterm' TERM
|
||||||
|
|
||||||
|
#printf '%s\n' 'Start-up 30s ...'
|
||||||
|
#${pkgs.coreutils}/bin/sleep 30s
|
||||||
|
systemd-notify READY=1
|
||||||
|
|
||||||
|
while :; do
|
||||||
|
printf '%s\n' 'Still alive'
|
||||||
|
${pkgs.coreutils}/bin/sleep 5s
|
||||||
|
done
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
@ -1,19 +1,30 @@
|
|||||||
{ config, pkgs, ... }:
|
{ config, pkgs, ... }:
|
||||||
|
|
||||||
# TODO Note: One can specify ExecStart and ExecStop. Maybe to pause some script during shutdown/suspend? This would be nice for backups. Just finish the current snapshot then pause.
|
# TODO Note: One can specify ExecStart and ExecStop. Maybe to pause some script during shutdown/suspend? This would be nice for backups. Just finish the current snapshot then pause.
|
||||||
#
|
|
||||||
# ExecStop=
|
|
||||||
# Commands to execute to stop the service started via ExecStart=.
|
|
||||||
# The command that asks the service to stop should wait for it to do so!
|
|
||||||
# After the commands configured in this option are run, it is implied that the service is stopped, and any processes remaining for it are terminated.
|
|
||||||
#
|
|
||||||
# If this option is not specified, the process is terminated when service stop is requested.
|
|
||||||
|
|
||||||
# TODO: https://unix.stackexchange.com/questions/619987/stop-systemd-service-before-suspend-start-again-after-resume
|
# TODO: https://unix.stackexchange.com/questions/619987/stop-systemd-service-before-suspend-start-again-after-resume
|
||||||
|
|
||||||
|
# Suspend, hibernate, shutdown
|
||||||
|
#
|
||||||
|
# Some of the upstream system units:
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/5c43dee215c279dceee7861eec85862ad85cc330/nixos/modules/system/boot/systemd.nix#L104
|
||||||
|
# - suspend.target
|
||||||
|
# - hibernate.target
|
||||||
|
# - sleep.target
|
||||||
|
# - hybrid-sleep.target
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/5c43dee215c279dceee7861eec85862ad85cc330/nixos/modules/system/boot/systemd.nix#L115
|
||||||
|
# - reboot.target
|
||||||
|
# - poweroff.target
|
||||||
|
#
|
||||||
|
# BTRFS scrub prevents suspend2ram and proper shutdown
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/5c43dee215c279dceee7861eec85862ad85cc330/nixos/modules/tasks/filesystems/btrfs.nix#L131
|
||||||
|
# conflicts = [ "shutdown.target" "sleep.target" ];
|
||||||
|
# before = [ "shutdown.target" "sleep.target" ];
|
||||||
|
|
||||||
# Benefits of Systemd Timers over cron: https://wiki.archlinux.org/title/Systemd/Timers#Benefits
|
# Benefits of Systemd Timers over cron: https://wiki.archlinux.org/title/Systemd/Timers#Benefits
|
||||||
# Example: https://nixos.wiki/wiki/Nix_Cookbook#Creating_periodic_services
|
# Timer example: https://nixos.wiki/wiki/Nix_Cookbook#Creating_periodic_services
|
||||||
# Example: https://nixos.wiki/wiki/Systemd/Timers
|
# Timer example: https://nixos.wiki/wiki/Systemd/Timers
|
||||||
|
|
||||||
{
|
{
|
||||||
systemd.timers."hello-world" = {
|
systemd.timers."hello-world" = {
|
||||||
# description = "My Timer";
|
# description = "My Timer";
|
||||||
@ -46,12 +57,19 @@
|
|||||||
systemd.services."hello-world" = {
|
systemd.services."hello-world" = {
|
||||||
# description = "My Oneshot Service";
|
# description = "My Oneshot Service";
|
||||||
|
|
||||||
# TODO: Prevents suspend2ram or proper shutdown?
|
# Prevent suspend2ram and proper shutdown.
|
||||||
# https://github.com/NixOS/nixpkgs/blob/e9b4b56e5a20ac322c0c01ccab7ec697ab076ea0/nixos/modules/tasks/filesystems/btrfs.nix#L128-L130
|
#
|
||||||
|
# TODO Additionally:
|
||||||
|
# Option I:
|
||||||
|
# Use ExecStart and ExecStop. ExecStop initiates an early stop of the service and waits until this has finished.
|
||||||
|
# In `serviceConfig`, set `Type` to `simple` (and not `oneshot`, otherwise ExecStop is not used).
|
||||||
|
# Option II:
|
||||||
|
# Set `TimeoutSec` to `infinity`.
|
||||||
#
|
#
|
||||||
# If the specified units are started, then this unit is stopped and vice versa.
|
# If the specified units are started, then this unit is stopped and vice versa.
|
||||||
conflicts = [ "shutdown.target" "sleep.target" ];
|
conflicts = [ "shutdown.target" "sleep.target" ];
|
||||||
# If the specified units are started at the same time as this unit, delay them until this unit has started.
|
# If this unit and one from `before` are being started,
|
||||||
|
# the start-up of the latter is delayed until this service has finished starting up.
|
||||||
before = [ "shutdown.target" "sleep.target" ];
|
before = [ "shutdown.target" "sleep.target" ];
|
||||||
|
|
||||||
# https://man.archlinux.org/man/systemd.service.5.en#OPTIONS
|
# https://man.archlinux.org/man/systemd.service.5.en#OPTIONS
|
||||||
@ -60,6 +78,27 @@
|
|||||||
# Example: https://github.com/NixOS/nixpkgs/blob/e9b4b56e5a20ac322c0c01ccab7ec697ab076ea0/nixos/modules/tasks/filesystems/btrfs.nix#L132-L142
|
# Example: https://github.com/NixOS/nixpkgs/blob/e9b4b56e5a20ac322c0c01ccab7ec697ab076ea0/nixos/modules/tasks/filesystems/btrfs.nix#L132-L142
|
||||||
serviceConfig = {
|
serviceConfig = {
|
||||||
Type = "oneshot";
|
Type = "oneshot";
|
||||||
|
|
||||||
|
# Takes a boolean value that specifies whether the service shall be considered active even when all its processes exited.
|
||||||
|
# Defaults to `false`.
|
||||||
|
#RemainAfterExit = true;
|
||||||
|
|
||||||
|
# A shorthand for configuring both TimeoutStartSec= and TimeoutStopSec= to the specified value.
|
||||||
|
# TimeoutStopSec:
|
||||||
|
# If no ExecStop= commands are specified, the service gets the SIGTERM immediately.
|
||||||
|
# It configures the time to wait for the service itself to stop.
|
||||||
|
# If it doesn't terminate in the specified time, it will be forcibly terminated by SIGKILL (see KillMode).
|
||||||
|
# SIGTERM and SIGKILL:
|
||||||
|
# The SIGTERM signal is a generic signal used to cause program termination.
|
||||||
|
# Unlike SIGKILL, this signal can be blocked, handled, and ignored.
|
||||||
|
# It is the normal way to politely ask a program to terminate.
|
||||||
|
# SIGINT:
|
||||||
|
# The SIGINT (“program interrupt”) signal is sent when the user types the INTR character (normally C-c).
|
||||||
|
# Example:
|
||||||
|
# grow-partition.nix conflicts with `shutdown.target` and has an infinite `TimeoutStopSec` to make sure that resizing a partition is not interrupted.
|
||||||
|
# https://github.com/NixOS/nixpkgs/blob/008d84ab67c4f4ccbd7c0996005e46c8bd32d675/nixos/modules/system/boot/grow-partition.nix#L34
|
||||||
|
#TimeoutSec = "infinity";
|
||||||
|
|
||||||
PrivateTmp = true;
|
PrivateTmp = true;
|
||||||
|
|
||||||
#User = "myuser";
|
#User = "myuser";
|
||||||
@ -69,7 +108,16 @@
|
|||||||
# Takes one of the strings realtime, best-effort or idle.
|
# Takes one of the strings realtime, best-effort or idle.
|
||||||
IOSchedulingClass = "idle";
|
IOSchedulingClass = "idle";
|
||||||
|
|
||||||
#ExecStart = "${pkgs.python3.withPackages my-python-packages}/bin/netcup-dns";
|
#ExecStart = "${pkgs.coreutils}/bin/echo 'Hello World'";
|
||||||
|
# Commands to execute to stop the service started via ExecStart=.
|
||||||
|
# The command that asks the service to stop should wait for it to do so!
|
||||||
|
# After the commands configured in this option are run, it is implied that the service is stopped, and any processes remaining for it are terminated.
|
||||||
|
#
|
||||||
|
# If this option is not specified, the process is terminated when service stop is requested.
|
||||||
|
#ExecStop = pkgs.writeShellScript "cancel-hello-world" ''
|
||||||
|
# set -eu -o pipefail
|
||||||
|
# echo 'Cancelling execution of hello-world'
|
||||||
|
#'';
|
||||||
};
|
};
|
||||||
|
|
||||||
# Packages required for the script.
|
# Packages required for the script.
|
||||||
@ -87,7 +135,7 @@
|
|||||||
# Shell commands executed as the service's main process.
|
# Shell commands executed as the service's main process.
|
||||||
script = ''
|
script = ''
|
||||||
set -eu -o pipefail
|
set -eu -o pipefail
|
||||||
${pkgs.coreutils}/bin/echo "Hello World"
|
${pkgs.coreutils}/bin/echo 'Hello World'
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user