projects/guix·blob java-team · refs

676 lines · 25.3 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2025, 2026 Tomas Volf <[email protected]>
3;;;
4;;; This file is part of GNU Guix.
5;;;
6;;; GNU Guix is free software; you can redistribute it and/or modify
7;;; it under the terms of the GNU General Public License as published by
8;;; the Free Software Foundation, either version 3 of the License, or
9;;; (at your option) any later version.
10;;;
11;;; GNU Guix is distributed in the hope that it will be useful,
12;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;;; GNU General Public License for more details.
15;;;
16;;; You should have received a copy of the GNU General Public License
17;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
18
19;;;; Commentary:
20
21;;; Power-related services.
22
23;;;; Code:
24
25(define-module (gnu services power)
26 #:use-module (gnu)
27 #:use-module (gnu packages admin)
28 #:use-module (gnu packages linux)
29 #:use-module (gnu packages power)
30 #:use-module (gnu services configuration)
31 #:use-module (gnu services shepherd)
32 #:use-module (gnu services)
33 #:use-module (guix packages)
34 #:use-module (guix records)
35 #:use-module (ice-9 match)
36 #:use-module (srfi srfi-1)
37 #:use-module (srfi srfi-26)
38 #:export (apcupsd-service-type
39
40 apcupsd-configuration
41 apcupsd-configuration-apcupsd
42 apcupsd-configuration-shepherd-service-name
43 apcupsd-configuration-auto-start?
44 apcupsd-configuration-pid-file
45 apcupsd-configuration-debug-level
46 apcupsd-configuration-run-dir
47 apcupsd-configuration-name
48 apcupsd-configuration-cable
49 apcupsd-configuration-type
50 apcupsd-configuration-device
51 apcupsd-configuration-poll-time
52 apcupsd-configuration-on-batery-delay
53 apcupsd-configuration-battery-level
54 apcupsd-configuration-remaining-minutes
55 apcupsd-configuration-timeout
56 apcupsd-configuration-annoy-interval
57 apcupsd-configuration-annoy-delay
58 apcupsd-configuration-no-logon
59 apcupsd-configuration-kill-delay
60 apcupsd-configuration-net-server
61 apcupsd-configuration-net-server-ip
62 apcupsd-configuration-net-server-port
63 apcupsd-configuration-net-server-events-file
64 apcupsd-configuration-net-server-events-file-max-size
65 apcupsd-configuration-class
66 apcupsd-configuration-mode
67 apcupsd-configuration-stat-time
68 apcupsd-configuration-log-stats
69 apcupsd-configuration-data-time
70 apcupsd-configuration-facility
71 apcupsd-configuration-event-handlers
72
73 apcupsd-event-handlers
74 apcupsd-event-handlers-modules
75 apcupsd-event-handlers-annoyme
76 apcupsd-event-handlers-battattach
77 apcupsd-event-handlers-battdetach
78 apcupsd-event-handlers-changeme
79 apcupsd-event-handlers-commfailure
80 apcupsd-event-handlers-commok
81 apcupsd-event-handlers-doreboot
82 apcupsd-event-handlers-doshutdown
83 apcupsd-event-handlers-emergency
84 apcupsd-event-handlers-endselftest
85 apcupsd-event-handlers-failing
86 apcupsd-event-handlers-killpower
87 apcupsd-event-handlers-loadlimit
88 apcupsd-event-handlers-mainsback
89 apcupsd-event-handlers-offbattery
90 apcupsd-event-handlers-onbattery
91 apcupsd-event-handlers-powerout
92 apcupsd-event-handlers-remotedown
93 apcupsd-event-handlers-runlimit
94 apcupsd-event-handlers-startselftest
95 apcupsd-event-handlers-timeout))
96
97(define-configuration/no-serialization apcupsd-event-handlers
98 (modules
99 (gexp #~())
100 "Additional modules to import into the generated handler script.")
101 (killpower
102 (gexp
103 #~(begin
104 (wall "Apccontrol doing: apcupsd --killpower on UPS ~a" name)
105 (sleep 10)
106 (apcupsd "--killpower")
107 (wall "Apccontrol has done: apcupsd --killpower on UPS ~a" name)))
108 "The handler for the killpower event.")
109 (commfailure
110 (gexp
111 #~(begin
112 (let ((msg (format #f "~a Communications with UPS ~a lost."
113 (gethostname) name)))
114 (mail-to-root msg msg))
115 (wall "Warning: communications lost with UPS ~a" name)))
116 "The handler for the commfailure event.")
117 (commok
118 (gexp
119 #~(begin
120 (let ((msg (format #f "~a Communications with UPS ~a restored."
121 (gethostname) name)))
122 (mail-to-root msg msg))
123 (wall "Communications restored with UPS ~a" name)))
124 "The handler for the commfailure event.")
125 (powerout
126 (gexp
127 #~#t)
128 "The handler for the powerout event.")
129 (onbattery
130 (gexp
131 #~(begin
132 (let ((msg (format #f "~a UPS ~a Power Failure !!!"
133 (gethostname) name)))
134 (mail-to-root msg msg))
135 (wall "Power failure on UPS ~a. Running on batteries." name)))
136 "The handler for the onbattery event.")
137 (offbattery
138 (gexp
139 #~(begin
140 (let ((msg (format #f "~a UPS ~a Power has returned."
141 (gethostname) name)))
142 (mail-to-root msg msg))
143 (wall "Power has returned on UPS ~a..." name)))
144 "The handler for the offbattery event.")
145 (mainsback
146 (gexp
147 #~(when (file-exists? powerfail-file)
148 (wall "Continuing with shutdown.")))
149 "The handler for the mainsback event.")
150 (failing
151 (gexp
152 #~(wall "Battery power exhausted on UPS ~a. Doing shutdown." name))
153 "The handler for the failing event.")
154 (timeout
155 (gexp
156 #~(wall "Battery time limit exceeded on UPS ~a. Doing shutdown." name))
157 "The handler for the timeout event.")
158 (loadlimit
159 (gexp
160 #~(wall "Remaining battery charge below limit on UPS ~a. Doing shutdown." name))
161 "The handler for the loadlimit event.")
162 (runlimit
163 (gexp
164 #~(wall "Remaining battery runtime below limit on UPS ~a. Doing shutdown." name))
165 "The handler for the runlimit event.")
166 (doreboot
167 (gexp
168 #~(begin
169 (wall "UPS ~a initiating Reboot Sequence" name)
170 (system* #$(file-append shepherd "/sbin/reboot"))))
171 "The handler for the doreboot event.")
172 (doshutdown
173 (gexp
174 #~(begin
175 (wall "UPS ~a initiated Shutdown Sequence" name)
176 (system* #$(file-append shepherd "/sbin/halt"))))
177 "The handler for the doshutdown event.")
178 (annoyme
179 (gexp
180 #~(wall "Power problems with UPS ~a. Please logoff." name))
181 "The handler for the annoyme event.")
182 (emergency
183 (gexp
184 #~(wall "Emergency Shutdown. Possible battery failure on UPS ~a." name))
185 "The handler for the emergency event.")
186 (changeme
187 (gexp
188 #~(begin
189 (let ((msg (format #f "~a UPS ~a battery needs changing NOW."
190 (gethostname) name)))
191 (mail-to-root msg msg))
192 (wall "Emergency! Batteries have failed on UPS ~a. Change them NOW." name)))
193 "The handler for the changeme event.")
194 (remotedown
195 (gexp
196 #~(wall "Remote Shutdown. Beginning Shutdown Sequence."))
197 "The handler for the remotedown event.")
198 (startselftest
199 (gexp
200 #~#t)
201 "The handler for the startselftest event.")
202 (endselftest
203 (gexp
204 #~#t)
205 "The handler for the endselftest event.")
206 (battdetach
207 (gexp
208 #~#t)
209 "The handler for the battdetach event.")
210 (battattach
211 (gexp
212 #~#t)
213 "The handler for the battattach event."))
214
215(define mangle-field-name
216 (match-lambda
217 ('name "UPSNAME")
218 ('cable "UPSCABLE")
219 ('type "UPSTYPE")
220 ('device "DEVICE")
221 ('poll-time "POLLTIME")
222 ('lock-dir "LOCKFILE")
223 ('power-fail-dir "PWRFAILDIR")
224 ('no-login-dir "NOLOGINDIR")
225 ('on-batery-delay "ONBATTERYDELAY")
226 ('battery-level "BATTERYLEVEL")
227 ('remaining-minutes "MINUTES")
228 ('timeout "TIMEOUT")
229 ('annoy-interval "ANNOY")
230 ('annoy-delay "ANNOYDELAY")
231 ('no-logon "NOLOGON")
232 ('kill-delay "KILLDELAY")
233 ('net-server "NETSERVER")
234 ('net-server-ip "NISIP")
235 ('net-server-port "NISPORT")
236 ('net-server-events-file "EVENTSFILE")
237 ('net-server-events-file-max-size "EVENTSFILEMAX")
238 ('class "UPSCLASS")
239 ('mode "UPSMODE")
240 ('stat-time "STATTIME")
241 ('stat-file "STATFILE")
242 ('log-stats "LOGSTATS")
243 ('data-time "DATATIME")
244 ('facility "FACILITY")))
245
246(define (serialize-field field-name value)
247 #~(format #f "~a ~a\n" #$(mangle-field-name field-name) '#$value))
248(define serialize-string serialize-field)
249(define serialize-symbol serialize-field)
250(define serialize-integer serialize-field)
251(define (serialize-boolean field-name value)
252 (serialize-field field-name (if value "on" "off")))
253
254(define-maybe string)
255
256(define-enumerated-field-type enum-cable
257 ( simple smart ether usb
258 940-0119A 940-0127A 940-0128A 940-0020B 940-0020C
259 940-0023A 940-0024B 940-0024C 940-1524C 940-0024G
260 940-0095A 940-0095B 940-0095C 940-0625A MAM-04-02-2000))
261(define-enumerated-field-type enum-type (apcsmart usb net snmp netsnmp dumb pcnet modbus test))
262(define-enumerated-field-type enum-no-logon (disable timeout percent minutes always))
263(define-enumerated-field-type enum-class (standalone shareslave sharemaster))
264(define-enumerated-field-type enum-mode (disable share))
265
266(define-configuration apcupsd-configuration
267 (apcupsd (package apcupsd) "The @code{apcupsd} package to use.")
268
269 (shepherd-service-name
270 (symbol 'apcupsd)
271 "The name of the shepherd service. You can add the service multiple times
272with different names to manage multiple UPSes."
273 empty-serializer)
274 (auto-start?
275 (boolean #t)
276 "Should the shepherd service auto-start?"
277 empty-serializer)
278 (pid-file
279 (string "/run/apcupsd.pid")
280 "The file name of the PID file."
281 empty-serializer)
282 (debug-level
283 (integer 0)
284 "The logging verbosity. Bigger number means more logs. The source code
285uses up to @code{300} as debug level value, so a value of @code{999} seems
286reasonable to enable all the logs."
287 empty-serializer)
288
289 (run-dir
290 (string "/run/apcupsd")
291 "The directory containing runtime information. You need to change this if
292you desire to run multiple instances of the daemon."
293 empty-serializer)
294
295 ;; General configuration parameters
296 (name
297 maybe-string
298 "Use this to give your UPS a name in log files and such. This is
299particularly useful if you have multiple UPSes. This does not set the EEPROM.
300It should be 8 characters or less.")
301 (cable
302 (enum-cable 'usb)
303 "The type of a cable connecting the UPS to your computer. Possible generic
304choices are @code{'simple}, @code{'smart}, @code{'ether} and
305@code{'usb}.
306
307Alternatively, a specific cable model number may be used: @code{'940-0119A},
308@code{'940-0127A}, @code{'940-0128A}, @code{'940-0020B}, @code{'940-0020C},
309@code{'940-0023A}, @code{'940-0024B}, @code{'940-0024C}, @code{'940-1524C},
310@code{'940-0024G}, @code{'940-0095A}, @code{'940-0095B}, @code{'940-0095C},
311@code{'940-0625A}, @code{'M-04-02-2000}.")
312 (type
313 (enum-type 'usb)
314 "The type of the UPS you have.
315
316@table @code
317@item apcsmart
318Newer serial character device, appropriate for SmartUPS models using a serial
319cable (not an USB).
320
321@item usb
322Most new UPSes are an USB.
323
324@item net
325Network link to a master apcupsd through apcupsd's Network Information Server.
326This is used if the UPS powering your computer is connected to a different
327computer for monitoring.
328
329@item snmp
330SNMP network link to an SNMP-enabled UPS device.
331
332@item netsnmp
333Same as the SNMP above but requires use of the net-snmp library. Unless you
334have a specific need for this old driver, you should use the @code{'snmp}
335instead.
336
337@item dumb
338An old serial character device for use with simple-signaling UPSes.
339
340@item pcnet
341A PowerChute Network Shutdown protocol which can be used as an alternative to
342an SNMP with the AP9617 family of smart slot cards.
343
344@item modbus
345A serial device for use with newest SmartUPS models supporting the MODBUS
346protocol.
347
348@end table")
349 (device
350 (string "")
351 "For USB UPSes, usually you want to set this to an empty string (the
352default). For other UPS types, you must specify an appropriate port or
353address.
354
355@table @code
356@item apcsmart
357Set to the appropriate @file{/dev/tty**} device.
358
359@item usb
360A null string setting enables auto-detection, which is the best choice for
361most installations.
362
363@item net
364Set to @code{@var{hostname}:@var{port}}.
365
366@item snmp
367Set to @code{@var{hostname}:@var{port}:@var{vendor}:@var{community}}. The
368@var{hostname} is the ip address or hostname of the UPS on the network. The
369@var{vendor} can be can be \"APC\" or \"APC_NOTRAP\". \"APC_NOTRAP\" will
370disable SNMP trap catching; you usually want \"APC\". The @var{port} is
371usually 161. The @var{community} is usually \"private\".
372
373@item netsnmp
374Same as the @code{'snmp}.
375
376@item dumb
377Set to the appropriate @file{/dev/tty**} device.
378
379@item pcnet
380Set to @code{@var{ipaddr}:@var{username}:@var{passphrase}:@var{port}}. The
381@var{ipaddr} is the IP address of the UPS management card. The @var{username}
382and the @var{passphrase} are the credentials for which the card has been
383configured. The @var{port} is the port number on which to listen for messages
384from the UPS, normally 3052. If this parameter is empty or missing, the
385default of 3052 will be used.
386
387@item modbus
388Set to the appropriate @file{/dev/tty**} device. You can also leave it empty
389for MODBUS over USB or set to the serial number of the UPS.
390
391@end table")
392 (poll-time
393 (integer 60)
394 "The interval (in seconds) at which apcupsd polls the UPS for status. This
395setting applies both to directly-attached UPSes (apcsmart, usb, dumb) and
396networked UPSes (net, snmp). Lowering this setting will improve the apcupsd's
397responsiveness to certain events at the cost of higher CPU utilization.")
398
399 ;; Configuration parameters used during power failures
400 (on-batery-delay
401 (integer 6)
402 "The time in seconds from when a power failure is detected until we react
403to it with an onbattery event. The @code{'powerout} event will be triggered
404immediately when a power failure is detected. However, the @code{'onbattery}
405event will be trigger only after this delay.")
406 (battery-level
407 (integer 5)
408 "If during a power failure, the remaining battery percentage (as reported
409by the UPS) is below or equal to this value, the apcupsd will initiate a
410system shutdown.
411
412@quotation Note
413@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work
414in a conjunction, so the first that occurs will cause the initation of a
415shutdown.
416@end quotation")
417 (remaining-minutes
418 (integer 3)
419 "If during a power failure, the remaining runtime in minutes (as calculated
420internally by the UPS) is below or equal to this value, apcupsd will initiate
421a system shutdown.
422
423@quotation Note
424@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work
425in a conjunction, so the first that occurs will cause the initation of a
426shutdown.
427@end quotation")
428 (timeout
429 (integer 0)
430 "If during a power failure, the UPS has run on batteries for this many
431seconds or longer, apcupsd will initiate a system shutdown. The value of 0
432disables this timer.
433
434@quotation Note
435@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work
436in a conjunction, so the first that occurs will cause the initation of a
437shutdown.
438@end quotation")
439 (annoy-interval
440 (integer 300)
441 "The time in seconds between annoying users (via the @code{'annoyme} event)
442to sign off prior to system shutdown. 0 disables.")
443 (annoy-delay
444 (integer 60)
445 "The initial delay in seconds after a power failure before warning users to
446get off the system.")
447 (no-logon
448 (enum-no-logon 'disable)
449 "The condition which determines when users are prevented from logging in
450during a power failure.")
451 (kill-delay
452 (integer 0)
453 "If this is non-zero, the apcupsd will continue running after a shutdown
454has been requested, and after the specified time in seconds attempt to kill
455the power. This is for use on systems where apcupsd cannot regain control
456after a shutdown.")
457
458 ;; Configuration statements for Network Information Server
459 (net-server
460 (boolean #f)
461 "If enabled, a network information server process will be started.")
462 (net-server-ip
463 (string "127.0.0.1")
464 "An IP address on which the NIS server will listen for incoming
465connections.")
466 (net-server-port
467 (integer 3551)
468 "An IP port on which the NIS server will listen for incoming connections.")
469 (net-server-events-file
470 maybe-string
471 "If you want the last few EVENTS to be available over the network by the
472network information server, you must set this to a file name.")
473 (net-server-events-file-max-size
474 (integer 10)
475 "The maximum size of the events file in kilobytes.")
476 ;; Configuration statements used if sharing a UPS with more than one machine
477 (class (enum-class 'standalone)
478 "Normally standalone unless you share an UPS using an APC ShareUPS card.")
479 (mode (enum-mode 'disable)
480 "Normally disable unless you share an UPS using an APC ShareUPS card.")
481 ;; Configuration statements to control apcupsd system logging
482 (stat-time
483 (integer 0)
484 "The time interval in seconds between writing the status file, 0
485disables.")
486 (log-stats
487 (boolean #f)
488 "Also write the stats as a logs. This generates a lot of output.")
489 (data-time
490 (integer 0)
491 "The time interval in seconds between writing the data records to the log
492file, 0 disables.")
493 (facility
494 maybe-string
495 "The logging facility for the syslog.")
496
497 ;; Event handlers
498 (event-handlers
499 (apcupsd-event-handlers (apcupsd-event-handlers))
500 "Handlers for events produced by apcupsd."
501 empty-serializer))
502
503(define (%apccontrol config)
504 (program-file
505 "apccontrol"
506 (match-record (apcupsd-configuration-event-handlers config)
507 <apcupsd-event-handlers>
508 ( killpower commfailure commok powerout onbattery offbattery mainsback
509 failing timeout loadlimit runlimit doreboot doshutdown annoyme
510 emergency changeme remotedown startselftest endselftest battdetach
511 battattach )
512 #~(begin
513 (use-modules (ice-9 format)
514 (ice-9 match)
515 (ice-9 popen)
516 (srfi srfi-9)
517 #$@(apcupsd-event-handlers-modules
518 (apcupsd-configuration-event-handlers config)))
519 ;; Script dir depends on these, and the configuration depends on the
520 ;; script dir. To sever the cyclic dependency, pass the file names via
521 ;; environment variables.
522 (define conf (getenv "GUIX_APCUPSD_CONF"))
523 (define powerfail-file (getenv "GUIX_APCUPSD_POWERFAIL_FILE"))
524
525 (define (err . args)
526 (apply format (current-error-port) args))
527 (define (wall . args)
528 (system* #$(file-append util-linux "/bin/wall") (apply format #f args)))
529 (define (apcupsd . args)
530 (apply system* #$(file-append apcupsd "/sbin/apcupsd") "-f" conf args))
531 (define (mail-to-root subject body)
532 (let ((port (open-pipe* OPEN_WRITE
533 "/run/privileged/bin/sendmail"
534 "-F" "apcupsd"
535 "root")))
536 (format port "Subject: ~a~%~%~a~&" subject body)
537 (close-pipe port)))
538 (match (cdr (command-line))
539 (((? string? cmd) name connected powered)
540 (let ((connected? (match connected
541 ("1" #t)
542 ("0" #f)))
543 (powered? (match powered
544 ("1" #t)
545 ("0" #f))))
546 (match cmd
547 ("killpower" #$killpower)
548 ("commfailure" #$commfailure)
549 ("commok" #$commok)
550 ("powerout" #$powerout)
551 ("onbattery" #$onbattery)
552 ("offbattery" #$offbattery)
553 ("mainsback" #$mainsback)
554 ("failing" #$failing)
555 ("timeout" #$timeout)
556 ("loadlimit" #$loadlimit)
557 ("runlimit" #$runlimit)
558 ("doreboot" #$doreboot)
559 ("doshutdown" #$doshutdown)
560 ("annoyme" #$annoyme)
561 ("emergency" #$emergency)
562 ("changeme" #$changeme)
563 ("remotedown" #$remotedown)
564 ("startselftest" #$startselftest)
565 ("endselftest" #$endselftest)
566 ("battdetach" #$battdetach)
567 ("battattach" #$battattach)
568 (_
569 (err "Unknown event: ~a~%" cmd)
570 (err "Iff the event was emitted by apcupsd, this is a bug.~%")
571 (err "Please report to [email protected].~%")
572 (exit #f)))))
573 (args
574 (err "Unknown arguments: ~a~%" args)
575 (err "Iff the arguments were passed by apcupsd, this is a bug.~%")
576 (err "Please report to [email protected].~%")
577 (exit #f)))))))
578
579(define (apcupsd-script-dir config)
580 (computed-file
581 "apcupsd-script-dir"
582 #~(begin
583 (mkdir #$output)
584 (chdir #$output)
585 (symlink #$(%apccontrol config) "apccontrol"))))
586
587(define (apcupsd-config-file config)
588 (let ((run-dir (apcupsd-configuration-run-dir config)))
589 (mixed-text-file
590 "apcupsd.conf"
591 "\
592## apcupsd.conf v1.1 ##
593#
594# for apcupsd - GNU Guix
595#
596# \"apcupsd\" POSIX config file (generated by apcupsd-service-type)
597"
598 (serialize-configuration config apcupsd-configuration-fields)
599 ;; This one is confusing. The manual page states:
600 ;;
601 ;; > It must be changed when running more than one copy of apcupsd on the
602 ;; > same computer to control multiple UPSes.
603 ;;
604 ;; However would you not want the lock to be per-device, not per-process?
605 ;; I decided to follow the documentation, but I do not understand why it
606 ;; should be like this. I do not have multiple UPSes to try.
607 (serialize-string 'lock-dir (string-append run-dir "/lock"))
608 (serialize-string 'power-fail-dir run-dir)
609 (serialize-string 'no-login-dir run-dir)
610 (serialize-string 'stat-file (string-append run-dir "/apcupsd.status"))
611 "SCRIPTDIR " (apcupsd-script-dir config) "\n")))
612
613(define (apcupsd-activation config)
614 (match-record config <apcupsd-configuration> (run-dir)
615 #~(begin
616 (use-modules (guix build utils))
617 (mkdir-p #$(string-append run-dir "/lock")))))
618
619(define (apcupsd-shepherd-services config)
620 (match-record config <apcupsd-configuration>
621 ( apcupsd pid-file debug-level run-dir
622 shepherd-service-name auto-start?)
623 (let ((config-file (apcupsd-config-file config)))
624 (list
625 (shepherd-service
626 (documentation "Run the apcupsd daemon.")
627 (requirement '(user-processes))
628 (provision (list shepherd-service-name))
629 (auto-start? auto-start?)
630 (start #~(make-forkexec-constructor
631 '(#$(file-append apcupsd "/sbin/apcupsd")
632 "-b" ;do not daemonize
633 "-f" #$config-file
634 "-P" #$pid-file
635 "-d" #$(number->string debug-level))
636 #:log-file
637 #$(format #f "/var/log/~a.log" shepherd-service-name)
638 #:environment-variables
639 (cons* (string-append "GUIX_APCUPSD_CONF="
640 #$config-file)
641 #$(string-append "GUIX_APCUPSD_POWERFAIL_FILE="
642 run-dir "/powerfail")
643 (default-environment-variables))))
644 (stop #~(make-kill-destructor))
645 (actions (list (shepherd-configuration-action config-file))))))))
646
647(define (apcupsd-pam-extensions config)
648 ;; The apcupsd can be configured to prevent users from logging in on certain
649 ;; conditions. This is implemented by creation of a "nologin" file, and
650 ;; using a pam nologin module to prevent the login (if the file exists).
651 (define pam-nologin
652 (pam-entry
653 (control "required")
654 (module "pam_nologin.so")
655 (arguments (list (string-append "file="
656 (apcupsd-configuration-run-dir config)
657 "/nologin")))))
658
659 (list (pam-extension
660 (transformer
661 (lambda (pam)
662 (pam-service
663 (inherit pam)
664 (auth (cons pam-nologin (pam-service-auth pam)))))))))
665
666(define apcupsd-service-type
667 (service-type
668 (name 'apcupsd)
669 (description "Configure and optionally start the apcupsd.")
670 (extensions (list (service-extension activation-service-type
671 apcupsd-activation)
672 (service-extension shepherd-root-service-type
673 apcupsd-shepherd-services)
674 (service-extension pam-root-service-type
675 apcupsd-pam-extensions)))
676 (default-value (apcupsd-configuration))))