Skip to content

Commit f8962ee

Browse files
committed
drivers/main.c: Split backgrounding driver into two stages
This is needed in particular with libusb on linux as it will create a thread to handle either netlink or udev messages. If this is created before we background, the driver will hang during exit trying to join the non-existant thread in the new process. Shows this warning while stopping the driver. Stopping /run/nut/usbhid-ups-xxxx.pid failed, retrying harder: Success Signed-off-by: Doug Nazar <nazard@nazar.ca>
1 parent 85235ee commit f8962ee

3 files changed

Lines changed: 74 additions & 16 deletions

File tree

common/common.c

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -797,30 +797,25 @@ void open_syslog(const char *progname)
797797
#endif /* WIN32 */
798798
}
799799

800-
/* close ttys and become a daemon */
801-
void background(void)
800+
int background_fork(void)
802801
{
803-
/* Normally we enable SYSLOG and disable STDERR,
804-
* unless NUT_DEBUG_SYSLOG envvar interferes as
805-
* interpreted in syslog_is_disabled() method: */
806-
int syslog_disabled = syslog_is_disabled(),
807-
stderr_disabled = (syslog_disabled == 0 || syslog_disabled == 2);
802+
int pid = 0;
808803

809804
#ifndef WIN32
810-
int pid;
811-
812805
if ((pid = fork()) < 0)
813806
fatal_with_errno(EXIT_FAILURE, "Unable to enter background");
814807
#endif /* !WIN32 */
815808

816-
if (!syslog_disabled)
817-
/* not disabled: NUT_DEBUG_SYSLOG is unset or invalid */
818-
xbit_set(&upslog_flags, UPSLOG_SYSLOG);
819-
if (stderr_disabled)
820-
/* NUT_DEBUG_SYSLOG="none" or unset/invalid */
821-
xbit_clear(&upslog_flags, UPSLOG_STDERR);
809+
return pid;
810+
}
822811

812+
/* close ttys and become a daemon */
813+
void background(void)
814+
{
823815
#ifndef WIN32
816+
int pid;
817+
818+
pid = background_fork();
824819
if (pid != 0) {
825820
/* parent */
826821
/* these are typically fds 0-2: */
@@ -829,9 +824,28 @@ void background(void)
829824
close(STDERR_FILENO);
830825
_exit(EXIT_SUCCESS);
831826
}
827+
#else /* WIN32 */
828+
NUT_WIN32_INCOMPLETE_MAYBE_NOT_APPLICABLE();
829+
#endif /* WIN32 */
830+
background_child();
831+
}
832+
833+
void background_child(void)
834+
{
835+
/* Normally we enable SYSLOG and disable STDERR,
836+
* unless NUT_DEBUG_SYSLOG envvar interferes as
837+
* interpreted in syslog_is_disabled() method: */
838+
int syslog_disabled = syslog_is_disabled(),
839+
stderr_disabled = (syslog_disabled == 0 || syslog_disabled == 2);
832840

833-
/* child */
841+
if (!syslog_disabled)
842+
/* not disabled: NUT_DEBUG_SYSLOG is unset or invalid */
843+
xbit_set(&upslog_flags, UPSLOG_SYSLOG);
844+
if (stderr_disabled)
845+
/* NUT_DEBUG_SYSLOG="none" or unset/invalid */
846+
xbit_clear(&upslog_flags, UPSLOG_STDERR);
834847

848+
#ifndef WIN32
835849
/* make fds 0-2 (typically) point somewhere defined */
836850
# ifdef HAVE_DUP2
837851
/* system can close (if needed) and (re-)open a specific FD number */

drivers/main.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2188,6 +2188,7 @@ int main(int argc, char **argv)
21882188
# ifndef WIN32
21892189
int cmd = 0;
21902190
pid_t oldpid = -1;
2191+
int background_pipefd[2];
21912192
# else /* WIN32 */
21922193
/* FIXME NUT_WIN32_INCOMPLETE : *actually* handle WIN32 builds too */
21932194
const char * cmd = NULL;
@@ -2995,6 +2996,33 @@ int main(int argc, char **argv)
29952996
* when its a pdu! */
29962997
dstate_setinfo("device.type", "ups");
29972998

2999+
#ifndef WIN32
3000+
if (foreground == 0) {
3001+
/* start backgrounding */
3002+
int ret, pid;
3003+
3004+
ret = pipe(background_pipefd);
3005+
if (ret)
3006+
fatal_with_errno(EXIT_FAILURE, "pipe creation failed");
3007+
3008+
pid = background_fork();
3009+
if (pid > 0) {
3010+
/* parent: wait for child to send success or exit */
3011+
char ch;
3012+
3013+
close(background_pipefd[1]);
3014+
// Wait for child
3015+
ret = read(background_pipefd[0], &ch, 1);
3016+
3017+
close(background_pipefd[0]);
3018+
close(STDIN_FILENO);
3019+
close(STDOUT_FILENO);
3020+
close(STDERR_FILENO);
3021+
_exit(ret == 1 ? EXIT_SUCCESS : EXIT_FAILURE);
3022+
}
3023+
}
3024+
#endif
3025+
29983026
dstate_setinfo("driver.state", "init.device");
29993027
upsdrv_callbacks.upsdrv_initups();
30003028
dstate_setinfo("driver.state", "init.quiet");
@@ -3192,11 +3220,23 @@ int main(int argc, char **argv)
31923220

31933221
switch (foreground) {
31943222
case 0:
3223+
#ifndef WIN32
3224+
/* close handles */
3225+
background_child();
3226+
3227+
/* notify parent of success */
3228+
i = write(background_pipefd[1], "G", 1);
3229+
if (i < 1)
3230+
upslogx(LOG_ERR, "Unable to call parent pipe for shutdown");
3231+
close(background_pipefd[1]);
3232+
#else
31953233
background();
3234+
#endif
31963235
/* We had saved a PID before backgrounding, but
31973236
* it changes when backgrounding - so save again
31983237
*/
31993238
writepid(pidfn);
3239+
32003240
break;
32013241

32023242
/* >0: Keep the initial PID; don't care about "!dump_data" here

include/common.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,10 @@ void open_syslog(const char *progname);
286286
/* close ttys and become a daemon */
287287
void background(void);
288288

289+
/* Support functions for backgrounding */
290+
int background_fork(void);
291+
void background_child(void);
292+
289293
/* allow tagging the (forked) process in logs to ease debugging */
290294
const char *getproctag(void);
291295
/* save a copy of tag, or call with NULL to clean and free the internal buffer;

0 commit comments

Comments
 (0)