init_command_task(cmd_task);
if (conf.daemon_given)
- daemonize();
+ daemonize(false /* parent exits immediately */);
register_task(&sig_task->task);
register_task(&cmd_task->task);
return me->flags & flag;
}
+static void dummy_sighandler(__a_unused int s)
+{
+}
+
/**
* Do the usual stuff to become a daemon.
*
- * Fork, become session leader, dup fd 0, 1, 2 to /dev/null.
+ * \param parent_waits Whether the parent process should pause before exit.
*
- * \sa fork(2), setsid(2), dup(2).
+ * Fork, become session leader, cd to /, and dup fd 0, 1, 2 to /dev/null. If \a
+ * parent_waits is false, the parent process terminates immediately.
+ * Otherwise, it calls pause() to sleep until it receives \p SIGTERM or \p
+ * SIGCHLD and exits successfully thereafter. This behaviour is useful if the
+ * daemon process should not detach from the console until the child process
+ * has completed its setup.
+ *
+ * \sa fork(2), setsid(2), dup(2), pause(2).
*/
-void daemonize(void)
+void daemonize(bool parent_waits)
{
pid_t pid;
int null;
pid = fork();
if (pid < 0)
goto err;
- if (pid)
+ if (pid) {
+ if (parent_waits) {
+ signal(SIGTERM, dummy_sighandler);
+ signal(SIGCHLD, dummy_sighandler);
+ pause();
+ }
exit(EXIT_SUCCESS); /* parent exits */
+ }
/* become session leader */
if (setsid() < 0)
goto err;
/** \file daemon.h exported symbols from daemon.c */
-void daemonize(void);
+void daemonize(bool parent_waits);
void daemon_open_log_or_die(void);
void daemon_close_log(void);
void log_welcome(const char *whoami);
init_user_list(user_list_file);
/* become daemon */
if (conf.daemon_given)
- daemonize();
+ daemonize(true /* parent waits for SIGTERM */);
PARA_NOTICE_LOG("initializing audio format handlers\n");
afh_init();
PARA_NOTICE_LOG("initializing virtual streaming system\n");
init_vss_task(afs_socket);
init_server_command_task(argc, argv);
+ if (conf.daemon_given)
+ kill(getppid(), SIGTERM);
PARA_NOTICE_LOG("server init complete\n");
}