Skip to content

Commit 1b9d2ed

Browse files
committed
drivers/upsdrvctl.c: refactor with forkexec_parent_analyze() and a re-check before retry - also for WIN32
Also revised WaitForSingleObject() result checking - there has to be a chance to succeed ;) Signed-off-by: Jim Klimov <jimklimov+nut@gmail.com>
1 parent 5212847 commit 1b9d2ed

1 file changed

Lines changed: 57 additions & 34 deletions

File tree

drivers/upsdrvctl.c

Lines changed: 57 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ typedef struct {
5454
pid_t pid;
5555
#else /* WIN32 */
5656
int pid; /* for WIN32 used just as a flag that this UPS was started by this tool in this run */
57+
PROCESS_INFORMATION ProcessInformation;
5758
#endif /* WIN32 */
5859
void *next;
5960
} ups_t;
@@ -807,12 +808,24 @@ static void debugcmdline(int level, const char *msg, char *const argv[])
807808
}
808809

809810
#ifndef WIN32
810-
static int forkexec_parent_analyze(pid_t waitret, int wstat, int *puexectimeout)
811+
static int forkexec_parent_analyze(pid_t waitret, int wstat, const ups_t *ups)
812+
#else
813+
static int forkexec_parent_analyze(DWORD res, const ups_t *ups)
814+
#endif
811815
{
816+
/* work around const for this one... */
817+
#ifdef WIN32
818+
int *pupid = (int *)&(ups->pid);
819+
#endif
820+
int *puexectimeout = (int *)&(ups->exceeded_timeout);
821+
822+
*puexectimeout = 0;
823+
824+
#ifndef WIN32
812825
if (waitret == -1) {
813826
upslogx(LOG_WARNING, "Startup timer elapsed, continuing...");
814827
exec_timeout++;
815-
if (puexectimeout) *puexectimeout = 1;
828+
*puexectimeout = 1;
816829
return 0;
817830
}
818831

@@ -838,10 +851,28 @@ static int forkexec_parent_analyze(pid_t waitret, int wstat, int *puexectimeout)
838851
return -3;
839852
}
840853

841-
if (puexectimeout) *puexectimeout = 0;
854+
#else /* WIN32 */
855+
856+
if (res == WAIT_OBJECT_0) {
857+
/* all ok, no-op */
858+
} else
859+
if (res == WAIT_TIMEOUT) {
860+
upslogx(LOG_WARNING, "Startup timer elapsed, continuing...");
861+
*pupid = 0; /* For WIN32, just a flag (not "-1" has a meaning) */
862+
*puexectimeout = 1;
863+
return 0;
864+
} else {
865+
DWORD exit_code = 0;
866+
GetExitCodeProcess( ups->ProcessInformation.hProcess, &exit_code );
867+
upslogx(LOG_WARNING, "Driver failed to start (exit status=%d)", exit_code);
868+
exec_error++;
869+
return -2;
870+
}
871+
#endif /* WIN32 */
872+
873+
upsdebugx(3, "%s: startup seems successful", __func__);
842874
return 1;
843875
}
844-
#endif /* WIN32 */
845876

846877
static void forkexec(char *const argv[], const ups_t *ups)
847878
{
@@ -943,7 +974,7 @@ static void forkexec(char *const argv[], const ups_t *ups)
943974
alarm(0);
944975

945976
/* Bump timeout or error counts if appropriate */
946-
forkexec_parent_analyze(waitret, wstat, puexectimeout);
977+
forkexec_parent_analyze(waitret, wstat, ups);
947978

948979
return;
949980
} /* end of pid != 0 (fork parent) part */
@@ -970,13 +1001,14 @@ static void forkexec(char *const argv[], const ups_t *ups)
9701001
#else /* WIN32 */
9711002
BOOL ret;
9721003
DWORD res;
973-
DWORD exit_code = 0;
9741004
char commandline[LARGEBUF];
9751005
STARTUPINFO StartupInfo;
976-
PROCESS_INFORMATION ProcessInformation;
1006+
/* work around const for this one... */
1007+
PROCESS_INFORMATION *pProcessInformation = (PROCESS_INFORMATION*)&(ups->ProcessInformation);
9771008
int i = 1, waited = 0;
9781009

9791010
memset(&StartupInfo, 0, sizeof(STARTUPINFO));
1011+
memset(pProcessInformation, 0, sizeof(PROCESS_INFORMATION));
9801012

9811013
/* the command line is made of the driver name followed by args */
9821014
if (strstr(argv[0], ups->driver)) {
@@ -1014,16 +1046,18 @@ static void forkexec(char *const argv[], const ups_t *ups)
10141046
NULL,
10151047
NULL,
10161048
&StartupInfo,
1017-
&ProcessInformation
1049+
pProcessInformation
10181050
);
10191051

1020-
if (ret == 0) {
1052+
if (!ret) {
10211053
fatal_with_errno(EXIT_FAILURE, "execv");
10221054
}
10231055

10241056
/* Wait a bit then look at driver process.
1025-
* Unlike under Linux, Windows spawn drivers directly. If the driver is alive, all is OK.
1026-
* An optimization can probably be implemented to prevent waiting so much time when all is OK.
1057+
* Unlike under Linux, Windows spawn drivers directly.
1058+
* If the driver is alive, all is OK.
1059+
* An optimization can probably be implemented
1060+
* to prevent waiting so much time when all is OK.
10271061
*/
10281062

10291063
/* Use the local maxstartdelay, if available */
@@ -1033,7 +1067,7 @@ static void forkexec(char *const argv[], const ups_t *ups)
10331067
"to check that driver survived this long "
10341068
"(per device configuration section)",
10351069
__func__, (unsigned int)ups->maxstartdelay);
1036-
res = WaitForSingleObject(ProcessInformation.hProcess,
1070+
res = WaitForSingleObject(pProcessInformation->hProcess,
10371071
((unsigned int)ups->maxstartdelay) * 1000);
10381072
waited = 1;
10391073
}
@@ -1043,7 +1077,7 @@ static void forkexec(char *const argv[], const ups_t *ups)
10431077
"to check that driver survived this long "
10441078
"(per global configuration section)",
10451079
__func__, (unsigned int)maxstartdelay);
1046-
res = WaitForSingleObject(ProcessInformation.hProcess,
1080+
res = WaitForSingleObject(pProcessInformation->hProcess,
10471081
((unsigned int)maxstartdelay) * 1000);
10481082
waited = 1;
10491083
}
@@ -1054,22 +1088,11 @@ static void forkexec(char *const argv[], const ups_t *ups)
10541088
"to check that driver survived this long "
10551089
"(not required by global nor by device "
10561090
"configuration sections)", __func__);
1057-
res = WaitForSingleObject(ProcessInformation.hProcess,
1091+
res = WaitForSingleObject(pProcessInformation->hProcess,
10581092
0);
10591093
}
10601094

1061-
if (res != WAIT_TIMEOUT) {
1062-
GetExitCodeProcess( ProcessInformation.hProcess, &exit_code );
1063-
upslogx(LOG_WARNING, "Driver failed to start (exit status=%d)", ret);
1064-
exec_error++;
1065-
return;
1066-
} else {
1067-
/* work around const for this one... */
1068-
int *pupid = (int *)&(ups->pid);
1069-
int *puexectimeout = (int *)&(ups->exceeded_timeout);
1070-
*pupid = 0; /* For WIN32, just a flag (not "-1" has a meaning) */
1071-
*puexectimeout = 1;
1072-
}
1095+
forkexec_parent_analyze(res, ups);
10731096

10741097
return;
10751098
#endif /* WIN32 */
@@ -1447,22 +1470,23 @@ static void start_driver(const ups_t *ups)
14471470
/* otherwise, retry if still needed */
14481471
if (drv_maxretry > 0)
14491472
if (drv_retrydelay >= 0) {
1450-
#ifndef WIN32
1451-
int *puexectimeout = (int *)&(ups->exceeded_timeout);
1452-
#endif
1453-
14541473
upsdebugx(3, "%s: retrying after %u seconds",
14551474
__func__, (unsigned int)drv_retrydelay);
14561475
sleep ((unsigned int)drv_retrydelay);
14571476

1477+
if (upscount > 1 && ups->exceeded_timeout) {
1478+
/* Final checks, similar to those in forkexec() */
14581479
#ifndef WIN32
1459-
if (upscount > 1 && *puexectimeout) {
14601480
int wstat;
14611481
pid_t waitret;
14621482

1463-
/* Final checks, similar to those in forkexec() */
14641483
waitret = waitpid(ups->pid, &wstat, WNOHANG);
1465-
if (forkexec_parent_analyze(waitret, wstat, puexectimeout) > 0) {
1484+
if (forkexec_parent_analyze(waitret, wstat, ups) > 0)
1485+
#else
1486+
DWORD res = WaitForSingleObject(ups->ProcessInformation->hProcess, 0);
1487+
if (forkexec_parent_analyze(res, ups))
1488+
#endif
1489+
{
14661490
upslogx(LOG_INFO, "%s: driver %s [%s] completed startup "
14671491
"while we were sleeping to retry", __func__,
14681492
ups->driver, ups->upsname);
@@ -1471,7 +1495,6 @@ static void start_driver(const ups_t *ups)
14711495
exec_timeout = initial_exec_timeout;
14721496
}
14731497
}
1474-
#endif
14751498

14761499
}
14771500
}

0 commit comments

Comments
 (0)