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
5 changes: 5 additions & 0 deletions NEWS.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ https://github.com/networkupstools/nut/milestone/12
operations. (Re-)registration of the "Network UPS Tools" service should
now populate a nice description of it. The `-U` (uninstall) action should
now also try to stop the service first. [PR #3235]
* Using `nut.exe -N` for testing and pressing 'Ctrl+C' should now cause the
started daemons to be killed off. Previously they would linger and e.g.
preclude subsequent experiments with the service wrapper. Console close
events are ignored, so there is a way to indefinitely keep the daemons
started by test-mode wrapper running (kill via Task Manager). [#3312]
* Revised WIN32 `WSAStartup()` and registration of `atexit(WSACleanup)` to
only be done once per program (and cleanups to be always registered); this
impacts the C `libupsclient` and C++ `libnutclient` libraries (and so most
Expand Down
6 changes: 6 additions & 0 deletions docs/man/nut.exe.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ Install as a Windows service called "Network UPS Tools". Does not start it.

*-N*::
Run once in non-service mode (for troubleshooting).
+
Since NUT v2.8.5, using `nut.exe -N` for testing and pressing 'Ctrl+C' should
cause the started daemons to be killed off. Previously they would linger and
e.g. preclude subsequent experiments with the service wrapper. Console close
events are ignored, so there is a way to indefinitely keep the daemons started
by the test-mode wrapper running (kill later if needed via Task Manager).

*start*::
Install as a Windows service called "Network UPS Tools" (if not yet done),
Expand Down
73 changes: 71 additions & 2 deletions scripts/Windows/wininit.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ typedef struct conn_s {
struct conn_s *next;
} conn_t;

static int exit_flag = 0;
static DWORD upsd_pid = 0;
static DWORD upsmon_pid = 0;
static DWORD upsdrvctl_pid = 0;
Expand Down Expand Up @@ -581,6 +582,54 @@ static void ReportSvcStatus(
SetServiceStatus(SvcStatusHandle, &SvcStatus);
}

/* For `nut.exe -N` runs
* https://learn.microsoft.com/en-us/windows/console/registering-a-control-handler-function
*/
static BOOL WINAPI ConsoleCtrlHandler(DWORD Ctrl)
{
switch(Ctrl)
{
case CTRL_C_EVENT:
print_event(LOG_INFO, "Ctrl+C received on console");
exit_flag = 1; /* Break SvcMain() infinite loop */
if (upsmon_pid) {
print_event(LOG_INFO, "Stopping upsmon");
stop_upsmon();
}
if (upsd_pid) {
print_event(LOG_INFO, "Stopping upsd");
stop_upsd();
}
if (upsdrvctl_pid) {
print_event(LOG_INFO, "Stopping drivers");
stop_drivers();
}
exit_flag = 2; /* Allow to finish SvcMain() infinite loop and proceed to exit() */
/* confirm that the user wants to exit */
return TRUE;

case CTRL_CLOSE_EVENT:
print_event(LOG_INFO, "Close event received on console, currently ignored");
return FALSE;

case CTRL_BREAK_EVENT:
print_event(LOG_INFO, "Ctrl+Break event received on console, currently ignored");
return FALSE;

/* TOTHINK: Do we in fact want these two handled specially? */
case CTRL_LOGOFF_EVENT:
print_event(LOG_INFO, "Logoff event received on console, currently ignored");
return FALSE;

case CTRL_SHUTDOWN_EVENT:
print_event(LOG_INFO, "Shutdown event received on console, currently ignored");
return FALSE;

default:
return FALSE;
}
}

static void WINAPI SvcCtrlHandler(DWORD Ctrl)
{
switch(Ctrl)
Expand Down Expand Up @@ -659,7 +708,7 @@ static void close_all(void)
static void WINAPI SvcMain(DWORD argc, LPTSTR *argv)
{
DWORD ret;
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; /* 64 per current WinAPI sheaders */
HANDLE handles[MAXIMUM_WAIT_OBJECTS]; /* 64 per current WinAPI headers */
size_t maxhandle = 0;
pipe_conn_t *conn;
DWORD priority;
Expand Down Expand Up @@ -697,7 +746,7 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv)
SvcReady();
}

while (1) {
while (!exit_flag) {
maxhandle = 0;
memset(&handles, 0, sizeof(handles));

Expand Down Expand Up @@ -766,6 +815,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv)
}
}

/* Do not check on daemons nor revive them in vain if we are exiting */
if (exit_flag)
break;

/* Check on each daemon: Was it supposed to run? Does it still? */
if (upsdrvctl_pid) {
DWORD status = 0;
Expand All @@ -785,6 +838,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv)
}
}

/* Do not check on daemons nor revive them in vain if we are exiting */
if (exit_flag)
break;

if (upsd_pid) {
DWORD status = 0;
BOOL res = FALSE;
Expand All @@ -803,6 +860,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv)
}
}

/* Do not check on daemons nor revive them in vain if we are exiting */
if (exit_flag)
break;

if (upsmon_pid) {
DWORD status = 0;
BOOL res = FALSE;
Expand All @@ -821,6 +882,10 @@ static void WINAPI SvcMain(DWORD argc, LPTSTR *argv)
}
}
}

while (exit_flag < 2) {
Sleep(1000);
}
}

static void help(const char *arg_progname)
Expand Down Expand Up @@ -1020,6 +1085,10 @@ int main(int argc, char **argv)
}
}
else {
if (!SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE)) {
upslog_with_errno(LOG_ERR, "SetConsoleCtrlHandler failed, may ignore Ctrl+C");
}

SvcMain(argc, argv);
}

Expand Down
Loading