mirror of
https://github.com/openwrt/packages.git
synced 2026-10-12 12:27:26 +04:00
Include more inline comments to document the nut-server initscript and usb hotplug. Also trim an extraneous space in a comment. Signed-off-by: Daniel F. Dickinson <dfdpublic@wildtechgarden.ca>
205 lines
7.0 KiB
Bash
205 lines
7.0 KiB
Bash
#!/bin/sh
|
|
|
|
# In recent versions of shellcheck, busybox is a valid shell type
|
|
# shellcheck shell=busybox
|
|
|
|
# OpenWrt hotplug script to set permissions on USB serial
|
|
# ports to allow NUT to access UPSes attached via
|
|
# USB-to-serial cables
|
|
|
|
# OpenWrt hotplug calls this script with DEVNAME and
|
|
# ACTION set in the environment
|
|
|
|
# IPKG_INSTROOT is intentionally only set when building an image and
|
|
# is intentionally empty on a live OpenWrt device
|
|
|
|
# shellcheck source=net/nut/files/functions.sh.functions
|
|
. "${IPKG_INSTROOT}"/lib/functions.sh || {
|
|
# Before our sourcing error logging definitions are sourced
|
|
logger -t nut-serial-hotplug[$$] "Unable to source 'functions.sh' in 'nut-serial' hotplug. Bailing"
|
|
exit 1
|
|
}
|
|
|
|
# 'shellcheck' complains about nut-common.sh due to a case pattern it does not understand, even
|
|
# though it is correctly POSIX compliant
|
|
# shellcheck disable=SC1094
|
|
# shellcheck source=net/nut/files/nut-common.sh.functions
|
|
. "${IPKG_INSTROOT}"/lib/functions/nut/nut-common.sh || {
|
|
# Before our sourcing error logging definitions are sourced
|
|
logger -t nut-serial-hotplug[$$] "Unable to source 'nut-common.sh' in 'nut-serial' hotplug. Bailing"
|
|
exit 1
|
|
}
|
|
|
|
# shellcheck source=net/nut/files/nut-service.sh.functions
|
|
. "${IPKG_INSTROOT}"/lib/functions/nut/nut-service.sh || {
|
|
log_source_error "nut-service.sh" "nut-serial" "nut-serial-hotplug"
|
|
exit 1
|
|
}
|
|
|
|
# Group of RUNAS user; used to allow access to the USB serial device
|
|
DEVICE_GROUP=""
|
|
|
|
# 'shellcheck' does not understand config_foreach and therefore treats
|
|
# functions and variables referenced only from config_foreach as not reachable,
|
|
# or never invoked.
|
|
# shellcheck disable=SC2317,SC2329
|
|
nut_set_serial_port_permissions() {
|
|
local devname="$1" # Must be full path (e.g. /dev/...)
|
|
local ups="$2"
|
|
|
|
# Guard against disappearing device (e.g. due to 'bouncing' device)
|
|
if [ -e "$devname" ]; then
|
|
# Allow RUNAS user (which is user of driver process) to access device
|
|
if ! chgrp "$DEVICE_GROUP" "$devname"; then
|
|
log_error "Unable to set group on '$devname'" nut-serial nut-serial-hotplug
|
|
return 1
|
|
fi
|
|
else
|
|
log_error "'$devname' disappeared before setting group" nut-serial nut-serial-hotplug
|
|
return 1
|
|
fi
|
|
|
|
# Device could disappear between chgrp and chmod
|
|
if [ -e "$devname" ]; then
|
|
if ! chmod g+rw "$devname"; then
|
|
log_error "Unable to set permissions on '$devname'" nut-serial nut-serial-hotplug
|
|
return 1
|
|
fi
|
|
else
|
|
log_error "'$devname' disappeared before setting permissions" nut-serial nut-serial-hotplug
|
|
return 1
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# If enable_usb_serial is set, set the permissions on applicable USB
|
|
# serial devices to allow NUT access
|
|
# We do not exit with error as that would stop processing of other UPS config
|
|
# sections.
|
|
# We use 'did_set_perms' as a 'pseudo-global' from nut_on_hotplug_add in order
|
|
# to return a value to config_foreach
|
|
|
|
# 'shellcheck' does not understand config_foreach and therefore treats
|
|
# functions and variables referenced only from config_foreach as not reachable,
|
|
# or never invoked.
|
|
# shellcheck disable=SC2317,SC2329
|
|
nut_serial() {
|
|
local ups="$1" # UCI section name is also the UPS configuration name
|
|
local enable_usb_serial port normal_devname
|
|
|
|
config_get_bool enable_usb_serial "$ups" enable_usb_serial 0
|
|
config_get port "$ups" port
|
|
|
|
[ "$enable_usb_serial" = "1" ] && {
|
|
# If port is specified only change tty's matching port
|
|
if [ -n "$port" ] && [ "${port#/dev/}" = "${port}" ]; then
|
|
port="/dev/$port"
|
|
fi
|
|
# Normalize DEVNAME
|
|
normal_devname="$DEVNAME"
|
|
if [ -n "$DEVNAME" ] && [ "${DEVNAME#/dev/}" = "${DEVNAME}" ]; then
|
|
normal_devname="/dev/$DEVNAME"
|
|
fi
|
|
# Empty port from configuration means match any device.
|
|
if [ "$port" = "$normal_devname" ] || [ "$port" = "" ]; then
|
|
if nut_set_serial_port_permissions "$normal_devname" "$ups"; then
|
|
did_set_perms="true"
|
|
fi
|
|
fi
|
|
}
|
|
}
|
|
|
|
nut_on_hotplug_add() {
|
|
# We use did_set_perms as a 'pseudo-global'. It is visible and can be
|
|
# modified by called functions, but the changes do not propagate up from
|
|
# this function.
|
|
local did_set_perms="false"
|
|
|
|
config_load nut_server || {
|
|
log_config_load_error "nut_server" "nut-serial" "nut-serial-hotplug"
|
|
exit 1
|
|
}
|
|
|
|
# Only find runas once per event
|
|
RUNAS="$(find_runas "upsd" "nut_server")" || {
|
|
log_error_exit "Failed to set RUNAS" nut-serial nut-serial-hotplug
|
|
}
|
|
[ -n "$RUNAS" ] || {
|
|
log_error_exit "Failed to set RUNAS" nut-serial nut-serial-hotplug
|
|
}
|
|
export RUNAS
|
|
|
|
# Get group of RUNAS user, to set the group of the hotplugged device node
|
|
# If RUNAS user does not exist, exit with an error.
|
|
DEVICE_GROUP="$(id -gn "${RUNAS}")" || {
|
|
log_error "Unable to find group for RUNAS user '$RUNAS'. Skipping serial usb hotplug." nut-serial nut-serial-hotplug
|
|
return 1
|
|
}
|
|
export DEVICE_GROUP
|
|
|
|
# Check if serial USB UPS for each NUT driver instance (UPS), and if so
|
|
# configure permissions to allow NUT to access the port
|
|
config_foreach nut_serial driver
|
|
|
|
# If we set permissions on a device that may have a UPS attached, run
|
|
# the UPS (NUT) server reload to check for UPS configuration and
|
|
# attempt to reload the driver and/or server
|
|
if [ "$did_set_perms" = "true" ]; then
|
|
# Informational and not an error
|
|
log_msg "Successfully set permissions for serial device(s)" nut-serial nut-serial-hotplug info
|
|
# We shouldn't get here if hotplug is disabled (race condition if we do), so log it as an error
|
|
if ! allow_hotplug_restart; then
|
|
log_error "Did not restart NUT after setting permissions as hotplug restart is disabled" nut-serial nut-serial-hotplug
|
|
# Disabled hotplug is an allowed state
|
|
return 0
|
|
fi
|
|
if ! /etc/init.d/nut-server enabled; then
|
|
# shellcheck disable=SC2153
|
|
log_error "NUT server disabled when processing hotplug event 'add' for '$DEVNAME'." nut-serial nut-serial-hotplug
|
|
# Disabled nut-server is an allowed state
|
|
return 0
|
|
else
|
|
# Initscript should have its own logging
|
|
/etc/init.d/nut-server reload || return 1
|
|
fi
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
# Ignore incomplete (for our purposes) events
|
|
[ -n "$DEVNAME" ] || exit 0
|
|
[ -n "$ACTION" ] || exit 0
|
|
|
|
# Do not do any hotplug actions if hotplug is disabled. Not an error but log
|
|
# for information
|
|
if ! allow_hotplug_restart; then
|
|
# Don't spam logs on initial boot
|
|
# (before NUT_HOTPLUG_BOOT_COMPLETE_PATH exists)
|
|
if [ -f "$NUT_HOTPLUG_BOOT_COMPLETE_PATH" ]; then
|
|
# Informational and not an error
|
|
log_msg "Did not set permissions on serial port hotplug as NUT hotplug is disabled" nut-serial nut-serial-hotplug notice
|
|
fi
|
|
exit 0
|
|
fi
|
|
|
|
if ! [ "$(id -u)" = "0" ]; then
|
|
log_error_exit "Cannot set update device node on serial port hotplug. Hotplug not running as root." nut-serial nut-serial-hotplug
|
|
fi
|
|
|
|
# Only act on hotplug events with ACTION 'add' and where
|
|
# the hotplugged device is a USB serial port
|
|
# shellcheck disable=SC2153
|
|
if [ "$ACTION" = "add" ] && [ -n "$DEVNAME" ]; then
|
|
# On add of a USB serial port with name
|
|
# ttyUSB* or ttyAMA* or ttyACM* or ttyGS*
|
|
case "$DEVNAME" in
|
|
ttyUSB* | ttyAMA* | ttyACM* | ttyGS*)
|
|
# As we are at the top-level of the hotplug event, this only aborts this
|
|
# hotplug event, not hotplug events for other devices
|
|
nut_on_hotplug_add || exit 1
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
exit 0
|