Skip to content

Commit

Permalink
Merge pull request networkupstools#2568 from jimklimov/issue-2567
Browse files Browse the repository at this point in the history
Teach `upsdrvctl` to list device config names and show run-time `status`, and to optionally hide the start-up banner
  • Loading branch information
jimklimov authored Jul 31, 2024
2 parents 3e35f5b + fac5343 commit ddcf7b9
Show file tree
Hide file tree
Showing 23 changed files with 691 additions and 109 deletions.
9 changes: 9 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ https://github.com/networkupstools/nut/milestone/11
command for a protocol equivalent of sending a `SIGTERM`, e.g. when
a newer instance of the driver program tries to start. [#1903, #2392]
- A new `NUT_QUIET_INIT_BANNER` envvar (presence or "true" value) can now
prevent the tool name and NUT version banner from being unilaterally
printed out when NUT programs start. [issues #1789 vs. #316]
- Extended `upsdrvctl` with a `list` operation (or `-l` option) to report
manageable device configuration names (possible `<ups>` arguments to
`start`, `stop` etc. operations), or to confirm a single name that it
is known, and a `status` operation for more information. [#2567]
- riello_ser updates:
* added `localcalculation` option to compute `battery.runtime` and
`battery.charge` if the device provides bogus values [issue #2390,
Expand Down
10 changes: 10 additions & 0 deletions UPGRADING.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,16 @@ Changes from 2.8.2 to 2.8.3
Also the NUT daemons should request to double-check against their
run-time process name (if it can be detected). [issue #2463]
- More environment variable support was added to NUT programs, primarily
aimed at wrappers such as init scripts and service unit definitions,
allowing to tweak what (and whether) they write into debug traces, and
so "make noise" or "bring invaluable insights" to logs or terminal;
they can generally be used for services and init scripts via `nut.conf`:
* See `NUT_IGNORE_CHECKPROCNAME` and `NUT_DEBUG_SYSLOG` above. [#1915]
* A `NUT_QUIET_INIT_BANNER` envvar (presence or "true" value) prevents
tool name and NUT version banner from being printed out when programs
start. [issues #1789 vs. #316]
Changes from 2.8.1 to 2.8.2
---------------------------
Expand Down
5 changes: 4 additions & 1 deletion clients/upslog.c
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,10 @@ int main(int argc, char **argv)
logformat = DEFAULT_LOGFORMAT;
user = RUN_AS_USER;

printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
if (!banner_is_disabled()) {
printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
fflush(stdout);
}

while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:FBm:")) != -1) {
switch(i) {
Expand Down
6 changes: 4 additions & 2 deletions clients/upsmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -2908,8 +2908,10 @@ int main(int argc, char *argv[])
}
#endif

printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
fflush(stdout);
if (!banner_is_disabled()) {
printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
fflush(stdout);
}

/* if no configuration file is specified on the command line, use default */
configfile = xmalloc(SMALLBUF);
Expand Down
48 changes: 41 additions & 7 deletions common/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,26 @@ int syslog_is_disabled(void)
return value;
}

int banner_is_disabled(void)
{
static int value = -1;

if (value < 0) {
char *s = getenv("NUT_QUIET_INIT_BANNER");
/* Envvar present and empty or true-ish means NUT tool name+version
* banners disabled by the setting: default is enabled (inversed per
* method name) */
value = 0;
if (s) {
if (*s == '\0' || !strcasecmp(s, "true") || strcmp(s, "1")) {
value = 1;
}
}
}

return value;
}

/* enable writing upslog_with_errno() and upslogx() type messages to
the syslog */
void syslogbit_set(void)
Expand Down Expand Up @@ -1411,17 +1431,15 @@ pid_t parsepid(const char *buf)
return pid;
}

/* open pidfn, get the pid, then send it sig
/* open pidfn, get the pid;
* returns negative codes for errors, or
* zero for a successfully sent signal
* zero for a successfully discovered value
*/
#ifndef WIN32
int sendsignalfn(const char *pidfn, int sig, const char *progname, int check_current_progname)
pid_t parsepidfile(const char *pidfn)
{
char buf[SMALLBUF];
FILE *pidf;
pid_t pid = -1;
int ret = -1;

pidf = fopen(pidfn, "r");
if (!pidf) {
Expand All @@ -1441,7 +1459,9 @@ int sendsignalfn(const char *pidfn, int sig, const char *progname, int check_cur
fclose(pidf);
return -2;
}
/* TOTHINK: Original code only closed pidf before

/* TOTHINK: Original sendsignalfn code (which this
* was extracted from) only closed pidf before
* exiting the method, on error or "normally".
* Why not here? Do we want an (exclusive?) hold
* on it while being active in the method?
Expand All @@ -1450,12 +1470,26 @@ int sendsignalfn(const char *pidfn, int sig, const char *progname, int check_cur
/* this method actively reports errors, if any */
pid = parsepid(buf);

fclose(pidf);

return pid;
}

/* open pidfn, get the pid, then send it sig
* returns negative codes for errors, or
* zero for a successfully sent signal
*/
#ifndef WIN32
int sendsignalfn(const char *pidfn, int sig, const char *progname, int check_current_progname)
{
int ret = -1;
pid_t pid = parsepidfile(pidfn);

if (pid >= 0) {
/* this method actively reports errors, if any */
ret = sendsignalpid(pid, sig, progname, check_current_progname);
}

fclose(pidf);
return ret;
}

Expand Down
51 changes: 49 additions & 2 deletions conf/nut.conf.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@
#
# IMPORTANT NOTES:
# This file is intended to be sourced by standard POSIX shell scripts
# (so there is no guaranteed `export VAR=VAL` syntax) and additionally
# by systemd on Linux (no guaranteed expansion of variables).
# (so there is no guaranteed `export VAR=VAL` syntax, while you may need
# to `export VAR` when sourcing it into init-scripts, for propagation to
# NUT programs eventually), and additionally by systemd on Linux (with no
# guaranteed expansion of variables -- only verbatim assignments).
#
# You MUST NOT use spaces around the equal sign!
#
# Practical support for this file and its settings currently varies between
# various OS packages and NUT sample scripts, but should converge over time.
#
# Contents of this file should be pure ASCII (character codes not in range
# would be ignored with a warning message).
#
Expand Down Expand Up @@ -93,6 +98,13 @@ MODE=none
# verbosity passed to NUT daemons. As an environment variable, its priority sits
# between that of 'DEBUG_MIN' setting of a driver and the command-line options.
#NUT_DEBUG_LEVEL=0
#export NUT_DEBUG_LEVEL

# Optionally add current process ID to tags with debug-level identifiers.
# This may be useful when many NUT daemons write to the same console or log
# file, such as in containers/plugins for Home Assistant, storage appliances...
#NUT_DEBUG_PID=true
#export NUT_DEBUG_PID

# Normally NUT can (attempt to) use the syslog or Event Log (WIN32), but the
# environment variable 'NUT_DEBUG_SYSLOG' allows to bypass it, and perhaps keep
Expand All @@ -103,6 +115,7 @@ MODE=none
# `none` Disabled and background() detaches stderr as usual
# `default`/unset/other Not disabled
#NUT_DEBUG_SYSLOG=stderr
#export NUT_DEBUG_SYSLOG

# Normally NUT can (attempt to) verify that the program file name matches the
# name associated with a running process, when using PID files to send signals.
Expand All @@ -112,3 +125,37 @@ MODE=none
# optionally set in init-scripts or service methods for `upsd`, `upsmon` and
# NUT drivers/`upsdrvctl`.
#NUT_IGNORE_CHECKPROCNAME=true
#export NUT_IGNORE_CHECKPROCNAME

# Optional flag to prevent daemons which can notify service management frameworks
# (such as systemd) about passing their lifecycle milestones, to not report
# loudly if they could NOT do so (e.g. running on a system without a framework,
# or misconfigured so they could not report and the OS could eventually restart
# the false-positively identified "unresponsive" service.
# Currently such reports, done by default, help troubleshoot service start-up
# and highlight that NUT sources (or package build) did not take advantage of
# tighter OS service management framework integration (if one exists, so that
# developers could focus on adding that). Reasons to set this flag could include
# platforms without such a framework and not expecting one, although nagging
# your favourite OS or contributing development to make it better is also a way.
#NUT_QUIET_INIT_UPSNOTIFY=true
#export NUT_QUIET_INIT_UPSNOTIFY

##############################################################################
# Variables that can be helpful more for tool scripting than service daemons
##############################################################################

# Optionally prevent `libupsclient` consumers (notoriously `upsc`, maybe
# also `dummy-ups` driver or `nut-scanner` tool) from reporting whether
# they have initialized SSL support -- or, loudly, failed to initialize
# as it was not configured on this system.
#NUT_QUIET_INIT_SSL=true
#export NUT_QUIET_INIT_SSL

# Optionally suppress NUT tool name and version banner (normally shown in most
# NUT programs unilaterally, before processing any CLI options and possibly
# failing due to that).
# NOT recommended for services due to adverse troubleshooting impact, but may
# be helpful in shell profiles or scripts which process NUT tool outputs.
#NUT_QUIET_INIT_BANNER=true
#export NUT_QUIET_INIT_BANNER
2 changes: 2 additions & 0 deletions docs/maintainer-guide.txt
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,8 @@ MAINTAINER SANDBOX (to be completed and pushed)

* announce on mailing list, IRC, etc.

* update https://en.wikipedia.org/wiki/Network_UPS_Tools

* create a GitHub issue label for the new release, e.g. at
https://github.com/networkupstools/nut/labels?q=impact :
----
Expand Down
34 changes: 33 additions & 1 deletion docs/man/nut.conf.txt
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,23 @@ comments.
IMPORTANT NOTES
---------------

* This file is intended to be sourced by shell scripts.
* This file is intended to be sourced by shell scripts as well as by
service management frameworks like systemd on Linux:
- There is no guaranteed `export VAR=VAL` syntax
- No guaranteed expansion of variables like `VAR1="$VAR2-something"` --
only verbatim assignments
- You may need to `export VAR` when sourcing it into init-scripts
or other scripts, for eventual propagation of certain settings
to NUT programs. Not-exported variables can only be consumed by
the script which "sourced" the file (and may choose to `export`
them independently).

* You MUST NOT use spaces around the equal sign!

* Practical support for this file and its settings currently varies
between different OS packages and NUT sample scripts, but should
converge over time.

* Contents of this file should be pure ASCII (character codes
not in range would be ignored with a warning message).

Expand Down Expand Up @@ -122,6 +135,11 @@ Optional, defaults to `0`. This setting controls the default debugging message
verbosity passed to NUT daemons. As an environment variable, its priority sits
between that of 'DEBUG_MIN' setting of a driver and the command-line options.

*NUT_DEBUG_PID*::
Optionally add current process ID to tags with debug-level identifiers.
This may be useful when many NUT daemons write to the same console or log
file, such as in containers/plugins for Home Assistant, storage appliances...

*NUT_DEBUG_SYSLOG*::
Optional, unset by default.
Normally NUT can (attempt to) use the syslog or Event Log (WIN32), but the
Expand Down Expand Up @@ -151,6 +169,20 @@ and do not match built-in expectations).
This environment variable can also be optionally set in init-scripts or
service methods for `upsd`, `upsmon` and NUT drivers/`upsdrvctl`.

*NUT_QUIET_INIT_UPSNOTIFY*::
Optional flag to prevent daemons which can notify service management frameworks
(such as systemd) about passing their lifecycle milestones, to not report
loudly if they could NOT do so (e.g. running on a system without a framework,
or misconfigured so they could not report and the OS could eventually restart
the false-positively identified "unresponsive" service.
+
Currently such reports, done by default, help troubleshoot service start-up
and highlight that NUT sources (or package build) did not take advantage of
tighter OS service management framework integration (if one exists, so that
developers could focus on adding that). Reasons to set this flag could include
platforms without such a framework and not expecting one, although nagging
your favourite OS or contributing development to make it better is also a way.

EXAMPLE
-------

Expand Down
56 changes: 55 additions & 1 deletion docs/man/upsdrvctl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ SYNOPSIS

*upsdrvctl* -h

*upsdrvctl* ['OPTIONS'] {start | stop | shutdown} ['ups']
*upsdrvctl* ['OPTIONS'] {start | stop | shutdown | status} ['ups']

*upsdrvctl* ['OPTIONS'] {list | -l} ['ups']

*upsdrvctl* ['OPTIONS'] -c COMMAND ['ups']

Expand Down Expand Up @@ -81,6 +83,9 @@ this mode (not saved by default when staying in foreground).
Drivers will run in the background, regardless of debugging settings,
as set by *-D* and passed-through by *-d* options.

*-l*::
Alias for `list` command.

COMMANDS
--------

Expand Down Expand Up @@ -118,6 +123,55 @@ NOTE: refer to linkman:ups.conf[5] for using the *nowait* parameter.
It can be overridden by `NUT_IGNORE_NOWAIT` environment variable
(e.g. used to work around certain issues with systemd otherwise).

*list*::
Without a further argument, report all currently known device configuration
names to `stdout`, one per line. With an argument, also try to report that
name, but exit with an error code if that name is not known.

NOTE: The tool would exit with an error if `ups.conf` file is not found,
readable, or does not define any device sections (whose names are reported
here and managed in other commands).

NOTE: The tool name and NUT version banner line is also printed to `stdout`
before any other processing. This can be suppressed by `NUT_QUIET_INIT_BANNER`
environment variable (exported by caller and empty or "true").

*status*::
Similar to `list`, but reports more information -- also the driver name, the
PID if it is running, and result of a signal probe to check it is responding.
The `NUT_QUIET_INIT_BANNER` suppression can be helpful for scripted parsing.
If there is anything to print (at least one device is known), the first line
of status report would be the heading with column names:

:; NUT_QUIET_INIT_BANNER=true upsdrvctl status
UPSNAME UPSDRV PF_RUNNING PF_PID S_RESPONSIVE S_PID S_STATUS
dummy dummy-ups N/A -3 NOT_RESPONSIVE N/A
eco650 usbhid-ups RUNNING 3559207 RESPONSIVE 3559207 "OL"
UPS2 dummy-ups RUNNING 31455 RESPONSIVE 31455 "OL BOOST"

Values are TAB-separated. Any complex string values would be encased in
double-quotes.

Fields reported (`PF_*` = according to PID file, if any; `S_*` = via socket
protocol):

*UPSNAME*;; driver section configuration name
*UPSDRV*;; driver program name per `ups.conf`
*PF_RUNNING*;; `RUNNING` if `PF_PID` is valid (PID file existed,
PID was parsed out of it and found running, program
name corresponds to driver, etc.); `STOPPED` if PID
was parsed but not running or has a wrong program
name; "N/A" if failed to parse it or no PID file
*PF_PID*;; PID of driver according to PID file (if any), or some
negative values upon errors (as defined in `common.c`)
*S_RESPONSIVE*;; `RESPONSIVE` if `PING`/`PONG` during socket protocol
session setup succeeded; `NOT_RESPONSIVE` otherwise
*S_PID*;; PID of driver according to `GETPID` active query
*S_STATUS*;; Value of `ups.status` variable

This mode does not discover drivers that are not in `ups.conf` (e.g. started
manually for experiments with many `-x` CLI options).

*-c* 'command'::
Send 'command' to the background process as a signal. Valid commands
are:
Expand Down
5 changes: 5 additions & 0 deletions docs/man/upsdrvsvcctl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,11 @@ by using the 'maxretry' and 'retrydelay' options - see linkman:ups.conf[5].
*stop*::
Stop the UPS driver(s).

*status*::
Query run-time status of all configured devices (or one specified device).
Currently defers work to linkman:upsdrvctl[8], and does not report service
unit information.

*upsdrvsvcctl* also supports further operations for troubleshooting the
mapping of NUT driver section names to the service instance names (which
may differ due to limitations of various systems).
Expand Down
Loading

0 comments on commit ddcf7b9

Please sign in to comment.