Browse Source

package: Port apcupsd

For USB-connected UPSs, kernel's USB_HIDDEV option is required as the
daemon communicates via /dev/usb/hiddev* raw HID devices. Therefore make
USB_HID select USB_HIDDEV (shouldn't hurt much on other systems) and
select the former if the package is enabled.

Ship a config which defaults to USB-based UPSs as they are probably the
most common ones. Also install a minimal apccontrol which merely
remounts relevant filesystems read-only in case of near blackout. The
core OpenADK fs layout should tolerate pulling the plug as-is already.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Phil Sutter 3 months ago
parent
commit
d7452d1a84

+ 44 - 0
package/apcupsd/Makefile

@@ -0,0 +1,44 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include $(ADK_TOPDIR)/rules.mk
+
+PKG_NAME:=		apcupsd
+PKG_VERSION:=		3.14.14
+PKG_RELEASE:=		1
+PKG_HASH:=		db7748559b6b4c3784f9856561ef6ac6199ef7bd019b3edcd7e0a647bf8f9867
+PKG_DESCR:=		APC UPS daemon with integrated tcp/ip remote shutdown
+PKG_SECTION:=		sys/misc
+PKG_DEPENDS:=		libusb
+PKG_BUILDDEP:=		libusb
+PKG_URL:=		http://www.apcupsd.org
+PKG_SITES:=		$(MASTER_SITE_SOURCEFORGE:=apcupsd/)
+DISTFILES:=             $(PKG_NAME)-$(PKG_VERSION).tar.gz
+
+PKG_CFLINE_APCUPSD:=	select BUSYBOX_WALL@
+PKG_CFLINE_APCUPSD+=	select ADK_LINUX_KERNEL_USB_HID@
+
+include $(ADK_TOPDIR)/mk/package.mk
+
+$(eval $(call PKG_template,APCUPSD,apcupsd,$(PKG_VERSION)-$(PKG_RELEASE),$(PKG_DEPENDS),$(PKG_DESCR),$(PKG_SECTION)))
+
+CONFIGURE_ARGS+=	--prefix="${WRKINST}" --sbindir="/usr/sbin" --enable-usb
+CONFIGURE_ENV+=		ac_cv_path_WALL=/usr/bin/wall
+XAKE_FLAGS:=		VERBOSE=1 STRIP=""
+
+# XXX: custom init script?
+apcupsd-install:
+	$(INSTALL_DIR) $(IDIR_APCUPSD)/usr/sbin
+	$(INSTALL_BIN) $(WRKINST)/usr/sbin/apc{access,test,upsd} \
+		$(IDIR_APCUPSD)/usr/sbin
+	$(INSTALL_DIR) $(IDIR_APCUPSD)/etc
+	$(INSTALL_DATA) $(WRKINST)/etc/apcupsd.conf $(IDIR_APCUPSD)/etc
+	# default to USB-based UPS, avoid writing to /etc to keep cfgfs clean
+	$(SED) 's/^UPSCABLE smart/UPSCABLE usb/' \
+		-e 's/^UPSTYPE apcsmart/UPSTYPE usb/' \
+		-e 's,^DEVICE /dev/ttyS0,DEVICE,' \
+		-e 's,^PWRFAILDIR /etc,PWRFAILDIR /tmp,' \
+		$(IDIR_APCUPSD)/etc/apcupsd.conf
+	$(INSTALL_BIN) ./files/apccontrol $(IDIR_APCUPSD)/etc/
+
+include $(ADK_TOPDIR)/mk/pkg-bottom.mk

+ 74 - 0
package/apcupsd/files/apccontrol

@@ -0,0 +1,74 @@
+#!/bin/sh
+#
+# A custom apccontrol for use in embedded systems: just make sure there's no
+# data in-flight and wait for the blackout to shut us down.
+
+# these filesystems are not relevant
+IGNORE_FS="tmpfs proc sysfs devtmpfs devpts nfsd"
+
+get_rw_mounts() {
+	local excl='\((ro,\|type \('
+	local sep=""
+	for fs in $IGNORE_FS; do
+		excl+="${sep}$fs"
+		sep='\|'
+	done
+	excl+='\)\)'
+	mount | grep -v "$excl" | while read dev on mnt opts; do
+		echo "$mnt"
+	done
+}
+
+log() {
+	logger -s -t "$(basename $0)" -p daemon.crit "$*"
+}
+__mount() { # (ro/rw, txt, mnt)
+	local opt=$1
+	local txt=$2
+	local mnt="$3"
+
+	mount -o remount,$opt "$mnt"
+	rc=$?
+	case $rc in
+	0) log "remounted $mnt $txt"
+	*) log "failed to remount $mnt $txt: rc=$rc"
+	esac
+	return $rc
+}
+mount_ro() {
+	__mount ro read-only "$1"
+}
+mount_rw() {
+	__mount rw read-write "$1"
+}
+
+romounts="/tmp/apcupsd.romounts"
+
+case "$1" in
+	emergency|failing)
+		log "UPS error condition happening"
+		;& # fall through
+	doshutdown)
+		log "bracing for upcoming blackout"
+
+		rm -f "$romounts"
+		sync
+		get_rw_mounts | while read mnt; do
+			mount_ro "$mnt" && echo "$mnt" >>"$romounts"
+		done
+		;;
+	mainsback)
+		log "returning to routine after near blackout"
+
+		touch "$romounts"
+		while read mnt; do
+			mount_rw "$mnt"
+		done <"$romounts"
+		rm "$romounts"
+		;;
+	*)
+		log "Called for $1"
+		;;
+esac
+
+exit 0

+ 1 - 0
package/apcupsd/files/apcupsd.conffiles

@@ -0,0 +1 @@
+/etc/apcupsd.conf

+ 38 - 0
package/apcupsd/files/apcupsd.init

@@ -0,0 +1,38 @@
+#!/bin/sh
+#PKG apcupsd
+#INIT 15
+. /etc/rc.conf
+
+pidfile=$(echo "$apcupsd_flags" | \
+	  sed -n 's/.*\(-P\|--pid-file\) \([^ ]\+\).*/\2/p')
+[ "$pidfile" ] || pidfile="/var/run/apcupsd.pid"
+
+case $1 in
+autostop) ;;
+autostart)
+	test x"${apcupsd:-NO}" = x"NO" && exit 0
+	test x"$apcupsd" = x"DAEMON" && test -x /bin/mksh && exec mksh -T- $0 start
+	exec sh $0 start
+	;;
+start)
+	mkdir -p /var/lock
+	/usr/sbin/apcupsd $apcupsd_flags
+	;;
+stop)
+	if [ -f "$pidfile" ]; then
+		kill $(<$pidfile)
+		rm -f $pidfile
+	else
+		kill $(pgrep -f /usr/sbin/apcupsd)
+	fi
+	;;
+restart)
+	sh $0 stop
+	sleep 1
+	sh $0 start
+	;;
+*)
+	echo "usage: $0 (start | stop | restart)"
+	exit 1
+esac
+exit $?

+ 3 - 0
package/apcupsd/files/apcupsd.postinst

@@ -0,0 +1,3 @@
+#!/bin/sh
+. $IPKG_INSTROOT/etc/functions.sh
+add_rcconf apcupsd NO

+ 1 - 0
target/linux/config/Config.in.input

@@ -115,6 +115,7 @@ config ADK_LINUX_KERNEL_USB_HID
 	select ADK_LINUX_KERNEL_HID
 	select ADK_LINUX_KERNEL_HID_SUPPORT
 	select ADK_LINUX_KERNEL_HID_GENERIC
+	select ADK_LINUX_KERNEL_USB_HIDDEV
 	depends on ADK_TARGET_WITH_USB \
 		|| ADK_TARGET_GENERIC \
 		|| ADK_TARGET_QEMU