From e8f6b80d59bdc0cff1315fc1acb9d45e392ca837 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 14:08:34 +0100 Subject: [PATCH 01/31] nut-driver-enumerator.sh : do not create a hashed SMF instance if failed to add a normally-named one because it already exists (clean it up and then add) --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 6c434b5387..496a18e7ad 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -563,8 +563,14 @@ smf_validInstanceSuffixName() { smf_registerInstance() { DEVICE="$1" SVCINST="$1" + if /usr/bin/svcs "nut-driver:$SVCINST" >/dev/null 2>&1 ; then + smf_unregisterInstance "$SVCINST" + fi /usr/sbin/svccfg -s nut-driver add "$DEVICE" || \ - { SVCINST="`smf_validInstanceName "$1"`" && \ + { SVCINST="`smf_validInstanceName "$1"`" || return + if /usr/bin/svcs "nut-driver:$SVCINST" >/dev/null 2>&1 ; then + smf_unregisterInstance "$SVCINST" + fi /usr/sbin/svccfg -s nut-driver add "$SVCINST" || return ; } echo "Added instance: 'nut-driver:$SVCINST' for NUT configuration section '$DEVICE'" >&2 From 68fddd7ee38505ea01d15f6215950ea22da0bfa1 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 14:44:48 +0100 Subject: [PATCH 02/31] nut-driver-enumerator.sh.in : smf_getSavedMD5() : do not spam stderr about yet-missing property --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 496a18e7ad..9309bd4a50 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -645,7 +645,7 @@ smf_getSavedMD5() { fi # Note: lookups for GLOBAL cause each service instance to show up - /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" | head -1 | awk '{print $NF}' + /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } smf_setSavedMD5() { # Save checksum value $2 into service instance $1 From c0da59ba2c0ef24cd6e582559cdffba6b6ab77cb Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 14:46:06 +0100 Subject: [PATCH 03/31] nut-driver-enumerator.sh.in : smf_setSavedMD5() : do not try to refresh the non-instance service (for global config) --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 9309bd4a50..0c3bbce410 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -664,7 +664,9 @@ smf_setSavedMD5() { /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$PG" application && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$PG/$PROP" = astring: "$2" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } - /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return + if [ -n "$1" ] ; then + /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return + fi } smf_restart_upsd() { echo "Restarting NUT data server to make sure it knows new configuration..." From ac0833a46a568b22c3836f2640f9e77208495270 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 15:01:39 +0100 Subject: [PATCH 04/31] nut-driver-enumerator.sh.in : smf_setSavedMD5() : do not spam stderr about yet-missing property --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 0c3bbce410..31d9b925ec 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -660,7 +660,7 @@ smf_setSavedMD5() { PROP="SECTION_CHECKSUM_GLOBAL" fi - /usr/sbin/svccfg -s "$TARGET_FMRI" delprop "$PG" || true + /usr/sbin/svccfg -s "$TARGET_FMRI" delprop "$PG" 2>/dev/null || true /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$PG" application && \ /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$PG/$PROP" = astring: "$2" [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } From 28af97173e94c033e39b6e1f164959ae90dbcfe8 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 15:45:40 +0100 Subject: [PATCH 05/31] nut-driver-enumerator.sh.in : smf_setSavedMD5() : refactor the actual setter into smf_setSavedUniq() for other use-cases --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 31d9b925ec..cf0db97d2a 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -647,6 +647,33 @@ smf_getSavedMD5() { # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } +smf_setSavedUniq() { + # Save data value $5 of type $4 into service FMRI $1 + # under (scrapped and) newly created property group $2 + # and property name $3 + _TARGET_FMRI="$1" + _PG="$2" + _PROP="$3" + _TYPE="$4" + case "${_TYPE}" in + *:) ;; + *) _TYPE="${_TYPE}:" ;; + esac + _VAL="$5" + /usr/sbin/svccfg -s "${_TARGET_FMRI}" delprop "${_PG}" 2>/dev/null || true + /usr/sbin/svccfg -s "${_TARGET_FMRI}" addpg "${_PG}" application && \ + /usr/sbin/svccfg -s "${_TARGET_FMRI}" setprop "${_PG}/${_PROP}" = "${_TYPE}" "${_VAL}" + [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property ${_PG}/${_PROP}">&2 ; return 1 ; } + + case "${_TARGET_FMRI}" in + svc:/*:*) ;; # A service instance by full FMRI, refresh + svc:/*/nut-driver|nut-driver) return 0 ;; # A base non-instance service item for nut-driver (known multi-instance only) + svc:/*) ;; # A base non-instance service item (not nut-driver) + *:*) ;; # A service instance by short FMRI, refresh + *) ;; # A base non-instance service item (not nut-driver) + esac + /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return +} smf_setSavedMD5() { # Save checksum value $2 into service instance $1 PG="nut-driver-enumerator-generated-checksum" @@ -659,14 +686,7 @@ smf_setSavedMD5() { TARGET_FMRI="nut-driver" PROP="SECTION_CHECKSUM_GLOBAL" fi - - /usr/sbin/svccfg -s "$TARGET_FMRI" delprop "$PG" 2>/dev/null || true - /usr/sbin/svccfg -s "$TARGET_FMRI" addpg "$PG" application && \ - /usr/sbin/svccfg -s "$TARGET_FMRI" setprop "$PG/$PROP" = astring: "$2" - [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the checksum">&2 ; return 1 ; } - if [ -n "$1" ] ; then - /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return - fi + smf_setSavedUniq "$TARGET_FMRI" "$PG" "$PROP" astring "$2" } smf_restart_upsd() { echo "Restarting NUT data server to make sure it knows new configuration..." From d36de0c9d1f0a459a00d4f08b9112397b31baa19 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 15:48:13 +0100 Subject: [PATCH 06/31] nut-driver-enumerator.sh.in : run smf_setSaved*() in subprocesses to avoid variable pollution in caller --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index cf0db97d2a..2741dcb21c 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -647,7 +647,7 @@ smf_getSavedMD5() { # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } -smf_setSavedUniq() { +smf_setSavedUniq() ( # Save data value $5 of type $4 into service FMRI $1 # under (scrapped and) newly created property group $2 # and property name $3 @@ -673,8 +673,8 @@ smf_setSavedUniq() { *) ;; # A base non-instance service item (not nut-driver) esac /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return -} -smf_setSavedMD5() { +) +smf_setSavedMD5() ( # Save checksum value $2 into service instance $1 PG="nut-driver-enumerator-generated-checksum" PROP="SECTION_CHECKSUM" @@ -687,7 +687,7 @@ smf_setSavedMD5() { PROP="SECTION_CHECKSUM_GLOBAL" fi smf_setSavedUniq "$TARGET_FMRI" "$PG" "$PROP" astring "$2" -} +) smf_restart_upsd() { echo "Restarting NUT data server to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-server" 2>/dev/null From 52aac8020910fd001ae6914942da83b95a37ec7a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 28 Mar 2019 15:57:32 +0100 Subject: [PATCH 07/31] nut-driver-enumerator.sh.in : save original device name into service props --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 2741dcb21c..e55a580549 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -608,6 +608,8 @@ smf_registerInstance() { fi smf_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" + # Save original device (config section) name to speed up some searches + smf_setSavedUniq "$TARGET_FMRI" "nut-driver-enumerator-generated-devicename" "DEVICE" astring "$DEVICE" /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return if [ "$AUTO_START" = yes ] ; then @@ -758,6 +760,7 @@ EOF fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" + _systemd_setSavedDevice "$SVCINST" "$DEVICE" if [ "$AUTO_START" = yes ] ; then $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return @@ -791,6 +794,16 @@ systemd_getSavedMD5() { && grep "Environment='$PROP=" "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf' with a $PROP" ; return 1; } } +_systemd_setSavedDevice() { + # Save device (config section) name $2 into service instance $1 + [ -n "$1" ] || return + mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ + cat > "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" << EOF +[Service] +Environment='DEVICE="$2"' +EOF + [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the device name">&2 ; return 1 ; } +} systemd_setSavedMD5() { # Save checksum value $2 into service instance $1 PROP="SECTION_CHECKSUM" From 2138d2b045a4ee4fba4b31e8e5b016a6f676bfbd Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 13:11:59 +0100 Subject: [PATCH 08/31] nut-driver-enumerator.sh.in : add a BIG NOTE about shell interpreter --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index e55a580549..7393bbbdca 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1,4 +1,5 @@ #!/bin/sh +# BIG NOTE: Not bash, not any other predetermined shell implementation # # NOTE: This script is intentionally written with portable shell constructs # with the aim and hope to work in different interpreters, so it is a From b6b29530dff294e8397a343f34841901693d8e03 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 13:17:02 +0100 Subject: [PATCH 09/31] nut-driver-enumerator.sh.in : refactor expansions "$_VAR" => "${_VAR}" for better readability --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 7393bbbdca..7dbcea8edf 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -285,22 +285,22 @@ upslist_equals() { _TMP_DEV_SVC="" for _DEV in $1 ; do - DEVINST="`$hook_validInstanceName "$_DEV"`" + DEVINST="`$hook_validInstanceName "${_DEV}"`" for _SVC in $2 ; do - [ "$_DEV" = "$_SVC" ] \ - || [ "$DEVINST" = "$_SVC" ] \ - && { [ -z "$_TMP_DEV_SVC" ] \ - && _TMP_DEV_SVC="$_DEV = $_SVC" \ - || _TMP_DEV_SVC="$_TMP_DEV_SVC -$_DEV = $_SVC" ; } + [ "${_DEV}" = "${_SVC}" ] \ + || [ "$DEVINST" = "${_SVC}" ] \ + && { [ -z "${_TMP_DEV_SVC}" ] \ + && _TMP_DEV_SVC="${_DEV} = ${_SVC}" \ + || _TMP_DEV_SVC="${_TMP_DEV_SVC} +${_DEV} = ${_SVC}" ; } done done # Input was not empty; did anything in output fit? - [ -z "$_TMP_DEV_SVC" ] && return 1 + [ -z "${_TMP_DEV_SVC}" ] && return 1 # Exit code : is the built mapping as long as the source list(s)? - [ "`echo "$1" | wc -l`" = "`echo "$_TMP_DEV_SVC" | wc -l`" ] + [ "`echo "$1" | wc -l`" = "`echo "${_TMP_DEV_SVC}" | wc -l`" ] } upssvcconf_checksum_unchanged() { @@ -320,21 +320,21 @@ upslist_checksums_unchanged() { _TMP_SVC="" for _DEV in $1 ; do - DEVINST="`$hook_validInstanceName "$_DEV"`" + DEVINST="`$hook_validInstanceName "${_DEV}"`" for _SVC in $2 ; do - if [ "$_DEV" = "$_SVC" ] \ - || [ "$DEVINST" = "$_SVC" ] \ + if [ "${_DEV}" = "${_SVC}" ] \ + || [ "$DEVINST" = "${_SVC}" ] \ ; then - upssvcconf_checksum_unchanged "$_DEV" "$_SVC" || \ - { [ -z "$_TMP_SVC" ] \ - && _TMP_SVC="$_SVC" \ - || _TMP_SVC="$_TMP_SVC -$_SVC" ; } + upssvcconf_checksum_unchanged "${_DEV}" "${_SVC}" || \ + { [ -z "${_TMP_SVC}" ] \ + && _TMP_SVC="${_SVC}" \ + || _TMP_SVC="${_TMP_SVC} +${_SVC}" ; } fi done done - [ -z "$_TMP_SVC" ] && return 0 - echo "$_TMP_SVC" + [ -z "${_TMP_SVC}" ] && return 0 + echo "${_TMP_SVC}" return 1 } @@ -513,7 +513,7 @@ upsconf_getDriverMedia() { upsconf_getMedia() { _DRVMED="`upsconf_getDriverMedia "$1"`" || return - echo "$_DRVMED" | tail -n +2 + echo "${_DRVMED}" | tail -n +2 return 0 } @@ -523,27 +523,27 @@ upsconf_debug() { _MED="`upsconf_getMedia "$1"`" _MD5="`upsconf_getSection_MD5 "$1"`" NAME_MD5="`calc_md5 "$1"`" - echo "INST: ${NAME_MD5}~[$1]: DRV='$_DRV' PORT='$_PRT' MEDIA='$_MED' SECTIONMD5='$_MD5'" + echo "INST: ${NAME_MD5}~[$1]: DRV='${_DRV}' PORT='${_PRT}' MEDIA='${_MED}' SECTIONMD5='${_MD5}'" } calc_md5() { # Tries several ways to produce an MD5 of the "$1" argument - _MD5="`echo "$1" | md5sum 2>/dev/null | awk '{print $1}'`" && [ -n "$_MD5" ] || \ - { _MD5="`echo "$1" | openssl dgst -md5 2>/dev/null | awk '{print $NF}'`" && [ -n "$_MD5" ]; } || \ + _MD5="`echo "$1" | md5sum 2>/dev/null | awk '{print $1}'`" && [ -n "${_MD5}" ] || \ + { _MD5="`echo "$1" | openssl dgst -md5 2>/dev/null | awk '{print $NF}'`" && [ -n "${_MD5}" ]; } || \ return 1 - echo "$_MD5" + echo "${_MD5}" } calc_md5_file() { # Tries several ways to produce an MD5 of the file named by "$1" argument [ -s "$1" ] || return 2 - _MD5="`md5sum 2>/dev/null < "$1" | awk '{print $1}'`" && [ -n "$_MD5" ] || \ - { _MD5="`openssl dgst -md5 2>/dev/null < "$1" | awk '{print $NF}'`" && [ -n "$_MD5" ]; } || \ + _MD5="`md5sum 2>/dev/null < "$1" | awk '{print $1}'`" && [ -n "${_MD5}" ] || \ + { _MD5="`openssl dgst -md5 2>/dev/null < "$1" | awk '{print $NF}'`" && [ -n "${_MD5}" ]; } || \ return 1 - echo "$_MD5" + echo "${_MD5}" } smf_validFullUnitName() { @@ -578,7 +578,7 @@ smf_registerInstance() { DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" - case "$_MED" in + case "${_MED}" in usb) DEPSVC="$DEPSVC_USB_SMF" DEPREQ="$DEPREQ_USB_SMF" ;; @@ -590,7 +590,7 @@ smf_registerInstance() { DEPREQ="$DEPREQ_NET_FULL_SMF" ;; serial) ;; '') ;; - *) echo "WARNING: Unexpected NUT media type ignored: '$_MED'" >&2 ;; + *) echo "WARNING: Unexpected NUT media type ignored: '${_MED}'" >&2 ;; esac TARGET_FMRI="nut-driver:$SVCINST" @@ -731,7 +731,7 @@ systemd_registerInstance() { DEPSVC="" DEPREQ="" _MED="`upsconf_getMedia "$DEVICE"`" - case "$_MED" in + case "${_MED}" in usb) DEPSVC="$DEPSVC_USB_SYSTEMD" DEPREQ="$DEPREQ_USB_SYSTEMD" ;; @@ -743,7 +743,7 @@ systemd_registerInstance() { DEPREQ="$DEPREQ_NET_FULL_SYSTEMD" ;; serial) ;; '') ;; - *) echo "WARNING: Unexpected NUT media type ignored: '$_MED'" >&2 ;; + *) echo "WARNING: Unexpected NUT media type ignored: '${_MED}'" >&2 ;; esac if [ -n "$DEPSVC" ]; then [ -n "$DEPREQ" ] || DEPREQ="#Wants" @@ -1408,7 +1408,7 @@ while [ $# -gt 0 ]; do echo "$OUT" | grep "$SVC" | ( \ while read _SVC _DEV ; do _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit - [ "${_SVC}" = "${SVC}" ] && echo "$_DEV" && exit 0 + [ "${_SVC}" = "${SVC}" ] && echo "${_DEV}" && exit 0 done ; exit 1 ) && exit 0 fi echo "No service instance '$2' was detected that matches a NUT device" >&2 From 49a04ba7f64f76970a8d27d9c47033dffff09eed Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 13:17:56 +0100 Subject: [PATCH 10/31] nut-driver-enumerator.sh.in : update (C) 2019 --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 7dbcea8edf..1ce079265e 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -9,7 +9,7 @@ # reference or 100% compliant with what the binary code uses; its aim # is to just pick out some strings relevant for tracking config changes. # -# Copyright (C) 2016-2018 Eaton +# Copyright (C) 2016-2019 Eaton # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by From c55b117bea285cf39d31ef790e0d9ae6d7ecef04 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 13:58:43 +0100 Subject: [PATCH 11/31] nut-driver-enumerator.sh.in : use hook_getSavedDeviceName() to speed up --get-device-for-service processing where possible --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 58 ++++++++++++++++--- 1 file changed, 50 insertions(+), 8 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 1ce079265e..b53e539b1e 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -183,6 +183,7 @@ hook_listInstances_raw="" hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" +hook_getSavedDeviceName="" hook_getSavedMD5="" hook_setSavedMD5="" hook_restart_upsd="" @@ -198,6 +199,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validInstanceName="smf_validInstanceName" hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" + hook_getSavedDeviceName="smf_getSavedDeviceName" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" hook_restart_upsd="smf_restart_upsd" @@ -212,6 +214,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validInstanceName="systemd_validInstanceName" hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" + hook_getSavedDeviceName="systemd_getSavedDeviceName" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" hook_restart_upsd="systemd_restart_upsd" @@ -226,6 +229,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validInstanceName="selftest_NOOP" hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" + hook_getSavedDeviceName="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" hook_restart_upsd="selftest_NOOP" @@ -650,6 +654,22 @@ smf_getSavedMD5() { # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } +smf_getSavedDeviceName() { + # Query service instance $1 + PG="nut-driver-enumerator-generated-devicename" + PROP="DEVICE" + + if [ -n "$1" ]; then + TARGET_FMRI="nut-driver:$1" + else + # Global section + echo "" + return 0 + fi + + # Note: lookups for GLOBAL cause each service instance to show up + /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' +} smf_setSavedUniq() ( # Save data value $5 of type $4 into service FMRI $1 # under (scrapped and) newly created property group $2 @@ -761,7 +781,7 @@ EOF fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" - _systemd_setSavedDevice "$SVCINST" "$DEVICE" + _systemd_setSavedDeviceName "$SVCINST" "$DEVICE" if [ "$AUTO_START" = yes ] ; then $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return @@ -791,15 +811,26 @@ systemd_getSavedMD5() { # Query service instance $1 or global section PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" - [ -s "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" ] \ - && grep "Environment='$PROP=" "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ - || { echo "Did not find '${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf' with a $PROP" ; return 1; } + PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" + [ -s "${PROPFILE}" ] \ + && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ + || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } +} +systemd_getSavedDeviceName() { + # Query service instance $1 or global section + [ -n "$1" ] || { echo ""; return 0; } + PROP="DEVICE" + PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" + [ -s "${PROPFILE}" ] \ + && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ + || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } -_systemd_setSavedDevice() { +_systemd_setSavedDeviceName() { # Save device (config section) name $2 into service instance $1 [ -n "$1" ] || return + PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ - cat > "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" << EOF + cat > "${PROPFILE}" << EOF [Service] Environment='DEVICE="$2"' EOF @@ -809,8 +840,9 @@ systemd_setSavedMD5() { # Save checksum value $2 into service instance $1 PROP="SECTION_CHECKSUM" [ -n "$1" ] || PROP="SECTION_CHECKSUM_GLOBAL" + PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ - cat > "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-checksum.conf" << EOF + cat > "${PROPFILE}" << EOF [Service] Environment='$PROP=$2' EOF @@ -1394,7 +1426,15 @@ while [ $# -gt 0 ]; do ;; --get-device-for-service) [ -z "$2" ] && echo "Service (instance) name argument required" >&2 && exit 1 # Instance name can be a hash or "native" NUT section name - SVC="`$hook_validInstanceSuffixName "$2"`" + SVC="`$hook_validInstanceSuffixName "$2"`" && [ -n "$SVC" ] \ + || { echo "Error getting SVC name from the inputs" >&2 ; exit 1; } + + # Reading the config is too expensive do do for every + # driver management attempt when there are many devices + # Try to use last-stashed values from service properties first + INST="`$hook_getSavedDeviceName "$SVC"`" || INST="" + [ -z "$INST" ] || { echo "$INST" ; exit 0 ; } + case "$SVC" in MD5_*) ;; # fall through to the bulk of code *) upslist_readFile_once || exit $? @@ -1402,6 +1442,8 @@ while [ $# -gt 0 ]; do exit $? ;; esac + + # Inspect SVC=MD5_* usecase FINAL_RES=0 OUT="`"$0" --list-services-for-devices`" && [ -n "$OUT" ] || FINAL_RES=$? if [ "$FINAL_RES" = 0 ]; then From cda04ef9a56e952aee94390fb162893083d4cd14 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 14:06:04 +0100 Subject: [PATCH 12/31] nut-driver-enumerator.sh.in : standardize hook_setSavedDeviceName() --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index b53e539b1e..61fd1d60d9 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -184,6 +184,7 @@ hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" hook_getSavedDeviceName="" +hook_setSavedDeviceName="" hook_getSavedMD5="" hook_setSavedMD5="" hook_restart_upsd="" @@ -200,6 +201,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" hook_getSavedDeviceName="smf_getSavedDeviceName" + hook_setSavedDeviceName="smf_setSavedDeviceName" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" hook_restart_upsd="smf_restart_upsd" @@ -215,6 +217,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" hook_getSavedDeviceName="systemd_getSavedDeviceName" + hook_setSavedDeviceName="systemd_setSavedDeviceName" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" hook_restart_upsd="systemd_restart_upsd" @@ -230,6 +233,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" hook_getSavedDeviceName="selftest_NOOP" + hook_setSavedDeviceName="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" hook_restart_upsd="selftest_NOOP" @@ -614,7 +618,7 @@ smf_registerInstance() { smf_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" # Save original device (config section) name to speed up some searches - smf_setSavedUniq "$TARGET_FMRI" "nut-driver-enumerator-generated-devicename" "DEVICE" astring "$DEVICE" + smf_setSavedDeviceName "$SVCINST" "$DEVICE" /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return if [ "$AUTO_START" = yes ] ; then @@ -711,6 +715,10 @@ smf_setSavedMD5() ( fi smf_setSavedUniq "$TARGET_FMRI" "$PG" "$PROP" astring "$2" ) +smf_setSavedDeviceName() { + [ -n "$1" ] || return # No-op for global section + smf_setSavedUniq "nut-driver:$1" "nut-driver-enumerator-generated-devicename" "DEVICE" astring "$2" +} smf_restart_upsd() { echo "Restarting NUT data server to make sure it knows new configuration..." /usr/sbin/svcadm enable "nut-server" 2>/dev/null @@ -781,7 +789,7 @@ EOF fi systemd_setSavedMD5 "$SVCINST" "`upsconf_getSection_MD5 "$DEVICE"`" - _systemd_setSavedDeviceName "$SVCINST" "$DEVICE" + systemd_setSavedDeviceName "$SVCINST" "$DEVICE" if [ "$AUTO_START" = yes ] ; then $TIMEOUT_CMD $TIMEOUT_ARGS /bin/systemctl start --no-block 'nut-driver@'"$SVCINST".service || return @@ -825,9 +833,9 @@ systemd_getSavedDeviceName() { && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } -_systemd_setSavedDeviceName() { +systemd_setSavedDeviceName() { # Save device (config section) name $2 into service instance $1 - [ -n "$1" ] || return + [ -n "$1" ] || return # No-op for global section PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" mkdir -p "${SYSTEMD_CONFPATH}/nut-driver@$1.service.d" && \ cat > "${PROPFILE}" << EOF From 57d5f36a0d39fc28aadcad0b3e7866a76133f153 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 14:09:04 +0100 Subject: [PATCH 13/31] nut-driver-enumerator.sh.in : use hook_getSavedDeviceName() to speed up --get-device-for-service processing where possible (typo fix) --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 61fd1d60d9..fa8738f5fa 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1437,7 +1437,7 @@ while [ $# -gt 0 ]; do SVC="`$hook_validInstanceSuffixName "$2"`" && [ -n "$SVC" ] \ || { echo "Error getting SVC name from the inputs" >&2 ; exit 1; } - # Reading the config is too expensive do do for every + # Reading the config is too expensive to do for every # driver management attempt when there are many devices # Try to use last-stashed values from service properties first INST="`$hook_getSavedDeviceName "$SVC"`" || INST="" From 5054ce2d7efb3927faf4d62e05dc678c8d7b4a78 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 16:21:38 +0100 Subject: [PATCH 14/31] nut-driver-enumerator.sh.in : introduce hook_findSavedDeviceName() for faster --get-service-for-device processing --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index fa8738f5fa..cfbd2699d5 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -184,6 +184,7 @@ hook_validInstanceName="" hook_validFullUnitName="" hook_validInstanceSuffixName="" hook_getSavedDeviceName="" +hook_findSavedDeviceName="" hook_setSavedDeviceName="" hook_getSavedMD5="" hook_setSavedMD5="" @@ -201,6 +202,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validFullUnitName="smf_validFullUnitName" hook_validInstanceSuffixName="smf_validInstanceSuffixName" hook_getSavedDeviceName="smf_getSavedDeviceName" + hook_findSavedDeviceName="smf_findSavedDeviceName" hook_setSavedDeviceName="smf_setSavedDeviceName" hook_getSavedMD5="smf_getSavedMD5" hook_setSavedMD5="smf_setSavedMD5" @@ -217,6 +219,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validFullUnitName="systemd_validFullUnitName" hook_validInstanceSuffixName="systemd_validInstanceSuffixName" hook_getSavedDeviceName="systemd_getSavedDeviceName" + hook_findSavedDeviceName="systemd_findSavedDeviceName" hook_setSavedDeviceName="systemd_setSavedDeviceName" hook_getSavedMD5="systemd_getSavedMD5" hook_setSavedMD5="systemd_setSavedMD5" @@ -233,6 +236,7 @@ case "${SERVICE_FRAMEWORK-}" in hook_validFullUnitName="selftest_NOOP" hook_validInstanceSuffixName="selftest_NOOP" hook_getSavedDeviceName="selftest_NOOP" + hook_findSavedDeviceName="selftest_NOOP" hook_setSavedDeviceName="selftest_NOOP" hook_getSavedMD5="selftest_NOOP" hook_setSavedMD5="selftest_NOOP" @@ -658,6 +662,19 @@ smf_getSavedMD5() { # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } +smf_findSavedDeviceName() { + # Returns long service FMRI which has DEVICE=="$1" + # For empty "$1" returns a list of all recorded "FMRIDEVICE" + if [ -z "$1" ]; then + /usr/bin/svcprop -p "nut-driver-enumerator-generated-devicename/DEVICE" \ + 'svc:/system/power/nut-driver:*' 2>/dev/null \ + | sed 's|^\(svc:/[^:]*:[^/:]*\)/:properties/nut-driver-enumerator-generated-devicename/DEVICE astring \(.*\)$|\1\t\2|' + else + /usr/bin/svcprop -p "nut-driver-enumerator-generated-devicename/DEVICE" \ + "svc:/system/power/nut-driver:$1" 2>/dev/null \ + | sed 's|^\(svc:/[^:]*:[^/:]*\)/:prop.*$|\1|' + fi +} smf_getSavedDeviceName() { # Query service instance $1 PG="nut-driver-enumerator-generated-devicename" @@ -824,6 +841,19 @@ systemd_getSavedMD5() { && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } +systemd_findSavedDeviceName() { + # Returns long service instance name which has DEVICE=="$1" + # For empty "$1" returns a list of all recorded "SVCDEVICE" + if [ -z "$1" ]; then + grep -H "Environment='DEVICE=" \ + /etc/systemd/system/nut-driver@.service.d/nut-driver-enumerator-generated-devicename.conf \ + | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*DEVICE='"[\"']*"'\(.*\)'"[\"']*"'$|\1\t\2|' + else + grep -H "Environment='DEVICE=$1'" \ + /etc/systemd/system/nut-driver@.service.d/nut-driver-enumerator-generated-devicename.conf \ + | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*$|\1|' + fi +} systemd_getSavedDeviceName() { # Query service instance $1 or global section [ -n "$1" ] || { echo ""; return 0; } @@ -1401,6 +1431,10 @@ while [ $# -gt 0 ]; do ;; --get-service-for-device) [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 DEV="$2" + # Cheap check in service instance metadata, if saved + SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" + [ -z "$SAVEDSVC" ] || { echo "$SAVEDSVC" ; exit 0 ; } + # Trawl all the data we have... upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ || { echo "No service instances detected" >&2 ; exit 1; } UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ @@ -1440,8 +1474,8 @@ while [ $# -gt 0 ]; do # Reading the config is too expensive to do for every # driver management attempt when there are many devices # Try to use last-stashed values from service properties first - INST="`$hook_getSavedDeviceName "$SVC"`" || INST="" - [ -z "$INST" ] || { echo "$INST" ; exit 0 ; } + SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" + [ -z "$SAVEDINST" ] || { echo "$SAVEDINST" ; exit 0 ; } case "$SVC" in MD5_*) ;; # fall through to the bulk of code From 0ee0455b236f7eba16d22e46c0a90dbf2bc3e440 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 18:35:11 +0100 Subject: [PATCH 15/31] nut-driver-enumerator.sh.in : to be sure, chop instance names from SMF FMRIs more intensively --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index cfbd2699d5..861e7c0ab0 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -644,7 +644,8 @@ smf_listInstances_raw() { /usr/bin/svcs -a -H -o fmri | egrep '/nut-driver:' } smf_listInstances() { - smf_listInstances_raw | sed 's/^.*://' | sort -n + # Chop twice, in case there is a leading "svc:/...." + smf_listInstances_raw | sed -e 's/^.*://' -e 's/^.*://' | sort -n } smf_getSavedMD5() { # Query service instance $1 From 0a04a33076b1aa1bf73f382b55e4304216adad4f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 18:36:01 +0100 Subject: [PATCH 16/31] nut-driver-enumerator.sh.in : comment that we trust hook_getSavedDeviceName data to be consistent (ensuring it is is expensive and belongs elsewhere) --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 861e7c0ab0..70473fdbf3 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1433,6 +1433,7 @@ while [ $# -gt 0 ]; do --get-service-for-device) [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 DEV="$2" # Cheap check in service instance metadata, if saved + # (NOTE: saved value is assumed to be valid if present) SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" [ -z "$SAVEDSVC" ] || { echo "$SAVEDSVC" ; exit 0 ; } # Trawl all the data we have... @@ -1475,6 +1476,7 @@ while [ $# -gt 0 ]; do # Reading the config is too expensive to do for every # driver management attempt when there are many devices # Try to use last-stashed values from service properties first + # (NOTE: saved value is assumed to be valid if present) SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" [ -z "$SAVEDINST" ] || { echo "$SAVEDINST" ; exit 0 ; } From a8e5a498a02130cadf573c2306742d4a016a5400 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 19:06:03 +0100 Subject: [PATCH 17/31] nut-driver-enumerator.sh.in : introduce upslist_savednames_missing() and upslist_savednames_find_mismatch() to upgrade entries without saved names --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 70473fdbf3..e1faf2ae19 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -350,6 +350,50 @@ ${_SVC}" ; } return 1 } +upslist_savednames_find_missing() { + # Verify that all existing service units have a saved DEVICE name + # Report those that do not have a value there (any value) so we can + # amend those quickly after an upgrade. Otherwise we trust these. + + # Get full instance names from system and from props + SVCINSTS="`$hook_listInstances_raw`" && [ -n "$SVCINSTS" ] || return 1 + # If no props were found, (over)write them all + SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ -n "$SVCINST_PROPS" ] \ + || { echo $SVCINSTS ; return 2; } + + # Find services which do not have saved names in props + for SVCINST in $SVCINSTS ; do + echo "$SVCINST_PROPS" | egrep "^${SVCINST_PROPS}\t"'$' >/dev/null || echo "$SVCINST" + done +} + +upslist_savednames_find_mismatch() { + # TODO: Make use of this to fsck the enumerator configs + # + # Verify that all existing service units have a saved DEVICE name + # and that such name does match the unit instance's name (original + # or MD5 normalized version). If something does not match, returns + # the unit name so it can be redefined by caller. This does not + # inspect whether such DEVICE is defined in NUT configuration. + # This situation might occur in some errors, but the likely case + # is updating from versions that did not track this info yet (but + # upslist_savednames_find_missing() should have handled those). + + # Get full instance names from system and from props + SVCINSTS="`$hook_listInstances_raw`" && [ -n "$SVCINSTS" ] || return 1 + SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ -n "$SVCINST_PROPS" ] || return 2 + + # Find services whose props exist but services do not + echo "$SVCINST_PROPS" | while read SVCINST_PROP DEVNAME_PROP ; do + echo "$SVCINSTS" | egrep "^${SVCINST_PROP}"'$' >/dev/null || echo "$SVCINST_PROP" + done + + # Find services which do not have saved names in props + for SVCINST in $SVCINSTS ; do + echo "$SVCINST_PROPS" | egrep "^${SVCINST_PROP}\t"'$' >/dev/null || echo "$SVCINST" + done +} + upsconf_getSection_content() { # "$1" = name of ups.conf section to display in whole, from whatever # comes on stdin (file or a pre-made normalized variable) @@ -1572,6 +1616,14 @@ while [ $# -gt 0 ]; do upslist_debug exit $? ;; + upslist_savednames_find_missing) # Not public, not in usage() + upslist_savednames_find_missing + exit $? + ;; + upslist_savednames_find_mismatch) # Not public, not in usage() + upslist_savednames_find_mismatch + exit $? + ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift From 2ddea8dc5e3d0bd0d16df10d2e1c8bc643e9f32b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 20:52:34 +0100 Subject: [PATCH 18/31] nut-driver-enumerator.sh.in : refactor list_services_for_devices(_once) and get_device_for_service() into routines --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 166 +++++++++++------- 1 file changed, 98 insertions(+), 68 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index e1faf2ae19..3158243e76 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1235,6 +1235,97 @@ nut_driver_enumerator_main() { return 13 } +list_services_for_devices() { + FINAL_RES=0 + upslist_readFile_once && [ -n "$UPSLIST_FILE" ] \ + || { echo "No devices detected in '$UPSCONF'" >&2 ; return 1 ; } + upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ + || { echo "No service instances detected" >&2 ; return 1; } + UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ + || { echo "No service units detected" >&2 ; return 1; } + for DEV in $UPSLIST_FILE ; do + vINST="`$hook_validInstanceName "$DEV"`" + vUNITD="`$hook_validFullUnitName "$DEV"`" + vUNITI="`$hook_validFullUnitName "$vINST"`" + # First pass over simple verbatim names + for INST in $UPSLIST_SVCS ; do + if [ "$INST" = "$DEV" ] ; then + for UNIT in $UPSLIST_SVCS_RAW ; do + if [ "$UNIT" = "$vUNITD" ] ; then + printf '%s\t%s\n' "$UNIT" "$DEV" + continue 3 + fi + done + fi + done + for INST in $UPSLIST_SVCS ; do + if [ "$INST" = "$vINST" ] ; then + for UNIT in $UPSLIST_SVCS_RAW ; do + if [ "$UNIT" = "$vUNITI" ] ; then + printf '%s\t%s\n' "$UNIT" "$DEV" + continue 3 + fi + done + fi + done + echo "WARNING: no service instances detected that match device '$DEV'" >&2 + FINAL_RES=1 + done + return $FINAL_RES +} + +SVCS_DEVS_LIST="" +list_services_for_devices_once() { + # On first call, caches the system reponse + # On next calls returns what it got earlier + # Does not return any text, just the exit code + # (0 = data avail, even if empty, in SVCS_DEVS_LIST) + [ "${#SVCS_DEVS_LIST}" != 0 ] && return + + # Pre-cache config file data, if nobody read it yet, + # and keep in main script context for reuse (no subshell) + upslist_readFile_once && \ + SVCS_DEVS_LIST="`list_services_for_devices "$@"`" || return $? +} + +get_device_for_service() { + [ -z "$1" ] && echo "Service (instance) name argument required" >&2 && return 1 + + # Instance name can be a hash or "native" NUT section name + SVC="`$hook_validInstanceSuffixName "$1"`" && [ -n "$SVC" ] \ + || { echo "Error getting SVC name from the inputs" >&2 ; return 1; } + + # Reading the config is too expensive to do for every + # driver management attempt when there are many devices + if [ "${USE_SAVEDINST-}" != false ]; then + # Try to use last-stashed values from service properties first + # (NOTE: saved value is assumed to be valid if present) + SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" + [ -z "$SAVEDINST" ] || { echo "$SAVEDINST" ; return 0 ; } + fi + + case "$SVC" in + MD5_*) ;; # fall through to the bulk of code + *) upslist_readFile_once || return $? + echo "$UPSLIST_FILE" | egrep "^$SVC\$" + return $? + ;; + esac + + # Inspect SVC=MD5_* usecase + FINAL_RES=0 + list_services_for_devices_once && [ -n "$SVCS_DEVS_LIST" ] || FINAL_RES=$? + if [ "$FINAL_RES" = 0 ]; then + echo "$SVCS_DEVS_LIST" | grep "$SVC" | ( \ + while read _SVC _DEV ; do + _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit + [ "${_SVC}" = "${SVC}" ] && echo "${_DEV}" && exit 0 + done ; exit 1 ) && return 0 + fi + echo "No service instance '$1' was detected that matches a NUT device" >&2 + return 1 +} + RECONFIGURE_ASAP=false trap_handle_hup_main() { echo "`date -u` : Received a HUP during processing, scheduling reconfiguration to repeat ASAP (after the current iteration is done)" >&2 @@ -1512,76 +1603,15 @@ while [ $# -gt 0 ]; do echo "No service instances detected that match device '$2'" >&2 exit 1 ;; - --get-device-for-service) [ -z "$2" ] && echo "Service (instance) name argument required" >&2 && exit 1 - # Instance name can be a hash or "native" NUT section name - SVC="`$hook_validInstanceSuffixName "$2"`" && [ -n "$SVC" ] \ - || { echo "Error getting SVC name from the inputs" >&2 ; exit 1; } - - # Reading the config is too expensive to do for every - # driver management attempt when there are many devices - # Try to use last-stashed values from service properties first - # (NOTE: saved value is assumed to be valid if present) - SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" - [ -z "$SAVEDINST" ] || { echo "$SAVEDINST" ; exit 0 ; } - - case "$SVC" in - MD5_*) ;; # fall through to the bulk of code - *) upslist_readFile_once || exit $? - echo "$UPSLIST_FILE" | egrep "^$SVC\$" - exit $? - ;; - esac - - # Inspect SVC=MD5_* usecase - FINAL_RES=0 - OUT="`"$0" --list-services-for-devices`" && [ -n "$OUT" ] || FINAL_RES=$? - if [ "$FINAL_RES" = 0 ]; then - echo "$OUT" | grep "$SVC" | ( \ - while read _SVC _DEV ; do - _SVC="`$hook_validInstanceSuffixName "${_SVC}"`" || exit - [ "${_SVC}" = "${SVC}" ] && echo "${_DEV}" && exit 0 - done ; exit 1 ) && exit 0 - fi - echo "No service instance '$2' was detected that matches a NUT device" >&2 - exit 1 + --get-device-for-service) + shift + get_device_for_service "$@" + exit $? ;; --list-services-for-devices) - FINAL_RES=0 - upslist_readFile_once && [ -n "$UPSLIST_FILE" ] \ - || { echo "No devices detected in '$UPSCONF'" >&2 ; exit 1 ; } - upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ - || { echo "No service instances detected" >&2 ; exit 1; } - UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ - || { echo "No service units detected" >&2 ; exit 1; } - for DEV in $UPSLIST_FILE ; do - vINST="`$hook_validInstanceName "$DEV"`" - vUNITD="`$hook_validFullUnitName "$DEV"`" - vUNITI="`$hook_validFullUnitName "$vINST"`" - # First pass over simple verbatim names - for INST in $UPSLIST_SVCS ; do - if [ "$INST" = "$DEV" ] ; then - for UNIT in $UPSLIST_SVCS_RAW ; do - if [ "$UNIT" = "$vUNITD" ] ; then - printf '%s\t%s\n' "$UNIT" "$DEV" - continue 3 - fi - done - fi - done - for INST in $UPSLIST_SVCS ; do - if [ "$INST" = "$vINST" ] ; then - for UNIT in $UPSLIST_SVCS_RAW ; do - if [ "$UNIT" = "$vUNITI" ] ; then - printf '%s\t%s\n' "$UNIT" "$DEV" - continue 3 - fi - done - fi - done - echo "WARNING: no service instances detected that match device '$DEV'" >&2 - FINAL_RES=1 - done - exit $FINAL_RES + shift + list_services_for_devices "$@" + exit $? ;; --show-configs|--show-device-configs|--show-all-configs|--show-all-device-configs) RES=0 From 75bb1c0805e347feec1cf40c850052aca8a61c6b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 21:05:30 +0100 Subject: [PATCH 19/31] nut-driver-enumerator.sh.in : added update_upslist_savednames_find_missing() into single-run and daemonized modes, to update inconsistent configs --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 3158243e76..06c51ec5e2 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1326,6 +1326,35 @@ get_device_for_service() { return 1 } +update_upslist_savednames_find_missing() { + # Runs once in production modes that inspect and reconcile + # configs, to handle upgraded NUT deployments + SVCINSTS_NO_DEVICE="`upslist_savednames_find_missing`" || \ + case "$?" in + 1) return 0 ;; # No services defined yet + 2) ;; # All service units do not have DEVICE values + esac + # Something found... or not? Or all is populated? + [ -n "$SVCINSTS_NO_DEVICE" ] || return 0 + + # Make a list of what devices are known in config matched + # to service instances defined in the system, if any + # Note to not check the service instance properties which + # we are validating and currently to not quite trust. + USE_SAVEDINST=false list_services_for_devices_once && [ -n "$SVCS_DEVS_LIST" ] || return 0 + + # Go over services with no device value saved into properties, + # and write the values learned from mapping above + _MISSING_RES=0 + for SVCINST in $SVCINSTS_NO_DEVICE ; do + _DEV="`printf '%s\n' "$SVCS_DEVS_LIST" | awk '( \$1 == "'"${SVCINST}"'" ) {print \$NF}'`" + echo "Service instance '$SVCINST' did not have a device recorded into properties, setting to '${_DEV}'" + [ -n "${_DEV}" ] || { echo "The device name value for '$SVCINST' is empty, skipping" >&2 ; _MISSING_RES=1 ; continue ; } + $hook_setSavedDeviceName "`$hook_validInstanceSuffixName "$SVCINST"`" "${_DEV}" || _MISSING_RES=$? + done + return ${_MISSING_RES} +} + RECONFIGURE_ASAP=false trap_handle_hup_main() { echo "`date -u` : Received a HUP during processing, scheduling reconfiguration to repeat ASAP (after the current iteration is done)" >&2 @@ -1359,6 +1388,8 @@ daemonize() { RECONFIGURE_ASAP=false trap 'trap_handle_hup_main' $RECONFIGURATION_SIGNALS + update_upslist_savednames_find_missing + # Note: this loop would die on errors with config file or # inability to ensure that it matches the list of services. # If caller did not `export REPORT_RESTART_42=no` then the @@ -1395,6 +1426,7 @@ UPSCONF_CHECKSUM_START="`calc_md5_file "$UPSCONF"`" || true # By default, update wrapping of devices into services if [ $# = 0 ]; then + update_upslist_savednames_find_missing nut_driver_enumerator_main ; exit $? fi @@ -1654,6 +1686,10 @@ while [ $# -gt 0 ]; do upslist_savednames_find_mismatch exit $? ;; + update_upslist_savednames_find_missing) # Not public, not in usage() + update_upslist_savednames_find_missing + exit $? + ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift From bf6d51b75f6e4ae321508ade893ce65245331441 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 21:44:38 +0100 Subject: [PATCH 20/31] nut-driver-enumerator.sh.in : refactor get_service_for_device() into a routine --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 88 +++++++++++-------- 1 file changed, 51 insertions(+), 37 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 06c51ec5e2..0f5b13ef3d 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1326,6 +1326,53 @@ get_device_for_service() { return 1 } +get_service_for_device() { + DEV="$1" + [ -z "$DEV" ] && echo "Device name argument required" >&2 && return 1 + + # Cheap check in service instance metadata, if saved + # (NOTE: saved value is assumed to be valid if present) + if [ "${USE_SAVEDSVC-}" != false ]; then + SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" + [ -z "$SAVEDSVC" ] || { echo "$SAVEDSVC" ; return 0 ; } + fi + + # Trawl all the data we have... + # TODO: Reorder to avoid extra parsing if we have an early hit? + upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ + || { echo "No service instances detected" >&2 ; return 1; } + UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ + || { echo "No service units detected" >&2 ; return 1; } + vINST="`$hook_validInstanceName "$DEV"`" + vUNITD="`$hook_validFullUnitName "$DEV"`" + vUNITI="`$hook_validFullUnitName "$vINST"`" + + # First pass over simple verbatim names + for INST in $UPSLIST_SVCS ; do + if [ "$INST" = "$DEV" ] ; then + for UNIT in $UPSLIST_SVCS_RAW ; do + if [ "$UNIT" = "$vUNITD" ] ; then + echo "$UNIT" + return 0 + fi + done + fi + done + # Second pass over other options + for INST in $UPSLIST_SVCS ; do + if [ "$INST" = "$vINST" ] ; then + for UNIT in $UPSLIST_SVCS_RAW ; do + if [ "$UNIT" = "$vUNITI" ] ; then + echo "$UNIT" + return 0 + fi + done + fi + done + echo "No service instances detected that match device '$DEV'" >&2 + return 1 +} + update_upslist_savednames_find_missing() { # Runs once in production modes that inspect and reconcile # configs, to handle upgraded NUT deployments @@ -1597,43 +1644,10 @@ while [ $# -gt 0 ]; do echo "No service instances detected" >&2 exit 1 ;; - --get-service-for-device) [ -z "$2" ] && echo "Device name argument required" >&2 && exit 1 - DEV="$2" - # Cheap check in service instance metadata, if saved - # (NOTE: saved value is assumed to be valid if present) - SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" - [ -z "$SAVEDSVC" ] || { echo "$SAVEDSVC" ; exit 0 ; } - # Trawl all the data we have... - upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ - || { echo "No service instances detected" >&2 ; exit 1; } - UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ - || { echo "No service units detected" >&2 ; exit 1; } - vINST="`$hook_validInstanceName "$DEV"`" - vUNITD="`$hook_validFullUnitName "$DEV"`" - vUNITI="`$hook_validFullUnitName "$vINST"`" - # First pass over simple verbatim names - for INST in $UPSLIST_SVCS ; do - if [ "$INST" = "$DEV" ] ; then - for UNIT in $UPSLIST_SVCS_RAW ; do - if [ "$UNIT" = "$vUNITD" ] ; then - echo "$UNIT" - exit 0 - fi - done - fi - done - for INST in $UPSLIST_SVCS ; do - if [ "$INST" = "$vINST" ] ; then - for UNIT in $UPSLIST_SVCS_RAW ; do - if [ "$UNIT" = "$vUNITI" ] ; then - echo "$UNIT" - exit 0 - fi - done - fi - done - echo "No service instances detected that match device '$2'" >&2 - exit 1 + --get-service-for-device) + shift + get_service_for_device "$@" + exit $? ;; --get-device-for-service) shift From 01559c38df4b406aa5165b24a49cb9e7c0fbf8b5 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 29 Mar 2019 21:55:23 +0100 Subject: [PATCH 21/31] nut-driver-enumerator.sh.in : refactor nut_driver_enumerator_full_reconfigure() into a routine --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 129 +++++++++--------- 1 file changed, 68 insertions(+), 61 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 0f5b13ef3d..159cd9574b 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1235,6 +1235,72 @@ nut_driver_enumerator_main() { return 13 } +nut_driver_enumerator_full_reconfigure() { + # Similar to the main routine for reconciling data, + # but this one removes all service instances and + # defines current mappings from scratch after that + upslist_readFile_once || return $? + upslist_readSvcs "before manipulations" + + if [ -n "$UPSLIST_SVCS" ]; then + for UPSS in $UPSLIST_SVCS ; do + echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 + $hook_unregisterInstance "$UPSS" + done + upslist_readSvcs "after dropping" + fi + if [ -n "$UPSLIST_FILE" ]; then + upslist_addSvcs + upslist_readSvcs "after checking for new config sections to define service instances" + fi + + # Save new checksum of global config + $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" + + # Service units were manipulated, including saving of checksums; + # refresh the service management daemon if needed + $hook_refreshSupervizor + + if [ -n "$UPSLIST_SVCS" ] ; then + echo "=== The currently defined service instances are:" + echo "$UPSLIST_SVCS" + fi + + if [ -n "$UPSLIST_FILE" ] ; then + echo "=== The currently defined configurations in '$UPSCONF' are:" + echo "$UPSLIST_FILE" + fi + + # We had some changes to the config file; upsd must be made aware + if [ "$AUTO_START" = yes ] ; then + $hook_restart_upsd + fi + + # Return 42 if there was a change applied succesfully + # (but e.g. some services should restart - upsd, maybe upsmon) + UPSLIST_EQ_RES=0 + upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? + + # File processing and service startups take a while; + # make sure upsconf did not change while we worked... + # NOTE: Check this at the last moment to minimize + # the chance of still not noticing the change made + # at just the wrong moment. + UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true + if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then + echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up and reconcile the late-coming changes" + nut_driver_enumerator_main ; return $? + # The "main" routine will do REPORT_RESTART_42 logic too + fi + + if [ "$UPSLIST_EQ_RES" = 0 ] ; then + echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" + [ "${REPORT_RESTART_42-}" = no ] && return 0 || return 42 + fi + + return 13 +} + list_services_for_devices() { FINAL_RES=0 upslist_readFile_once && [ -n "$UPSLIST_FILE" ] \ @@ -1552,67 +1618,8 @@ while [ $# -gt 0 ]; do --help|-h|-help) usage; exit 0 ;; --get-service-framework) echo "${SERVICE_FRAMEWORK}" ; exit 0 ;; --reconfigure) - upslist_readFile_once || exit $? - upslist_readSvcs "before manipulations" - - if [ -n "$UPSLIST_SVCS" ]; then - for UPSS in $UPSLIST_SVCS ; do - echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 - $hook_unregisterInstance "$UPSS" - done - upslist_readSvcs "after dropping" - fi - - if [ -n "$UPSLIST_FILE" ]; then - upslist_addSvcs - upslist_readSvcs "after checking for new config sections to define service instances" - fi - - # Save new checksum of global config - $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" - - # Service units were manipulated, including saving of checksums; - # refresh the service management daemon if needed - $hook_refreshSupervizor - - if [ -n "$UPSLIST_SVCS" ] ; then - echo "=== The currently defined service instances are:" - echo "$UPSLIST_SVCS" - fi - - if [ -n "$UPSLIST_FILE" ] ; then - echo "=== The currently defined configurations in '$UPSCONF' are:" - echo "$UPSLIST_FILE" - fi - - # We had some changes to the config file; upsd must be made aware - if [ "$AUTO_START" = yes ] ; then - $hook_restart_upsd - fi - - # Return 42 if there was a change applied succesfully - # (but e.g. some services should restart - upsd, maybe upsmon) - UPSLIST_EQ_RES=0 - upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" || UPSLIST_EQ_RES=$? - - # File processing and service startups take a while; - # make sure upsconf did not change while we worked... - # NOTE: Check this at the last moment to minimize - # the chance of still not noticing the change made - # at just the wrong moment. - UPSCONF_CHECKSUM_END="`calc_md5_file "$UPSCONF"`" || true - if [ "$UPSCONF_CHECKSUM_END" != "$UPSCONF_CHECKSUM_START" ] ; then - echo "`date -u` : '$UPSCONF' changed while $0 $* was processing its older contents; re-running the script to pick up the late-coming changes" - $0 ; exit $? - # The "main" routine will do REPORT_RESTART_42 logic too - fi - - if [ "$UPSLIST_EQ_RES" = 0 ] ; then - echo "`date -u` : OK: No more changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" - [ "${REPORT_RESTART_42-}" = no ] && exit 0 || exit 42 - fi - - exit 13 + nut_driver_enumerator_full_reconfigure "$@" + exit $? ;; --list-devices) upslist_readFile_once && \ From d030df6f0c817bcffa38ae262b1c8abb1c246582 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 1 Apr 2019 11:37:32 +0200 Subject: [PATCH 22/31] nut-driver-enumerator.sh.in man/nut-driver-enumerator.txt : document --daemon-after mode --- docs/man/nut-driver-enumerator.txt | 6 ++++++ scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 7 ++++--- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/docs/man/nut-driver-enumerator.txt b/docs/man/nut-driver-enumerator.txt index 72e50df3c3..725691b512 100644 --- a/docs/man/nut-driver-enumerator.txt +++ b/docs/man/nut-driver-enumerator.txt @@ -51,6 +51,12 @@ Update wrapping of devices into services Update wrapping of devices into services in an infinite loop; Default freq is 60 sec. +*nut-driver-enumerator.sh --daemon-after(=freq)*:: +Update wrapping of devices into services in an infinite loop; +first do one run of the loop though, then daemonize (this way +service unit is deemed started only when NUT config and driver +instances are in sync). Default freq is 60 sec. + *nut-driver-enumerator.sh --reconfigure*:: Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 159cd9574b..aa6d6f32b0 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1572,9 +1572,10 @@ $0 --daemon(=freq) Update wrapping of devices into services in an infinite loop Default freq is 60 sec $0 --daemon-after(=freq) - Update wrapping of devices into services in an infinite loop - First do one run of the loop though - Default freq is 60 sec + Update wrapping of devices into services in an infinite loop; + first do one run of the loop though, then daemonize (this way + service unit is deemed started only when NUT config and driver + instances are in sync). Default freq is 60 sec. $0 --reconfigure Stop and un-register all service instances and recreate them (e.g. if new dependency template was defined in a new From 8593085393820b8b107f8b0f45ec1811a3207c7b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 1 Apr 2019 12:09:05 +0200 Subject: [PATCH 23/31] nut.dict : add "daemonize" --- docs/nut.dict | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/nut.dict b/docs/nut.dict index 3d915a902e..1c7ba09b06 100644 --- a/docs/nut.dict +++ b/docs/nut.dict @@ -1,4 +1,4 @@ -personal_ws-1.1 en 2475 utf-8 +personal_ws-1.1 en 2476 utf-8 AAS ACFAIL ACFREQ @@ -1396,6 +1396,7 @@ cx cyberpower d'un da +daemonize daisychain daisychained datacenter From 1a40ad7e839cd41a3a350e362a1bf5cf238e3273 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Fri, 5 Apr 2019 18:25:17 +0200 Subject: [PATCH 24/31] nut-driver-enumerator.sh.in : typo fix in systemd_findSavedDeviceName() --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index aa6d6f32b0..f6abd5683e 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -891,11 +891,11 @@ systemd_findSavedDeviceName() { # For empty "$1" returns a list of all recorded "SVCDEVICE" if [ -z "$1" ]; then grep -H "Environment='DEVICE=" \ - /etc/systemd/system/nut-driver@.service.d/nut-driver-enumerator-generated-devicename.conf \ + /etc/systemd/system/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*DEVICE='"[\"']*"'\(.*\)'"[\"']*"'$|\1\t\2|' else grep -H "Environment='DEVICE=$1'" \ - /etc/systemd/system/nut-driver@.service.d/nut-driver-enumerator-generated-devicename.conf \ + /etc/systemd/system/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*$|\1|' fi } From d330ce4a9d575c00ddad4668ef29805c05969a47 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 11 Apr 2019 13:49:14 +0200 Subject: [PATCH 25/31] nut-driver-enumerator.sh.in : escape the verbatim dollar in doublequotes --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index f6abd5683e..1e4e9c216f 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -495,7 +495,7 @@ upsconf_getValue() { VALUE="" LINE="`echo "$SECTION_CONTENT" | egrep '(^'"$1"'=|^'"$1"'$)'`" \ - && VALUE="$(echo "$LINE" | sed -e "s,^$1=,," -e 's,^\"\(.*\)\"$,\1,' -e "s,^'\(.*\)'$,\1,")" \ + && VALUE="$(echo "$LINE" | sed -e "s,^$1=,," -e 's,^\"\(.*\)\"$,\1,' -e "s,^'\(.*\)'\$,\1,")" \ || RES_L=$? [ "$RES_L" = 0 ] || { RES="$RES_L" ; echo "ERROR: Section [$CURR_SECTION] or key '$1' in it was not found in the '$UPSCONF' file" >&2 ; } From ee7730e590e2c2363aeb472893cccabe46fb8877 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Thu, 11 Apr 2019 14:27:33 +0200 Subject: [PATCH 26/31] nut-driver-enumerator.sh.in : in systemd_getSavedDeviceName() strip quotes around returned DEVICE == "..." value --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 1e4e9c216f..96badc3211 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -900,12 +900,14 @@ systemd_findSavedDeviceName() { fi } systemd_getSavedDeviceName() { - # Query service instance $1 or global section + # Query service instance "$1" (quiet NO-OP if empty, for mis-use + # in global sections context) to get the unquoted saved DEVICE + # section name corresponding to this service instance [ -n "$1" ] || { echo ""; return 0; } PROP="DEVICE" PROPFILE="${SYSTEMD_CONFPATH}/nut-driver@$1.service.d/nut-driver-enumerator-generated-devicename.conf" [ -s "${PROPFILE}" ] \ - && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," \ + && grep "Environment='$PROP=" "${PROPFILE}" | sed -e "s,^Environment='$PROP=,," -e "s,'\$,," -e 's,^"\(.*\)"$,\1,' \ || { echo "Did not find '${PROPFILE}' with a $PROP" ; return 1; } } systemd_setSavedDeviceName() { From a02128987c94966b5a31b34b20d74abab381f12f Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 15 Apr 2019 16:02:21 +0200 Subject: [PATCH 27/31] nut-driver-enumerator.sh.in : avoid sub-shelling and varname clash in smf_setSavedUniq() and smf_setSavedMD5() --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 96badc3211..998ed71121 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -736,47 +736,47 @@ smf_getSavedDeviceName() { # Note: lookups for GLOBAL cause each service instance to show up /usr/bin/svcprop -p "$PG/$PROP" "$TARGET_FMRI" 2>/dev/null | head -1 | awk '{print $NF}' } -smf_setSavedUniq() ( +smf_setSavedUniq() { # Save data value $5 of type $4 into service FMRI $1 # under (scrapped and) newly created property group $2 # and property name $3 - _TARGET_FMRI="$1" - _PG="$2" - _PROP="$3" - _TYPE="$4" - case "${_TYPE}" in + __TARGET_FMRI="$1" + __PG="$2" + __PROP="$3" + __TYPE="$4" + case "${__TYPE}" in *:) ;; - *) _TYPE="${_TYPE}:" ;; + *) __TYPE="${__TYPE}:" ;; esac - _VAL="$5" - /usr/sbin/svccfg -s "${_TARGET_FMRI}" delprop "${_PG}" 2>/dev/null || true - /usr/sbin/svccfg -s "${_TARGET_FMRI}" addpg "${_PG}" application && \ - /usr/sbin/svccfg -s "${_TARGET_FMRI}" setprop "${_PG}/${_PROP}" = "${_TYPE}" "${_VAL}" - [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property ${_PG}/${_PROP}">&2 ; return 1 ; } + __VAL="$5" + /usr/sbin/svccfg -s "${__TARGET_FMRI}" delprop "${__PG}" 2>/dev/null || true + /usr/sbin/svccfg -s "${__TARGET_FMRI}" addpg "${__PG}" application && \ + /usr/sbin/svccfg -s "${__TARGET_FMRI}" setprop "${__PG}/${__PROP}" = "${__TYPE}" "${__VAL}" + [ $? = 0 ] && echo "OK" || { echo "FAILED to stash the service property ${__PG}/${__PROP}">&2 ; return 1 ; } - case "${_TARGET_FMRI}" in + case "${__TARGET_FMRI}" in svc:/*:*) ;; # A service instance by full FMRI, refresh svc:/*/nut-driver|nut-driver) return 0 ;; # A base non-instance service item for nut-driver (known multi-instance only) svc:/*) ;; # A base non-instance service item (not nut-driver) *:*) ;; # A service instance by short FMRI, refresh *) ;; # A base non-instance service item (not nut-driver) esac - /usr/sbin/svcadm refresh "${TARGET_FMRI}" || return -) -smf_setSavedMD5() ( + /usr/sbin/svcadm refresh "${__TARGET_FMRI}" || return +} +smf_setSavedMD5() { # Save checksum value $2 into service instance $1 - PG="nut-driver-enumerator-generated-checksum" - PROP="SECTION_CHECKSUM" + _PG="nut-driver-enumerator-generated-checksum" + _PROP="SECTION_CHECKSUM" if [ -n "$1" ]; then - TARGET_FMRI="nut-driver:$1" + _TARGET_FMRI="nut-driver:$1" else # Global section - TARGET_FMRI="nut-driver" - PROP="SECTION_CHECKSUM_GLOBAL" + _TARGET_FMRI="nut-driver" + _PROP="SECTION_CHECKSUM_GLOBAL" fi - smf_setSavedUniq "$TARGET_FMRI" "$PG" "$PROP" astring "$2" -) + smf_setSavedUniq "${_TARGET_FMRI}" "${_PG}" "${_PROP}" astring "$2" +} smf_setSavedDeviceName() { [ -n "$1" ] || return # No-op for global section smf_setSavedUniq "nut-driver:$1" "nut-driver-enumerator-generated-devicename" "DEVICE" astring "$2" From 6c3668109d8eecbf060eb0c4fe104f6ad785f977 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 15 Apr 2019 16:03:10 +0200 Subject: [PATCH 28/31] nut-driver-enumerator.sh.in : fix systemd_findSavedDeviceName() to return expected values --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 998ed71121..e91cd08e5c 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -892,9 +892,9 @@ systemd_findSavedDeviceName() { if [ -z "$1" ]; then grep -H "Environment='DEVICE=" \ /etc/systemd/system/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ - | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*DEVICE='"[\"']*"'\(.*\)'"[\"']*"'$|\1\t\2|' + | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*DEVICE='"[\"']*\([^\"']*\)[\"']*"'$|\1\t\2|' else - grep -H "Environment='DEVICE=$1'" \ + egrep -H "Environment='DEVICE=($1|\"$1\")'" \ /etc/systemd/system/nut-driver@*.service.d/nut-driver-enumerator-generated-devicename.conf \ | sed 's|^/etc/systemd/system/\(nut-driver@[^/]*\.service\)\.d/.*$|\1|' fi From 688d25724c86ae189fef9abb9dd5e9261e81e0dc Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 15 Apr 2019 16:04:02 +0200 Subject: [PATCH 29/31] nut-driver-enumerator.sh.in : expose for debugging hook_findSavedDeviceName and hook_getSavedDeviceName --- scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index e91cd08e5c..d1ef378741 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1714,6 +1714,8 @@ while [ $# -gt 0 ]; do update_upslist_savednames_find_missing exit $? ;; + hook_findSavedDeviceName) shift ; $hook_findSavedDeviceName "$@" ; exit $? ;; + hook_getSavedDeviceName) shift ; $hook_getSavedDeviceName "$@" ; exit $? ;; *) echo "Unrecognized argument: $1" >&2 ; exit 1 ;; esac shift From 47ee157925e41078fb134218d8f519a1332c14ca Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 15 Apr 2019 16:17:08 +0200 Subject: [PATCH 30/31] nut-driver-enumerator.sh.in : optimize large string-emptiness tests --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 92 ++++++++++--------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index d1ef378741..628ca6a246 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -4,7 +4,10 @@ # NOTE: This script is intentionally written with portable shell constructs # with the aim and hope to work in different interpreters, so it is a # bit dumber and less efficient than could be achieved with the more -# featured shells in the spectrum. +# featured shells in the spectrum. Also, to minimize the in-memory and +# debug-console traffics, tests for (non-)emptiness of anticipated large +# strings are not done by `test -n/-z`, but by counting the size of the +# string (zero or not). # NOTE ALSO: The configuration parser in this script is not meant to be a # reference or 100% compliant with what the binary code uses; its aim # is to just pick out some strings relevant for tracking config changes. @@ -259,7 +262,7 @@ selftest_NOOP() { } common_isFiled() { - [ -n "$UPSLIST_FILE" ] && \ + [ "${#UPSLIST_FILE}" != 0 ] && \ for UPSF in $UPSLIST_FILE ; do [ "$1" = "$UPSF" ] && return 0 [ "`$hook_validInstanceName "$UPSF"`" = "$1" ] && return 0 @@ -268,7 +271,7 @@ common_isFiled() { } common_isRegistered() { - [ -n "$UPSLIST_SVCS" ] && \ + [ "${#UPSLIST_SVCS}" != 0 ] && \ for UPSS in $UPSLIST_SVCS ; do [ "$1" = "$UPSS" ] && return 0 [ "`$hook_validInstanceName "$1"`" = "$UPSS" ] && return 0 @@ -287,8 +290,8 @@ upslist_equals() { # Trivial case 0: one string is empty, another is not # Note: `echo '' | wc -l` == "1" not "0"! - [ -n "$1" -a -z "$2" ] && return 1 - [ -z "$1" -a -n "$2" ] && return 1 + [ "${#1}" != 0 -a "${#2}" = 0 ] && return 1 + [ "${#1}" = 0 -a "${#2}" != 0 ] && return 1 # Trivial case 1: equal strings [ "$1" = "$2" ] && return 0 @@ -301,7 +304,7 @@ upslist_equals() { for _SVC in $2 ; do [ "${_DEV}" = "${_SVC}" ] \ || [ "$DEVINST" = "${_SVC}" ] \ - && { [ -z "${_TMP_DEV_SVC}" ] \ + && { [ "${#_TMP_DEV_SVC}" = 0 ] \ && _TMP_DEV_SVC="${_DEV} = ${_SVC}" \ || _TMP_DEV_SVC="${_TMP_DEV_SVC} ${_DEV} = ${_SVC}" ; } @@ -309,7 +312,7 @@ ${_DEV} = ${_SVC}" ; } done # Input was not empty; did anything in output fit? - [ -z "${_TMP_DEV_SVC}" ] && return 1 + [ "${#_TMP_DEV_SVC}" = 0 ] && return 1 # Exit code : is the built mapping as long as the source list(s)? [ "`echo "$1" | wc -l`" = "`echo "${_TMP_DEV_SVC}" | wc -l`" ] @@ -328,7 +331,7 @@ upslist_checksums_unchanged() { # configuration section from the file and the stashed configuration in # a service instance. Prints a list of mismatching service names that # should get reconfigured. - [ -z "$1" -o -z "$2" ] && return 1 + [ "${#1}" = 0 -o "${#2}" = 0 ] && return 1 _TMP_SVC="" for _DEV in $1 ; do @@ -338,14 +341,14 @@ upslist_checksums_unchanged() { || [ "$DEVINST" = "${_SVC}" ] \ ; then upssvcconf_checksum_unchanged "${_DEV}" "${_SVC}" || \ - { [ -z "${_TMP_SVC}" ] \ + { [ "${#_TMP_SVC}" = 0 ] \ && _TMP_SVC="${_SVC}" \ || _TMP_SVC="${_TMP_SVC} ${_SVC}" ; } fi done done - [ -z "${_TMP_SVC}" ] && return 0 + [ "${#_TMP_SVC}" = 0 ] && return 0 echo "${_TMP_SVC}" return 1 } @@ -356,9 +359,9 @@ upslist_savednames_find_missing() { # amend those quickly after an upgrade. Otherwise we trust these. # Get full instance names from system and from props - SVCINSTS="`$hook_listInstances_raw`" && [ -n "$SVCINSTS" ] || return 1 + SVCINSTS="`$hook_listInstances_raw`" && [ "${#SVCINSTS}" != 0 ] || return 1 # If no props were found, (over)write them all - SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ -n "$SVCINST_PROPS" ] \ + SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ "${#SVCINST_PROPS}" != 0 ] \ || { echo $SVCINSTS ; return 2; } # Find services which do not have saved names in props @@ -380,8 +383,8 @@ upslist_savednames_find_mismatch() { # upslist_savednames_find_missing() should have handled those). # Get full instance names from system and from props - SVCINSTS="`$hook_listInstances_raw`" && [ -n "$SVCINSTS" ] || return 1 - SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ -n "$SVCINST_PROPS" ] || return 2 + SVCINSTS="`$hook_listInstances_raw`" && [ "${#SVCINSTS}" != 0 ] || return 1 + SVCINST_PROPS="`$hook_findSavedDeviceName`" && [ "${#SVCINST_PROPS}" != 0 ] || return 2 # Find services whose props exist but services do not echo "$SVCINST_PROPS" | while read SVCINST_PROP DEVNAME_PROP ; do @@ -1010,7 +1013,7 @@ upslist_normalizeFile() { # Also use a SDP subset with just section, driver and port info # for faster parsing when determining driver-required media etc. UPSCONF_DATA="$(upslist_normalizeFile_filter < "$UPSCONF")" \ - && [ -n "$UPSCONF_DATA" ] \ + && [ "${#UPSCONF_DATA}" != 0 ] \ && UPSCONF_DATA_SDP="`egrep '^(\[.*\]|driver=|port=)' << EOF $UPSCONF_DATA EOF`" \ @@ -1024,7 +1027,7 @@ upslist_normalizeFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) - [ -z "$UPSCONF_DATA" ] && [ -z "$UPSCONF_DATA_SDP" ] || return 0 + [ "${#UPSCONF_DATA}" = 0 ] && [ "${#UPSCONF_DATA_SDP}" = 0 ] || return 0 upslist_normalizeFile } @@ -1040,11 +1043,11 @@ upslist_readFile() { upslist_normalizeFile || return # Propagate errors upwards fi - if [ -n "$UPSCONF_DATA" ] ; then + if [ "${#UPSCONF_DATA}" != 0 ] ; then # Note that section-name brackets should contain a single token UPSLIST_FILE="$(echo "$UPSCONF_DATA_SDP" | egrep '^\[[^'"$TABCHAR"'\ ]*\]$' | sed 's,^\[\(.*\)\]$,\1,' | sort -n)" \ || UPSLIST_FILE="" - if [ -z "$UPSLIST_FILE" ] ; then + if [ "${#UPSLIST_FILE}" = 0 ] ; then echo "Error reading the '$UPSCONF' file or it does not declare any device configurations: no section declarations in parsed normalized contents" >&2 fi fi @@ -1055,13 +1058,13 @@ upslist_readFile_once() { # Wrapper that ensures that the parsing is only done once # (will re-parse if there were no devices listed on the # first time, though) - [ -z "$UPSLIST_FILE" ] || return 0 + [ "${#UPSLIST_FILE}" = 0 ] || return 0 DO_NORMALIZE_ONCE=yes upslist_readFile } upslist_readSvcs() { UPSLIST_SVCS="`$hook_listInstances`" || UPSLIST_SVCS="" - if [ -z "$UPSLIST_SVCS" ] && [ "$1" != "-" ] ; then + if [ "${#UPSLIST_SVCS}" = 0 ] && [ "$1" != "-" ] ; then EXPLAIN="" [ -z "$1" ] || EXPLAIN=" - $1" echo "Error reading the list of ${SERVICE_FRAMEWORK-} service instances for UPS drivers, or none are defined${EXPLAIN}" >&2 @@ -1152,14 +1155,14 @@ nut_driver_enumerator_main() { # We can only exit quickly if both there are no changed sections and no # new or removed sections since last run. NEW_CHECKSUM="`upslist_checksums_unchanged "$UPSLIST_FILE" "$UPSLIST_SVCS"`" \ - && [ -z "$NEW_CHECKSUM" ] \ + && [ "${#NEW_CHECKSUM}" = 0 ] \ && upslist_equals "$UPSLIST_FILE" "$UPSLIST_SVCS" \ && if [ -z "$DAEMON_SLEEP" -o "${VERBOSE_LOOP}" = yes ] ; then \ echo "`date -u` : OK: No changes to reconcile between ${SERVICE_FRAMEWORK} service instances and device configurations in '$UPSCONF'" ; \ fi \ && [ "$RESTART_ALL" = no ] && return 0 - if [ -n "$NEW_CHECKSUM" ]; then + if [ "${#NEW_CHECKSUM}" != 0 ]; then for UPSS in $NEW_CHECKSUM ; do echo "Dropping old ${SERVICE_FRAMEWORK} service instance ${UPSS} whose section in config file has changed..." >&2 $hook_unregisterInstance "$UPSS" @@ -1167,7 +1170,7 @@ nut_driver_enumerator_main() { upslist_readSvcs "after updating for new config section checksums" fi - if [ -n "$UPSLIST_SVCS" ]; then + if [ "${#UPSLIST_SVCS}" != 0 ]; then # Drop services that are not in config file (any more?) upslist_delSvcs @@ -1183,7 +1186,7 @@ nut_driver_enumerator_main() { $hook_setSavedMD5 "" "`upsconf_getSection_MD5 ""`" fi - if [ -n "$UPSLIST_FILE" ]; then + if [ "${#UPSLIST_FILE}" != 0 ]; then # Add services for sections that are in config file but not yet wrapped upslist_addSvcs $hook_refreshSupervizor @@ -1191,12 +1194,12 @@ nut_driver_enumerator_main() { fi upslist_readSvcs - if [ -n "$UPSLIST_SVCS" ] ; then + if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi - if [ -n "$UPSLIST_FILE" ] ; then + if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi @@ -1244,14 +1247,14 @@ nut_driver_enumerator_full_reconfigure() { upslist_readFile_once || return $? upslist_readSvcs "before manipulations" - if [ -n "$UPSLIST_SVCS" ]; then + if [ "${#UPSLIST_SVCS}" != 0 ]; then for UPSS in $UPSLIST_SVCS ; do echo "Dropping old ${SERVICE_FRAMEWORK} service instance for power device [${UPSS}] to reconfigure the service unit..." >&2 $hook_unregisterInstance "$UPSS" done upslist_readSvcs "after dropping" fi - if [ -n "$UPSLIST_FILE" ]; then + if [ "${#UPSLIST_FILE}" != 0 ]; then upslist_addSvcs upslist_readSvcs "after checking for new config sections to define service instances" fi @@ -1263,12 +1266,12 @@ nut_driver_enumerator_full_reconfigure() { # refresh the service management daemon if needed $hook_refreshSupervizor - if [ -n "$UPSLIST_SVCS" ] ; then + if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" echo "$UPSLIST_SVCS" fi - if [ -n "$UPSLIST_FILE" ] ; then + if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" echo "$UPSLIST_FILE" fi @@ -1305,11 +1308,11 @@ nut_driver_enumerator_full_reconfigure() { list_services_for_devices() { FINAL_RES=0 - upslist_readFile_once && [ -n "$UPSLIST_FILE" ] \ + upslist_readFile_once && [ "${#UPSLIST_FILE}" != 0 ] \ || { echo "No devices detected in '$UPSCONF'" >&2 ; return 1 ; } - upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ + upslist_readSvcs "by user request" && [ "${#UPSLIST_SVCS}" != 0 ] \ || { echo "No service instances detected" >&2 ; return 1; } - UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ + UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ "${#UPSLIST_SVCS_RAW}" != 0 ] \ || { echo "No service units detected" >&2 ; return 1; } for DEV in $UPSLIST_FILE ; do vINST="`$hook_validInstanceName "$DEV"`" @@ -1369,7 +1372,7 @@ get_device_for_service() { # Try to use last-stashed values from service properties first # (NOTE: saved value is assumed to be valid if present) SAVEDINST="`$hook_getSavedDeviceName "$SVC"`" || SAVEDINST="" - [ -z "$SAVEDINST" ] || { echo "$SAVEDINST" ; return 0 ; } + [ "${#SAVEDINST}" = 0 ] || { echo "$SAVEDINST" ; return 0 ; } fi case "$SVC" in @@ -1382,7 +1385,7 @@ get_device_for_service() { # Inspect SVC=MD5_* usecase FINAL_RES=0 - list_services_for_devices_once && [ -n "$SVCS_DEVS_LIST" ] || FINAL_RES=$? + list_services_for_devices_once && [ "${#SVCS_DEVS_LIST}" != 0 ] || FINAL_RES=$? if [ "$FINAL_RES" = 0 ]; then echo "$SVCS_DEVS_LIST" | grep "$SVC" | ( \ while read _SVC _DEV ; do @@ -1402,14 +1405,14 @@ get_service_for_device() { # (NOTE: saved value is assumed to be valid if present) if [ "${USE_SAVEDSVC-}" != false ]; then SAVEDSVC="`$hook_findSavedDeviceName "$DEV"`" || SAVEDSVC="" - [ -z "$SAVEDSVC" ] || { echo "$SAVEDSVC" ; return 0 ; } + [ "${#SAVEDSVC}" = 0 ] || { echo "$SAVEDSVC" ; return 0 ; } fi # Trawl all the data we have... # TODO: Reorder to avoid extra parsing if we have an early hit? - upslist_readSvcs "by user request" && [ -n "$UPSLIST_SVCS" ] \ + upslist_readSvcs "by user request" && [ "${#UPSLIST_SVCS}" != 0 ] \ || { echo "No service instances detected" >&2 ; return 1; } - UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ -n "$UPSLIST_SVCS_RAW" ] \ + UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && [ "${#UPSLIST_SVCS_RAW}" != 0 ] \ || { echo "No service units detected" >&2 ; return 1; } vINST="`$hook_validInstanceName "$DEV"`" vUNITD="`$hook_validFullUnitName "$DEV"`" @@ -1450,13 +1453,14 @@ update_upslist_savednames_find_missing() { 2) ;; # All service units do not have DEVICE values esac # Something found... or not? Or all is populated? - [ -n "$SVCINSTS_NO_DEVICE" ] || return 0 + [ "${#SVCINSTS_NO_DEVICE}" != 0 ] || return 0 # Make a list of what devices are known in config matched # to service instances defined in the system, if any # Note to not check the service instance properties which # we are validating and currently to not quite trust. - USE_SAVEDINST=false list_services_for_devices_once && [ -n "$SVCS_DEVS_LIST" ] || return 0 + USE_SAVEDINST=false list_services_for_devices_once \ + && [ "${#SVCS_DEVS_LIST}" != 0 ] || return 0 # Go over services with no device value saved into properties, # and write the values learned from mapping above @@ -1626,7 +1630,7 @@ while [ $# -gt 0 ]; do ;; --list-devices) upslist_readFile_once && \ - if [ -n "$UPSLIST_FILE" ] ; then + if [ "${#UPSLIST_FILE}" != 0 ] ; then echo "=== The currently defined configurations in '$UPSCONF' are:" >&2 echo "$UPSLIST_FILE" exit 0 @@ -1636,7 +1640,7 @@ while [ $# -gt 0 ]; do ;; --list-services) UPSLIST_SVCS_RAW="`$hook_listInstances_raw`" && \ - if [ -n "$UPSLIST_SVCS_RAW" ] ; then + if [ "${#UPSLIST_SVCS_RAW}" != 0 ] ; then echo "=== The currently defined service units are:" >&2 echo "$UPSLIST_SVCS_RAW" exit 0 @@ -1646,7 +1650,7 @@ while [ $# -gt 0 ]; do ;; --list-instances) upslist_readSvcs "by user request" && \ - if [ -n "$UPSLIST_SVCS" ] ; then + if [ "${#UPSLIST_SVCS}" != 0 ] ; then echo "=== The currently defined service instances are:" >&2 echo "$UPSLIST_SVCS" exit 0 @@ -1673,7 +1677,7 @@ while [ $# -gt 0 ]; do RES=0 upslist_readFile_once || RES=$? [ "$RES" != 0 ] && { echo "ERROR: upslist_readFile_once () failed with code $RES" >&2; exit $RES; } - [ -n "$UPSLIST_FILE" ] \ + [ "${#UPSLIST_FILE}" != 0 ] \ || { echo "WARNING: No devices detected in '$UPSCONF'" >&2 ; RES=1 ; } echo "$UPSCONF_DATA" exit $RES From 71d014f2630125e70f30140518ba53b7de7d1bd2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Tue, 18 Dec 2018 16:00:02 +0100 Subject: [PATCH 31/31] nut-driver-enumerator.sh.in : prepare TIMEOUT command-line setting (not active for simple and daemon modes currently) --- .../upsdrvsvcctl/nut-driver-enumerator.sh.in | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in index 628ca6a246..16b4080192 100755 --- a/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in +++ b/scripts/upsdrvsvcctl/nut-driver-enumerator.sh.in @@ -1618,11 +1618,41 @@ $0 --show-device-config-value DEV KEY [KEY...] one per line in the same order (including empty lines for missing values); any missing value yields a non-zero exit code. EOF + +# TODO: refactor no-arg and daemonized runs into common loop, set ACTION +# and process that all uniformly. +#COMMON OPTIONS: +# --timeout-cmd service management calls will be time-limited +# --timeout-args by calling the specified program with its args. +# By default, if coreutils timeout is found, it +# would be used to limit service calls by 90 sec. + } while [ $# -gt 0 ]; do case "$1" in --help|-h|-help) usage; exit 0 ;; + --timeout-length|--timeout-len|--timeout-args) + TIMEOUT_ARGS="$2" + shift + ;; + --timeout-cmd) + if [ -n "$2" ] ; then + if [ -x "$2" ] || which "$2" 2>/dev/null >/dev/null ; then + TIMEOUT_CMD="$2" + else + echo "ERROR: Received a '$2' argument for $1, and can not find such program; clearing the option so the basic functionality can proceed" >&2 + TIMEOUT_CMD="" + TIMEOUT_ARGS="" + fi + else + echo "INFO: Received an empty argument for $1, clearing the option" >&2 + TIMEOUT_CMD="" + TIMEOUT_ARGS="" + fi + shift + ;; + --get-service-framework) echo "${SERVICE_FRAMEWORK}" ; exit 0 ;; --reconfigure) nut_driver_enumerator_full_reconfigure "$@"