From 45a55d061dd8fef63a50095c9f8d53735a261a95 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:18:18 +0200 Subject: [PATCH 1/7] common/wincompat.c: tcflush(): fix bitwise OR to boolean OR Signed-off-by: Jim Klimov --- common/wincompat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/wincompat.c b/common/wincompat.c index 7671c13b96..a71ede0b54 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -1125,7 +1125,7 @@ int tcflush(serial_handler_t *sh, int queue) if (queue == TCOFLUSH || queue == TCIOFLUSH) PurgeComm(sh->handle, PURGE_TXABORT | PURGE_TXCLEAR); - if ((queue == TCIFLUSH) | (queue == TCIOFLUSH)) + if ((queue == TCIFLUSH) || (queue == TCIOFLUSH)) { /* Input flushing by polling until nothing turns up * (we stop after 1000 chars anyway) */ From 8f55a571871f0c81807ce75bf40d79aab14e2a2b Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:25:29 +0200 Subject: [PATCH 2/7] common/wincompat.c: fix filter_path() to measure strlen(source) once [#3302] Signed-off-by: Jim Klimov --- common/wincompat.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/common/wincompat.c b/common/wincompat.c index a71ede0b54..004a9bbf74 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -417,20 +417,22 @@ int win_system(const char * command) } /* the " character is forbiden in Windows files , so we filter this character -in data file paths to be coherent with command line which require " to -distinguish the command from its parameter. This avoid complicated -explanation in the documentation */ + * in data file paths to be coherent with command line which require " to + * distinguish the command from its parameter. This avoid complicated + * explanation in the documentation */ char * filter_path(const char * source) { char *res; unsigned int i, j; + size_t len; if (source == NULL) { return NULL; } - res = xmalloc(strlen(source) + 1); - for (i=0, j=0; i <= strlen(source); i++) { + len = strlen(source); + res = xmalloc(len + 1); + for (i=0, j=0; i <= len; i++) { if (source[i] != '"') { res[j] = source[i]; j++; From 5df66501c2b4f12053a28524985ba207cc6937c2 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:28:39 +0200 Subject: [PATCH 3/7] common/wincompat.c: fix getpass() to measure strlen(wincompat_password) once [#3302] Signed-off-by: Jim Klimov --- common/wincompat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/wincompat.c b/common/wincompat.c index 004a9bbf74..d55f642bc6 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -68,6 +68,7 @@ char *getpass(const char *prompt) { HANDLE hStdin; DWORD mode; + size_t len; hStdin = GetStdHandle(STD_INPUT_HANDLE); if (hStdin == INVALID_HANDLE_VALUE) { @@ -86,8 +87,9 @@ char *getpass(const char *prompt) } /* deal with that pesky newline */ - if (strlen(wincompat_password) > 1) { - wincompat_password[strlen(wincompat_password) - 1] = '\0'; + len = strlen(wincompat_password); + if (len > 1) { + wincompat_password[len - 1] = '\0'; } hStdin = GetStdHandle(STD_INPUT_HANDLE); From d9d04f73a9f51e3d4d090d55b905fc13a3ba370a Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:29:34 +0200 Subject: [PATCH 4/7] common/wincompat.c: fix send_to_named_pipe() to measure strlen(data) once [#3302] Signed-off-by: Jim Klimov --- common/wincompat.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/common/wincompat.c b/common/wincompat.c index d55f642bc6..f7e193bf16 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -661,6 +661,7 @@ int send_to_named_pipe(const char * pipe_name, const char * data) BOOL result = FALSE; DWORD bytesWritten = 0; char pipe_full_name[NUT_PATH_MAX + 1]; + size_t len; snprintf(pipe_full_name, sizeof(pipe_full_name), "\\\\.\\pipe\\%s", pipe_name); @@ -677,9 +678,10 @@ int send_to_named_pipe(const char * pipe_name, const char * data) return 1; } - result = WriteFile(pipe, data, strlen(data) + 1, &bytesWritten, NULL); + len = strlen(data); + result = WriteFile(pipe, data, len + 1, &bytesWritten, NULL); - if (result == 0 || bytesWritten != strlen(data) + 1) { + if (result == 0 || bytesWritten != len + 1) { CloseHandle(pipe); return 1; } From 674ec0e7b464f0c22c3affa9e70afcb45f985570 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:47:05 +0200 Subject: [PATCH 5/7] common/wincompat.c: log progress through pipe*() methods [#3302, #3368] Signed-off-by: Jim Klimov --- common/wincompat.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/common/wincompat.c b/common/wincompat.c index f7e193bf16..7f4232d422 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -409,6 +409,7 @@ int win_system(const char * command) si.cb = sizeof(si); memset(&pi, 0, sizeof(pi)); + upsdebugx(4, "%s: calling CreateProcess: %s", __func__, NUT_STRARG(command)); res = CreateProcess(NULL, (char *)command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (res != 0) { @@ -478,6 +479,7 @@ void syslog(int priority, const char *fmt, ...) /* then comes the message */ memcpy(buf1 + sizeof(DWORD), buf2, sizeof(buf2)); + upsdebugx(6, "%s: posting to event log NAMED_PIPE: '%s'", __func__, pipe_full_name); pipe = CreateFile( pipe_full_name, /* pipe name */ GENERIC_WRITE, @@ -496,6 +498,7 @@ void syslog(int priority, const char *fmt, ...) /* testing result is useless. If we have an error and try to report it, * this will probably lead to a call to this function and an infinite * loop */ + upsdebugx(6, "%s: closing event log NAMED_PIPE", __func__); CloseHandle(pipe); } @@ -530,6 +533,7 @@ void pipe_create(const char * pipe_name) CloseHandle(pipe_connection_overlapped.hEvent); } memset(&pipe_connection_overlapped, 0, sizeof(pipe_connection_overlapped)); + upsdebugx(2, "%s: creating NAMED_PIPE (listener): '%s'", __func__, pipe_full_name); pipe_connection_handle = CreateNamedPipe( pipe_full_name, PIPE_ACCESS_INBOUND /* to server only */ @@ -573,6 +577,12 @@ void pipe_connect() /* We have detected a connection on the opened pipe. So we start by saving its handle and create a new pipe for future connections */ pipe_conn_t *conn; + /* TOTHINK: Here we seem to have assumptions about a general connection + * via overlapped I/O being the signal to daemon (via named_pipe_name)... + * might this conflict with other I/Os (driver/server sockets, dummy-ups + * files, etc.)? + */ + upsdebugx(3, "%s: handle incoming connection on NAMED PIPE", __func__); conn = xcalloc(1, sizeof(*conn)); conn->handle = pipe_connection_handle; @@ -609,17 +619,22 @@ void pipe_connect() void pipe_disconnect(pipe_conn_t *conn) { + upsdebugx(3, "%s: starting", __func__); + if (conn->overlapped.hEvent != INVALID_HANDLE_VALUE) { + upsdebugx(4, "%s: calling CloseHandle() for conn->overlapped.hEvent", __func__); CloseHandle(conn->overlapped.hEvent); conn->overlapped.hEvent = INVALID_HANDLE_VALUE; } if (conn->handle != INVALID_HANDLE_VALUE) { + upsdebugx(4, "%s: calling DisconnectNamedPipe() for not-yet-invalid conn->handle", __func__); if (DisconnectNamedPipe(conn->handle) == 0) { upslogx(LOG_ERR, "DisconnectNamedPipe error : %d", (int)GetLastError()); } + upsdebugx(4, "%s: calling CloseHandle() for conn->handle", __func__); CloseHandle(conn->handle); conn->handle = INVALID_HANDLE_VALUE; } @@ -665,6 +680,7 @@ int send_to_named_pipe(const char * pipe_name, const char * data) snprintf(pipe_full_name, sizeof(pipe_full_name), "\\\\.\\pipe\\%s", pipe_name); + upsdebugx(6, "%s: posting to NAMED_PIPE: '%s'", __func__, pipe_full_name); pipe = CreateFile( pipe_full_name, GENERIC_WRITE, @@ -686,6 +702,7 @@ int send_to_named_pipe(const char * pipe_name, const char * data) return 1; } + upsdebugx(6, "%s: closing event log NAMED_PIPE", __func__); CloseHandle(pipe); return 0; } From 8d7d8a1db33a14abaf2a0b40ee75aeb8bd2048f0 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:47:50 +0200 Subject: [PATCH 6/7] common/wincompat.c: log errors after methods faults via upslog_with_errno() not plain upslogx() [#3302] Signed-off-by: Jim Klimov --- common/wincompat.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/common/wincompat.c b/common/wincompat.c index 7f4232d422..8dda96c1a8 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -568,7 +568,7 @@ void pipe_create(const char * pipe_name) /* Wait for a connection */ ret = ConnectNamedPipe(pipe_connection_handle, &pipe_connection_overlapped); if (ret == 0 && GetLastError() != ERROR_IO_PENDING) { - upslogx(LOG_ERR, "ConnectNamedPipe error"); + upslog_with_errno(LOG_ERR, "ConnectNamedPipe error"); } } @@ -601,7 +601,7 @@ void pipe_connect() ); if (conn->overlapped.hEvent == NULL) { /* FIXME: Is this (still) about event log only? */ - upslogx(LOG_ERR, "Can't create event for reading event log"); + upslog_with_errno(LOG_ERR, "Can't create event for reading event log"); return; } @@ -630,9 +630,7 @@ void pipe_disconnect(pipe_conn_t *conn) if (conn->handle != INVALID_HANDLE_VALUE) { upsdebugx(4, "%s: calling DisconnectNamedPipe() for not-yet-invalid conn->handle", __func__); if (DisconnectNamedPipe(conn->handle) == 0) { - upslogx(LOG_ERR, - "DisconnectNamedPipe error : %d", - (int)GetLastError()); + upslog_with_errno(LOG_ERR, "DisconnectNamedPipe failed"); } upsdebugx(4, "%s: calling CloseHandle() for conn->handle", __func__); CloseHandle(conn->handle); @@ -661,7 +659,7 @@ int pipe_ready(pipe_conn_t *conn) res = GetOverlappedResult(conn->handle, &conn->overlapped, &bytesRead, FALSE); if (res == 0) { - upslogx(LOG_ERR, "Pipe read error"); + upslog_with_errno(LOG_ERR, "Pipe read error"); pipe_disconnect(conn); return 0; } @@ -698,6 +696,7 @@ int send_to_named_pipe(const char * pipe_name, const char * data) result = WriteFile(pipe, data, len + 1, &bytesWritten, NULL); if (result == 0 || bytesWritten != len + 1) { + upsdebug_with_errno(6, "%s: closing event log NAMED_PIPE, did not write as much as expected to", __func__); CloseHandle(pipe); return 1; } @@ -978,7 +977,7 @@ serial_handler_t * w32_serial_open(const char *name, int flags) 0); if (sh->handle == INVALID_HANDLE_VALUE) { - upslogx(LOG_ERR, "could not open %s", name); + upslog_with_errno(LOG_ERR, "could not open %s", name); errno = EPERM; return NULL; } @@ -1017,7 +1016,7 @@ serial_handler_t * w32_serial_open(const char *name, int flags) state.fAbortOnError = TRUE; if (!SetCommState(sh->handle, &state)) { - upslogx(LOG_ERR, + upslog_with_errno(LOG_ERR, "couldn't set initial state for %s", name); } @@ -1492,7 +1491,7 @@ TCSAFLUSH: flush output and discard input, then change attributes. res = SetCommTimeouts(sh->handle, &to); if (!res) { - upslogx(LOG_ERR, "SetCommTimeout failed"); + upslog_with_errno(LOG_ERR, "SetCommTimeout failed"); errno = EIO; return -1; } From ac4af58ab4efc3f2f48b219461e31b640e679e88 Mon Sep 17 00:00:00 2001 From: Jim Klimov Date: Mon, 6 Apr 2026 00:51:54 +0200 Subject: [PATCH 7/7] common/wincompat.c: syslog(), send_to_named_pipe(): debug-log when we failed to open existing NAMED_PIPE and so move on [#3302] Signed-off-by: Jim Klimov --- common/wincompat.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/common/wincompat.c b/common/wincompat.c index 8dda96c1a8..43721b2ee8 100644 --- a/common/wincompat.c +++ b/common/wincompat.c @@ -490,6 +490,10 @@ void syslog(int priority, const char *fmt, ...) NULL); /* no template file */ if (pipe == INVALID_HANDLE_VALUE) { + upsdebug_with_errno(1, + "%s: SKIP: can't open existing event log NAMED_PIPE: '%s'", + __func__, pipe_full_name); + return; } @@ -689,6 +693,10 @@ int send_to_named_pipe(const char * pipe_name, const char * data) NULL); /* no template file */ if (pipe == INVALID_HANDLE_VALUE) { + upsdebug_with_errno(1, + "%s: SKIP: can't open existing NAMED_PIPE: '%s'", + __func__, pipe_full_name); + return 1; }