Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add net start/stop docs and practical support to nut.exe #2456

Merged
merged 5 commits into from
May 27, 2024
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
47 changes: 47 additions & 0 deletions docs/man/nut.exe.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,46 @@ UPS shutdown command in case of FSD handling, or for mere 'netclient' systems
it would run just the 'upsmon' client to monitor remote UPS device(s) and
initiate the OS shut down on the local Windows system as applicable.

Beside launching or stopping a set of the NUT programs in certain cases,
this helper program also allows to register (or un-register) itself as a
Windows service. To actually manage the service from command line you can
execute the Windows `net` command, e.g.:

----
net stop "Network UPS Tools"
net start "Network UPS Tools"
----

You can also execute `nut start` to automatically register the service
(if not yet registered) and start it, and `nut stop` to stop the service
(if registered and running).

Note that for a Windows machine to act as a NUT data server for further
clients, you may have to add Windows Firewall rules to allow incoming
connections (by default to port `3493/tcp`), e.g. using PowerShell to
elevate (alternately right-click a "Command Prompt" shortcut and select
"Run as administrator"), and execute `netsh` to actually configure the
needed "Advanced Firewall" rule:

----
REM Elevate to administrator status then run netsh to add firewall rule.
REM Recommended to adapt "LocalIP" to expected listeners of this server,
REM and "RemoteIP" to your single or comma-separated subnet(s) in CIDR
REM notation, specific client IP address(es), or ranges of address(es)
REM (dash-separated, as IP1-IP2).

REM The following goes as one long command line:

powershell.exe -Command "Start-Process netsh.exe -ArgumentList
\"advfirewall firewall add rule name=NUT-upsd-data-server
dir=in action=allow localip=ANY remoteip=ANY
program=%ProgramFiles%\NUT\sbin\upsd.exe
localport=3493 protocol=tcp\" -Verb RunAs"
----

Keep in mind that by default NUT `upsd` only listens on `localhost`, so
you would need to add some `LISTEN` directives in `upsd.conf` as well.

OPTIONS
-------

Expand Down Expand Up @@ -56,6 +96,13 @@ Uninstall the Windows service.
*-N*::
Run once in non-service mode (for troubleshooting).

*start*::
Install as a Windows service called "Network UPS Tools" (if not yet done),
and try to start this service.

*stop*::
Try to stop a Windows service called "Network UPS Tools".

DIAGNOSTICS
-----------

Expand Down
15 changes: 14 additions & 1 deletion docs/nut.dict
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
personal_ws-1.1 en 3151 utf-8
personal_ws-1.1 en 3165 utf-8
AAC
AAS
ABI
Expand Down Expand Up @@ -60,6 +60,7 @@ Antonino
Apodaca
AppData
AppVeyor
ArgumentList
Arjen
Arkadiusz
Armin
Expand Down Expand Up @@ -611,6 +612,7 @@ LineB
Lintian
ListClients
Lite's
LocalIP
LogMax
LogMin
LowBatt
Expand Down Expand Up @@ -907,6 +909,7 @@ PowerPS
PowerPal
PowerPanel
PowerShare
PowerShell
PowerShield
PowerSure
PowerTech
Expand All @@ -924,6 +927,7 @@ PresentStatus
Priv
ProductID
Progra
ProgramFiles
Proxmox
Prynych
Pulizzi
Expand Down Expand Up @@ -997,6 +1001,7 @@ Redhat
Regados
Reinholdtsen
Remi
RemoteIP
Remoting
Rene
René
Expand All @@ -1014,6 +1019,7 @@ Rodríguez
Rouben
Rozman
Rucelf
RunAs
RunUPSCommand
RxD
Ryabov
Expand Down Expand Up @@ -1405,6 +1411,7 @@ adm
admin's
adminbox
adoc
advfirewall
advorder
ae
aec
Expand Down Expand Up @@ -2204,6 +2211,8 @@ lnetsnmp
loadPercentage
localcalculation
localhost
localip
localport
localtime
lockf
logfacility
Expand Down Expand Up @@ -2350,6 +2359,7 @@ nds
netcat
netclient
netserver
netsh
netsnmp
netvision
networkupstools
Expand Down Expand Up @@ -2530,6 +2540,7 @@ powernet
poweroff
powerpal
powerpanel
powershell
powerup
powervalue
powerware
Expand Down Expand Up @@ -2610,6 +2621,7 @@ regtype
relatime
releasekeyring
relicensing
remoteip
renderer
renderers
repindex
Expand Down Expand Up @@ -2823,6 +2835,7 @@ sublicense
sublicenses
submodule
submodules
subnet
subtree
sudo
suid
Expand Down
81 changes: 76 additions & 5 deletions scripts/Windows/wininit.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/* wininit.c - MS Windows service which replace the init script
(compiled as "nut.exe")

Copyright (C)
2010 Frederic Bohe <fredericbohe@eaton.com>
Expand Down Expand Up @@ -423,6 +424,45 @@ static int SvcInstall(const char * SvcName, const char * args)
return EXIT_SUCCESS;
}

/* Returns a positive value if the service name exists
* -2 if we can not open the service manager
* -1 if we can not open the service itself
* +1 SvcName exists
*/
static int SvcExists(const char * SvcName)
{
SC_HANDLE SCManager;
SC_HANDLE Service;

SCManager = OpenSCManager(
NULL, /* local computer */
NULL, /* ServicesActive database */
SC_MANAGER_ALL_ACCESS); /* full access rights */

if (NULL == SCManager) {
upsdebugx(1, "OpenSCManager failed (%d)\n", (int)GetLastError());
return -2;
}

Service = OpenService(
SCManager, /* SCM database */
SvcName, /* name of service */
DELETE); /* need delete access */

if (Service == NULL) {
upsdebugx(1, "OpenService failed (%d) for \"%s\"\n",
(int)GetLastError(), SvcName);
CloseServiceHandle(SCManager);
return -1;
}

CloseServiceHandle(Service);
CloseServiceHandle(SCManager);

upsdebugx(1, "Service \"%s\" seems to exist", SvcName);
return 1;
}

static int SvcUninstall(const char * SvcName)
{
SC_HANDLE SCManager;
Expand Down Expand Up @@ -666,9 +706,14 @@ static void help(const char *arg_progname)

printf("NUT for Windows all-in-one wrapper for driver(s), data server and monitoring client\n");
printf("including shutdown and power-off handling (where supported). All together they rely\n");
printf("on nut.conf and other files in %s\n\n", confpath());
printf("on nut.conf and other files in %s\n", confpath());

printf("Usage: %s [OPTION]\n\n", arg_progname);
printf("\nUsage: %s {start | stop}\n\n", arg_progname);
printf(" start Install as a service (%s) if not yet done, then `net start` it\n", SVCNAME);
printf(" stop If the service (%s) is installed, command it to `net stop`\n", SVCNAME);
printf("Note you may have to run this in an elevated privilege command shell, or use `runas`\n");

printf("\nUsage: %s [OPTION]\n\n", arg_progname);

printf("Options (note minus not slash as the control character), one of:\n");
printf(" -I Install as a service (%s)\n", SVCNAME);
Expand All @@ -684,9 +729,35 @@ int main(int argc, char **argv)
int i, default_opterr = opterr;
const char *progname = xbasename(argc > 0 ? argv[0] : "nut.exe");

if (argc > 1 && !strcmp(argv[1], "/?")) {
help(progname);
return EXIT_SUCCESS;
if (argc > 1) {
if (!strcmp(argv[1], "/?")) {
help(progname);
return EXIT_SUCCESS;
}

if (!strcmp(argv[1], "stop")) {
int ret;
if (SvcExists(SVCNAME) < 0)
fprintf(stderr, "WARNING: Can not access service \"%s\"", SVCNAME);

ret = system("net stop \"" SVCNAME "\"");
if (ret == 0)
return EXIT_SUCCESS;
fatalx(EXIT_FAILURE, "FAILED stopping %s: %i", SVCNAME, ret);
}

if (!strcmp(argv[1], "start")) {
int ret;
if (SvcExists(SVCNAME) < 0) {
fprintf(stderr, "WARNING: Can not access service \"%s\", registering first", SVCNAME);
SvcInstall(SVCNAME, NULL);
}

ret = system("net start \"" SVCNAME "\"");
if (ret == 0)
return EXIT_SUCCESS;
fatalx(EXIT_FAILURE, "FAILED starting %s: %i", SVCNAME, ret);
}
}

/* TODO: Do not warn about unknown args - pass them to SvcMain()
Expand Down
Loading