diff --git a/common/common.c b/common/common.c index ef9e68f71e..9236cc0bbd 100644 --- a/common/common.c +++ b/common/common.c @@ -797,29 +797,24 @@ void open_syslog(const char *progname) #endif /* WIN32 */ } -/* close ttys and become a daemon */ -void background(void) +int background_fork(void) { - /* Normally we enable SYSLOG and disable STDERR, - * unless NUT_DEBUG_SYSLOG envvar interferes as - * interpreted in syslog_is_disabled() method: */ - int syslog_disabled = syslog_is_disabled(), - stderr_disabled = (syslog_disabled == 0 || syslog_disabled == 2); + int pid = 0; #ifndef WIN32 - int pid; - if ((pid = fork()) < 0) fatal_with_errno(EXIT_FAILURE, "Unable to enter background"); #endif /* !WIN32 */ - if (!syslog_disabled) - /* not disabled: NUT_DEBUG_SYSLOG is unset or invalid */ - xbit_set(&upslog_flags, UPSLOG_SYSLOG); - if (stderr_disabled) - /* NUT_DEBUG_SYSLOG="none" or unset/invalid */ - xbit_clear(&upslog_flags, UPSLOG_STDERR); + return pid; +} + +/* close ttys and become a daemon */ +void background(void) +{ + int pid; + pid = background_fork(); #ifndef WIN32 if (pid != 0) { /* parent */ @@ -829,8 +824,26 @@ void background(void) close(STDERR_FILENO); _exit(EXIT_SUCCESS); } +#else /* WIN32 */ + NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); +#endif /* WIN32 */ + background_child(); +} - /* child */ +void background_child(void) +{ + /* Normally we enable SYSLOG and disable STDERR, + * unless NUT_DEBUG_SYSLOG envvar interferes as + * interpreted in syslog_is_disabled() method: */ + int syslog_disabled = syslog_is_disabled(), + stderr_disabled = (syslog_disabled == 0 || syslog_disabled == 2); + + if (!syslog_disabled) + /* not disabled: NUT_DEBUG_SYSLOG is unset or invalid */ + xbit_set(&upslog_flags, UPSLOG_SYSLOG); + if (stderr_disabled) + /* NUT_DEBUG_SYSLOG="none" or unset/invalid */ + xbit_clear(&upslog_flags, UPSLOG_STDERR); /* make fds 0-2 (typically) point somewhere defined */ # ifdef HAVE_DUP2 @@ -887,9 +900,6 @@ void background(void) # ifdef HAVE_SETSID setsid(); /* make a new session to dodge signals */ # endif -#else /* WIN32 */ - NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE(); -#endif /* WIN32 */ upslogx(LOG_INFO, "Startup successful: %s", getmyprocbasename()); } diff --git a/drivers/main.c b/drivers/main.c index 6845ab0a8f..8465ad3ff1 100644 --- a/drivers/main.c +++ b/drivers/main.c @@ -2184,6 +2184,7 @@ int main(int argc, char **argv) struct passwd *new_uid = NULL; int opt_ret = 0, do_forceshutdown = 0, i; int update_count = 0; + int background_pipefd[2]; # ifndef WIN32 int cmd = 0; @@ -2995,6 +2996,31 @@ int main(int argc, char **argv) * when its a pdu! */ dstate_setinfo("device.type", "ups"); + if (foreground == 0) { + /* start backgrounding */ + int ret, pid; + + ret = pipe(background_pipefd); + if (ret) + fatal_with_errno(EXIT_FAILURE, "pipe creation failed"); + + pid = background_fork(); + if (pid > 0) { + /* parent: wait for child to send success or exit */ + char ch; + + close(background_pipefd[1]); + // Wait for child + ret = read(background_pipefd[0], &ch, 1); + + close(background_pipefd[0]); + close(STDIN_FILENO); + close(STDOUT_FILENO); + close(STDERR_FILENO); + _exit(ret == 1 ? EXIT_SUCCESS : EXIT_FAILURE); + } + } + dstate_setinfo("driver.state", "init.device"); upsdrv_callbacks.upsdrv_initups(); dstate_setinfo("driver.state", "init.quiet"); @@ -3192,11 +3218,19 @@ int main(int argc, char **argv) switch (foreground) { case 0: - background(); /* We had saved a PID before backgrounding, but * it changes when backgrounding - so save again */ writepid(pidfn); + + /* close handles */ + background_child(); + + /* notify parent of success */ + i = write(background_pipefd[1], "G", 1); + if (i < 1) + upslogx(LOG_ERR, "Unable to call parent pipe for shutdown"); + close(background_pipefd[1]); break; /* >0: Keep the initial PID; don't care about "!dump_data" here diff --git a/drivers/usbhid-ups.c b/drivers/usbhid-ups.c index 990cffcd11..ae80a68bd5 100644 --- a/drivers/usbhid-ups.c +++ b/drivers/usbhid-ups.c @@ -1971,9 +1971,13 @@ void upsdrv_cleanup(void) comm_driver->close_dev(udev); Free_ReportDesc(pDesc); free_report_buffer(reportbuf); + pDesc = NULL; + reportbuf = NULL; #if !((defined SHUT_MODE) && SHUT_MODE) USBFreeExactMatcher(exact_matcher); USBFreeRegexMatcher(regex_matcher); + exact_matcher = NULL; + regex_matcher = NULL; free(curDevice.Vendor); free(curDevice.Product); @@ -1983,6 +1987,7 @@ void upsdrv_cleanup(void) # if (defined WITH_USB_BUSPORT) && (WITH_USB_BUSPORT) free(curDevice.BusPort); # endif + memset(&curDevice, '\0', sizeof(curDevice)); #endif /* !SHUT_MODE => USB */ } diff --git a/include/common.h b/include/common.h index d493ac7565..86e2721608 100644 --- a/include/common.h +++ b/include/common.h @@ -286,6 +286,10 @@ void open_syslog(const char *progname); /* close ttys and become a daemon */ void background(void); +/* Support functions for backgrounding */ +int background_fork(void); +void background_child(void); + /* allow tagging the (forked) process in logs to ease debugging */ const char *getproctag(void); /* save a copy of tag, or call with NULL to clean and free the internal buffer;