mirror of
https://codeberg.org/privacy1st/nix-git
synced 2024-11-20 21:58:06 +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, ... }:
|
||||
|
||||
# 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
|
||||
|
||||
# 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
|
||||
# Example: https://nixos.wiki/wiki/Nix_Cookbook#Creating_periodic_services
|
||||
# Example: https://nixos.wiki/wiki/Systemd/Timers
|
||||
# Timer example: https://nixos.wiki/wiki/Nix_Cookbook#Creating_periodic_services
|
||||
# Timer example: https://nixos.wiki/wiki/Systemd/Timers
|
||||
|
||||
{
|
||||
systemd.timers."hello-world" = {
|
||||
# description = "My Timer";
|
||||
@ -46,12 +57,19 @@
|
||||
systemd.services."hello-world" = {
|
||||
# description = "My Oneshot Service";
|
||||
|
||||
# TODO: Prevents suspend2ram or proper shutdown?
|
||||
# https://github.com/NixOS/nixpkgs/blob/e9b4b56e5a20ac322c0c01ccab7ec697ab076ea0/nixos/modules/tasks/filesystems/btrfs.nix#L128-L130
|
||||
# Prevent suspend2ram and proper shutdown.
|
||||
#
|
||||
# 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.
|
||||
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" ];
|
||||
|
||||
# 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
|
||||
serviceConfig = {
|
||||
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;
|
||||
|
||||
#User = "myuser";
|
||||
@ -69,7 +108,16 @@
|
||||
# Takes one of the strings realtime, best-effort or 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.
|
||||
@ -87,7 +135,7 @@
|
||||
# Shell commands executed as the service's main process.
|
||||
script = ''
|
||||
set -eu -o pipefail
|
||||
${pkgs.coreutils}/bin/echo "Hello World"
|
||||
${pkgs.coreutils}/bin/echo 'Hello World'
|
||||
'';
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user