Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ https://github.com/networkupstools/nut/milestone/8
be sufficient without deprecation warnings for builds against openssl-3.0.x
(but no real-time testing was done yet) [#1547]

- upslog: Added support for logging multiple devices with one call to the
program [#1604]

- some fixes applied to Solaris/illumos packaging and SMF service support
[#1554, #1564]

Expand Down
169 changes: 121 additions & 48 deletions clients/upslog.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,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", logfn);
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)
Expand Down Expand Up @@ -131,6 +148,8 @@ static void help(const char *prog)
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");
Expand Down Expand Up @@ -215,7 +234,7 @@ static void getvar(const char *var)
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");
Expand Down Expand Up @@ -368,7 +387,7 @@ static void compile_format(void)
}

/* 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;

Expand All @@ -382,8 +401,8 @@ static void run_flist(void)
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>
Expand All @@ -396,6 +415,7 @@ static void run_flist(void)
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;
Expand All @@ -407,14 +427,41 @@ int main(int argc, char **argv)

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);
#ifndef HAVE___ATTRIBUTE__NORETURN
break;
#endif

case 'm': { /* var scope */
char *m_arg, *s;

monhost_ups_prev = monhost_ups_current;
monhost_ups_current = xmalloc(sizeof(struct monhost_ups));
if (monhost_ups_anchor == NULL)
monhost_ups_anchor = monhost_ups_current;
else
monhost_ups_prev->next = monhost_ups_current;
monhost_ups_current->next = NULL;
monhost_len++;

/* Be sure to not mangle original optarg, 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(strsep(&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_current->monhost, &(monhost_ups_current->upsname), &(monhost_ups_current->hostname), &(monhost_ups_current->port)) != 0) {
fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]\n");
}
free(s);
} /* var scope */
break;
case 's':
monhost = optarg;
break;
Expand Down Expand Up @@ -479,42 +526,58 @@ int main(int argc, char **argv)
snprintfcat(logformat, LARGEBUF, "%s ", argv[i]);
}

if (!monhost)
fatalx(EXIT_FAILURE, "No UPS defined for monitoring - use -s <system>");
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 - use -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 impossible");

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->logfn, interval);
if (upscli_splitname(monhost_ups_current->monhost, &(monhost_ups_current->upsname), &(monhost_ups_current->hostname), &(monhost_ups_current->port)) != 0) {
fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required 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_current->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)
upslogx(LOG_INFO, "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_current->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", logfn);
}

/* 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;
Expand Down Expand Up @@ -552,25 +615,35 @@ int main(int argc, char **argv)
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 ideal */
/* reconnect if necessary */
if (upscli_fd(ups) < 0) {
upscli_connect(ups, monhost_ups_current->hostname, 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 shortly */
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);
}
Expand Down
5 changes: 5 additions & 0 deletions docs/man/upslog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ upslog will run in the background, regardless of logging target.
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
Expand Down