From patchwork Sun Jan 12 23:05:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tomas Volf <~@wolfsden.cz> X-Patchwork-Id: 37004 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 7C86F27BBEA; Sun, 12 Jan 2025 23:06:22 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_ALL,DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_VALIDITY_CERTIFIED,RCVD_IN_VALIDITY_RPBL, RCVD_IN_VALIDITY_SAFE,SPF_HELO_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id BF65427BBE2 for ; Sun, 12 Jan 2025 23:06:21 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tX71y-0002w6-Eu; Sun, 12 Jan 2025 18:06:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tX71u-0002vi-JU for guix-patches@gnu.org; Sun, 12 Jan 2025 18:06:02 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tX71u-0002y2-1N for guix-patches@gnu.org; Sun, 12 Jan 2025 18:06:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:References:In-Reply-To:Date:From:To:Subject; bh=8arUhCTIEfKS5sUBGE78PjcT3F1AruEAs+UyK+GtGZU=; b=TzlfAiYi48SAcvWGmNdmLTOT2k5ZGKySAYKAFQFI/dpuPmtklaP5124t9R1xiK/AUirAkDLF14DcdlVVBKpGgYLT78aCIanXrjBdXEuAgJwkdCOOlME998Jq7ghS7t31qpsJJU/mnriO2GpOelwJY19KqONrdPAaa/HrbksOXWAIDoOiyvpEUnTgf8vp7jtGRu8XZfM24MESOHndfFwHY7oq5jF/rhDU/l4B0lVQkb6IrLCIPEmV3SamlQZ8j0DqDnvIV2byJQz37JIIK98kj5Q+289FdPGyycwWIt4gvFAXAxG811HTc0p8lQZVeEsfcdzuEx2FRRwXmIQ+7h94/A==; Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tX71t-00079I-SJ for guix-patches@gnu.org; Sun, 12 Jan 2025 18:06:01 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#75528] [PATCH 1/2] gnu: Add apcupsd. Resent-From: Tomas Volf <~@wolfsden.cz> Original-Sender: "Debbugs-submit" Resent-CC: guix-patches@gnu.org Resent-Date: Sun, 12 Jan 2025 23:06:01 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 75528 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75528@debbugs.gnu.org Cc: Tomas Volf <~@wolfsden.cz> Received: via spool by 75528-submit@debbugs.gnu.org id=B75528.173672313227428 (code B ref 75528); Sun, 12 Jan 2025 23:06:01 +0000 Received: (at 75528) by debbugs.gnu.org; 12 Jan 2025 23:05:32 +0000 Received: from localhost ([127.0.0.1]:49448 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tX71P-00078J-K4 for submit@debbugs.gnu.org; Sun, 12 Jan 2025 18:05:32 -0500 Received: from wolfsden.cz ([37.205.8.62]:59848) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from <~@wolfsden.cz>) id 1tX71M-000788-7L for 75528@debbugs.gnu.org; Sun, 12 Jan 2025 18:05:29 -0500 Received: by wolfsden.cz (Postfix, from userid 104) id D6036342C1D; Sun, 12 Jan 2025 23:05:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1736723126; bh=p0bKALsrwxfPOLQkolSwo4qZhiRU8Etm+n76/Meke8U=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=RP/2ORxPaEdcQtl5WsjLev/9oB93Wj+tosAyE3GrT7P+DAW0JU8VafZrtTQVf1ek3 yIohgWmHB30Whu/ktIMLV4D8zBevNCgTGOt2FWPiowzmLkDDem7b39srggfm8bCSyX XLeCZs0Yc9Oy+kbALrfTuNXUeVuujz0+f5G9UjUwgLDLOk9UcHf4CYV/kJDQ3t8L1P EfG0AbuewzQXzxTqSVNjW555nFt1hPxnG6lZnAc0A+HJvmXw5VwZFOA9EtNMyQCtT+ fFyYbMv3fc6BBC0wjGD6pJNPOGyaGSxO1TE6wQduGCeo8Ss5HyZK4WW27K+onmC25a +XFcFeRMAZIOu/f23ySxsqzWFNP8lSJdYVGLbE1O4bq0Arn5zm7KHGbQ/dVAVYrfg9 2YebP1qHQ6ie+AWORu2t7oMPbDgdVUtwz9HXGBqZ0HRe9odWV423E3P8yD2KF4MQq4 mmVo4jX1r2V4ywK5kQ3LmGQQPQTSTBGeVrsUq0Mfo51jiSJe7ocbo6uuWHgYeuRKEI scKnPbbvWubV6jk1U8FPdQuic+5fOQrJl6q/dcgR99OCMC9yloNaCeMvjTGs4aUYF7 AKHH5m18LUT8M0TaC22nU6Wj9ODDG+fK2AB16iBFDBA1fno1VBQ0rMN1SmBReCSvC5 Dslcb/ucoesb1Ui3ez3RLxns= Received: from localhost (unknown [128.0.188.242]) by wolfsden.cz (Postfix) with ESMTPSA id F2D12341673; Sun, 12 Jan 2025 23:05:25 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1736723126; bh=p0bKALsrwxfPOLQkolSwo4qZhiRU8Etm+n76/Meke8U=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=RP/2ORxPaEdcQtl5WsjLev/9oB93Wj+tosAyE3GrT7P+DAW0JU8VafZrtTQVf1ek3 yIohgWmHB30Whu/ktIMLV4D8zBevNCgTGOt2FWPiowzmLkDDem7b39srggfm8bCSyX XLeCZs0Yc9Oy+kbALrfTuNXUeVuujz0+f5G9UjUwgLDLOk9UcHf4CYV/kJDQ3t8L1P EfG0AbuewzQXzxTqSVNjW555nFt1hPxnG6lZnAc0A+HJvmXw5VwZFOA9EtNMyQCtT+ fFyYbMv3fc6BBC0wjGD6pJNPOGyaGSxO1TE6wQduGCeo8Ss5HyZK4WW27K+onmC25a +XFcFeRMAZIOu/f23ySxsqzWFNP8lSJdYVGLbE1O4bq0Arn5zm7KHGbQ/dVAVYrfg9 2YebP1qHQ6ie+AWORu2t7oMPbDgdVUtwz9HXGBqZ0HRe9odWV423E3P8yD2KF4MQq4 mmVo4jX1r2V4ywK5kQ3LmGQQPQTSTBGeVrsUq0Mfo51jiSJe7ocbo6uuWHgYeuRKEI scKnPbbvWubV6jk1U8FPdQuic+5fOQrJl6q/dcgR99OCMC9yloNaCeMvjTGs4aUYF7 AKHH5m18LUT8M0TaC22nU6Wj9ODDG+fK2AB16iBFDBA1fno1VBQ0rMN1SmBReCSvC5 Dslcb/ucoesb1Ui3ez3RLxns= From: Tomas Volf <~@wolfsden.cz> Date: Mon, 13 Jan 2025 00:05:13 +0100 Message-ID: <51cba7679af5c4aa9cf0e6d70453e369ff0909d6.1736722765.git.~@wolfsden.cz> X-Mailer: git-send-email 2.47.1 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches * gnu/packages/power.scm (apcupsd): New variable. Change-Id: I74f59cd1fa2a13954117ff1683a10a84576cc839 --- gnu/local.mk | 1 + gnu/packages/power.scm | 125 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100644 gnu/packages/power.scm diff --git a/gnu/local.mk b/gnu/local.mk index 855f2acccc..6ca7bf68ac 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -557,6 +557,7 @@ GNU_SYSTEM_MODULES = \ %D%/packages/polkit.scm \ %D%/packages/popt.scm \ %D%/packages/potassco.scm \ + %D%/packages/power.scm \ %D%/packages/printers.scm \ %D%/packages/profiling.scm \ %D%/packages/prolog.scm \ diff --git a/gnu/packages/power.scm b/gnu/packages/power.scm new file mode 100644 index 0000000000..98dc98c6e4 --- /dev/null +++ b/gnu/packages/power.scm @@ -0,0 +1,125 @@ +;;; Copyright (C) 2025 Tomas Volf <~@wolfsden.cz> +;;; Copyright (C) 2023 Raven Hallsby + +;;;; Commentary: + +;;; Power-related packages. + +;;;; Code: + +(define-module (gnu packages power) + #:use-module (gnu) + #:use-module (gnu packages libusb) + #:use-module (gnu packages linux) + #:use-module (gnu packages pkg-config) + #:use-module (gnu packages python-xyz) + #:use-module (guix build-system gnu) + #:use-module (guix download) + #:use-module (guix gexp) + #:use-module ((guix licenses) #:prefix license:) + #:use-module (guix packages)) + +(define-public apcupsd + (package + (name "apcupsd") + (version "3.14.14") + (source (origin + (method url-fetch) + (uri + (string-append + "mirror://sourceforge/" name "/" name " - Stable/" version + "/" name "-" version ".tar.gz")) + (sha256 + (base32 + "0rwqiyzlg9p0szf3x6q1ppvrw6f6dbpn2rc5z623fk3bkdalhxyv")))) + (native-inputs + (list pkg-config python-docutils)) + (inputs + (list libusb libusb-compat)) + (outputs '("out" "doc")) + (build-system gnu-build-system) + (arguments + (list + #:configure-flags + #~(list + ;; The configure script ignores --prefix for most of the paths. + (string-append "--exec-prefix=" #$output) + (string-append "--mandir=" #$output "/share/man") + (string-append "--sbindir=" #$output "/sbin") + (string-append "--sysconfdir=" #$output "/etc/apcupsd") + (string-append "--with-halpolicydir=" #$output "/share/halpolicy") + + ;; Put us into the version string. + "--with-distname=GNU/Guix" + "--disable-install-distdir" + + ;; State directories. + "--localstatedir=/var" + "--with-log-dir=/var/log" + "--with-pid-dir=/var/run" + "--with-lock-dir=/var/run/apcupsd/lock" + "--with-nologin=/var/run/apcupsd" + "--with-pwrfail-dir=/var/run/apcupsd" + + ;; Configure requires these, but we do not use the genenerated + ;; apcupsd.conf, so in order to reduce dependencies of the package, + ;; provide fake values. + (string-append "ac_cv_path_SHUTDOWN=/nope") + (string-append "ac_cv_path_APCUPSD_MAIL=/nope") + ;; While `wall' is not expanded anywhere, it still is searched for. + (string-append "ac_cv_path_WALL=/nope") + + ;; Enable additional drivers. + "--enable-test" + "--enable-usb" + "--enable-modbus-usb") + #:tests? #f ; There are no tests. + #:modules (cons '(ice-9 ftw) %default-gnu-modules) + #:phases + #~(modify-phases %standard-phases + ;; These are not installed, so trick Make into thinking they were + ;; already generated. Allows us not to depend on mandoc, util-linux. + (add-before 'configure 'touch-txt-docs + (lambda _ + (for-each (lambda (f) + (call-with-output-file f close-port)) + '("doc/apcupsd.man.txt" + "doc/apcaccess.man.txt" + "doc/apctest.man.txt" + "doc/apccontrol.man.txt" + "doc/apcupsd.conf.man.txt")))) + (add-after 'build 'build-manual + (lambda _ + (invoke "make" "-C" "doc/manual" "manual.html"))) + (add-after 'install-license-files 'move-doc + (lambda _ + (let ((target (string-append #$output:doc + "/share/doc/" + (strip-store-file-name #$output)))) + (mkdir-p target) + (for-each (lambda (f) + (copy-file (string-append "doc/manual/" f) + (string-append target "/" f))) + (scandir "doc/manual" + (lambda (f) + (or (string-suffix? ".png" f) + (string-suffix? ".html" f)))))))) + ;; If sending mails is required, use proper mail program. + (add-after 'install 'remove-smtp + (lambda _ + (delete-file (string-append #$output "/sbin/smtp")))) + ;; The configuration files and scripts are not really suitable for + ;; Guix, and our service provides its own version anyway. So nuke + ;; these to make sure `apcupsd' and `apctest' executed without any + ;; arguments fail. `apctest' actually segfaults, but only after + ;; printing an error ¯\_(ツ)_/¯. + (add-after 'install 'remove-etc-apcupsd + (lambda _ + (delete-file-recursively (string-append #$output "/etc/apcupsd"))))))) + (home-page "https://www.apcupsd.org") + (synopsis "A daemon for controlling APC UPSes") + (description "Apcupsd can be used for power mangement and controlling most +of APC’s UPS models on Unix and Windows machines. Apcupsd works with most of +APC’s Smart-UPS models as well as most simple signalling models such a Back-UPS, +and BackUPS-Office.") + (license license:gpl2))) From patchwork Sun Jan 12 23:05:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Tomas Volf <~@wolfsden.cz> X-Patchwork-Id: 37005 Return-Path: X-Original-To: patchwork@mira.cbaines.net Delivered-To: patchwork@mira.cbaines.net Received: by mira.cbaines.net (Postfix, from userid 113) id 168D227BBEA; Sun, 12 Jan 2025 23:06:34 +0000 (GMT) X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mira.cbaines.net X-Spam-Level: X-Spam-Status: No, score=-6.8 required=5.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_ADSP_ALL,DKIM_SIGNED,DKIM_VALID,MAILING_LIST_MULTI, RCVD_IN_DNSWL_BLOCKED,RCVD_IN_VALIDITY_CERTIFIED,RCVD_IN_VALIDITY_RPBL, RCVD_IN_VALIDITY_SAFE,SPF_HELO_PASS,URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) by mira.cbaines.net (Postfix) with ESMTPS id D1D5527BBE2 for ; Sun, 12 Jan 2025 23:06:31 +0000 (GMT) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1tX71y-0002w7-NJ; Sun, 12 Jan 2025 18:06:06 -0500 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1tX71u-0002vp-Vm for guix-patches@gnu.org; Sun, 12 Jan 2025 18:06:05 -0500 Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1tX71u-0002y6-H9; Sun, 12 Jan 2025 18:06:02 -0500 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=MIME-Version:References:In-Reply-To:Date:From:To:Subject; bh=x/W3RTo88wogo+u3bKlhObh68aLm1GQosnLA8tU6PNw=; b=bVJekCo3b6CCbevEwg4UxeCoxd6bVxluCDf1wpy21OV4by5eZnEuCh9jOmAz8BkS6ajU6WTU1FdgM1VbsStHlollOh+sG9/tGURspeDbo/fLWrlIzQek+Ro5iUiphYdR4SWEAPov4Y/2MGQzZsGeuw3HJjGMS2gAD431+OTodYyeeNbNX1Bib6DT/YyA5yi0NnlLsmEHhA5mlxHVkiruBUIpE47U5z4nBvPt5aTCJZVSV1gZy5wKh5UwDLyHsWFIh5ZeOfTPh10bbsAG6IVbDp61PQ6A/0NNT+Dl1xXtOESisqPVA6c3KWmlz0Lg7gTwtG6u3y9eBFCuiFzFaJpaqQ==; Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1tX71u-00079P-CB; Sun, 12 Jan 2025 18:06:02 -0500 X-Loop: help-debbugs@gnu.org Subject: [bug#75528] [PATCH 2/2] services: Add power. Resent-From: Tomas Volf <~@wolfsden.cz> Original-Sender: "Debbugs-submit" Resent-CC: ludo@gnu.org, maxim.cournoyer@gmail.com, guix-patches@gnu.org Resent-Date: Sun, 12 Jan 2025 23:06:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 75528 X-GNU-PR-Package: guix-patches X-GNU-PR-Keywords: patch To: 75528@debbugs.gnu.org Cc: Tomas Volf <~@wolfsden.cz>, Ludovic =?utf-8?q?Court=C3=A8s?= , Maxim Cournoyer X-Debbugs-Original-Xcc: Ludovic =?utf-8?q?Court=C3=A8s?= , Maxim Cournoyer Received: via spool by 75528-submit@debbugs.gnu.org id=B75528.173672313827448 (code B ref 75528); Sun, 12 Jan 2025 23:06:02 +0000 Received: (at 75528) by debbugs.gnu.org; 12 Jan 2025 23:05:38 +0000 Received: from localhost ([127.0.0.1]:49450 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1tX71U-00078c-I1 for submit@debbugs.gnu.org; Sun, 12 Jan 2025 18:05:38 -0500 Received: from wolfsden.cz ([37.205.8.62]:59852) by debbugs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.84_2) (envelope-from <~@wolfsden.cz>) id 1tX71O-00078H-Rw for 75528@debbugs.gnu.org; Sun, 12 Jan 2025 18:05:33 -0500 Received: by wolfsden.cz (Postfix, from userid 104) id E84613414EE; Sun, 12 Jan 2025 23:05:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1736723129; bh=IQ6imuI/xWTpcFS3o6s/qnP05FzScxSeK9RdNZROh6Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=pDlUZUvuZegoTTAZ6YjcpkxqSZqLHyk/sHRq8HcVAb/acjQpRO7lyRWDMwI5y3fl9 QddCyzx3ohlrGF903NNDrhhMjpFTavsLzCZVrfI+tMlSNfL1cvZEmn3gE9BNM8SJU6 wAunANTteV/DNk65Af8gq8pr/HNI8k9FfYDPzxkocYulHiGiP+DgVvXse5ilZTexw7 f+DZ/b3WzPyABk4o4MA2do6bp2ljm/dtABkGQT43jm82f3Rk47yu+ZREflbP4A7XCo eJpSJUnfRzJ8Fj2sOXFkQbEuMVLhNLRNFs2XRaxpxAifjzFAhmHKvsRunlYGyNAP9x gQ5DLqzNokePWy9Ls7y/Y9/1SvO9hVRgu7jiKgYyWuL1dLV1Qjt7UXx6KpQUr37p39 PCYcA/SD52pTZoaW2W2WY+kwymOgUo0fKOg59iUyaNu+yXrjxtWI3cTrdg9U1VsTh3 MCmZz0ns7MUgGdwgwygzEqK+h5sNKV0cij2Ufel4NbDsPaqcpLGi+icszEEPDAC0pS xdIdWqahkJF0T/hwE0lC4cxO6g4v+7MS/brPaz5/2mGlNBesZt5U5kCxQY7qax29cX bWC3b9E9Sjwxuu7Cn8dkuNYlv2DNm4Z6Kg3sSWvCgzUYzDDGkFHkvvxZF7hjFtp60P 62a3ntdrD04aabBgG9t2XH2k= Received: from localhost (unknown [128.0.188.242]) by wolfsden.cz (Postfix) with ESMTPSA id 7FD0C34242F; Sun, 12 Jan 2025 23:05:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=wolfsden.cz; s=mail; t=1736723126; bh=IQ6imuI/xWTpcFS3o6s/qnP05FzScxSeK9RdNZROh6Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=klbBR33rxP30rS96Q4MDlPmpUYu4ZtuO9NdLzyOX7obfmR32F0uZUup/Jp161KjzT 2lEpBrKdTdgpw8YdVSnvUtVpKlFjjzQa3MbNDpWCLiAUVYL/fasKxOSKJWxGMl0tCi a9/V66YL4Hh+2Y4UCvH8xSBCZ+YKmORrZDOSrVLrOUZcuKU0JiQY4oTOhbRyYrNYt1 YIF0AxKtQZN9ezGzi6TpIflAbJluUnSxg/uLB1A8yrSbPXb7svqXGEtJ82udEwL8Xx v19li8YLWoizPaSvKIFUFQtS89RQ3HQ2G8tFJM2cXoR9GvKHOcAhaQnIDE4PYSl2dC Oik2TOdu+i6plLXTzthgFe7gghkSlUhNEuiSoZe5Gco6lzGXgyQXxr5Cay+MN0OLg6 iHS9IBkcbb6Epnc45cXHEdid+Ivf8HfgUxzg/A3GtuYb/3d33zJNyVf0/Uk+8bBjWF juDosGjRNKDxCbH/kLAt/myDFHhXztLuiTzcZDIlMK660+j/MU1crjCnBJH7sxk5O9 dAY6/zkTRErorxoJ8rPx9g7Zi0O1Qbubo79FEBgIZq3xi95iyX0sUlrVj3ISnHeDWv RYB8LjtcVUxPwGebTT0zlP7e6+4qeiS79WBKNM4LiyrbcyH7EnoV0pJszUF3tskjff Cb7Q8548JouLQdfD4yamMics= From: Tomas Volf <~@wolfsden.cz> Date: Mon, 13 Jan 2025 00:05:14 +0100 Message-ID: <05ba17f2babc772a26072dca72c2e6e6f852e0ad.1736722765.git.~@wolfsden.cz> X-Mailer: git-send-email 2.47.1 In-Reply-To: References: MIME-Version: 1.0 X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: guix-patches@gnu.org List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org Sender: guix-patches-bounces+patchwork=mira.cbaines.net@gnu.org X-getmail-retrieved-from-mailbox: Patches * gnu/services/power.scm: New file. * gnu/local.mk (GNU_SYSTEM_MODULES): Add it. * doc/guix.texi (Power Management Services): Document service and data types. Change-Id: If205d19bea1d20a99309626e28521a2d6fe6702f --- doc/guix.texi | 374 +++++++++++++++++++++- gnu/local.mk | 1 + gnu/services/power.scm | 690 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1062 insertions(+), 3 deletions(-) create mode 100644 gnu/services/power.scm diff --git a/doc/guix.texi b/doc/guix.texi index d6e17c74cd..6cb11200cd 100644 --- a/doc/guix.texi +++ b/doc/guix.texi @@ -123,7 +123,7 @@ Copyright @copyright{} 2023 Thomas Ieong@* Copyright @copyright{} 2023 Saku Laesvuori@* Copyright @copyright{} 2023 Graham James Addis@* -Copyright @copyright{} 2023, 2024 Tomas Volf@* +Copyright @copyright{} 2023-2025 Tomas Volf@* Copyright @copyright{} 2024 Herman Rimm@* Copyright @copyright{} 2024 Matthew Trzcinski@* Copyright @copyright{} 2024 Richard Sent@* @@ -420,7 +420,7 @@ Top * Network File System:: NFS related services. * Samba Services:: Samba services. * Continuous Integration:: Cuirass and Laminar services. -* Power Management Services:: Extending battery life. +* Power Management Services:: Extending battery life, etc. * Audio Services:: The MPD. * Virtualization Services:: Virtualization services. * Version Control Services:: Providing remote access to Git repositories. @@ -19255,7 +19255,7 @@ Services * Network File System:: NFS related services. * Samba Services:: Samba services. * Continuous Integration:: Cuirass and Laminar services. -* Power Management Services:: Extending battery life. +* Power Management Services:: Extending battery life, etc. * Audio Services:: The MPD. * Virtualization Services:: Virtualization services. * Version Control Services:: Providing remote access to Git repositories. @@ -36263,6 +36263,374 @@ Power Management Services @end table @end deftp +The @code{(gnu services power)} module provides a service definition for +@uref{http://www.apcupsd.org/, apcupsd}, a utility to interact with APC +UPSes. Apcupsd also works with some OEM-branded products manufactured +by APC. + +@defvar apcupsd-service-type +The service type for apcupsd. For USB UPSes no configuration is +necessary, however tweaking some fields to better suit your needs might +be desirable. The defaults are taken from the upstream configuration +and they are not very conservative (@code{battery-level} of 5% is too +low in my opinion). + +The default event handlers do send emails, read more in +@ref{apcupsd-event-handlers}. + +@lisp +(service apcupsd-service-type) +@end lisp +@end defvar + +@deftp {Data Type} apcupsd-configuration + +Available @code{apcupsd-configuration} fields are: + +@table @asis +@item @code{package} (default: @code{apcupsd}) (type: package) +Package to use. + +@item @code{shepherd-base-name} (default: @code{apcupsd}) (type: symbol) +Base name of the shepherd service. You can add the service multiple +times with different prefix to manage multiple UPSes. + +@item @code{auto-start?} (default: @code{#t}) (type: boolean) +Should the shepherd service auto-start? + +@item @code{pid-file} (default: @code{"/var/run/apcupsd.pid"}) (type: string) +Path to the pid file. + +@item @code{debug-level} (default: @code{0}) (type: integer) +Logging verbosity. Bigger number means more logs. In the source code I +saw up to @code{300}, so for all logs, @code{999} seems reasonable. + +@item @code{run-dir} (default: @code{"/var/run/apcupsd"}) (type: string) +Directory containing runtime information. You need to change this if +you desire to run multiple instances of the daemon. + +@item @code{name} (type: maybe-string) +Use this to give your UPS a name in log files and such. This is +particularly useful if you have multiple UPSes. This does not set the +EEPROM. It should be 8 characters or less. + +@item @code{cable} (default: @code{usb}) (type: enum-cable) +The type of cable connecting the UPS to your computer. Possible generic +choices are @code{'simple}, @code{'smart}, @code{'ether} and +@code{'usb}. Or a specific cable model number may be used: +@code{'940-0119A}, @code{'940-0127A}, @code{'940-0128A}, +@code{'940-0020B}, @code{'940-0020C}, @code{'940-0023A}, +@code{'940-0024B}, @code{'940-0024C}, @code{'940-1524C}, +@code{'940-0024G}, @code{'940-0095A}, @code{'940-0095B}, +@code{'940-0095C}, @code{'940-0625A}, @code{'M-04-02-2000}. + +@item @code{type} (default: @code{usb}) (type: enum-type) +Type of the UPS you have. + +@table @code +@item apcsmart +Newer serial character device, appropriate for SmartUPS models using a +serial cable (not USB). + +@item usb +Most new UPSes are USB. + +@item net +Network link to a master apcupsd through apcupsd's Network Information +Server. This is used if the UPS powering your computer is connected to +a different computer for monitoring. + +@item snmp +SNMP network link to an SNMP-enabled UPS device. + +@item netsnmp +Same as SNMP above but requires use of the net-snmp library. Unless you +have a specific need for this old driver, you should use @code{'snmp} +instead. + +@item dumb +Old serial character device for use with simple-signaling UPSes. + +@item pcnet +PowerChute Network Shutdown protocol which can be used as an alternative +to SNMP with the AP9617 family of smart slot cards. + +@item modbus +Serial device for use with newest SmartUPS models supporting the MODBUS +protocol. + +@end table + +@item @code{device} (default: @code{""}) (type: string) +For USB UPSes, usually you want to set this to an empty string (the +default). For other UPS types, you must specify an appropriate port or +address. + +@table @code +@item apcsmart +Set to the appropriate @file{/dev/tty**} device. + +@item usb +A null string setting enables autodetection, which is the best choice +for most installations. + +@item net +Set to @code{@var{hostname}:@var{port}}. + +@item snmp +Set to @code{@var{hostname}:@var{port}:@var{vendor}:@var{community}}. +@var{hostname} is the ip address or hostname of the UPS on the network. +@var{vendor} can be can be "APC" or "APC_NOTRAP". "APC_NOTRAP" will +disable SNMP trap catching; you usually want "APC". @var{port} is +usually 161. @var{community} is usually "private". + +@item netsnmp +Same as @code{'snmp}. + +@item dumb +Set to the appropriate @file{/dev/tty**} device. + +@item pcnet +Set to @code{@var{ipaddr}:@var{username}:@var{passphrase}:@var{port}}. +@var{ipaddr} is the IP address of the UPS management card. +@var{username} and @var{passphrase} are the credentials for which the +card has been configured. @var{port} is the port number on which to +listen for messages from the UPS, normally 3052. If this parameter is +empty or missing, the default of 3052 will be used. + +@item modbus +Set to the appropriate @file{/dev/tty**} device. You can also leave it +empty for MODBUS over USB or set to the serial number of the UPS. + +@end table + +@item @code{poll-time} (default: @code{60}) (type: integer) +Interval (in seconds) at which apcupsd polls the UPS for status. This +setting applies both to directly-attached UPSes (apcsmart, usb, dumb) +and networked UPSes (net, snmp). Lowering this setting will improve +apcupsd's responsiveness to certain events at the cost of higher CPU +utilization. + +@item @code{on-batery-delay} (default: @code{6}) (type: integer) +The the time in seconds from when a power failure is detected until we +react to it with an onbattery event. The @code{'powerout} event will be +triggered immediately when a power failure is detected. However, the +@code{'onbattery} event will be trigger only after this delay. + +@item @code{battery-level} (default: @code{5}) (type: integer) +If during a power failure, the remaining battery percentage (as reported +by the UPS) is below or equal to this value, apcupsd will initiate a +system shutdown. + +@quotation Note +@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work +in conjunction, so the first that occurs will cause the initation of a +shutdown. +@end quotation + +@item @code{remaining-minutes} (default: @code{3}) (type: integer) +If during a power failure, the remaining runtime in minutes (as +calculated internally by the UPS) is below or equal to this value, +apcupsd will initiate a system shutdown. + +@quotation Note +@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work +in conjunction, so the first that occurs will cause the initation of a +shutdown. +@end quotation + +@item @code{timeout} (default: @code{0}) (type: integer) +If during a power failure, the UPS has run on batteries for this many +seconds or longer, apcupsd will initiate a system shutdown. A value of +0 disables this timer. + +@quotation Note +@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work +in conjunction, so the first that occurs will cause the initation of a +shutdown. +@end quotation + +@item @code{annoy-interval} (default: @code{300}) (type: integer) +Time in seconds between annoying users (via the @code{'annoyme} event) +to sign off prior to system shutdown. 0 disables. + +@item @code{annoy-delay} (default: @code{60}) (type: integer) +Initial delay in seconds after power failure before warning users to get +off the system. + +@item @code{no-logon} (default: @code{disable}) (type: enum-no-logon) +The condition which determines when users are prevented from logging in +during a power failure. + +@item @code{kill-delay} (default: @code{0}) (type: integer) +If this is non-zero, apcupsd will continue running after a shutdown has +been requested, and after the specified time in seconds attempt to kill +the power. This is for use on systems where apcupsd cannot regain +control after a shutdown. + +@item @code{net-server} (default: @code{#f}) (type: boolean) +If enabled, a network information server process will be started. + +@item @code{net-server-ip} (default: @code{"127.0.0.1"}) (type: string) +IP address on which NIS server will listen for incoming connections. + +@item @code{net-server-port} (default: @code{3551}) (type: integer) +IP port on which NIS server will listen for incoming connections. + +@item @code{net-server-events-file} (type: maybe-string) +If you want the last few EVENTS to be available over the network by the +network information server, you must set this to a file patch. + +@item @code{net-server-events-file-max-size} (default: @code{10}) (type: integer) +Maximum size of the events file in kilobytes. + +@item @code{class} (default: @code{standalone}) (type: enum-class) +Normally standalone unless you share an UPS using an APC ShareUPS card. + +@item @code{mode} (default: @code{disable}) (type: enum-mode) +Normally disable unless you share an UPS using an APC ShareUPS card. + +@item @code{stat-time} (default: @code{0}) (type: integer) +Time interval in seconds between writing the status file, 0 disables. + +@item @code{log-stats} (default: @code{#f}) (type: boolean) +Also write the stats as a logs. This generates a lot of output. + +@item @code{data-time} (default: @code{0}) (type: integer) +Time interval in seconds between writing the data records to the log +file, 0 disables. + +@item @code{facility} (type: maybe-string) +The logging facility for the syslog. + +@item @code{event-handlers} (type: apcupsd-event-handlers) +Handlers for events produced by apcupsd. + +@end table + +@end deftp + +@anchor{apcupsd-event-handlers} +@deftp {Data Type} apcupsd-event-handlers + +For description of the events please refer to the @command{apcupsd}'s +manual, which can be found in the @samp{apcupsd-doc} package. + +Each handler shall be a gexp. It is spliced into the control script for +the daemon. In addition to the standard Guile programming environment, +these procedures and variables are also available. + +@table @code +@item conf +Variable containing path to the configuration file. + +@item powerfail-file +Variable containing path to the powerfail file. + +@item cmd +The event currently being handled. + +@item name +The name of the UPS as specified in the configuration file. + +@item connected +Is @code{"1"} if apcupsd is connected to the UPS via a serial port (or a +USB port). In most configurations, this will be the case. In the case +of a Slave machine where apcupsd is not directly connected to the UPS, +this value will be @code{"0"}. + +@item powered +Is @code{"1"} if the computer on which @command{apcupsd} is running is +powered by the UPS and @code{"0"} if not. At the moment, this value is +unimplemented and always @code{"0"}. + +@item (err @var{fmt} @var{args...}) +Wrapper around @code{format} outputting to @code{(current-error-port)}. + +@item (wall @var{fmt} @var{args...}) +Wrapper around @code{format} outputting via @command{wall}. + +@item (apcupsd @var{args...}) +Call @command{apcupsd} while passing the correct configuration file and +all the arguments. + +@item (mail-to-root @var{subject} @var{body}) +Send an email to the local administrator. This procedure assumes the +@command{sendmail} is located at @command{/run/privileged/bin/sendmail} +(as would be the case with @code{opensmtpd-service-type}). + +@end table + +Available @code{apcupsd-event-handlers} fields are: + +@table @asis +@item @code{killpower} (type: gexp) +Handler for killpower event. + +@item @code{commfailure} (type: gexp) +Handler for commfailure event. + +@item @code{commok} (type: gexp) +Handler for commfailure event. + +@item @code{powerout} (type: gexp) +Handler for powerout event. + +@item @code{onbattery} (type: gexp) +Handler for onbattery event. + +@item @code{offbattery} (type: gexp) +Handler for offbattery event. + +@item @code{mainsback} (type: gexp) +Handler for mainsback event. + +@item @code{failing} (type: gexp) +Handler for failing event. + +@item @code{timeout} (type: gexp) +Handler for timeout event. + +@item @code{loadlimit} (type: gexp) +Handler for loadlimit event. + +@item @code{runlimit} (type: gexp) +Handler for runlimit event. + +@item @code{doreboot} (type: gexp) +Handler for doreboot event. + +@item @code{doshutdown} (type: gexp) +Handler for doshutdown event. + +@item @code{annoyme} (type: gexp) +Handler for annoyme event. + +@item @code{emergency} (type: gexp) +Handler for emergency event. + +@item @code{changeme} (type: gexp) +Handler for changeme event. + +@item @code{remotedown} (type: gexp) +Handler for remotedown event. + +@item @code{startselftest} (type: gexp) +Handler for startselftest event. + +@item @code{endselftest} (type: gexp) +Handler for endselftest event. + +@item @code{battdetach} (type: gexp) +Handler for battdetach event. + +@item @code{battattach} (type: gexp) +Handler for battattach event. + +@end table + +@end deftp + @node Audio Services @subsection Audio Services diff --git a/gnu/local.mk b/gnu/local.mk index 6ca7bf68ac..dea0e43fe6 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -758,6 +758,7 @@ GNU_SYSTEM_MODULES = \ %D%/services/nix.scm \ %D%/services/nfs.scm \ %D%/services/pam-mount.scm \ + %D%/services/power.scm \ %D%/services/science.scm \ %D%/services/security.scm \ %D%/services/security-token.scm \ diff --git a/gnu/services/power.scm b/gnu/services/power.scm new file mode 100644 index 0000000000..a6f9259eb3 --- /dev/null +++ b/gnu/services/power.scm @@ -0,0 +1,690 @@ +;;; Copyright (C) 2025 Tomas Volf <~@wolfsden.cz> + +;;;; Commentary: + +;;; Power-related services. + +;;;; Code: + +(define-module (gnu services power) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:use-module (ice-9 match) + #:use-module (gnu) + #:use-module (gnu packages admin) + #:use-module (gnu packages linux) + #:use-module (gnu packages power) + #:use-module (gnu services) + #:use-module (gnu services configuration) + #:use-module (gnu services shepherd) + #:use-module (guix packages) + #:use-module (guix records) + #:export (apcupsd-service-type + + apcupsd-configuration + apcupsd-configuration-package + apcupsd-configuration-shepherd-base-name + apcupsd-configuration-auto-start? + apcupsd-configuration-pid-file + apcupsd-configuration-debug-level + apcupsd-configuration-run-dir + apcupsd-configuration-name + apcupsd-configuration-cable + apcupsd-configuration-type + apcupsd-configuration-device + apcupsd-configuration-poll-time + apcupsd-configuration-on-batery-delay + apcupsd-configuration-battery-level + apcupsd-configuration-remaining-minutes + apcupsd-configuration-timeout + apcupsd-configuration-annoy-interval + apcupsd-configuration-annoy-delay + apcupsd-configuration-no-logon + apcupsd-configuration-kill-delay + apcupsd-configuration-net-server + apcupsd-configuration-net-server-ip + apcupsd-configuration-net-server-port + apcupsd-configuration-net-server-events-file + apcupsd-configuration-net-server-events-file-max-size + apcupsd-configuration-class + apcupsd-configuration-mode + apcupsd-configuration-stat-time + apcupsd-configuration-log-stats + apcupsd-configuration-data-time + apcupsd-configuration-facility + apcupsd-configuration-event-handlers + + apcupsd-event-handlers-annoyme + apcupsd-event-handlers-battattach + apcupsd-event-handlers-battdetach + apcupsd-event-handlers-changeme + apcupsd-event-handlers-commfailure + apcupsd-event-handlers-commok + apcupsd-event-handlers-doreboot + apcupsd-event-handlers-doshutdown + apcupsd-event-handlers-emergency + apcupsd-event-handlers-endselftest + apcupsd-event-handlers-failing + apcupsd-event-handlers-killpower + apcupsd-event-handlers-loadlimit + apcupsd-event-handlers-mainsback + apcupsd-event-handlers-offbattery + apcupsd-event-handlers-onbattery + apcupsd-event-handlers-powerout + apcupsd-event-handlers-remotedown + apcupsd-event-handlers-runlimit + apcupsd-event-handlers-startselftest + apcupsd-event-handlers-timeout)) + +(define-configuration/no-serialization apcupsd-event-handlers + (killpower + (gexp + #~((wall "Apccontrol doing: apcupsd --killpower on UPS ~a" name) + (sleep 10) + (apcupsd "--killpower") + (wall "Apccontrol has done: apcupsd --killpower on UPS ~a" name))) + "Handler for killpower event.") + (commfailure + (gexp + #~((let ((msg (format #f "~a Communications with UPS ~a lost." + (gethostname) name))) + (mail-to-root msg msg)) + (wall "Warning: communications lost with UPS ~a" name))) + "Handler for commfailure event.") + (commok + (gexp + #~((let ((msg (format #f "~a Communications with UPS ~a restored." + (gethostname) name))) + (mail-to-root msg msg)) + (wall "Communications restored with UPS ~a" name))) + "Handler for commfailure event.") + (powerout + (gexp + #~(#t)) + "Handler for powerout event.") + (onbattery + (gexp + #~((let ((msg (format #f "~a UPS ~a Power Failure !!!" + (gethostname) name))) + (mail-to-root msg msg)) + (wall "Power failure on UPS ~a. Running on batteries." name))) + "Handler for onbattery event.") + (offbattery + (gexp + #~((let ((msg (format #f "~a UPS ~a Power has returned." + (gethostname) name))) + (mail-to-root msg msg)) + (wall "Power has returned on UPS ~a..." name))) + "Handler for offbattery event.") + (mainsback + (gexp + #~((when (file-exists? powerfail-file) + (wall "Continuing with shutdown.")))) + "Handler for mainsback event.") + (failing + (gexp + #~((wall "Battery power exhausted on UPS ~a. Doing shutdown." name))) + "Handler for failing event.") + (timeout + (gexp + #~((wall "Battery time limit exceeded on UPS ~a. Doing shutdown." name))) + "Handler for timeout event.") + (loadlimit + (gexp + #~((wall "Remaining battery charge below limit on UPS ~a. Doing shutdown." name))) + "Handler for loadlimit event.") + (runlimit + (gexp + #~((wall "Remaining battery runtime below limit on UPS ~a. Doing shutdown." name))) + "Handler for runlimit event.") + (doreboot + (gexp + #~((wall "UPS ~a initiating Reboot Sequence" name) + (system* #$(file-append shepherd "/sbin/reboot")))) + "Handler for doreboot event.") + (doshutdown + (gexp + #~((wall "UPS ~a initiated Shutdown Sequence" name) + (system* #$(file-append shepherd "/sbin/halt")))) + "Handler for doshutdown event.") + (annoyme + (gexp + #~((wall "Power problems with UPS ~a. Please logoff." name))) + "Handler for annoyme event.") + (emergency + (gexp + #~((wall "Emergency Shutdown. Possible battery failure on UPS ~a." name))) + "Handler for emergency event.") + (changeme + (gexp + #~((let ((msg (format #f "~a UPS ~a battery needs changing NOW." + (gethostname) name))) + (mail-to-root msg msg)) + (wall "Emergency! Batteries have failed on UPS ~a. Change them NOW." name))) + "Handler for changeme event.") + (remotedown + (gexp + #~((wall "Remote Shutdown. Beginning Shutdown Sequence."))) + "Handler for remotedown event.") + (startselftest + (gexp + #~(#t)) + "Handler for startselftest event.") + (endselftest + (gexp + #~(#t)) + "Handler for endselftest event.") + (battdetach + (gexp + #~(#t)) + "Handler for battdetach event.") + (battattach + (gexp + #~(#t)) + "Handler for battattach event.")) + +(define-syntax define-enum + (lambda (x) + (syntax-case x () + ((_ name values) + (let* ((d/n (syntax->datum #'name)) + (d/predicate (string->symbol + (format #f "enum-~a?" d/n))) + (d/serialize (string->symbol + (format #f "serialize-enum-~a" d/n)))) + (with-syntax + ((predicate (datum->syntax x d/predicate)) + (serialize (datum->syntax x d/serialize))) + #'(begin + (define (predicate value) + (memq value values)) + (define serialize serialize-symbol)))))))) + +(define mangle-field-name + (match-lambda + ('name "UPSNAME") + ('cable "UPSCABLE") + ('type "UPSTYPE") + ('device "DEVICE") + ('poll-time "POLLTIME") + ('lock-dir "LOCKFILE") + ('power-fail-dir "PWRFAILDIR") + ('no-login-dir "NOLOGINDIR") + ('on-batery-delay "ONBATTERYDELAY") + ('battery-level "BATTERYLEVEL") + ('remaining-minutes "MINUTES") + ('timeout "TIMEOUT") + ('annoy-interval "ANNOY") + ('annoy-delay "ANNOYDELAY") + ('no-logon "NOLOGON") + ('kill-delay "KILLDELAY") + ('net-server "NETSERVER") + ('net-server-ip "NISIP") + ('net-server-port "NISPORT") + ('net-server-events-file "EVENTSFILE") + ('net-server-events-file-max-size "EVENTSFILEMAX") + ('class "UPSCLASS") + ('mode "UPSMODE") + ('stat-time "STATTIME") + ('stat-file "STATFILE") + ('log-stats "LOGSTATS") + ('data-time "DATATIME") + ('facility "FACILITY"))) + +(define (serialize-string field-name value) + #~(format #f "~a ~a\n" #$(mangle-field-name field-name) '#$value)) +(define serialize-symbol serialize-string) +(define serialize-integer serialize-string) +(define (serialize-boolean field-name value) + #~(format #f "~a ~a\n" #$(mangle-field-name field-name) #$(if value "on" "off"))) + +(define-maybe string) + +(define-enum cable '( simple smart ether usb + 940-0119A 940-0127A 940-0128A 940-0020B 940-0020C + 940-0023A 940-0024B 940-0024C 940-1524C 940-0024G + 940-0095A 940-0095B 940-0095C 940-0625A MAM-04-02-2000)) +(define-enum type '(apcsmart usb net snmp netsnmp dumb pcnet modbus test)) +(define-enum no-logon '(disable timeout percent minutes always)) +(define-enum class '(standalone shareslave sharemaster)) +(define-enum mode '(disable share)) + +(define-configuration apcupsd-configuration + (package (package apcupsd) "Package to use.") + + (shepherd-base-name + (symbol 'apcupsd) + "Base name of the shepherd service. You can add the service multiple times +with different prefix to manage multiple UPSes." + empty-serializer) + (auto-start? + (boolean #t) + "Should the shepherd service auto-start?" + empty-serializer) + (pid-file + (string "/var/run/apcupsd.pid") + "Path to the pid file." + empty-serializer) + (debug-level + (integer 0) + "Logging verbosity. Bigger number means more logs. In the source code I saw +up to @code{300}, so for all logs, @code{999} seems reasonable." + empty-serializer) + + (run-dir + (string "/var/run/apcupsd") + "Directory containing runtime information. You need to change this if you +desire to run multiple instances of the daemon." + empty-serializer) + + ;; General configuration parameters + (name + maybe-string + "Use this to give your UPS a name in log files and such. This is +particularly useful if you have multiple UPSes. This does not set the EEPROM. +It should be 8 characters or less.") + (cable + (enum-cable 'usb) + "The type of cable connecting the UPS to your computer. Possible generic +choices are @code{'simple}, @code{'smart}, @code{'ether} and +@code{'usb}. + +Or a specific cable model number may be used: @code{'940-0119A}, +@code{'940-0127A}, @code{'940-0128A}, @code{'940-0020B}, @code{'940-0020C}, +@code{'940-0023A}, @code{'940-0024B}, @code{'940-0024C}, @code{'940-1524C}, +@code{'940-0024G}, @code{'940-0095A}, @code{'940-0095B}, @code{'940-0095C}, +@code{'940-0625A}, @code{'M-04-02-2000}.") + (type + (enum-type 'usb) + "Type of the UPS you have. + +@table @code +@item apcsmart +Newer serial character device, appropriate for SmartUPS models using a serial +cable (not USB). + +@item usb +Most new UPSes are USB. + +@item net +Network link to a master apcupsd through apcupsd's Network Information Server. +This is used if the UPS powering your computer is connected to a different +computer for monitoring. + +@item snmp +SNMP network link to an SNMP-enabled UPS device. + +@item netsnmp +Same as SNMP above but requires use of the net-snmp library. Unless you have a +specific need for this old driver, you should use @code{'snmp} instead. + +@item dumb +Old serial character device for use with simple-signaling UPSes. + +@item pcnet +PowerChute Network Shutdown protocol which can be used as an alternative to SNMP +with the AP9617 family of smart slot cards. + +@item modbus +Serial device for use with newest SmartUPS models supporting the MODBUS +protocol. + +@end table") + (device + (string "") + "For USB UPSes, usually you want to set this to an empty string (the +default). For other UPS types, you must specify an appropriate port or address. + +@table @code +@item apcsmart +Set to the appropriate @file{/dev/tty**} device. + +@item usb +A null string setting enables autodetection, which is the best choice for most +installations. + +@item net +Set to @code{@var{hostname}:@var{port}}. + +@item snmp +Set to @code{@var{hostname}:@var{port}:@var{vendor}:@var{community}}. +@var{hostname} is the ip address or hostname of the UPS on the network. +@var{vendor} can be can be \"APC\" or \"APC_NOTRAP\". \"APC_NOTRAP\" will +disable SNMP trap catching; you usually want \"APC\". @var{port} is usually +161. @var{community} is usually \"private\". + +@item netsnmp +Same as @code{'snmp}. + +@item dumb +Set to the appropriate @file{/dev/tty**} device. + +@item pcnet +Set to @code{@var{ipaddr}:@var{username}:@var{passphrase}:@var{port}}. +@var{ipaddr} is the IP address of the UPS management card. @var{username} and +@var{passphrase} are the credentials for which the card has been configured. +@var{port} is the port number on which to listen for messages from the UPS, +normally 3052. If this parameter is empty or missing, the default of 3052 will +be used. + +@item modbus +Set to the appropriate @file{/dev/tty**} device. You can also leave it empty +for MODBUS over USB or set to the serial number of the UPS. + +@end table") + (poll-time + (integer 60) + "Interval (in seconds) at which apcupsd polls the UPS for status. This +setting applies both to directly-attached UPSes (apcsmart, usb, dumb) and +networked UPSes (net, snmp). Lowering this setting will improve apcupsd's +responsiveness to certain events at the cost of higher CPU utilization.") + + ;; Configuration parameters used during power failures + (on-batery-delay + (integer 6) + "The the time in seconds from when a power failure is detected until we react +to it with an onbattery event. The @code{'powerout} event will be triggered +immediately when a power failure is detected. However, the @code{'onbattery} +event will be trigger only after this delay.") + (battery-level + (integer 5) + "If during a power failure, the remaining battery percentage (as reported by +the UPS) is below or equal to this value, apcupsd will initiate a system +shutdown. + +@quotation Note +@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work +in conjunction, so the first that occurs will cause the initation of a +shutdown. +@end quotation") + (remaining-minutes + (integer 3) + "If during a power failure, the remaining runtime in minutes (as calculated +internally by the UPS) is below or equal to this value, apcupsd will initiate a +system shutdown. + +@quotation Note +@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work +in conjunction, so the first that occurs will cause the initation of a +shutdown. +@end quotation") + (timeout + (integer 0) + "If during a power failure, the UPS has run on batteries for this many +seconds or longer, apcupsd will initiate a system shutdown. A value of 0 +disables this timer. + +@quotation Note +@code{battery-level}, @code{remaining-minutes}, and @code{timeout} work +in conjunction, so the first that occurs will cause the initation of a +shutdown. +@end quotation") + (annoy-interval + (integer 300) + "Time in seconds between annoying users (via the @code{'annoyme} event) to +sign off prior to system shutdown. 0 disables.") + (annoy-delay + (integer 60) + "Initial delay in seconds after power failure before warning users to get off +the system.") + (no-logon + (enum-no-logon 'disable) + "The condition which determines when users are prevented from logging in +during a power failure.") + (kill-delay + (integer 0) + "If this is non-zero, apcupsd will continue running after a shutdown has been +requested, and after the specified time in seconds attempt to kill the power. +This is for use on systems where apcupsd cannot regain control after a +shutdown.") + + ;; Configuration statements for Network Information Server + (net-server + (boolean #f) + "If enabled, a network information server process will be started.") + (net-server-ip + (string "127.0.0.1") + "IP address on which NIS server will listen for incoming connections.") + (net-server-port + (integer 3551) + "IP port on which NIS server will listen for incoming connections.") + (net-server-events-file + maybe-string + "If you want the last few EVENTS to be available over the network by the +network information server, you must set this to a file patch.") + (net-server-events-file-max-size + (integer 10) + "Maximum size of the events file in kilobytes.") + ;; Configuration statements used if sharing a UPS with more than one machine + (class (enum-class 'standalone) + "Normally standalone unless you share an UPS using an APC ShareUPS card.") + (mode (enum-mode 'disable) + "Normally disable unless you share an UPS using an APC ShareUPS card.") + ;; Configuration statements to control apcupsd system logging + (stat-time + (integer 0) + "Time interval in seconds between writing the status file, 0 disables.") + (log-stats + (boolean #f) + "Also write the stats as a logs. This generates a lot of output.") + (data-time + (integer 0) + "Time interval in seconds between writing the data records to the log file, 0 +disables.") + (facility + maybe-string + "The logging facility for the syslog.") + + ;; Event handlers + (event-handlers + (apcupsd-event-handlers (apcupsd-event-handlers)) + "Handlers for events produced by apcupsd." + empty-serializer)) + +(define (s/apccontrol cfg) + (program-file + "apccontrol" + #~(begin + (use-modules (srfi srfi-9) + (ice-9 format) + (ice-9 match) + (ice-9 popen)) + ;; Script dir depends on these, and the configuration depends on the script + ;; dir. To sever the cyclic dependency, pass the paths via environment + ;; variables. + (define conf (getenv "GUIX_APCUPSD_CONF")) + (define powerfail-file (getenv "GUIX_APCUPSD_POWERFAIL_FILE")) + + (define (err . args) + (apply format (current-error-port) args)) + (define (wall . args) + (system* #$(file-append util-linux "/bin/wall") (apply format #f args))) + (define (apcupsd . args) + (apply system* #$(file-append apcupsd "/sbin/apcupsd") "-f" conf args)) + (define (mail-to-root subject body) + (let ((port (open-pipe* OPEN_WRITE + "/run/privileged/bin/sendmail" + "-F" "apcupsd" + "root"))) + (format port "Subject: ~a~%~%~a~&" subject body) + (close-pipe port))) + (match (cdr (command-line)) + (((? string? cmd) name connected powered) + (match cmd + ;; I am sure this could be done by macro, but meh. Last release of + ;; apcupsd was in 2016, so maintaining this will not be much work. + ("killpower" + #$@(apcupsd-event-handlers-killpower + (apcupsd-configuration-event-handlers cfg))) + ("commfailure" + #$@(apcupsd-event-handlers-commfailure + (apcupsd-configuration-event-handlers cfg))) + ("commok" + #$@(apcupsd-event-handlers-commok + (apcupsd-configuration-event-handlers cfg))) + ("powerout" + #$@(apcupsd-event-handlers-powerout + (apcupsd-configuration-event-handlers cfg))) + ("onbattery" + #$@(apcupsd-event-handlers-onbattery + (apcupsd-configuration-event-handlers cfg))) + ("offbattery" + #$@(apcupsd-event-handlers-offbattery + (apcupsd-configuration-event-handlers cfg))) + ("mainsback" + #$@(apcupsd-event-handlers-mainsback + (apcupsd-configuration-event-handlers cfg))) + ("failing" + #$@(apcupsd-event-handlers-failing + (apcupsd-configuration-event-handlers cfg))) + ("timeout" + #$@(apcupsd-event-handlers-timeout + (apcupsd-configuration-event-handlers cfg))) + ("loadlimit" + #$@(apcupsd-event-handlers-loadlimit + (apcupsd-configuration-event-handlers cfg))) + ("runlimit" + #$@(apcupsd-event-handlers-runlimit + (apcupsd-configuration-event-handlers cfg))) + ("doreboot" + #$@(apcupsd-event-handlers-doreboot + (apcupsd-configuration-event-handlers cfg))) + ("doshutdown" + #$@(apcupsd-event-handlers-doshutdown + (apcupsd-configuration-event-handlers cfg))) + ("annoyme" + #$@(apcupsd-event-handlers-annoyme + (apcupsd-configuration-event-handlers cfg))) + ("emergency" + #$@(apcupsd-event-handlers-emergency + (apcupsd-configuration-event-handlers cfg))) + ("changeme" + #$@(apcupsd-event-handlers-changeme + (apcupsd-configuration-event-handlers cfg))) + ("remotedown" + #$@(apcupsd-event-handlers-remotedown + (apcupsd-configuration-event-handlers cfg))) + ("startselftest" + #$@(apcupsd-event-handlers-startselftest + (apcupsd-configuration-event-handlers cfg))) + ("endselftest" + #$@(apcupsd-event-handlers-endselftest + (apcupsd-configuration-event-handlers cfg))) + ("battdetach" + #$@(apcupsd-event-handlers-battdetach + (apcupsd-configuration-event-handlers cfg))) + ("battattach" + #$@(apcupsd-event-handlers-battattach + (apcupsd-configuration-event-handlers cfg))) + (_ + (err "Unknown event: ~a~%" cmd) + (err "Iff the event was passed by apcupsd, this is a bug.~%") + (err "Please report to bug-guix@gnu.org.~%") + (exit #f)))) + (args + (err "Unknown arguments: ~a~%" args) + (err "Iff the arguments were passed by apcupsd, this is a bug.~%") + (err "Please report to bug-guix@gnu.org.~%") + (exit #f)))))) + +(define (apcupsd-script-dir cfg) + (computed-file + "apcupsd-script-dir" + #~(begin + (mkdir #$output) + (chdir #$output) + (symlink #$(s/apccontrol cfg) "apccontrol")))) + +(define (apcupsd-config-file cfg) + (let ((run-dir (apcupsd-configuration-run-dir cfg))) + (mixed-text-file + "apcupsd.conf" + "\ +## apcupsd.conf v1.1 ## +# +# for apcupsd release 3.14.14 (31 May 2016) - GNU Guix +# +# \"apcupsd\" POSIX config file (crafted via apcupsd-service-type) +" + (serialize-configuration cfg apcupsd-configuration-fields) + ;; This one is confusing. The manual page states: + ;; + ;; > It must be changed when running more than one copy of apcupsd on the + ;; > same computer to control multiple UPSes. + ;; + ;; However would you not want the lock to be per-device, not per-process? + ;; I decided to follow the documentation, but I do not understand why it + ;; should be like this. I do not have multiple UPSes to try. + (serialize-string 'lock-dir (string-append run-dir "/lock")) + (serialize-string 'power-fail-dir run-dir) + (serialize-string 'no-login-dir run-dir) + (serialize-string 'stat-file (string-append run-dir "/apcupsd.status")) + "SCRIPTDIR " (apcupsd-script-dir cfg) "\n"))) + +(define (apcupsd-shepherd-services cfg) + (match-record cfg + ( package pid-file debug-level run-dir + shepherd-base-name auto-start?) + (let* ((config-file (apcupsd-config-file cfg)) + (s/ shepherd-base-name) + (s/run-dirs (string->symbol (format #f "~a-run-dirs" s/)))) + (list + (shepherd-service + (documentation "Create the run directories.") + (provision (list s/run-dirs)) + (one-shot? #t) + (auto-start? auto-start?) + (start #~(lambda _ + ((@ (guix build utils) mkdir-p) + #$(string-append run-dir "/lock")) + #t))) + (shepherd-service + (documentation "Run apcupsd daemon.") + (requirement (list s/run-dirs)) + (provision (list s/)) + (auto-start? auto-start?) + (start #~(make-forkexec-constructor + '(#$(file-append package "/sbin/apcupsd") + "-b" ; Do not daemonize. + "-f" #$config-file + "-P" #$pid-file + "-d" #$(number->string debug-level)) + #:log-file + #$(format #f "/var/log/~a.log" shepherd-base-name) + #:environment-variables + (cons* (string-append "GUIX_APCUPSD_CONF=" + #$config-file) + #$(string-append "GUIX_APCUPSD_POWERFAIL_FILE=" + run-dir "/powerfail") + (default-environment-variables)))) + (stop #~(make-kill-destructor)) + (actions (list (shepherd-configuration-action config-file)))))))) + +(define (apcupsd-pam-extensions cfg) + (define pam-nologin + (pam-entry + (control "required") + (module "pam_nologin.so") + (arguments (list (string-append "file=" + (apcupsd-configuration-run-dir cfg) + "/nologin"))))) + + (list (pam-extension + (transformer + (lambda (pam) + (pam-service + (inherit pam) + (auth (cons pam-nologin (pam-service-auth pam))))))))) + +(define apcupsd-service-type + (service-type + (name 'apcupsd) + (description "Configure and optionally start apcupsd.") + (extensions (list (service-extension shepherd-root-service-type + apcupsd-shepherd-services) + (service-extension pam-root-service-type + apcupsd-pam-extensions))) + (compose identity) + (extend (λ (cfg lst) + (fold (cut <> <>) cfg lst))) + (default-value (apcupsd-configuration))))