Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 30 Aug 2022 13:15:28 -0700
From:      Cy Schubert <Cy.Schubert@cschubert.com>
To:        ports-committers@FreeBSD.org, dev-commits-ports-all@FreeBSD.org, dev-commits-ports-main@FreeBSD.org
Subject:   Re: git: 9c4a120c36bf - main - sysutils/nut*: Add upslog support  for multiple UPSs
Message-ID:  <20220830201528.CB318293@slippy.cwsent.com>
In-Reply-To: <202208301811.27UIBus9084236@gitrepo.freebsd.org>
References:  <202208301811.27UIBus9084236@gitrepo.freebsd.org>

next in thread | previous in thread | raw e-mail | index | archive | help
In message <202208301811.27UIBus9084236@gitrepo.freebsd.org>, Cy Schubert 
write
s:
> The branch main has been updated by cy:
>
> URL: https://cgit.FreeBSD.org/ports/commit/?id=9c4a120c36bfb61a307d04c843eeda
> 4f3c43cf4c
>
> commit 9c4a120c36bfb61a307d04c843eeda4f3c43cf4c
> Author:     Cy Schubert <cy@FreeBSD.org>
> AuthorDate: 2022-08-30 05:27:41 +0000
> Commit:     Cy Schubert <cy@FreeBSD.org>
> CommitDate: 2022-08-30 18:04:26 +0000
>
>     sysutils/nut*: Add upslog support for multiple UPSs
>     
>     upslog is a utility that logs UPS status at regular intervals, specified
>     by the -i option. Unfortunately upslog supports only on UPS. For sites
>     that need to monitor multiple UPSs the options are to cobble an rc script
>     for each or doctor up the nut_upslog.in script to support cloning of the
>     script. Unfortunately an rc script capable of being cloned would become
>     the source of more PRs and would require significanly more tehcnical
>     documentation that by itself might become confusing for the average
>     system administrator.
>     
>     Therefore a new -m option is added to support multiple UPSs using the
>     same invocation of upslog. The patch parses a new -m option and using a
>     single connection to upsd, queries it for stats about multiple UPSs.
>     
>     An rc.conf exemple of how to use this new feature:
>     nut_upslog_flags="-p /var/db/nut/upslog.pid -m ups1@localhost,/var/log/nu
> t\
>     /ups1.log -m ups2@localhost,/var/log/nut/ups2.log"
>     
>     PR:             265963
>     Reported by:    vvd@unislabs.com
> ---
>  sysutils/nut-devel/Makefile                        |   2 +-
>  sysutils/nut-devel/files/patch-clients_upslog.c    | 291 +++++++++++++++++++
> ++
>  sysutils/nut-devel/files/patch-docs_man_upslog.txt |  14 +
>  sysutils/nut/Makefile                              |   2 +-
>  sysutils/nut/files/patch-clients_upslog.c          | 291 +++++++++++++++++++
> ++
>  sysutils/nut/files/patch-docs_man_upslog.8         |  16 ++
>  sysutils/nut/files/patch-docs_man_upslog.txt       |  14 +
>  7 files changed, 628 insertions(+), 2 deletions(-)
>
> diff --git a/sysutils/nut-devel/Makefile b/sysutils/nut-devel/Makefile
> index b3d796bfec97..39a576b32ea6 100644
> --- a/sysutils/nut-devel/Makefile
> +++ b/sysutils/nut-devel/Makefile
> @@ -1,6 +1,6 @@
>  PORTNAME=	nut
>  PORTVERSION=	${NUT_COMMIT_DATE}
> -PORTREVISION=	2
> +PORTREVISION=	3
>  CATEGORIES=	sysutils
>  PKGNAMESUFFIX=	-devel
>  # MASTER_SITES=	http://www.networkupstools.org/source/${PORTVERSION:R}/
> diff --git a/sysutils/nut-devel/files/patch-clients_upslog.c b/sysutils/nut-d
> evel/files/patch-clients_upslog.c
> new file mode 100644
> index 000000000000..c06eaf45e992
> --- /dev/null
> +++ b/sysutils/nut-devel/files/patch-clients_upslog.c
> @@ -0,0 +1,291 @@
> +--- clients/upslog.c.orig	2022-08-29 22:20:20.954722000 -0700
> ++++ clients/upslog.c	2022-08-29 22:21:18.844395000 -0700
> +@@ -32,6 +32,10 @@
> +  */
> + 
> + #include "common.h"
> ++#include <signal.h>
> ++#include <unistd.h>
> ++#include <sys/types.h>
> ++#include <sys/wait.h>
> + #include "nut_platform.h"
> + #include "upsclient.h"
> + 
> +@@ -41,32 +45,49 @@
> + #include "upslog.h"
> + 
> + 	static	int	reopen_flag = 0, exit_flag = 0;
> +-	static	uint16_t	port;
> +-	static	char	*upsname, *hostname;
> +-	static	UPSCONN_t	ups;
> ++	static	char	*upsname;
> ++	static	UPSCONN_t	*ups;
> + 
> +-	static	FILE	*logfile;
> +-	static	const	char *logfn, *monhost;
> ++	static	char *logfn, *monhost;
> + 	static	sigset_t	nut_upslog_sigmask;
> + 	static	char	logbuffer[LARGEBUF], *logformat;
> + 
> + 	static	flist_t	*fhead = NULL;
> ++	struct 	monhost_ups {
> ++		char	*monhost;
> ++		char	*logfn;
> ++		char	*upsname;
> ++		char	*hostname;
> ++		uint16_t	port;
> ++		UPSCONN_t	*ups;
> ++		FILE	*logfile;
> ++		struct	monhost_ups	*next;
> ++	};
> ++	static	struct	monhost_ups *monhost_ups_anchor = NULL;
> ++	static	struct	monhost_ups *monhost_ups_current = NULL;
> ++	static	struct	monhost_ups *monhost_ups_prev = NULL;
> + 
> ++
> + #define DEFAULT_LOGFORMAT "%TIME @Y@m@d @H@M@S% %VAR battery.charge% " \
> + 		"%VAR input.voltage% %VAR ups.load% [%VAR ups.status%] " \
> + 		"%VAR ups.temperature% %VAR input.frequency%"
> + 
> + static void reopen_log(void)
> + {
> +-	if (logfile == stdout) {
> +-		upslogx(LOG_INFO, "logging to stdout");
> +-		return;
> +-	}
> ++	for (monhost_ups_current = monhost_ups_anchor;
> ++	     monhost_ups_current != NULL;
> ++	     monhost_ups_current = monhost_ups_current->next) {
> ++		if (monhost_ups_current->logfile == stdout) {
> ++			upslogx(LOG_INFO, "logging to stdout");
> ++			return;
> ++		}
> + 
> +-	fclose(logfile);
> +-	logfile = fopen(logfn, "a");
> +-	if (logfile == NULL)
> +-		fatal_with_errno(EXIT_FAILURE, "could not reopen logfile %s", l
> ogfn);
> ++		if ((monhost_ups_current->logfile = freopen(
> ++		    monhost_ups_current->logfn, "a",
> ++		    monhost_ups_current->logfile)) == NULL)
> ++			fatal_with_errno(EXIT_FAILURE,
> ++				"could not reopen logfile %s", logfn);
> ++	}
> + }
> + 
> + static void set_reopen_flag(int sig)
> +@@ -131,6 +152,8 @@
> + 	printf("  -p <pidbase>  - Base name for PID file (defaults to \"%s\")\n
> ", prog);
> + 	printf("  -s <ups>	- Monitor UPS <ups> - <upsname>@<host>[:<port>]
> \n");
> + 	printf("        	- Example: -s myups@server\n");
> ++	printf("  -m <tuple>	- Monitor UPS <ups,logfile>\n");
> ++	printf("		- Example: -m myups@server,/var/log/myups.log\n
> ");
> + 	printf("  -u <user>	- Switch to <user> if started as root\n");
> + 
> + 	printf("\n");
> +@@ -215,7 +238,7 @@
> + 	query[2] = var;
> + 	numq = 3;
> + 
> +-	ret = upscli_get(&ups, numq, query, &numa, &answer);
> ++	ret = upscli_get(ups, numq, query, &numa, &answer);
> + 
> + 	if ((ret < 0) || (numa < numq)) {
> + 		snprintfcat(logbuffer, sizeof(logbuffer), "NA");
> +@@ -368,7 +391,7 @@
> + }
> + 
> + /* go through the list of functions and call them in order */
> +-static void run_flist(void)
> ++static void run_flist(struct monhost_ups *monhost_ups_print)
> + {
> + 	flist_t	*tmp;
> + 
> +@@ -382,8 +405,8 @@
> + 		tmp = tmp->next;
> + 	}
> + 
> +-	fprintf(logfile, "%s\n", logbuffer);
> +-	fflush(logfile);
> ++	fprintf(monhost_ups_print->logfile, "%s\n", logbuffer);
> ++	fflush(monhost_ups_print->logfile);
> + }
> + 
> + 	/* -s <monhost>
> +@@ -396,6 +419,7 @@
> + int main(int argc, char **argv)
> + {
> + 	int	interval = 30, i, foreground = -1;
> ++	size_t	monhost_len = 0;
> + 	const char	*prog = xbasename(argv[0]);
> + 	time_t	now, nextpoll = 0;
> + 	const char	*user = NULL;
> +@@ -407,7 +431,7 @@
> + 
> + 	printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
> + 
> +-	while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:FB")) != -1) {
> ++	while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:FBm:")) != -1) {
> + 		switch(i) {
> + 			case 'h':
> + 				help(prog);
> +@@ -415,6 +439,33 @@
> + 				break;
> + #endif
> + 
> ++			case 'm': { /* var scope */
> ++					char *m_arg, *s;
> ++
> ++					monhost_ups_prev = monhost_ups_current;
> ++					monhost_ups_current = xmalloc(sizeof(st
> ruct monhost_ups));
> ++					if (monhost_ups_anchor == NULL)
> ++						monhost_ups_anchor = monhost_up
> s_current;
> ++					else
> ++						monhost_ups_prev->next = monhos
> t_ups_current;
> ++					monhost_ups_current->next = NULL;
> ++					monhost_len++;
> ++
> ++					/* Be sure to not mangle original optar
> g, nor rely on its longevity */
> ++					s = xstrdup(optarg);
> ++					m_arg = s;
> ++					monhost_ups_current->monhost = xstrdup(
> strsep(&m_arg, ","));
> ++					if (!m_arg)
> ++						fatalx(EXIT_FAILURE, "Argument 
> '-m upsspec,logfile' requires exactly 2 components in the tuple");
> ++					monhost_ups_current->logfn = xstrdup(st
> rsep(&m_arg, ","));
> ++					if (m_arg) /* Had a third comma - also 
> unexpected! */
> ++						fatalx(EXIT_FAILURE, "Argument 
> '-m upsspec,logfile' requires exactly 2 components in the tuple");
> ++					if (upscli_splitname(monhost_ups_curren
> t->monhost, &(monhost_ups_current->upsname), &(monhost_ups_current->hostname)
> , &(monhost_ups_current->port)) != 0) {
> ++						fatalx(EXIT_FAILURE, "Error: in
> valid UPS definition.  Required format: upsname[@hostname[:port]]\n");
> ++					}
> ++					free(s);
> ++				} /* var scope */
> ++				break;
> + 			case 's':
> + 				monhost = optarg;
> + 				break;
> +@@ -479,42 +530,59 @@
> + 			snprintfcat(logformat, LARGEBUF, "%s ", argv[i]);
> + 	}
> + 
> +-	if (!monhost)
> +-		fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s <s
> ystem>");
> ++	if (monhost_ups_anchor == NULL) {
> ++		if (monhost) {
> ++			monhost_ups_current = xmalloc(sizeof(struct monhost_ups
> ));
> ++			monhost_ups_anchor = monhost_ups_current;
> ++			monhost_ups_current->next = NULL;
> ++			monhost_ups_current->monhost = monhost;
> ++			monhost_len=1;
> ++		} else {
> ++			fatalx(EXIT_FAILURE, "No UPS defined for monitoring - u
> se -s <system>");
> ++		}
> + 
> +-	if (!logfn)
> +-		fatalx(EXIT_FAILURE, "No filename defined for logging - use -l 
> <file>");
> ++		if (logfn)
> ++			monhost_ups_current->logfn = logfn;
> ++		else
> ++			fatalx(EXIT_FAILURE, "No filename defined for logging -
>  use -l <file>");
> ++	}
> + 
> + 	/* shouldn't happen */
> + 	if (!logformat)
> + 		fatalx(EXIT_FAILURE, "No format defined - but this should be im
> possible");
> + 
> +-	printf("logging status of %s to %s (%is intervals)\n",
> +-		monhost, logfn, interval);
> ++	for (monhost_ups_current = monhost_ups_anchor;
> ++	     monhost_ups_current != NULL;
> ++	     monhost_ups_current = monhost_ups_current->next) {
> ++		printf("logging status of %s to %s (%is intervals)\n",
> ++			monhost_ups_current->monhost, monhost_ups_current->logf
> n, interval);
> ++		if (upscli_splitname(monhost_ups_current->monhost, &(monhost_up
> s_current->upsname), &(monhost_ups_current->hostname), &(monhost_ups_current-
> >port)) != 0) {
> ++			fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  R
> equired format: upsname[@hostname[:port]]\n");
> ++		}
> + 
> +-	if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) {
> +-		fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  Required 
> format: upsname[@hostname[:port]]\n");
> +-	}
> ++		monhost_ups_current->ups = xmalloc(sizeof(UPSCONN_t));
> ++		if (upscli_connect(monhost_ups_current->ups, monhost_ups_curren
> t->hostname, monhost_ups_current->port, UPSCLI_CONN_TRYSSL) < 0)
> ++			fprintf(stderr, "Warning: initial connect failed: %s\n"
> ,
> ++				upscli_strerror(monhost_ups_current->ups));
> + 
> +-	if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0)
> +-		fprintf(stderr, "Warning: initial connect failed: %s\n",
> +-			upscli_strerror(&ups));
> ++		if (strcmp(monhost_ups_current->logfn, "-") == 0)
> ++			monhost_ups_current->logfile = stdout;
> ++		else
> ++			monhost_ups_current->logfile = fopen(monhost_ups_curren
> t->logfn, "a");
> + 
> +-	if (strcmp(logfn, "-") == 0)
> +-		logfile = stdout;
> +-	else
> +-		logfile = fopen(logfn, "a");
> ++		if (monhost_ups_current->logfile == NULL)
> ++			fatal_with_errno(EXIT_FAILURE, "could not open logfile 
> %s", logfn);
> + 
> +-	if (logfile == NULL)
> +-		fatal_with_errno(EXIT_FAILURE, "could not open logfile %s", log
> fn);
> ++	}
> + 
> ++
> + 	/* now drop root if we have it */
> + 	new_uid = get_user_pwent(user);
> + 
> + 	open_syslog(prog);
> + 
> + 	if (foreground < 0) {
> +-		if (logfile == stdout) {
> ++		if (monhost_ups_anchor->logfile == stdout) {
> + 			foreground = 1;
> + 		} else {
> + 			foreground = 0;
> +@@ -552,25 +620,35 @@
> + 			reopen_flag = 0;
> + 		}
> + 
> +-		/* reconnect if necessary */
> +-		if (upscli_fd(&ups) < 0) {
> +-			upscli_connect(&ups, hostname, port, 0);
> +-		}
> ++		for (monhost_ups_current = monhost_ups_anchor;
> ++		     monhost_ups_current != NULL;
> ++		     monhost_ups_current = monhost_ups_current->next) {
> ++			ups = monhost_ups_current->ups;	/* XXX Not ideal */
> ++			upsname = monhost_ups_current->upsname;	/* XXX Not idea
> l */
> ++			/* reconnect if necessary */
> ++			if (upscli_fd(ups) < 0) {
> ++				upscli_connect(ups, monhost_ups_current->hostna
> me, monhost_ups_current->port, 0);
> ++			}
> + 
> +-		run_flist();
> ++			run_flist(monhost_ups_current);
> + 
> +-		/* don't keep connection open if we don't intend to use it shor
> tly */
> +-		if (interval > 30) {
> +-			upscli_disconnect(&ups);
> ++			/* don't keep connection open if we don't intend to use
>  it shortly */
> ++			if (interval > 30) {
> ++				upscli_disconnect(ups);
> ++			}
> + 		}
> + 	}
> + 
> + 	upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
> ++	for (monhost_ups_current = monhost_ups_anchor;
> ++	     monhost_ups_current != NULL;
> ++	     monhost_ups_current = monhost_ups_current->next) {
> + 
> +-	if (logfile != stdout)
> +-		fclose(logfile);
> ++		if (monhost_ups_current->logfile != stdout)
> ++			fclose(monhost_ups_current->logfile);
> + 
> +-	upscli_disconnect(&ups);
> ++		upscli_disconnect(monhost_ups_current->ups);
> ++	}
> + 
> + 	exit(EXIT_SUCCESS);
> + }
> diff --git a/sysutils/nut-devel/files/patch-docs_man_upslog.txt b/sysutils/nu
> t-devel/files/patch-docs_man_upslog.txt
> new file mode 100644
> index 000000000000..9e139ccb6105
> --- /dev/null
> +++ b/sysutils/nut-devel/files/patch-docs_man_upslog.txt
> @@ -0,0 +1,14 @@
> +--- docs/man/upslog.txt.orig	2022-08-30 05:56:15.850373000 -0700
> ++++ docs/man/upslog.txt	2022-08-30 06:01:45.955996000 -0700
> +@@ -78,6 +78,11 @@
> + Monitor this UPS.  The format for this option is
> + +upsname[@hostname[:port]]+.  The default hostname is "localhost".
> + 
> ++*-m* 'tuple'::
> ++Monitor multiple UPSs. The format for this option is a tuple of
> ++ups and logfile separated by commas. An example would be:
> ++`upsname@hostname:9999,/var/log/nut/cps.log`
> ++
> + *-u* 'username'::
> + 
> + If started as root, upslog will *setuid*(2) to the user id
> diff --git a/sysutils/nut/Makefile b/sysutils/nut/Makefile
> index 1bad77416107..30eb3474f0c3 100644
> --- a/sysutils/nut/Makefile
> +++ b/sysutils/nut/Makefile
> @@ -1,6 +1,6 @@
>  PORTNAME=	nut
>  PORTVERSION=	2.8.0
> -PORTREVISION=	10
> +PORTREVISION=	11
>  CATEGORIES=	sysutils
>  MASTER_SITES=	http://www.networkupstools.org/source/${PORTVERSION:R}/
>  
> diff --git a/sysutils/nut/files/patch-clients_upslog.c b/sysutils/nut/files/p
> atch-clients_upslog.c
> new file mode 100644
> index 000000000000..bcebe5bba28c
> --- /dev/null
> +++ b/sysutils/nut/files/patch-clients_upslog.c
> @@ -0,0 +1,291 @@
> +--- clients/upslog.c.orig	2022-08-29 22:20:14.342137000 -0700
> ++++ clients/upslog.c	2022-08-29 22:21:10.934419000 -0700
> +@@ -32,6 +32,10 @@
> +  */
> + 
> + #include "common.h"
> ++#include <signal.h>
> ++#include <unistd.h>
> ++#include <sys/types.h>
> ++#include <sys/wait.h>
> + #include "nut_platform.h"
> + #include "upsclient.h"
> + 
> +@@ -41,32 +45,49 @@
> + #include "upslog.h"
> + 
> + 	static	int	reopen_flag = 0, exit_flag = 0;
> +-	static	uint16_t	port;
> +-	static	char	*upsname, *hostname;
> +-	static	UPSCONN_t	ups;
> ++	static	char	*upsname;
> ++	static	UPSCONN_t	*ups;
> + 
> +-	static	FILE	*logfile;
> +-	static	const	char *logfn, *monhost;
> ++	static	char *logfn, *monhost;
> + 	static	sigset_t	nut_upslog_sigmask;
> + 	static	char	logbuffer[LARGEBUF], *logformat;
> + 
> + 	static	flist_t	*fhead = NULL;
> ++	struct 	monhost_ups {
> ++		char	*monhost;
> ++		char	*logfn;
> ++		char	*upsname;
> ++		char	*hostname;
> ++		uint16_t	port;
> ++		UPSCONN_t	*ups;
> ++		FILE	*logfile;
> ++		struct	monhost_ups	*next;
> ++	};
> ++	static	struct	monhost_ups *monhost_ups_anchor = NULL;
> ++	static	struct	monhost_ups *monhost_ups_current = NULL;
> ++	static	struct	monhost_ups *monhost_ups_prev = NULL;
> + 
> ++
> + #define DEFAULT_LOGFORMAT "%TIME @Y@m@d @H@M@S% %VAR battery.charge% " \
> + 		"%VAR input.voltage% %VAR ups.load% [%VAR ups.status%] " \
> + 		"%VAR ups.temperature% %VAR input.frequency%"
> + 
> + static void reopen_log(void)
> + {
> +-	if (logfile == stdout) {
> +-		upslogx(LOG_INFO, "logging to stdout");
> +-		return;
> +-	}
> ++	for (monhost_ups_current = monhost_ups_anchor;
> ++	     monhost_ups_current != NULL;
> ++	     monhost_ups_current = monhost_ups_current->next) {
> ++		if (monhost_ups_current->logfile == stdout) {
> ++			upslogx(LOG_INFO, "logging to stdout");
> ++			return;
> ++		}
> + 
> +-	fclose(logfile);
> +-	logfile = fopen(logfn, "a");
> +-	if (logfile == NULL)
> +-		fatal_with_errno(EXIT_FAILURE, "could not reopen logfile %s", l
> ogfn);
> ++		if ((monhost_ups_current->logfile = freopen(
> ++		    monhost_ups_current->logfn, "a",
> ++		    monhost_ups_current->logfile)) == NULL)
> ++			fatal_with_errno(EXIT_FAILURE,
> ++				"could not reopen logfile %s", logfn);
> ++	}
> + }
> + 
> + static void set_reopen_flag(int sig)
> +@@ -131,6 +152,8 @@
> + 	printf("  -p <pidbase>  - Base name for PID file (defaults to \"%s\")\n
> ", prog);
> + 	printf("  -s <ups>	- Monitor UPS <ups> - <upsname>@<host>[:<port>]
> \n");
> + 	printf("        	- Example: -s myups@server\n");
> ++	printf("  -m <tuple>	- Monitor UPS <ups,logfile>\n");
> ++	printf("		- Example: -m myups@server,/var/log/myups.log\n
> ");
> + 	printf("  -u <user>	- Switch to <user> if started as root\n");
> + 
> + 	printf("\n");
> +@@ -215,7 +238,7 @@
> + 	query[2] = var;
> + 	numq = 3;
> + 
> +-	ret = upscli_get(&ups, numq, query, &numa, &answer);
> ++	ret = upscli_get(ups, numq, query, &numa, &answer);
> + 
> + 	if ((ret < 0) || (numa < numq)) {
> + 		snprintfcat(logbuffer, sizeof(logbuffer), "NA");
> +@@ -368,7 +391,7 @@
> + }
> + 
> + /* go through the list of functions and call them in order */
> +-static void run_flist(void)
> ++static void run_flist(struct monhost_ups *monhost_ups_print)
> + {
> + 	flist_t	*tmp;
> + 
> +@@ -382,8 +405,8 @@
> + 		tmp = tmp->next;
> + 	}
> + 
> +-	fprintf(logfile, "%s\n", logbuffer);
> +-	fflush(logfile);
> ++	fprintf(monhost_ups_print->logfile, "%s\n", logbuffer);
> ++	fflush(monhost_ups_print->logfile);
> + }
> + 
> + 	/* -s <monhost>
> +@@ -396,6 +419,7 @@
> + int main(int argc, char **argv)
> + {
> + 	int	interval = 30, i, foreground = -1;
> ++	size_t	monhost_len = 0;
> + 	const char	*prog = xbasename(argv[0]);
> + 	time_t	now, nextpoll = 0;
> + 	const char	*user = NULL;
> +@@ -407,7 +431,7 @@
> + 
> + 	printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
> + 
> +-	while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:FB")) != -1) {
> ++	while ((i = getopt(argc, argv, "+hs:l:i:f:u:Vp:FBm:")) != -1) {
> + 		switch(i) {
> + 			case 'h':
> + 				help(prog);
> +@@ -415,6 +439,33 @@
> + 				break;
> + #endif
> + 
> ++			case 'm': { /* var scope */
> ++					char *m_arg, *s;
> ++
> ++					monhost_ups_prev = monhost_ups_current;
> ++					monhost_ups_current = xmalloc(sizeof(st
> ruct monhost_ups));
> ++					if (monhost_ups_anchor == NULL)
> ++						monhost_ups_anchor = monhost_up
> s_current;
> ++					else
> ++						monhost_ups_prev->next = monhos
> t_ups_current;
> ++					monhost_ups_current->next = NULL;
> ++					monhost_len++;
> ++
> ++					/* Be sure to not mangle original optar
> g, nor rely on its longevity */
> ++					s = xstrdup(optarg);
> ++					m_arg = s;
> ++					monhost_ups_current->monhost = xstrdup(
> strsep(&m_arg, ","));
> ++					if (!m_arg)
> ++						fatalx(EXIT_FAILURE, "Argument 
> '-m upsspec,logfile' requires exactly 2 components in the tuple");
> ++					monhost_ups_current->logfn = xstrdup(st
> rsep(&m_arg, ","));
> ++					if (m_arg) /* Had a third comma - also 
> unexpected! */
> ++						fatalx(EXIT_FAILURE, "Argument 
> '-m upsspec,logfile' requires exactly 2 components in the tuple");
> ++					if (upscli_splitname(monhost_ups_curren
> t->monhost, &(monhost_ups_current->upsname), &(monhost_ups_current->hostname)
> , &(monhost_ups_current->port)) != 0) {
> ++						fatalx(EXIT_FAILURE, "Error: in
> valid UPS definition.  Required format: upsname[@hostname[:port]]\n");
> ++					}
> ++					free(s);
> ++				} /* var scope */
> ++				break;
> + 			case 's':
> + 				monhost = optarg;
> + 				break;
> +@@ -479,42 +530,59 @@
> + 			snprintfcat(logformat, LARGEBUF, "%s ", argv[i]);
> + 	}
> + 
> +-	if (!monhost)
> +-		fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s <s
> ystem>");
> ++	if (monhost_ups_anchor == NULL) {
> ++		if (monhost) {
> ++			monhost_ups_current = xmalloc(sizeof(struct monhost_ups
> ));
> ++			monhost_ups_anchor = monhost_ups_current;
> ++			monhost_ups_current->next = NULL;
> ++			monhost_ups_current->monhost = monhost;
> ++			monhost_len=1;
> ++		} else {
> ++			fatalx(EXIT_FAILURE, "No UPS defined for monitoring - u
> se -s <system>");
> ++		}
> + 
> +-	if (!logfn)
> +-		fatalx(EXIT_FAILURE, "No filename defined for logging - use -l 
> <file>");
> ++		if (logfn)
> ++			monhost_ups_current->logfn = logfn;
> ++		else
> ++			fatalx(EXIT_FAILURE, "No filename defined for logging -
>  use -l <file>");
> ++	}
> + 
> + 	/* shouldn't happen */
> + 	if (!logformat)
> + 		fatalx(EXIT_FAILURE, "No format defined - but this should be im
> possible");
> + 
> +-	printf("logging status of %s to %s (%is intervals)\n",
> +-		monhost, logfn, interval);
> ++	for (monhost_ups_current = monhost_ups_anchor;
> ++	     monhost_ups_current != NULL;
> ++	     monhost_ups_current = monhost_ups_current->next) {
> ++		printf("logging status of %s to %s (%is intervals)\n",
> ++			monhost_ups_current->monhost, monhost_ups_current->logf
> n, interval);
> ++		if (upscli_splitname(monhost_ups_current->monhost, &(monhost_up
> s_current->upsname), &(monhost_ups_current->hostname), &(monhost_ups_current-
> >port)) != 0) {
> ++			fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  R
> equired format: upsname[@hostname[:port]]\n");
> ++		}
> + 
> +-	if (upscli_splitname(monhost, &upsname, &hostname, &port) != 0) {
> +-		fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  Required 
> format: upsname[@hostname[:port]]\n");
> +-	}
> ++		monhost_ups_current->ups = xmalloc(sizeof(UPSCONN_t));
> ++		if (upscli_connect(monhost_ups_current->ups, monhost_ups_curren
> t->hostname, monhost_ups_current->port, UPSCLI_CONN_TRYSSL) < 0)
> ++			fprintf(stderr, "Warning: initial connect failed: %s\n"
> ,
> ++				upscli_strerror(monhost_ups_current->ups));
> + 
> +-	if (upscli_connect(&ups, hostname, port, UPSCLI_CONN_TRYSSL) < 0)
> +-		fprintf(stderr, "Warning: initial connect failed: %s\n",
> +-			upscli_strerror(&ups));
> ++		if (strcmp(monhost_ups_current->logfn, "-") == 0)
> ++			monhost_ups_current->logfile = stdout;
> ++		else
> ++			monhost_ups_current->logfile = fopen(monhost_ups_curren
> t->logfn, "a");
> + 
> +-	if (strcmp(logfn, "-") == 0)
> +-		logfile = stdout;
> +-	else
> +-		logfile = fopen(logfn, "a");
> ++		if (monhost_ups_current->logfile == NULL)
> ++			fatal_with_errno(EXIT_FAILURE, "could not open logfile 
> %s", logfn);
> + 
> +-	if (logfile == NULL)
> +-		fatal_with_errno(EXIT_FAILURE, "could not open logfile %s", log
> fn);
> ++	}
> + 
> ++
> + 	/* now drop root if we have it */
> + 	new_uid = get_user_pwent(user);
> + 
> + 	open_syslog(prog);
> + 
> + 	if (foreground < 0) {
> +-		if (logfile == stdout) {
> ++		if (monhost_ups_anchor->logfile == stdout) {
> + 			foreground = 1;
> + 		} else {
> + 			foreground = 0;
> +@@ -552,25 +620,35 @@
> + 			reopen_flag = 0;
> + 		}
> + 
> +-		/* reconnect if necessary */
> +-		if (upscli_fd(&ups) < 0) {
> +-			upscli_connect(&ups, hostname, port, 0);
> +-		}
> ++		for (monhost_ups_current = monhost_ups_anchor;
> ++		     monhost_ups_current != NULL;
> ++		     monhost_ups_current = monhost_ups_current->next) {
> ++			ups = monhost_ups_current->ups;	/* XXX Not ideal */
> ++			upsname = monhost_ups_current->upsname;	/* XXX Not idea
> l */
> ++			/* reconnect if necessary */
> ++			if (upscli_fd(ups) < 0) {
> ++				upscli_connect(ups, monhost_ups_current->hostna
> me, monhost_ups_current->port, 0);
> ++			}
> + 
> +-		run_flist();
> ++			run_flist(monhost_ups_current);
> + 
> +-		/* don't keep connection open if we don't intend to use it shor
> tly */
> +-		if (interval > 30) {
> +-			upscli_disconnect(&ups);
> ++			/* don't keep connection open if we don't intend to use
>  it shortly */
> ++			if (interval > 30) {
> ++				upscli_disconnect(ups);
> ++			}
> + 		}
> + 	}
> + 
> + 	upslogx(LOG_INFO, "Signal %d: exiting", exit_flag);
> ++	for (monhost_ups_current = monhost_ups_anchor;
> ++	     monhost_ups_current != NULL;
> ++	     monhost_ups_current = monhost_ups_current->next) {
> + 
> +-	if (logfile != stdout)
> +-		fclose(logfile);
> ++		if (monhost_ups_current->logfile != stdout)
> ++			fclose(monhost_ups_current->logfile);
> + 
> +-	upscli_disconnect(&ups);
> ++		upscli_disconnect(monhost_ups_current->ups);
> ++	}
> + 
> + 	exit(EXIT_SUCCESS);
> + }
> diff --git a/sysutils/nut/files/patch-docs_man_upslog.8 b/sysutils/nut/files/
> patch-docs_man_upslog.8
> new file mode 100644
> index 000000000000..37b1379ca6bf
> --- /dev/null
> +++ b/sysutils/nut/files/patch-docs_man_upslog.8
> @@ -0,0 +1,16 @@
> +--- docs/man/upslog.8.orig	2022-08-30 05:56:02.734873000 -0700
> ++++ docs/man/upslog.8	2022-08-30 06:09:47.928348000 -0700
> +@@ -134,6 +134,13 @@
> + upsname[@hostname[:port]]\&. The default hostname is "localhost"\&.
> + .RE
> + .PP
> ++\fB\-m\fR \fItuple\fR
> ++.RS 4
> ++Monitor multiple UPSs\&. The format for this option is a tuple of
> ++ups and logfile separated by commas\&. An example would be:
> ++upsname@hostname:9999,/var/log/nut/cps.log
> ++.RE
> ++.PP
> + \fB\-u\fR \fIusername\fR
> + .RS 4
> + If started as root, upslog will
> diff --git a/sysutils/nut/files/patch-docs_man_upslog.txt b/sysutils/nut/file
> s/patch-docs_man_upslog.txt
> new file mode 100644
> index 000000000000..e26d91e2d5f2
> --- /dev/null
> +++ b/sysutils/nut/files/patch-docs_man_upslog.txt
> @@ -0,0 +1,14 @@
> +--- docs/man/upslog.txt.orig	2022-08-30 05:56:02.761764000 -0700
> ++++ docs/man/upslog.txt	2022-08-30 06:04:33.428455000 -0700
> +@@ -78,6 +78,11 @@
> + Monitor this UPS.  The format for this option is
> + +upsname[@hostname[:port]]+.  The default hostname is "localhost".
> + 
> ++*-m* 'tuple'::
> ++Monitor multiple UPSs. The format for this option is a tuple of
> ++ups and logfile separated by commas. An example would be:
> ++`upsname@hostname:9999,/var/log/nut/cps.log`
> ++
> + *-u* 'username'::
> + 
> + If started as root, upslog will *setuid*(2) to the user id

A pull request implementing this has been sent to our upstream.


-- 
Cheers,
Cy Schubert <Cy.Schubert@cschubert.com>
FreeBSD UNIX:  <cy@FreeBSD.org>   Web:  http://www.FreeBSD.org
NTP:           <cy@nwtime.org>    Web:  https://nwtime.org

			e^(i*pi)+1=0





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20220830201528.CB318293>