Skip to content

Commit ff24189

Browse files
authored
Merge pull request #2118 from jimklimov/nit-warn
Clean up `dummy-ups` code, behavior and logs; added `NUT_DEBUG_PID` option
2 parents 425a2d6 + 71710c2 commit ff24189

File tree

5 files changed

+256
-140
lines changed

5 files changed

+256
-140
lines changed

NEWS.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@ as part of https://github.com/networkupstools/nut/issues/1410 solution.
139139
of UID/GID (everywhere), which makes troubleshooting harder (e.g. lack
140140
of access to config files or USB device nodes). Now we have it [#1694]
141141

142+
- A `NUT_DEBUG_PID` envvar (presence) support was added to add current
143+
process ID to tags with debug-level identifiers. This may be useful
144+
when many NUT daemons write to the same console or log file. [#2118]
145+
142146
- huawei-ups2000 is now known to support more devices, noted in docs and
143147
for auto-detection [#1448, #1684]
144148

UPGRADING.adoc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ Changes from 2.8.0 to 2.8.1
128128
and exposed in `libnutscan.so` builds in particular - API version for the
129129
public library was bumped [#317]
130130
131+
- A `NUT_DEBUG_PID` envvar (presence) support was added to add current
132+
process ID to tags with debug-level identifiers. This may be useful
133+
when many NUT daemons write to the same console or log file, such as
134+
in containers/plugins for Home Assistant, storage appliances, etc. [#2118]
135+
131136
- `configure` script, reference init-script and packaging templates updated
132137
to eradicate `@PIDPATH@/nut` ambiguity in favor of `@ALTPIDPATH@` for the
133138
unprivileged processes vs. `@PIDPATH@` for those running as root [#1719]

common/common.c

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,7 @@ void s_upsdebug_with_errno(int level, const char *fmt, ...)
15191519
{
15201520
va_list va;
15211521
char fmt2[LARGEBUF];
1522+
static int NUT_DEBUG_PID = -1;
15221523

15231524
/* Note: Thanks to macro wrapping, we do not quite need this
15241525
* test now, but we still need the "level" value to report
@@ -1534,7 +1535,18 @@ void s_upsdebug_with_errno(int level, const char *fmt, ...)
15341535
* can help limit this debug stream quicker, than experimentally picking ;) */
15351536
if (level > 0) {
15361537
int ret;
1537-
ret = snprintf(fmt2, sizeof(fmt2), "[D%d] %s", level, fmt);
1538+
1539+
if (NUT_DEBUG_PID < 0) {
1540+
NUT_DEBUG_PID = (getenv("NUT_DEBUG_PID") != NULL);
1541+
}
1542+
1543+
if (NUT_DEBUG_PID) {
1544+
/* Note that we re-request PID every time as it can
1545+
* change during the run-time (forking etc.) */
1546+
ret = snprintf(fmt2, sizeof(fmt2), "[D%d:%" PRIiMAX "] %s", level, (intmax_t)getpid(), fmt);
1547+
} else {
1548+
ret = snprintf(fmt2, sizeof(fmt2), "[D%d] %s", level, fmt);
1549+
}
15381550
if ((ret < 0) || (ret >= (int) sizeof(fmt2))) {
15391551
syslog(LOG_WARNING, "upsdebug_with_errno: snprintf needed more than %d bytes",
15401552
LARGEBUF);
@@ -1564,14 +1576,27 @@ void s_upsdebugx(int level, const char *fmt, ...)
15641576
{
15651577
va_list va;
15661578
char fmt2[LARGEBUF];
1579+
static int NUT_DEBUG_PID = -1;
15671580

15681581
if (nut_debug_level < level)
15691582
return;
15701583

15711584
/* See comments above in upsdebug_with_errno() - they apply here too. */
15721585
if (level > 0) {
15731586
int ret;
1574-
ret = snprintf(fmt2, sizeof(fmt2), "[D%d] %s", level, fmt);
1587+
1588+
if (NUT_DEBUG_PID < 0) {
1589+
NUT_DEBUG_PID = (getenv("NUT_DEBUG_PID") != NULL);
1590+
}
1591+
1592+
if (NUT_DEBUG_PID) {
1593+
/* Note that we re-request PID every time as it can
1594+
* change during the run-time (forking etc.) */
1595+
ret = snprintf(fmt2, sizeof(fmt2), "[D%d:%" PRIiMAX "] %s", level, (intmax_t)getpid(), fmt);
1596+
} else {
1597+
ret = snprintf(fmt2, sizeof(fmt2), "[D%d] %s", level, fmt);
1598+
}
1599+
15751600
if ((ret < 0) || (ret >= (int) sizeof(fmt2))) {
15761601
syslog(LOG_WARNING, "upsdebugx: snprintf needed more than %d bytes",
15771602
LARGEBUF);

drivers/dummy-ups.c

Lines changed: 58 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
Copyright (C)
44
2005 - 2015 Arnaud Quette <http://arnaud.quette.free.fr/contact.html>
5+
2014 - 2023 Jim Klimov <jimklimov+nut@gmail.com>
56
67
This program is free software; you can redistribute it and/or modify
78
it under the terms of the GNU General Public License as published by
@@ -47,7 +48,7 @@
4748
#include "dummy-ups.h"
4849

4950
#define DRIVER_NAME "Device simulation and repeater driver"
50-
#define DRIVER_VERSION "0.16"
51+
#define DRIVER_VERSION "0.17"
5152

5253
/* driver description structure */
5354
upsdrv_info_t upsdrv_info =
@@ -98,7 +99,7 @@ static struct stat datafile_stat;
9899

99100
static int setvar(const char *varname, const char *val);
100101
static int instcmd(const char *cmdname, const char *extra);
101-
static int parse_data_file(TYPE_FD upsfd);
102+
static int parse_data_file(TYPE_FD arg_upsfd);
102103
static dummy_info_t *find_info(const char *varname);
103104
static int is_valid_data(const char* varname);
104105
static int is_valid_value(const char* varname, const char *value);
@@ -207,6 +208,36 @@ void upsdrv_initinfo(void)
207208
dstate_addcmd("load.off");
208209
}
209210

211+
static int prepare_filepath(char *fn, size_t buflen)
212+
{
213+
/* Note: device_path is a global variable,
214+
* the "port=..." value parsed in main.c */
215+
if (device_path[0] == '/'
216+
#ifdef WIN32
217+
|| device_path[1] == ':' /* "C:\..." */
218+
#endif
219+
) {
220+
/* absolute path */
221+
return snprintf(fn, buflen, "%s", device_path);
222+
} else if (device_path[0] == '.') {
223+
/* "./" or "../" e.g. via CLI, relative to current working
224+
* directory of the driver process... at this moment */
225+
if (getcwd(fn, buflen)) {
226+
return snprintf(fn + strlen(fn), buflen - strlen(fn), "/%s", device_path);
227+
} else {
228+
return snprintf(fn, buflen, "%s", device_path);
229+
}
230+
} else {
231+
/* assumed to be a filename in NUT config file path
232+
* (possibly under, with direct use of dirname without dots)
233+
* Note that we do not fiddle with file-path separator,
234+
* modern Windows (at least via MinGW/MSYS2) supports
235+
* the POSIX slash.
236+
*/
237+
return snprintf(fn, buflen, "%s/%s", confpath(), device_path);
238+
}
239+
}
240+
210241
void upsdrv_updateinfo(void)
211242
{
212243
upsdebugx(1, "upsdrv_updateinfo...");
@@ -227,42 +258,35 @@ void upsdrv_updateinfo(void)
227258
struct stat fs;
228259
char fn[SMALLBUF];
229260

230-
if (device_path[0] == '/'
231-
#ifdef WIN32
232-
|| device_path[1] == ':' /* "C:\..." */
233-
#endif
234-
)
235-
snprintf(fn, sizeof(fn), "%s", device_path);
236-
else if (device_path[0] == '.') {
237-
/* "./" or "../" e.g. via CLI */
238-
if (getcwd(fn, sizeof(fn))) {
239-
snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", device_path);
240-
} else
241-
snprintf(fn, sizeof(fn), "%s", device_path);
242-
} else
243-
snprintf(fn, sizeof(fn), "%s/%s", confpath(), device_path);
261+
prepare_filepath(fn, sizeof(fn));
244262

245263
/* Determine if file modification timestamp has changed
246264
* since last use (so we would want to re-read it) */
247265
#ifndef WIN32
248-
/* Either successful stat is OK to fill the "fs" struct */
249-
if (0 != fstat (upsfd, &fs) && 0 != stat (fn, &fs))
266+
/* Either successful stat (zero return) is OK to
267+
* fill the "fs" struct. Note that currently
268+
* "upsfd" is a no-op for files, they are re-opened
269+
* and re-parsed every time so callers can modify
270+
* the data without complications.
271+
*/
272+
if ( (INVALID_FD(upsfd) || 0 != fstat (upsfd, &fs)) && 0 != stat (fn, &fs))
250273
#else
251274
/* Consider GetFileAttributesEx() for WIN32_FILE_ATTRIBUTE_DATA?
252275
* https://stackoverflow.com/questions/8991192/check-the-file-size-without-opening-file-in-c/8991228#8991228
253276
*/
254277
if (0 != stat (fn, &fs))
255278
#endif
256279
{
257-
upsdebugx(2, "Can't open %s currently", fn);
280+
upsdebugx(2, "%s: MODE_DUMMY_ONCE: Can't stat %s currently", __func__, fn);
258281
/* retry ASAP until we get a file */
259282
memset(&datafile_stat, 0, sizeof(struct stat));
260283
next_update = 1;
261284
} else {
262285
if (datafile_stat.st_mtime != fs.st_mtime) {
263286
upsdebugx(2,
264-
"upsdrv_updateinfo: input file was already read once "
265-
"to the end, but changed later - re-reading: %s", fn);
287+
"%s: MODE_DUMMY_ONCE: input file was already read once "
288+
"to the end, but changed later - re-reading: %s",
289+
__func__, fn);
266290
/* updated file => retry ASAP */
267291
next_update = 1;
268292
datafile_stat = fs;
@@ -271,7 +295,7 @@ void upsdrv_updateinfo(void)
271295
}
272296

273297
if (ctx == NULL && next_update == -1) {
274-
upsdebugx(2, "upsdrv_updateinfo: NO-OP: input file was already read once to the end");
298+
upsdebugx(2, "%s: MODE_DUMMY_ONCE: NO-OP: input file was already read once to the end", __func__);
275299
dstate_dataok();
276300
} else {
277301
/* initial parsing interrupted by e.g. TIMER line */
@@ -474,33 +498,25 @@ void upsdrv_initups(void)
474498
#endif
475499
}
476500

477-
if (device_path[0] == '/'
478-
#ifdef WIN32
479-
|| device_path[1] == ':' /* "C:\..." */
480-
#endif
481-
)
482-
snprintf(fn, sizeof(fn), "%s", device_path);
483-
else if (device_path[0] == '.') {
484-
/* "./" or "../" e.g. via CLI */
485-
if (getcwd(fn, sizeof(fn))) {
486-
snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", device_path);
487-
} else
488-
snprintf(fn, sizeof(fn), "%s", device_path);
489-
} else
490-
snprintf(fn, sizeof(fn), "%s/%s", confpath(), device_path);
501+
prepare_filepath(fn, sizeof(fn));
491502

492503
/* Update file modification timestamp (and other data) */
493504
#ifndef WIN32
494-
/* Either successful stat is OK to fill the "datafile_stat" struct */
495-
if (0 != fstat (upsfd, &datafile_stat) && 0 != stat (device_path, &datafile_stat))
505+
/* Either successful stat (zero return) is OK to fill the
506+
* "datafile_stat" struct. Note that currently "upsfd" is
507+
* a no-op for files, they are re-opened and re-parsed
508+
* every time so callers can modify the data without
509+
* complications.
510+
*/
511+
if ( (INVALID_FD(upsfd) || 0 != fstat (upsfd, &datafile_stat)) && 0 != stat (fn, &datafile_stat))
496512
#else
497513
/* Consider GetFileAttributesEx() for WIN32_FILE_ATTRIBUTE_DATA?
498514
* https://stackoverflow.com/questions/8991192/check-the-file-size-without-opening-file-in-c/8991228#8991228
499515
*/
500-
if (0 != stat (device_path, &datafile_stat))
516+
if (0 != stat (fn, &datafile_stat))
501517
#endif
502518
{
503-
upsdebugx(2, "Can't open %s (%s) currently", device_path, fn);
519+
upsdebugx(2, "%s: Can't stat %s (%s) currently", __func__, device_path, fn);
504520
} else {
505521
upsdebugx(2, "Located %s for device simulation data: %s", device_path, fn);
506522
}
@@ -642,7 +658,7 @@ static dummy_info_t *find_info(const char *varname)
642658
return item;
643659
}
644660

645-
upsdebugx(2, "find_info: unknown variable: %s\n", varname);
661+
upsdebugx(2, "find_info: unknown variable: %s", varname);
646662

647663
return NULL;
648664
}
@@ -719,21 +735,7 @@ static int parse_data_file(TYPE_FD arg_upsfd)
719735
{
720736
ctx = (PCONF_CTX_t *)xmalloc(sizeof(PCONF_CTX_t));
721737

722-
if (device_path[0] == '/'
723-
#ifdef WIN32
724-
|| device_path[1] == ':' /* "C:\..." */
725-
#endif
726-
)
727-
snprintf(fn, sizeof(fn), "%s", device_path);
728-
else if (device_path[0] == '.') {
729-
/* "./" or "../" e.g. via CLI */
730-
if (getcwd(fn, sizeof(fn))) {
731-
snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", device_path);
732-
} else
733-
snprintf(fn, sizeof(fn), "%s", device_path);
734-
} else
735-
snprintf(fn, sizeof(fn), "%s/%s", confpath(), device_path);
736-
738+
prepare_filepath(fn, sizeof(fn));
737739
pconf_init(ctx, upsconf_err);
738740

739741
if (!pconf_file_begin(ctx, fn))

0 commit comments

Comments
 (0)