mirror of
https://codeberg.org/guix/guix.git
synced 2026-01-25 20:15:25 -06:00
services: elogind: Split sleep.conf and port to define-configuration.
* gnu/services/desktop.scm (pascal-case): New procedure. (<elogind-configuration>): Rewrite in terms of define-configuration. (elogind-configuration-file): Delete. (maybe-list-of-suspend-states?, maybe-list-of-suspend-modes?) maybe-list-of-user-names?, maybe-boolean?maybe-package?) (maybe-action?, maybe-percent?, maybe-list-of-strings?) (maybe-list-of-hibernation-modes?, maybe-non-negative-integer?) (non-negative-integer?, percent?, char-set:user-name, user-name?) (list-of-user-names?, %elogind-actions, action?, %linux-suspend-states) (string->symbol/maybe, suspend-state?, list-of-suspend-states?) (%linux-suspend-modes, suspend-mode?, list-of-suspend-modes?) (%linux-hibernation-modes, hibernation-mode?, list-of-hibernation-modes?) (elogind-deprecated-empty-serializer, list-of-file-likes?) (elogind-serialize-boolean, elogind-base-serializer, elogind-serialize-action) (elogind-serialize-non-negative-integer, elogind-serialize-percent) (elogind-list-serializer, elogind-serialize-list-of-strings) (elogind-serialize-list-of-user-names, elogind-serialize-list-of-suspend-states) (elogind-serialize-list-of-suspend-modes) (elogind-serialize-list-of-hibernation-modes) (%elogind-configuration-sleep-fields, logind.conf, sleep.conf): New procedures. (elogind-etc-directory): Create the main configuration files there too. (elogind-dbus-service): Adjust for package accessor name change. (pam-extension-procedure, elogind-shepherd-service) (elogind-service-type): Likewise. (shepherd-configuration-action*): New procedure. * doc/guix.texi (Desktop Services): Fully document configuration options. Fixes: https://issues.guix.gnu.org/77806 Change-Id: I8767891871d83e58d64995ec986a7d01689fa6d8 Reported-by: Ludovic Courtès <ludo@gnu.org>
This commit is contained in:
parent
ab39ed52a0
commit
f10d00e4e2
2 changed files with 556 additions and 314 deletions
243
doc/guix.texi
243
doc/guix.texi
|
|
@ -26264,129 +26264,158 @@ seat management daemon. The value for this service is a
|
|||
@code{<elogind-configuration>} object.
|
||||
@end defvar
|
||||
|
||||
@c TODO: field descriptions. This is best done by refactoring
|
||||
@c elogind-configuration to use define-configuration which embeds the
|
||||
@c descriptions in the code and then use configuration->documentation.
|
||||
@c Auto-generated via (configuration->documentation 'elogind-configuration).
|
||||
@c %start of fragment
|
||||
|
||||
@deftp {Data Type} elogind-configuration
|
||||
Data type representing the configuration of @command{elogind}.
|
||||
Available @code{elogind-configuration} fields are:
|
||||
|
||||
@table @asis
|
||||
@item @code{elogind} (default: @code{elogind}) (type: file-like)
|
||||
...
|
||||
The elogind package to use.
|
||||
|
||||
@item @code{kill-user-processes?} (default: @code{#f}) (type: boolean)
|
||||
...
|
||||
|
||||
@item @code{kill-only-users} (default: @code{'()}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{kill-exclude-users} (default: @code{'("root")}) (type: list-of-string)
|
||||
...
|
||||
|
||||
@item @code{inhibit-delay-max-seconds} (default: @code{5}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{handle-power-key} (default: @code{'poweroff}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{handle-suspend-key} (default: @code{'suspend}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{handle-hibernate-key} (default: @code{'hibernate}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{handle-lid-switch} (default: @code{'suspend}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{handle-lid-switch-docked} (default: @code{'ignore}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{handle-lid-switch-external-power} (default: @code{*unspecified*}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{power-key-ignore-inhibited?} (default: @code{#f}) (type: boolean)
|
||||
...
|
||||
|
||||
@item @code{suspend-key-ignore-inhibited?} (default: @code{#f}) (type: boolean)
|
||||
...
|
||||
|
||||
@item @code{hibernate-key-ignore-inhibited?} (default: @code{#f}) (type: boolean)
|
||||
...
|
||||
|
||||
@item @code{lid-switch-ignore-inhibited?} (default: @code{#t}) (type: boolean)
|
||||
...
|
||||
|
||||
@item @code{holdoff-timeout-seconds} (default: @code{30}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{idle-action} (default: @code{'ignore}) (type: symbol)
|
||||
...
|
||||
|
||||
@item @code{idle-action-seconds} (default: @code{(* 30 60)}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{runtime-directory-size-percent} (default: @code{10}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{runtime-directory-size} (default: @code{#f}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{remove-ipc?} (default: @code{#t}) (type: boolean)
|
||||
...
|
||||
|
||||
@item @code{suspend-state} (default: @code{'("mem" "standby" "freeze")}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{suspend-mode} (default: @code{'()}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{hibernate-state} (default: @code{'("disk")}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{hibernate-mode} (default: @code{'("platform" "shutdown")}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{hybrid-sleep-state} (default: @code{'("disk")}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{hybrid-sleep-mode} (default: @code{'("suspend" "platform" "shutdown")}) (type: list)
|
||||
...
|
||||
|
||||
@item @code{hibernate-delay-seconds} (default: @code{*unspecified*}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{suspend-estimation-seconds} (default: @code{*unspecified*}) (type: integer)
|
||||
...
|
||||
|
||||
@item @code{system-sleep-hook-files} (default: @code{'()}) (type: list)
|
||||
@item @code{system-sleep-hook-files} (default: @code{()}) (type: list-of-file-likes)
|
||||
A list of executables (file-like objects) that will be installed into
|
||||
the @file{/etc/elogind/system-sleep/} hook directory. For example:
|
||||
the @file{/etc/elogind/system-sleep} hook directory. See `Hook
|
||||
directories' in the @samp{loginctl(1)} man page for more information.
|
||||
|
||||
@lisp
|
||||
(elogind-configuration
|
||||
(system-sleep-hook-files
|
||||
(list (local-file "sleep-script"))))
|
||||
@end lisp
|
||||
|
||||
See `Hook directories' in the @code{loginctl(1)} man page for more information.
|
||||
|
||||
@item @code{system-shutdown-hook-files} (default: @code{'()}) (type: list)
|
||||
@item @code{system-shutdown-hook-files} (default: @code{()}) (type: list-of-file-likes)
|
||||
A list of executables (file-like objects) that will be installed into
|
||||
the @file{/etc/elogind/system-shutdown/} hook directory.
|
||||
|
||||
@item @code{allow-power-off-interrupts?} (default: @code{#f}) (type: boolean)
|
||||
@itemx @code{allow-suspend-interrupts?} (default: @code{#f}) (type: boolean)
|
||||
@item @code{allow-power-off-interrupts?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether the executables in elogind's hook directories (see above) can
|
||||
cause a power-off or suspend action to be cancelled (interrupted) by
|
||||
printing an appropriate error message to stdout.
|
||||
cause a power-off action to be cancelled (interrupted) by printing an
|
||||
appropriate error message to stdout.
|
||||
|
||||
@item @code{broadcast-power-off-interrupts?} (default: @code{#t}) (type: boolean)
|
||||
@itemx @code{broadcast-suspend-interrupts?} (default: @code{#t}) (type: boolean)
|
||||
Whether an interrupt of a power-off or suspend action is broadcasted.
|
||||
@item @code{allow-suspend-interrupts?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Likewise as the @code{allow-power-off-interrupts?} option, but for the
|
||||
suspend action.
|
||||
|
||||
@item @code{broadcast-power-off-interrupts?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether an interrupt of a power-off action is broadcasted.
|
||||
|
||||
@item @code{broadcast-suspend-interrupts?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether an interrupt of a suspend action is broadcasted.
|
||||
|
||||
@item @code{kill-user-processes?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether the processes of a user should be killed when the user logs out.
|
||||
|
||||
@item @code{kill-only-users} (type: maybe-list-of-user-names)
|
||||
Usernames whose processes should be killed, regardless the value of
|
||||
@code{kill-user-processes?}.
|
||||
|
||||
@item @code{kill-exclude-users} (default: @code{("root")}) (type: maybe-list-of-user-names)
|
||||
Usernames whose processes should @emph{not} be killed, regardless the
|
||||
value of @code{kill-user-processes?}.
|
||||
|
||||
@item @code{inhibit-delay-max-seconds} (default: @code{5}) (type: maybe-non-negative-integer)
|
||||
The maximum time a system shutdown or sleep request is delayed due to an
|
||||
inhibitor lock of type delay being active before the inhibitor is
|
||||
ignored and the operation executes anyway.
|
||||
|
||||
@item @code{handle-power-key} (default: @code{poweroff}) (type: maybe-action)
|
||||
The action done when the power key is pressed. The compiled default is
|
||||
@code{'poweroff}.
|
||||
|
||||
@item @code{handle-suspend-key} (default: @code{suspend}) (type: maybe-action)
|
||||
The action done when the suspend key is pressed. The
|
||||
|
||||
@item @code{handle-hibernate-key} (default: @code{hibernate}) (type: maybe-action)
|
||||
The action done when the hibernate key is pressed.
|
||||
|
||||
@item @code{handle-lid-switch} (default: @code{suspend}) (type: maybe-action)
|
||||
The action done when the lid is closed.
|
||||
|
||||
@item @code{handle-lid-switch-docked} (default: @code{ignore}) (type: maybe-action)
|
||||
The action done when the lid is closed and the device docked.
|
||||
|
||||
@item @code{handle-lid-switch-external-power} (default: @code{suspend}) (type: maybe-action)
|
||||
The action done when the lid is closed and the device is externally
|
||||
powered.
|
||||
|
||||
@item @code{power-key-ignore-inhibited?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the power key is pressed.
|
||||
|
||||
@item @code{suspend-key-ignore-inhibited?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the suspend key is pressed.
|
||||
|
||||
@item @code{hibernate-key-ignore-inhibited?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the hibernate key is pressed.
|
||||
|
||||
@item @code{lid-switch-ignore-inhibited?} (default: @code{#f}) (type: maybe-boolean)
|
||||
Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the lid is closed.
|
||||
|
||||
@item @code{holdoff-timeout-seconds} (default: @code{30}) (type: maybe-non-negative-integer)
|
||||
Specifies the number of seconds after system startup or system resume
|
||||
during which elogind will hold off on reacting to lid events.
|
||||
|
||||
@item @code{idle-action} (default: @code{ignore}) (type: maybe-action)
|
||||
Action to take when the system is idle.
|
||||
|
||||
@item @code{idle-action-seconds} (type: maybe-non-negative-integer)
|
||||
The delay after which the action configured in @code{idle-action} is
|
||||
taken after the system is idle.
|
||||
|
||||
@item @code{runtime-directory-size-percent} (type: maybe-percent)
|
||||
Set the size limit, in percent, on the @env{XDG_RUNTIME_DIR} runtime
|
||||
directory for each user who logs in. This specifies the per-user size
|
||||
limit relative to the amount of physical @acronym{RAM,read access
|
||||
memory}. This value takes precedence over that specified via
|
||||
@code{runtime-directory-size}.
|
||||
|
||||
@item @code{runtime-directory-size} (type: maybe-non-negative-integer)
|
||||
Set the size limit, in bytes, on the @env{XDG_RUNTIME_DIR} runtime
|
||||
directory for each user who logs in.
|
||||
|
||||
@item @code{remove-ipc?} (default: @code{#t}) (type: maybe-boolean)
|
||||
Whether @acronym{IPC,inter-process communication} objects belonging to
|
||||
the user shall be removed when the user fully logs out.
|
||||
|
||||
@item @code{suspend-state} (default: @code{(mem standby freeze)}) (type: maybe-list-of-suspend-states)
|
||||
The suspend state values to be write to @file{/sys/power/state} by
|
||||
elogind when suspending the system. They will be tried in turn, until
|
||||
one is written without error.
|
||||
|
||||
@item @code{suspend-mode} (type: maybe-list-of-suspend-modes)
|
||||
The suspend mode values to write to @file{/sys/power/mem_sleep} by
|
||||
elogind when suspending the system.
|
||||
|
||||
@item @code{suspend-estimation-seconds} (default: @code{3600}) (type: maybe-non-negative-integer)
|
||||
Cause the RTC alarm to wake the system after the specified time span to
|
||||
measure the system battery capacity level and estimate the battery
|
||||
discharging rate, which is used for estimating the time span until the
|
||||
system battery charge level goes down to 5%. This option is only used
|
||||
by elogind when using the @code{'suspend-then-hibernate} action.
|
||||
|
||||
@item @code{hibernate-mode} (default: @code{(platform shutdown)}) (type: maybe-list-of-hibernation-modes)
|
||||
The hibernation mode values to write to @file{/sys/power/disk} by
|
||||
elogind when hibernating the system.
|
||||
|
||||
@item @code{hibernate-delay-seconds} (type: maybe-non-negative-integer)
|
||||
The amount of time the system spends in suspend mode before the system
|
||||
is automatically put into hibernate mode.
|
||||
|
||||
@item @code{hibernate-state} (type: maybe-list-of-strings)
|
||||
Deprecated option.
|
||||
|
||||
@item @code{hybrid-sleep-state} (type: maybe-list-of-strings)
|
||||
Deprecated option.
|
||||
|
||||
@item @code{hybrid-sleep-mode} (type: maybe-list-of-strings)
|
||||
Deprecated option.
|
||||
|
||||
@end table
|
||||
|
||||
@end deftp
|
||||
|
||||
|
||||
@c %end of fragment
|
||||
|
||||
@defvar accountsservice-service-type
|
||||
Type for the service that runs AccountsService, a system service that can
|
||||
list available accounts, change their passwords, and so on.
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
(define-module (gnu services desktop)
|
||||
#:use-module ((gnu home services utils) #:select (object->camel-case-string))
|
||||
#:use-module (gnu services)
|
||||
#:use-module (gnu services shepherd)
|
||||
#:use-module (gnu services base)
|
||||
|
|
@ -228,6 +229,8 @@ is a list, it recursively searches it until it locates the last item of TREE."
|
|||
(loop (cdr tree)
|
||||
(car (assoc-ref (package-direct-inputs package)
|
||||
(car tree))))))))
|
||||
(define (pascal-case text)
|
||||
(object->camel-case-string text 'upper))
|
||||
|
||||
|
||||
;;;
|
||||
|
|
@ -1025,173 +1028,367 @@ and many other) available for GIO applications.")
|
|||
;;; Elogind login and seat management service.
|
||||
;;;
|
||||
|
||||
(define-record-type* <elogind-configuration> elogind-configuration
|
||||
make-elogind-configuration
|
||||
elogind-configuration?
|
||||
(elogind elogind-package
|
||||
(default elogind))
|
||||
(kill-user-processes? elogind-kill-user-processes?
|
||||
(default #f))
|
||||
(kill-only-users elogind-kill-only-users
|
||||
(default '()))
|
||||
(kill-exclude-users elogind-kill-exclude-users
|
||||
(default '("root")))
|
||||
(inhibit-delay-max-seconds elogind-inhibit-delay-max-seconds
|
||||
(default 5))
|
||||
(handle-power-key elogind-handle-power-key
|
||||
(default 'poweroff))
|
||||
(handle-suspend-key elogind-handle-suspend-key
|
||||
(default 'suspend))
|
||||
(handle-hibernate-key elogind-handle-hibernate-key
|
||||
(default 'hibernate))
|
||||
(handle-lid-switch elogind-handle-lid-switch
|
||||
(default 'suspend))
|
||||
(handle-lid-switch-docked elogind-handle-lid-switch-docked
|
||||
(default 'ignore))
|
||||
(handle-lid-switch-external-power elogind-handle-lid-switch-external-power
|
||||
(default *unspecified*))
|
||||
(power-key-ignore-inhibited? elogind-power-key-ignore-inhibited?
|
||||
(default #f))
|
||||
(suspend-key-ignore-inhibited? elogind-suspend-key-ignore-inhibited?
|
||||
(default #f))
|
||||
(hibernate-key-ignore-inhibited? elogind-hibernate-key-ignore-inhibited?
|
||||
(default #f))
|
||||
(lid-switch-ignore-inhibited? elogind-lid-switch-ignore-inhibited?
|
||||
(default #t))
|
||||
(holdoff-timeout-seconds elogind-holdoff-timeout-seconds
|
||||
(default 30))
|
||||
(idle-action elogind-idle-action
|
||||
(default 'ignore))
|
||||
(idle-action-seconds elogind-idle-action-seconds
|
||||
(default (* 30 60)))
|
||||
(runtime-directory-size-percent elogind-runtime-directory-size-percent
|
||||
(default 10))
|
||||
(runtime-directory-size elogind-runtime-directory-size
|
||||
(default #f))
|
||||
(remove-ipc? elogind-remove-ipc?
|
||||
(default #t))
|
||||
;;; Elogind configuration types.
|
||||
(define-maybe boolean
|
||||
(prefix elogind-))
|
||||
|
||||
(suspend-state elogind-suspend-state
|
||||
(default '("mem" "standby" "freeze")))
|
||||
(suspend-mode elogind-suspend-mode
|
||||
(default '()))
|
||||
(hibernate-state elogind-hibernate-state
|
||||
(default '("disk")))
|
||||
(hibernate-mode elogind-hibernate-mode
|
||||
(default '("platform" "shutdown")))
|
||||
(hybrid-sleep-state elogind-hybrid-sleep-state
|
||||
(default '("disk")))
|
||||
(hybrid-sleep-mode elogind-hybrid-sleep-mode
|
||||
(default
|
||||
'("suspend" "platform" "shutdown")))
|
||||
(hibernate-delay-seconds elogind-hibernate-delay-seconds
|
||||
(default *unspecified*))
|
||||
(suspend-estimation-seconds elogind-suspend-estimation-seconds
|
||||
(default *unspecified*))
|
||||
(system-sleep-hook-files elogind-system-sleep-hook-files
|
||||
(default '()))
|
||||
(system-shutdown-hook-files elogind-system-shutdown-hook-files
|
||||
(default '()))
|
||||
(allow-power-off-interrupts? elogind-allow-power-off-interrupts?
|
||||
(default #f))
|
||||
(allow-suspend-interrupts? elogind-allow-suspend-interrupts?
|
||||
(default #f))
|
||||
(broadcast-power-off-interrupts? elogind-broadcast-power-off-interrupts?
|
||||
(default #t))
|
||||
(broadcast-suspend-interrupts? elogind-broadcast-suspend-interrupts?
|
||||
(default #t)))
|
||||
(define (non-negative-integer? x)
|
||||
(and (exact-integer? x)
|
||||
(not (negative? x))))
|
||||
|
||||
(define (elogind-configuration-file config)
|
||||
(define (yesno x)
|
||||
(match x
|
||||
(#t "yes")
|
||||
(#f "no")
|
||||
(_ (error "expected #t or #f, instead got:" x))))
|
||||
(define char-set:user-name
|
||||
(string->char-set "abcdefghijklmnopqrstuvwxyz0123456789_-"))
|
||||
(define (valid-list? l pred)
|
||||
(and-map (lambda (x) (string-every pred x)) l))
|
||||
(define (user-name-list users)
|
||||
(unless (valid-list? users char-set:user-name)
|
||||
(error "invalid user list" users))
|
||||
(string-join users " "))
|
||||
(define (enum val allowed)
|
||||
(unless (memq val allowed)
|
||||
(error "invalid value" val allowed))
|
||||
(symbol->string val))
|
||||
(define (non-negative-integer x)
|
||||
(unless (exact-integer? x) (error "not an integer" x))
|
||||
(when (negative? x) (error "negative number not allowed" x))
|
||||
(number->string x))
|
||||
(define (maybe-non-negative-integer x)
|
||||
(or (and (unspecified? x) x)
|
||||
(non-negative-integer x)))
|
||||
(define handle-actions
|
||||
'(ignore poweroff reboot halt kexec suspend hibernate hybrid-sleep suspend-then-hibernate lock))
|
||||
(define (handle-action x)
|
||||
(if (unspecified? x)
|
||||
x ;let the unspecified value go through
|
||||
(enum x handle-actions)))
|
||||
(define (sleep-list tokens)
|
||||
(unless (valid-list? tokens char-set:user-name)
|
||||
(error "invalid sleep list" tokens))
|
||||
(string-join tokens " "))
|
||||
(define-syntax ini-file-clause
|
||||
(syntax-rules ()
|
||||
;; Produce an empty line when encountering an unspecified value. This
|
||||
;; is better than an empty string value, which can, in some cases, cause
|
||||
;; warnings such as "Failed to parse handle action setting".
|
||||
((_ config (prop (parser getter)))
|
||||
(let ((value (parser (getter config))))
|
||||
(if (unspecified? value)
|
||||
""
|
||||
(string-append prop "=" value "\n"))))
|
||||
((_ config str)
|
||||
(if (unspecified? str)
|
||||
""
|
||||
(string-append str "\n")))))
|
||||
(define-syntax-rule (ini-file config file clause ...)
|
||||
(plain-file file (string-append (ini-file-clause config clause) ...)))
|
||||
(ini-file
|
||||
config "logind.conf"
|
||||
"[Login]"
|
||||
("KillUserProcesses" (yesno elogind-kill-user-processes?))
|
||||
("KillOnlyUsers" (user-name-list elogind-kill-only-users))
|
||||
("KillExcludeUsers" (user-name-list elogind-kill-exclude-users))
|
||||
("InhibitDelayMaxSec" (non-negative-integer elogind-inhibit-delay-max-seconds))
|
||||
("HandlePowerKey" (handle-action elogind-handle-power-key))
|
||||
("HandleSuspendKey" (handle-action elogind-handle-suspend-key))
|
||||
("HandleHibernateKey" (handle-action elogind-handle-hibernate-key))
|
||||
("HandleLidSwitch" (handle-action elogind-handle-lid-switch))
|
||||
("HandleLidSwitchDocked" (handle-action elogind-handle-lid-switch-docked))
|
||||
("HandleLidSwitchExternalPower" (handle-action elogind-handle-lid-switch-external-power))
|
||||
("PowerKeyIgnoreInhibited" (yesno elogind-power-key-ignore-inhibited?))
|
||||
("SuspendKeyIgnoreInhibited" (yesno elogind-suspend-key-ignore-inhibited?))
|
||||
("HibernateKeyIgnoreInhibited" (yesno elogind-hibernate-key-ignore-inhibited?))
|
||||
("LidSwitchIgnoreInhibited" (yesno elogind-lid-switch-ignore-inhibited?))
|
||||
("HoldoffTimeoutSec" (non-negative-integer elogind-holdoff-timeout-seconds))
|
||||
("IdleAction" (handle-action elogind-idle-action))
|
||||
("IdleActionSec" (non-negative-integer elogind-idle-action-seconds))
|
||||
("RuntimeDirectorySize"
|
||||
(identity
|
||||
(lambda (config)
|
||||
(match (elogind-runtime-directory-size-percent config)
|
||||
(#f (non-negative-integer (elogind-runtime-directory-size config)))
|
||||
(percent (string-append (non-negative-integer percent) "%"))))))
|
||||
("RemoveIPC" (yesno elogind-remove-ipc?))
|
||||
"[Sleep]"
|
||||
("SuspendState" (sleep-list elogind-suspend-state))
|
||||
("SuspendMode" (sleep-list elogind-suspend-mode))
|
||||
("HibernateState" (sleep-list elogind-hibernate-state))
|
||||
("HibernateMode" (sleep-list elogind-hibernate-mode))
|
||||
("HybridSleepState" (sleep-list elogind-hybrid-sleep-state))
|
||||
("HybridSleepMode" (sleep-list elogind-hybrid-sleep-mode))
|
||||
("HibernateDelaySec" (maybe-non-negative-integer elogind-hibernate-delay-seconds))
|
||||
("SuspendEstimationSec" (maybe-non-negative-integer elogind-suspend-estimation-seconds))
|
||||
("AllowPowerOffInterrupts" (yesno elogind-allow-power-off-interrupts?))
|
||||
("AllowSuspendInterrupts" (yesno elogind-allow-suspend-interrupts?))
|
||||
("BroadcastPowerOffInterrupts" (yesno elogind-broadcast-power-off-interrupts?))
|
||||
("BroadcastSuspendInterrupts" (yesno elogind-broadcast-suspend-interrupts?))))
|
||||
(define-maybe non-negative-integer
|
||||
(prefix elogind-))
|
||||
|
||||
(define (percent? x)
|
||||
(and (non-negative-integer? x)
|
||||
(>= x 0)
|
||||
(<= x 100)))
|
||||
|
||||
(define-maybe percent
|
||||
(prefix elogind-))
|
||||
|
||||
(define char-set:user-name
|
||||
(string->char-set "abcdefghijklmnopqrstuvwxyz0123456789_-"))
|
||||
|
||||
(define (user-name? x)
|
||||
(string-every char-set:user-name x))
|
||||
|
||||
(define list-of-user-names?
|
||||
(list-of user-name?))
|
||||
|
||||
(define-maybe list-of-user-names
|
||||
(prefix elogind-))
|
||||
|
||||
(define %elogind-actions
|
||||
'( ignore poweroff reboot halt kexec suspend hibernate hybrid-sleep
|
||||
suspend-then-hibernate lock factory-reset))
|
||||
|
||||
(define (action? x)
|
||||
(member x %elogind-actions))
|
||||
|
||||
(define-maybe action
|
||||
(prefix elogind-))
|
||||
|
||||
(define %linux-suspend-states
|
||||
;; The possible suspend states supported by the Linux kernel.
|
||||
;; See (info "(linux) Basic sysfs Interfaces for System Suspend and Hibernation").
|
||||
'(disk standby freeze mem))
|
||||
|
||||
(define (string->symbol/maybe x)
|
||||
(if (string? x)
|
||||
(string->symbol x)
|
||||
x))
|
||||
|
||||
(define (suspend-state? x)
|
||||
(member (string->symbol/maybe x) %linux-suspend-states))
|
||||
|
||||
(define list-of-suspend-states?
|
||||
(list-of suspend-state?))
|
||||
|
||||
(define-maybe list-of-suspend-states
|
||||
(prefix elogind-))
|
||||
|
||||
(define %linux-suspend-modes
|
||||
;; The possible suspend state variants supported by the Linux kernel.
|
||||
;; See (info "(linux) Basic sysfs Interfaces for System Suspend and Hibernation").
|
||||
'(s2idle shallow deep))
|
||||
|
||||
(define (suspend-mode? x)
|
||||
(member (string->symbol/maybe x) %linux-suspend-modes))
|
||||
|
||||
(define list-of-suspend-modes?
|
||||
(list-of suspend-mode?))
|
||||
|
||||
(define-maybe list-of-suspend-modes
|
||||
(prefix elogind-))
|
||||
|
||||
(define %linux-hibernation-modes
|
||||
;; The possible hibernation operating modes supported by the Linux kernel.
|
||||
;; See (info "(linux) Basic sysfs Interfaces for System Suspend and Hibernation").
|
||||
'(platform shutdown reboot suspend test_resume))
|
||||
|
||||
(define (hibernation-mode? x)
|
||||
(member (string->symbol/maybe x) %linux-hibernation-modes))
|
||||
|
||||
(define list-of-hibernation-modes?
|
||||
(list-of hibernation-mode?))
|
||||
|
||||
(define-maybe list-of-hibernation-modes
|
||||
(prefix elogind-))
|
||||
|
||||
(define (elogind-deprecated-empty-serializer name value)
|
||||
(when (maybe-value-set? value)
|
||||
(warn-about-deprecation name #f
|
||||
#:replacement #f))
|
||||
"")
|
||||
|
||||
(define list-of-file-likes?
|
||||
(list-of file-like?))
|
||||
|
||||
(define-maybe list-of-strings
|
||||
(prefix elogind-))
|
||||
|
||||
;;; Elogind serializers.
|
||||
(define (elogind-serialize-boolean name value)
|
||||
(let* ((name-str (symbol->string name))
|
||||
(name (if (string-suffix? "?" name-str)
|
||||
(string-drop-right name-str 1)
|
||||
name-str)))
|
||||
(format #f "~a=~:[no~;yes~]~%" (pascal-case name) value)))
|
||||
|
||||
(define (elogind-base-serializer name value)
|
||||
(let* ((name-str (symbol->string name))
|
||||
(name (if (string-suffix? "seconds" name-str)
|
||||
(string-drop-right name-str 4) ;seconds -> sec
|
||||
name-str)))
|
||||
(format #f "~a=~a~%" (pascal-case name) value)))
|
||||
|
||||
(define elogind-serialize-action elogind-base-serializer)
|
||||
(define elogind-serialize-non-negative-integer elogind-base-serializer)
|
||||
(define elogind-serialize-percent elogind-base-serializer)
|
||||
|
||||
(define (elogind-list-serializer name value)
|
||||
(format #f "~a=~{~a~^ ~}~%" (pascal-case name) value))
|
||||
|
||||
(define elogind-serialize-list-of-strings elogind-list-serializer)
|
||||
(define elogind-serialize-list-of-user-names elogind-list-serializer)
|
||||
(define elogind-serialize-list-of-suspend-states elogind-list-serializer)
|
||||
(define elogind-serialize-list-of-suspend-modes elogind-list-serializer)
|
||||
(define elogind-serialize-list-of-hibernation-modes elogind-list-serializer)
|
||||
|
||||
;;; XXX: For backward-compatible/historical reasons, the configuration object
|
||||
;;; is flat, containing the fields of both the logind.conf and sleep.conf
|
||||
;;; files. The list below contains the fields that should be serialized to
|
||||
;;; sleep.conf.
|
||||
(define %elogind-configuration-sleep-fields
|
||||
'( suspend-state suspend-mode suspend-estimation-seconds
|
||||
hibernate-mode hibernate-delay-seconds hibernate-state
|
||||
hybrid-sleep-state hybrid-sleep-mode))
|
||||
|
||||
(define-configuration elogind-configuration
|
||||
(elogind
|
||||
(file-like elogind)
|
||||
"The elogind package to use."
|
||||
(serializer empty-serializer))
|
||||
|
||||
(system-sleep-hook-files
|
||||
(list-of-file-likes '())
|
||||
"A list of executables (file-like objects) that will be installed into the
|
||||
@file{/etc/elogind/system-sleep} hook directory. See `Hook directories' in
|
||||
the @samp{loginctl(1)} man page for more information."
|
||||
(serializer empty-serializer))
|
||||
|
||||
(system-shutdown-hook-files
|
||||
(list-of-file-likes '())
|
||||
"A list of executables (file-like objects) that will be installed into the
|
||||
@file{/etc/elogind/system-shutdown/} hook directory."
|
||||
(serializer empty-serializer))
|
||||
|
||||
(allow-power-off-interrupts?
|
||||
(maybe-boolean #f)
|
||||
"Whether the executables in elogind's hook directories (see above) can
|
||||
cause a power-off action to be cancelled (interrupted) by printing an
|
||||
appropriate error message to stdout.")
|
||||
|
||||
(allow-suspend-interrupts?
|
||||
(maybe-boolean #f)
|
||||
"Likewise as the @code{allow-power-off-interrupts?} option, but for the
|
||||
suspend action.")
|
||||
|
||||
(broadcast-power-off-interrupts?
|
||||
(maybe-boolean #f)
|
||||
"Whether an interrupt of a power-off action is broadcasted.")
|
||||
|
||||
(broadcast-suspend-interrupts?
|
||||
(maybe-boolean #f)
|
||||
"Whether an interrupt of a suspend action is broadcasted.")
|
||||
|
||||
;; logind.conf options.
|
||||
(kill-user-processes?
|
||||
(maybe-boolean #f)
|
||||
"Whether the processes of a user should be killed when the user logs
|
||||
out.")
|
||||
|
||||
(kill-only-users
|
||||
maybe-list-of-user-names
|
||||
"Usernames whose processes should be killed, regardless the value of
|
||||
@code{kill-user-processes?}.")
|
||||
|
||||
(kill-exclude-users
|
||||
(maybe-list-of-user-names (list "root"))
|
||||
"Usernames whose processes should @emph{not} be killed, regardless the
|
||||
value of @code{kill-user-processes?}.")
|
||||
|
||||
(inhibit-delay-max-seconds
|
||||
(maybe-non-negative-integer 5)
|
||||
"The maximum time a system shutdown or sleep request is delayed due to an
|
||||
inhibitor lock of type delay being active before the inhibitor is ignored and
|
||||
the operation executes anyway.")
|
||||
|
||||
(handle-power-key
|
||||
(maybe-action 'poweroff)
|
||||
"The action done when the power key is pressed. The compiled default is
|
||||
@code{'poweroff}.")
|
||||
|
||||
(handle-suspend-key
|
||||
(maybe-action 'suspend)
|
||||
"The action done when the suspend key is pressed. The ")
|
||||
|
||||
(handle-hibernate-key
|
||||
(maybe-action 'hibernate)
|
||||
"The action done when the hibernate key is pressed.")
|
||||
|
||||
(handle-lid-switch
|
||||
(maybe-action 'suspend)
|
||||
"The action done when the lid is closed.")
|
||||
|
||||
(handle-lid-switch-docked
|
||||
(maybe-action 'ignore)
|
||||
"The action done when the lid is closed and the device docked.")
|
||||
|
||||
(handle-lid-switch-external-power
|
||||
(maybe-action 'suspend)
|
||||
"The action done when the lid is closed and the device is externally
|
||||
powered.")
|
||||
|
||||
(power-key-ignore-inhibited?
|
||||
(maybe-boolean #f)
|
||||
"Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the power key is pressed.")
|
||||
|
||||
(suspend-key-ignore-inhibited?
|
||||
(maybe-boolean #f)
|
||||
"Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the suspend key is pressed.")
|
||||
|
||||
(hibernate-key-ignore-inhibited?
|
||||
(maybe-boolean #f)
|
||||
"Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the hibernate key is pressed.")
|
||||
|
||||
(lid-switch-ignore-inhibited?
|
||||
(maybe-boolean #f)
|
||||
"Whether to ignore high-level inhibitor locks (shutdown, reboot, sleep or
|
||||
idle) when the lid is closed.")
|
||||
|
||||
(holdoff-timeout-seconds
|
||||
(maybe-non-negative-integer 30)
|
||||
"Specifies the number of seconds after system startup or system resume
|
||||
during which elogind will hold off on reacting to lid events.")
|
||||
|
||||
(idle-action
|
||||
(maybe-action 'ignore)
|
||||
"Action to take when the system is idle.")
|
||||
|
||||
(idle-action-seconds
|
||||
maybe-non-negative-integer
|
||||
"The delay after which the action configured in @code{idle-action} is
|
||||
taken after the system is idle.")
|
||||
|
||||
;; XXX: Perhaps deprecate in the future and handle all the accepted forms
|
||||
;; directly in 'runtime-directory-size' instead.
|
||||
(runtime-directory-size-percent
|
||||
maybe-percent
|
||||
"Set the size limit, in percent, on the @env{XDG_RUNTIME_DIR} runtime
|
||||
directory for each user who logs in. This specifies the per-user size limit
|
||||
relative to the amount of physical @acronym{RAM, read access memory}. This
|
||||
value takes precedence over that specified via @code{runtime-directory-size}."
|
||||
(serializer empty-serializer)) ;special cased at serialization time
|
||||
|
||||
(runtime-directory-size
|
||||
maybe-non-negative-integer
|
||||
"Set the size limit, in bytes, on the @env{XDG_RUNTIME_DIR} runtime
|
||||
directory for each user who logs in."
|
||||
(serializer empty-serializer)) ;special cased at serialization time
|
||||
|
||||
(remove-ipc?
|
||||
(maybe-boolean #t)
|
||||
"Whether @acronym{IPC, inter-process communication} objects belonging to
|
||||
the user shall be removed when the user fully logs out.")
|
||||
|
||||
;; sleep.conf options.
|
||||
;; CAUTION: all sleep.conf option names must be registered in the above
|
||||
;; %ELOGIND-CONFIGURATION-SLEEP-FIELDS variable: otherwise they will be
|
||||
;; serialized to logind.conf instead of sleep.conf!
|
||||
(suspend-state
|
||||
(maybe-list-of-suspend-states '(mem standby freeze))
|
||||
"The suspend state values to be write to @file{/sys/power/state} by elogind
|
||||
when suspending the system. They will be tried in turn, until one is written
|
||||
without error.")
|
||||
|
||||
(suspend-mode
|
||||
(maybe-list-of-suspend-modes)
|
||||
"The suspend mode values to write to @file{/sys/power/mem_sleep} by elogind
|
||||
when suspending the system.")
|
||||
|
||||
(suspend-estimation-seconds
|
||||
(maybe-non-negative-integer (* 60 60)) ;1 hour
|
||||
"Cause the RTC alarm to wake the system after the specified time span to
|
||||
measure the system battery capacity level and estimate the battery discharging
|
||||
rate, which is used for estimating the time span until the system battery
|
||||
charge level goes down to 5%. This option is only used by elogind when using
|
||||
the @code{'suspend-then-hibernate} action.")
|
||||
|
||||
(hibernate-mode
|
||||
(maybe-list-of-hibernation-modes '(platform shutdown))
|
||||
"The hibernation mode values to write to @file{/sys/power/disk} by elogind
|
||||
when hibernating the system.")
|
||||
|
||||
(hibernate-delay-seconds
|
||||
maybe-non-negative-integer
|
||||
"The amount of time the system spends in suspend mode before the system is
|
||||
automatically put into hibernate mode.")
|
||||
|
||||
;; TODO: Remove in May 2026.
|
||||
(hibernate-state
|
||||
maybe-list-of-strings
|
||||
"Deprecated option."
|
||||
(serializer elogind-deprecated-empty-serializer))
|
||||
|
||||
;; TODO: Remove in May 2026.
|
||||
(hybrid-sleep-state
|
||||
maybe-list-of-strings
|
||||
"Deprecated option."
|
||||
(serializer elogind-deprecated-empty-serializer))
|
||||
|
||||
;; TODO: Remove in May 2026.
|
||||
(hybrid-sleep-mode
|
||||
maybe-list-of-strings
|
||||
"Deprecated option."
|
||||
(serializer elogind-deprecated-empty-serializer))
|
||||
|
||||
(prefix elogind-))
|
||||
|
||||
(define (logind.conf config)
|
||||
(let ((logind-fields (remove (lambda (field)
|
||||
(memq (configuration-field-name field)
|
||||
%elogind-configuration-sleep-fields))
|
||||
elogind-configuration-fields)))
|
||||
(match-record config <elogind-configuration>
|
||||
(runtime-directory-size-percent runtime-directory-size)
|
||||
;; Handle the special-cased
|
||||
;; runtime-directory-size-percent/runtime-directory-size options pair.
|
||||
(let ((runtime-directory-size
|
||||
(if (maybe-value-set? runtime-directory-size-percent)
|
||||
(format #f "~a%~%" runtime-directory-size-percent) ;10 -> 10%
|
||||
runtime-directory-size)))
|
||||
(mixed-text-file
|
||||
"logind.conf"
|
||||
"[Login]\n"
|
||||
(if (maybe-value-set? runtime-directory-size)
|
||||
(list "RuntimeDirectorySize=" runtime-directory-size)
|
||||
"")
|
||||
(serialize-configuration config logind-fields))))))
|
||||
|
||||
(define (sleep.conf config)
|
||||
(let ((sleep-fields (filter (lambda (field)
|
||||
(memq (configuration-field-name field)
|
||||
%elogind-configuration-sleep-fields))
|
||||
elogind-configuration-fields)))
|
||||
(mixed-text-file
|
||||
"sleep.conf"
|
||||
"[Sleep]\n"
|
||||
(serialize-configuration config sleep-fields))))
|
||||
|
||||
(define (elogind-etc-directory config)
|
||||
"Return the /etc/elogind directory for CONFIG."
|
||||
|
|
@ -1213,12 +1410,21 @@ and many other) available for GIO applications.")
|
|||
(chmod dest #o500)))
|
||||
|
||||
(mkdir-p #$output) ;in case neither directory gets created
|
||||
|
||||
;; Symlink the main configuration files.
|
||||
(with-directory-excursion #$output
|
||||
(mkdir-p "logind.conf.d")
|
||||
(symlink #$(logind.conf config) "logind.conf.d/logind.conf")
|
||||
(mkdir-p "sleep.conf.d")
|
||||
(symlink #$(sleep.conf config) "sleep.conf.d/sleep.conf"))
|
||||
|
||||
(for-each (lambda (f)
|
||||
(copy-script f sleep-directory))
|
||||
'#$(elogind-system-sleep-hook-files config))
|
||||
'#$(elogind-configuration-system-sleep-hook-files config))
|
||||
(for-each (lambda (f)
|
||||
(copy-script f shutdown-directory))
|
||||
'#$(elogind-system-shutdown-hook-files config))))))
|
||||
'#$(elogind-configuration-system-shutdown-hook-files
|
||||
config))))))
|
||||
|
||||
(define (elogind-dbus-service config)
|
||||
"Return a @file{org.freedesktop.login1.service} file that tells D-Bus how to
|
||||
|
|
@ -1231,7 +1437,7 @@ explain how to start elogind; instead, it spawns a wrapper that waits for the
|
|||
;; <https://issues.guix.gnu.org/55444>.
|
||||
|
||||
(define elogind
|
||||
(elogind-package config))
|
||||
(elogind-configuration-elogind config))
|
||||
|
||||
(define wrapper
|
||||
(program-file "elogind-dbus-shepherd-sync"
|
||||
|
|
@ -1288,7 +1494,7 @@ seats.)"
|
|||
(define pam-elogind
|
||||
(pam-entry
|
||||
(control "required")
|
||||
(module (file-append (elogind-package config)
|
||||
(module (file-append (elogind-configuration-elogind config)
|
||||
"/lib/security/pam_elogind.so"))))
|
||||
|
||||
(list (pam-extension
|
||||
|
|
@ -1299,58 +1505,65 @@ seats.)"
|
|||
(session (cons pam-elogind (pam-service-session pam))))))
|
||||
(shepherd-requirements '(elogind)))))
|
||||
|
||||
(define* (shepherd-configuration-action* files)
|
||||
"Return a 'configuration' action to display FILES, which should be the names
|
||||
of the service's configuration files."
|
||||
(shepherd-action
|
||||
(name 'configuration)
|
||||
(documentation "Display the names of this service's configuration files.")
|
||||
(procedure #~(lambda (_)
|
||||
(format #t "~{~a~%~}" '#$files)
|
||||
'#$files))))
|
||||
|
||||
(define (elogind-shepherd-service config)
|
||||
"Return a Shepherd service to start elogind according to @var{config}."
|
||||
(define config-file
|
||||
(elogind-configuration-file config))
|
||||
|
||||
(list (shepherd-service
|
||||
(requirement '(user-processes dbus-system))
|
||||
(provision '(elogind))
|
||||
(start #~(make-forkexec-constructor
|
||||
(list #$(file-append (elogind-package config)
|
||||
"/libexec/elogind/elogind"))
|
||||
#:environment-variables
|
||||
(list (string-append "ELOGIND_CONF_FILE="
|
||||
#$config-file))))
|
||||
(list #$(file-append (elogind-configuration-elogind config)
|
||||
"/libexec/elogind/elogind"))))
|
||||
(stop #~(make-kill-destructor))
|
||||
(actions (list (shepherd-configuration-action config-file))))))
|
||||
(actions (list (shepherd-configuration-action*
|
||||
(list (logind.conf config)
|
||||
(sleep.conf config))))))))
|
||||
|
||||
(define elogind-service-type
|
||||
(service-type (name 'elogind)
|
||||
(extensions
|
||||
(list (service-extension dbus-root-service-type
|
||||
elogind-dbus-service)
|
||||
(service-extension udev-service-type
|
||||
(compose list elogind-package))
|
||||
(service-extension polkit-service-type
|
||||
(compose list elogind-package))
|
||||
(service-type
|
||||
(name 'elogind)
|
||||
(extensions
|
||||
(list (service-extension dbus-root-service-type
|
||||
elogind-dbus-service)
|
||||
(service-extension udev-service-type
|
||||
(compose list elogind-configuration-elogind))
|
||||
(service-extension polkit-service-type
|
||||
(compose list elogind-configuration-elogind))
|
||||
|
||||
;; Start elogind from the Shepherd rather than waiting
|
||||
;; for bus activation. This ensures that it can handle
|
||||
;; events like lid close, etc.
|
||||
(service-extension shepherd-root-service-type
|
||||
elogind-shepherd-service)
|
||||
;; Start elogind from the Shepherd rather than waiting
|
||||
;; for bus activation. This ensures that it can handle
|
||||
;; events like lid close, etc.
|
||||
(service-extension shepherd-root-service-type
|
||||
elogind-shepherd-service)
|
||||
|
||||
;; Provide the 'loginctl' command.
|
||||
(service-extension profile-service-type
|
||||
(compose list elogind-package))
|
||||
;; Provide the 'loginctl' command.
|
||||
(service-extension profile-service-type
|
||||
(compose list elogind-configuration-elogind))
|
||||
|
||||
;; Extend PAM with pam_elogind.so.
|
||||
(service-extension pam-root-service-type
|
||||
pam-extension-procedure)
|
||||
;; Extend PAM with pam_elogind.so.
|
||||
(service-extension pam-root-service-type
|
||||
pam-extension-procedure)
|
||||
|
||||
;; Install sleep/shutdown hook files.
|
||||
(service-extension etc-service-type
|
||||
(lambda (config)
|
||||
`(("elogind"
|
||||
,(elogind-etc-directory config)))))
|
||||
;; Install sleep/shutdown hook files.
|
||||
(service-extension etc-service-type
|
||||
(lambda (config)
|
||||
`(("elogind"
|
||||
,(elogind-etc-directory config)))))
|
||||
|
||||
;; We need /run/user, /run/systemd, etc.
|
||||
(service-extension file-system-service-type
|
||||
(const %elogind-file-systems))))
|
||||
(default-value (elogind-configuration))
|
||||
(description "Run the @command{elogind} login and seat
|
||||
;; We need /run/user, /run/systemd, etc.
|
||||
(service-extension file-system-service-type
|
||||
(const %elogind-file-systems))))
|
||||
(default-value (elogind-configuration))
|
||||
(description "Run the @command{elogind} login and seat
|
||||
management service. The @command{elogind} service integrates with PAM to
|
||||
allow other system components to know the set of logged-in users as well as
|
||||
their session types (graphical, console, remote, etc.). It can also clean up
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue